2 * exynos-nocp.c - EXYNOS NoC (Network On Chip) Probe support
4 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
5 * Author : Chanwoo Choi <cw00.choi@samsung.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
12 #include <linux/clk.h>
13 #include <linux/module.h>
14 #include <linux/devfreq-event.h>
15 #include <linux/kernel.h>
16 #include <linux/of_address.h>
17 #include <linux/platform_device.h>
18 #include <linux/regmap.h>
20 #include "exynos-nocp.h"
23 struct devfreq_event_dev
*edev
;
24 struct devfreq_event_desc desc
;
28 struct regmap
*regmap
;
33 * The devfreq-event ops structure for nocp probe.
35 static int exynos_nocp_set_event(struct devfreq_event_dev
*edev
)
37 struct exynos_nocp
*nocp
= devfreq_event_get_drvdata(edev
);
40 /* Disable NoC probe */
41 ret
= regmap_update_bits(nocp
->regmap
, NOCP_MAIN_CTL
,
42 NOCP_MAIN_CTL_STATEN_MASK
, 0);
44 dev_err(nocp
->dev
, "failed to disable the NoC probe device\n");
48 /* Set a statistics dump period to 0 */
49 ret
= regmap_write(nocp
->regmap
, NOCP_STAT_PERIOD
, 0x0);
53 /* Set the IntEvent fields of *_SRC */
54 ret
= regmap_update_bits(nocp
->regmap
, NOCP_COUNTERS_0_SRC
,
55 NOCP_CNT_SRC_INTEVENT_MASK
,
56 NOCP_CNT_SRC_INTEVENT_BYTE_MASK
);
60 ret
= regmap_update_bits(nocp
->regmap
, NOCP_COUNTERS_1_SRC
,
61 NOCP_CNT_SRC_INTEVENT_MASK
,
62 NOCP_CNT_SRC_INTEVENT_CHAIN_MASK
);
66 ret
= regmap_update_bits(nocp
->regmap
, NOCP_COUNTERS_2_SRC
,
67 NOCP_CNT_SRC_INTEVENT_MASK
,
68 NOCP_CNT_SRC_INTEVENT_CYCLE_MASK
);
72 ret
= regmap_update_bits(nocp
->regmap
, NOCP_COUNTERS_3_SRC
,
73 NOCP_CNT_SRC_INTEVENT_MASK
,
74 NOCP_CNT_SRC_INTEVENT_CHAIN_MASK
);
79 /* Set an alarm with a max/min value of 0 to generate StatALARM */
80 ret
= regmap_write(nocp
->regmap
, NOCP_STAT_ALARM_MIN
, 0x0);
84 ret
= regmap_write(nocp
->regmap
, NOCP_STAT_ALARM_MAX
, 0x0);
89 ret
= regmap_update_bits(nocp
->regmap
, NOCP_COUNTERS_0_ALARM_MODE
,
90 NOCP_CNT_ALARM_MODE_MASK
,
91 NOCP_CNT_ALARM_MODE_MIN_MAX_MASK
);
95 ret
= regmap_update_bits(nocp
->regmap
, NOCP_COUNTERS_1_ALARM_MODE
,
96 NOCP_CNT_ALARM_MODE_MASK
,
97 NOCP_CNT_ALARM_MODE_MIN_MAX_MASK
);
101 ret
= regmap_update_bits(nocp
->regmap
, NOCP_COUNTERS_2_ALARM_MODE
,
102 NOCP_CNT_ALARM_MODE_MASK
,
103 NOCP_CNT_ALARM_MODE_MIN_MAX_MASK
);
107 ret
= regmap_update_bits(nocp
->regmap
, NOCP_COUNTERS_3_ALARM_MODE
,
108 NOCP_CNT_ALARM_MODE_MASK
,
109 NOCP_CNT_ALARM_MODE_MIN_MAX_MASK
);
113 /* Enable the measurements by setting AlarmEn and StatEn */
114 ret
= regmap_update_bits(nocp
->regmap
, NOCP_MAIN_CTL
,
115 NOCP_MAIN_CTL_STATEN_MASK
| NOCP_MAIN_CTL_ALARMEN_MASK
,
116 NOCP_MAIN_CTL_STATEN_MASK
| NOCP_MAIN_CTL_ALARMEN_MASK
);
121 ret
= regmap_update_bits(nocp
->regmap
, NOCP_CFG_CTL
,
122 NOCP_CFG_CTL_GLOBALEN_MASK
,
123 NOCP_CFG_CTL_GLOBALEN_MASK
);
127 /* Enable NoC probe */
128 ret
= regmap_update_bits(nocp
->regmap
, NOCP_MAIN_CTL
,
129 NOCP_MAIN_CTL_STATEN_MASK
,
130 NOCP_MAIN_CTL_STATEN_MASK
);
137 /* Reset NoC probe */
138 if (regmap_update_bits(nocp
->regmap
, NOCP_MAIN_CTL
,
139 NOCP_MAIN_CTL_STATEN_MASK
, 0)) {
140 dev_err(nocp
->dev
, "Failed to reset NoC probe device\n");
146 static int exynos_nocp_get_event(struct devfreq_event_dev
*edev
,
147 struct devfreq_event_data
*edata
)
149 struct exynos_nocp
*nocp
= devfreq_event_get_drvdata(edev
);
150 unsigned int counter
[4];
153 /* Read cycle count */
154 ret
= regmap_read(nocp
->regmap
, NOCP_COUNTERS_0_VAL
, &counter
[0]);
158 ret
= regmap_read(nocp
->regmap
, NOCP_COUNTERS_1_VAL
, &counter
[1]);
162 ret
= regmap_read(nocp
->regmap
, NOCP_COUNTERS_2_VAL
, &counter
[2]);
166 ret
= regmap_read(nocp
->regmap
, NOCP_COUNTERS_3_VAL
, &counter
[3]);
170 edata
->load_count
= ((counter
[1] << 16) | counter
[0]);
171 edata
->total_count
= ((counter
[3] << 16) | counter
[2]);
173 dev_dbg(&edev
->dev
, "%s (event: %ld/%ld)\n", edev
->desc
->name
,
174 edata
->load_count
, edata
->total_count
);
179 dev_err(nocp
->dev
, "Failed to read the counter of NoC probe device\n");
184 static const struct devfreq_event_ops exynos_nocp_ops
= {
185 .set_event
= exynos_nocp_set_event
,
186 .get_event
= exynos_nocp_get_event
,
189 static const struct of_device_id exynos_nocp_id_match
[] = {
190 { .compatible
= "samsung,exynos5420-nocp", },
193 MODULE_DEVICE_TABLE(of
, exynos_nocp_id_match
);
195 static struct regmap_config exynos_nocp_regmap_config
= {
199 .max_register
= NOCP_COUNTERS_3_VAL
,
202 static int exynos_nocp_parse_dt(struct platform_device
*pdev
,
203 struct exynos_nocp
*nocp
)
205 struct device
*dev
= nocp
->dev
;
206 struct device_node
*np
= dev
->of_node
;
207 struct resource
*res
;
211 dev_err(dev
, "failed to find devicetree node\n");
215 nocp
->clk
= devm_clk_get(dev
, "nocp");
216 if (IS_ERR(nocp
->clk
))
219 /* Maps the memory mapped IO to control nocp register */
220 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
221 base
= devm_ioremap_resource(dev
, res
);
223 return PTR_ERR(base
);
225 exynos_nocp_regmap_config
.max_register
= resource_size(res
) - 4;
227 nocp
->regmap
= devm_regmap_init_mmio(dev
, base
,
228 &exynos_nocp_regmap_config
);
229 if (IS_ERR(nocp
->regmap
)) {
230 dev_err(dev
, "failed to initialize regmap\n");
231 return PTR_ERR(nocp
->regmap
);
237 static int exynos_nocp_probe(struct platform_device
*pdev
)
239 struct device
*dev
= &pdev
->dev
;
240 struct device_node
*np
= dev
->of_node
;
241 struct exynos_nocp
*nocp
;
244 nocp
= devm_kzalloc(&pdev
->dev
, sizeof(*nocp
), GFP_KERNEL
);
248 nocp
->dev
= &pdev
->dev
;
250 /* Parse dt data to get resource */
251 ret
= exynos_nocp_parse_dt(pdev
, nocp
);
254 "failed to parse devicetree for resource\n");
258 /* Add devfreq-event device to measure the bandwidth of NoC */
259 nocp
->desc
.ops
= &exynos_nocp_ops
;
260 nocp
->desc
.driver_data
= nocp
;
261 nocp
->desc
.name
= np
->full_name
;
262 nocp
->edev
= devm_devfreq_event_add_edev(&pdev
->dev
, &nocp
->desc
);
263 if (IS_ERR(nocp
->edev
)) {
265 "failed to add devfreq-event device\n");
266 return PTR_ERR(nocp
->edev
);
268 platform_set_drvdata(pdev
, nocp
);
270 clk_prepare_enable(nocp
->clk
);
272 pr_info("exynos-nocp: new NoC Probe device registered: %s\n",
278 static int exynos_nocp_remove(struct platform_device
*pdev
)
280 struct exynos_nocp
*nocp
= platform_get_drvdata(pdev
);
282 clk_disable_unprepare(nocp
->clk
);
287 static struct platform_driver exynos_nocp_driver
= {
288 .probe
= exynos_nocp_probe
,
289 .remove
= exynos_nocp_remove
,
291 .name
= "exynos-nocp",
292 .of_match_table
= exynos_nocp_id_match
,
295 module_platform_driver(exynos_nocp_driver
);
297 MODULE_DESCRIPTION("Exynos NoC (Network on Chip) Probe driver");
298 MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
299 MODULE_LICENSE("GPL");