1 // SPDX-License-Identifier: GPL-2.0-only
3 * exynos-nocp.c - Exynos NoC (Network On Chip) Probe support
5 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
6 * Author : Chanwoo Choi <cw00.choi@samsung.com>
10 #include <linux/module.h>
11 #include <linux/devfreq-event.h>
12 #include <linux/kernel.h>
13 #include <linux/of_address.h>
14 #include <linux/platform_device.h>
15 #include <linux/regmap.h>
17 #include "exynos-nocp.h"
20 struct devfreq_event_dev
*edev
;
21 struct devfreq_event_desc desc
;
25 struct regmap
*regmap
;
30 * The devfreq-event ops structure for nocp probe.
32 static int exynos_nocp_set_event(struct devfreq_event_dev
*edev
)
34 struct exynos_nocp
*nocp
= devfreq_event_get_drvdata(edev
);
37 /* Disable NoC probe */
38 ret
= regmap_update_bits(nocp
->regmap
, NOCP_MAIN_CTL
,
39 NOCP_MAIN_CTL_STATEN_MASK
, 0);
41 dev_err(nocp
->dev
, "failed to disable the NoC probe device\n");
45 /* Set a statistics dump period to 0 */
46 ret
= regmap_write(nocp
->regmap
, NOCP_STAT_PERIOD
, 0x0);
50 /* Set the IntEvent fields of *_SRC */
51 ret
= regmap_update_bits(nocp
->regmap
, NOCP_COUNTERS_0_SRC
,
52 NOCP_CNT_SRC_INTEVENT_MASK
,
53 NOCP_CNT_SRC_INTEVENT_BYTE_MASK
);
57 ret
= regmap_update_bits(nocp
->regmap
, NOCP_COUNTERS_1_SRC
,
58 NOCP_CNT_SRC_INTEVENT_MASK
,
59 NOCP_CNT_SRC_INTEVENT_CHAIN_MASK
);
63 ret
= regmap_update_bits(nocp
->regmap
, NOCP_COUNTERS_2_SRC
,
64 NOCP_CNT_SRC_INTEVENT_MASK
,
65 NOCP_CNT_SRC_INTEVENT_CYCLE_MASK
);
69 ret
= regmap_update_bits(nocp
->regmap
, NOCP_COUNTERS_3_SRC
,
70 NOCP_CNT_SRC_INTEVENT_MASK
,
71 NOCP_CNT_SRC_INTEVENT_CHAIN_MASK
);
76 /* Set an alarm with a max/min value of 0 to generate StatALARM */
77 ret
= regmap_write(nocp
->regmap
, NOCP_STAT_ALARM_MIN
, 0x0);
81 ret
= regmap_write(nocp
->regmap
, NOCP_STAT_ALARM_MAX
, 0x0);
86 ret
= regmap_update_bits(nocp
->regmap
, NOCP_COUNTERS_0_ALARM_MODE
,
87 NOCP_CNT_ALARM_MODE_MASK
,
88 NOCP_CNT_ALARM_MODE_MIN_MAX_MASK
);
92 ret
= regmap_update_bits(nocp
->regmap
, NOCP_COUNTERS_1_ALARM_MODE
,
93 NOCP_CNT_ALARM_MODE_MASK
,
94 NOCP_CNT_ALARM_MODE_MIN_MAX_MASK
);
98 ret
= regmap_update_bits(nocp
->regmap
, NOCP_COUNTERS_2_ALARM_MODE
,
99 NOCP_CNT_ALARM_MODE_MASK
,
100 NOCP_CNT_ALARM_MODE_MIN_MAX_MASK
);
104 ret
= regmap_update_bits(nocp
->regmap
, NOCP_COUNTERS_3_ALARM_MODE
,
105 NOCP_CNT_ALARM_MODE_MASK
,
106 NOCP_CNT_ALARM_MODE_MIN_MAX_MASK
);
110 /* Enable the measurements by setting AlarmEn and StatEn */
111 ret
= regmap_update_bits(nocp
->regmap
, NOCP_MAIN_CTL
,
112 NOCP_MAIN_CTL_STATEN_MASK
| NOCP_MAIN_CTL_ALARMEN_MASK
,
113 NOCP_MAIN_CTL_STATEN_MASK
| NOCP_MAIN_CTL_ALARMEN_MASK
);
118 ret
= regmap_update_bits(nocp
->regmap
, NOCP_CFG_CTL
,
119 NOCP_CFG_CTL_GLOBALEN_MASK
,
120 NOCP_CFG_CTL_GLOBALEN_MASK
);
124 /* Enable NoC probe */
125 ret
= regmap_update_bits(nocp
->regmap
, NOCP_MAIN_CTL
,
126 NOCP_MAIN_CTL_STATEN_MASK
,
127 NOCP_MAIN_CTL_STATEN_MASK
);
134 /* Reset NoC probe */
135 if (regmap_update_bits(nocp
->regmap
, NOCP_MAIN_CTL
,
136 NOCP_MAIN_CTL_STATEN_MASK
, 0)) {
137 dev_err(nocp
->dev
, "Failed to reset NoC probe device\n");
143 static int exynos_nocp_get_event(struct devfreq_event_dev
*edev
,
144 struct devfreq_event_data
*edata
)
146 struct exynos_nocp
*nocp
= devfreq_event_get_drvdata(edev
);
147 unsigned int counter
[4];
150 /* Read cycle count */
151 ret
= regmap_read(nocp
->regmap
, NOCP_COUNTERS_0_VAL
, &counter
[0]);
155 ret
= regmap_read(nocp
->regmap
, NOCP_COUNTERS_1_VAL
, &counter
[1]);
159 ret
= regmap_read(nocp
->regmap
, NOCP_COUNTERS_2_VAL
, &counter
[2]);
163 ret
= regmap_read(nocp
->regmap
, NOCP_COUNTERS_3_VAL
, &counter
[3]);
167 edata
->load_count
= ((counter
[1] << 16) | counter
[0]);
168 edata
->total_count
= ((counter
[3] << 16) | counter
[2]);
170 dev_dbg(&edev
->dev
, "%s (event: %ld/%ld)\n", edev
->desc
->name
,
171 edata
->load_count
, edata
->total_count
);
176 dev_err(nocp
->dev
, "Failed to read the counter of NoC probe device\n");
181 static const struct devfreq_event_ops exynos_nocp_ops
= {
182 .set_event
= exynos_nocp_set_event
,
183 .get_event
= exynos_nocp_get_event
,
186 static const struct of_device_id exynos_nocp_id_match
[] = {
187 { .compatible
= "samsung,exynos5420-nocp", },
190 MODULE_DEVICE_TABLE(of
, exynos_nocp_id_match
);
192 static struct regmap_config exynos_nocp_regmap_config
= {
196 .max_register
= NOCP_COUNTERS_3_VAL
,
199 static int exynos_nocp_parse_dt(struct platform_device
*pdev
,
200 struct exynos_nocp
*nocp
)
202 struct device
*dev
= nocp
->dev
;
203 struct device_node
*np
= dev
->of_node
;
204 struct resource
*res
;
208 dev_err(dev
, "failed to find devicetree node\n");
212 nocp
->clk
= devm_clk_get(dev
, "nocp");
213 if (IS_ERR(nocp
->clk
))
216 /* Maps the memory mapped IO to control nocp register */
217 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
218 base
= devm_ioremap_resource(dev
, res
);
220 return PTR_ERR(base
);
222 exynos_nocp_regmap_config
.max_register
= resource_size(res
) - 4;
224 nocp
->regmap
= devm_regmap_init_mmio(dev
, base
,
225 &exynos_nocp_regmap_config
);
226 if (IS_ERR(nocp
->regmap
)) {
227 dev_err(dev
, "failed to initialize regmap\n");
228 return PTR_ERR(nocp
->regmap
);
234 static int exynos_nocp_probe(struct platform_device
*pdev
)
236 struct device
*dev
= &pdev
->dev
;
237 struct device_node
*np
= dev
->of_node
;
238 struct exynos_nocp
*nocp
;
241 nocp
= devm_kzalloc(&pdev
->dev
, sizeof(*nocp
), GFP_KERNEL
);
245 nocp
->dev
= &pdev
->dev
;
247 /* Parse dt data to get resource */
248 ret
= exynos_nocp_parse_dt(pdev
, nocp
);
251 "failed to parse devicetree for resource\n");
255 /* Add devfreq-event device to measure the bandwidth of NoC */
256 nocp
->desc
.ops
= &exynos_nocp_ops
;
257 nocp
->desc
.driver_data
= nocp
;
258 nocp
->desc
.name
= np
->full_name
;
259 nocp
->edev
= devm_devfreq_event_add_edev(&pdev
->dev
, &nocp
->desc
);
260 if (IS_ERR(nocp
->edev
)) {
262 "failed to add devfreq-event device\n");
263 return PTR_ERR(nocp
->edev
);
265 platform_set_drvdata(pdev
, nocp
);
267 ret
= clk_prepare_enable(nocp
->clk
);
269 dev_err(&pdev
->dev
, "failed to prepare ppmu clock\n");
273 pr_info("exynos-nocp: new NoC Probe device registered: %s\n",
279 static int exynos_nocp_remove(struct platform_device
*pdev
)
281 struct exynos_nocp
*nocp
= platform_get_drvdata(pdev
);
283 clk_disable_unprepare(nocp
->clk
);
288 static struct platform_driver exynos_nocp_driver
= {
289 .probe
= exynos_nocp_probe
,
290 .remove
= exynos_nocp_remove
,
292 .name
= "exynos-nocp",
293 .of_match_table
= exynos_nocp_id_match
,
296 module_platform_driver(exynos_nocp_driver
);
298 MODULE_DESCRIPTION("Exynos NoC (Network on Chip) Probe driver");
299 MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
300 MODULE_LICENSE("GPL");