1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
4  *
5  * Description: CoreSight Replicator driver
6  */
7 
8 #include <linux/acpi.h>
9 #include <linux/amba/bus.h>
10 #include <linux/kernel.h>
11 #include <linux/device.h>
12 #include <linux/platform_device.h>
13 #include <linux/io.h>
14 #include <linux/err.h>
15 #include <linux/slab.h>
16 #include <linux/pm_runtime.h>
17 #include <linux/clk.h>
18 #include <linux/of.h>
19 #include <linux/coresight.h>
20 
21 #include "coresight-priv.h"
22 
23 #define REPLICATOR_IDFILTER0		0x000
24 #define REPLICATOR_IDFILTER1		0x004
25 
26 DEFINE_CORESIGHT_DEVLIST(replicator_devs, "replicator");
27 
28 /**
29  * struct replicator_drvdata - specifics associated to a replicator component
30  * @base:	memory mapped base address for this component. Also indicates
31  *		whether this one is programmable or not.
32  * @atclk:	optional clock for the core parts of the replicator.
33  * @csdev:	component vitals needed by the framework
34  */
35 struct replicator_drvdata {
36 	void __iomem		*base;
37 	struct clk		*atclk;
38 	struct coresight_device	*csdev;
39 };
40 
41 static void dynamic_replicator_reset(struct replicator_drvdata *drvdata)
42 {
43 	CS_UNLOCK(drvdata->base);
44 
45 	if (!coresight_claim_device_unlocked(drvdata->base)) {
46 		writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER0);
47 		writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER1);
48 		coresight_disclaim_device_unlocked(drvdata->base);
49 	}
50 
51 	CS_LOCK(drvdata->base);
52 }
53 
54 /*
55  * replicator_reset : Reset the replicator configuration to sane values.
56  */
57 static inline void replicator_reset(struct replicator_drvdata *drvdata)
58 {
59 	if (drvdata->base)
60 		dynamic_replicator_reset(drvdata);
61 }
62 
63 static int dynamic_replicator_enable(struct replicator_drvdata *drvdata,
64 				     int inport, int outport)
65 {
66 	int rc = 0;
67 	u32 reg;
68 
69 	switch (outport) {
70 	case 0:
71 		reg = REPLICATOR_IDFILTER0;
72 		break;
73 	case 1:
74 		reg = REPLICATOR_IDFILTER1;
75 		break;
76 	default:
77 		WARN_ON(1);
78 		return -EINVAL;
79 	}
80 
81 	CS_UNLOCK(drvdata->base);
82 
83 	if ((readl_relaxed(drvdata->base + REPLICATOR_IDFILTER0) == 0xff) &&
84 	    (readl_relaxed(drvdata->base + REPLICATOR_IDFILTER1) == 0xff))
85 		rc = coresight_claim_device_unlocked(drvdata->base);
86 
87 	/* Ensure that the outport is enabled. */
88 	if (!rc)
89 		writel_relaxed(0x00, drvdata->base + reg);
90 	CS_LOCK(drvdata->base);
91 
92 	return rc;
93 }
94 
95 static int replicator_enable(struct coresight_device *csdev, int inport,
96 			     int outport)
97 {
98 	int rc = 0;
99 	struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
100 
101 	if (drvdata->base)
102 		rc = dynamic_replicator_enable(drvdata, inport, outport);
103 	if (!rc)
104 		dev_dbg(&csdev->dev, "REPLICATOR enabled\n");
105 	return rc;
106 }
107 
108 static void dynamic_replicator_disable(struct replicator_drvdata *drvdata,
109 				       int inport, int outport)
110 {
111 	u32 reg;
112 
113 	switch (outport) {
114 	case 0:
115 		reg = REPLICATOR_IDFILTER0;
116 		break;
117 	case 1:
118 		reg = REPLICATOR_IDFILTER1;
119 		break;
120 	default:
121 		WARN_ON(1);
122 		return;
123 	}
124 
125 	CS_UNLOCK(drvdata->base);
126 
127 	/* disable the flow of ATB data through port */
128 	writel_relaxed(0xff, drvdata->base + reg);
129 
130 	if ((readl_relaxed(drvdata->base + REPLICATOR_IDFILTER0) == 0xff) &&
131 	    (readl_relaxed(drvdata->base + REPLICATOR_IDFILTER1) == 0xff))
132 		coresight_disclaim_device_unlocked(drvdata->base);
133 	CS_LOCK(drvdata->base);
134 }
135 
136 static void replicator_disable(struct coresight_device *csdev, int inport,
137 			       int outport)
138 {
139 	struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
140 
141 	if (drvdata->base)
142 		dynamic_replicator_disable(drvdata, inport, outport);
143 	dev_dbg(&csdev->dev, "REPLICATOR disabled\n");
144 }
145 
146 static const struct coresight_ops_link replicator_link_ops = {
147 	.enable		= replicator_enable,
148 	.disable	= replicator_disable,
149 };
150 
151 static const struct coresight_ops replicator_cs_ops = {
152 	.link_ops	= &replicator_link_ops,
153 };
154 
155 #define coresight_replicator_reg(name, offset) \
156 	coresight_simple_reg32(struct replicator_drvdata, name, offset)
157 
158 coresight_replicator_reg(idfilter0, REPLICATOR_IDFILTER0);
159 coresight_replicator_reg(idfilter1, REPLICATOR_IDFILTER1);
160 
161 static struct attribute *replicator_mgmt_attrs[] = {
162 	&dev_attr_idfilter0.attr,
163 	&dev_attr_idfilter1.attr,
164 	NULL,
165 };
166 
167 static const struct attribute_group replicator_mgmt_group = {
168 	.attrs = replicator_mgmt_attrs,
169 	.name = "mgmt",
170 };
171 
172 static const struct attribute_group *replicator_groups[] = {
173 	&replicator_mgmt_group,
174 	NULL,
175 };
176 
177 static int replicator_probe(struct device *dev, struct resource *res)
178 {
179 	int ret = 0;
180 	struct coresight_platform_data *pdata = NULL;
181 	struct replicator_drvdata *drvdata;
182 	struct coresight_desc desc = { 0 };
183 	void __iomem *base;
184 
185 	if (is_of_node(dev_fwnode(dev)) &&
186 	    of_device_is_compatible(dev->of_node, "arm,coresight-replicator"))
187 		dev_warn_once(dev,
188 			      "Uses OBSOLETE CoreSight replicator binding\n");
189 
190 	desc.name = coresight_alloc_device_name(&replicator_devs, dev);
191 	if (!desc.name)
192 		return -ENOMEM;
193 
194 	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
195 	if (!drvdata)
196 		return -ENOMEM;
197 
198 	drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */
199 	if (!IS_ERR(drvdata->atclk)) {
200 		ret = clk_prepare_enable(drvdata->atclk);
201 		if (ret)
202 			return ret;
203 	}
204 
205 	/*
206 	 * Map the device base for dynamic-replicator, which has been
207 	 * validated by AMBA core
208 	 */
209 	if (res) {
210 		base = devm_ioremap_resource(dev, res);
211 		if (IS_ERR(base)) {
212 			ret = PTR_ERR(base);
213 			goto out_disable_clk;
214 		}
215 		drvdata->base = base;
216 		desc.groups = replicator_groups;
217 	}
218 
219 	dev_set_drvdata(dev, drvdata);
220 
221 	pdata = coresight_get_platform_data(dev);
222 	if (IS_ERR(pdata)) {
223 		ret = PTR_ERR(pdata);
224 		goto out_disable_clk;
225 	}
226 	dev->platform_data = pdata;
227 
228 	desc.type = CORESIGHT_DEV_TYPE_LINK;
229 	desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
230 	desc.ops = &replicator_cs_ops;
231 	desc.pdata = dev->platform_data;
232 	desc.dev = dev;
233 
234 	drvdata->csdev = coresight_register(&desc);
235 	if (IS_ERR(drvdata->csdev)) {
236 		ret = PTR_ERR(drvdata->csdev);
237 		goto out_disable_clk;
238 	}
239 
240 	replicator_reset(drvdata);
241 	pm_runtime_put(dev);
242 
243 out_disable_clk:
244 	if (ret && !IS_ERR_OR_NULL(drvdata->atclk))
245 		clk_disable_unprepare(drvdata->atclk);
246 	return ret;
247 }
248 
249 static int static_replicator_probe(struct platform_device *pdev)
250 {
251 	int ret;
252 
253 	pm_runtime_get_noresume(&pdev->dev);
254 	pm_runtime_set_active(&pdev->dev);
255 	pm_runtime_enable(&pdev->dev);
256 
257 	/* Static replicators do not have programming base */
258 	ret = replicator_probe(&pdev->dev, NULL);
259 
260 	if (ret) {
261 		pm_runtime_put_noidle(&pdev->dev);
262 		pm_runtime_disable(&pdev->dev);
263 	}
264 
265 	return ret;
266 }
267 
268 #ifdef CONFIG_PM
269 static int replicator_runtime_suspend(struct device *dev)
270 {
271 	struct replicator_drvdata *drvdata = dev_get_drvdata(dev);
272 
273 	if (drvdata && !IS_ERR(drvdata->atclk))
274 		clk_disable_unprepare(drvdata->atclk);
275 
276 	return 0;
277 }
278 
279 static int replicator_runtime_resume(struct device *dev)
280 {
281 	struct replicator_drvdata *drvdata = dev_get_drvdata(dev);
282 
283 	if (drvdata && !IS_ERR(drvdata->atclk))
284 		clk_prepare_enable(drvdata->atclk);
285 
286 	return 0;
287 }
288 #endif
289 
290 static const struct dev_pm_ops replicator_dev_pm_ops = {
291 	SET_RUNTIME_PM_OPS(replicator_runtime_suspend,
292 			   replicator_runtime_resume, NULL)
293 };
294 
295 static const struct of_device_id static_replicator_match[] = {
296 	{.compatible = "arm,coresight-replicator"},
297 	{.compatible = "arm,coresight-static-replicator"},
298 	{}
299 };
300 
301 #ifdef CONFIG_ACPI
302 static const struct acpi_device_id static_replicator_acpi_ids[] = {
303 	{"ARMHC985", 0}, /* ARM CoreSight Static Replicator */
304 	{}
305 };
306 #endif
307 
308 static struct platform_driver static_replicator_driver = {
309 	.probe          = static_replicator_probe,
310 	.driver         = {
311 		.name   = "coresight-static-replicator",
312 		.of_match_table = of_match_ptr(static_replicator_match),
313 		.acpi_match_table = ACPI_PTR(static_replicator_acpi_ids),
314 		.pm	= &replicator_dev_pm_ops,
315 		.suppress_bind_attrs = true,
316 	},
317 };
318 builtin_platform_driver(static_replicator_driver);
319 
320 static int dynamic_replicator_probe(struct amba_device *adev,
321 				    const struct amba_id *id)
322 {
323 	return replicator_probe(&adev->dev, &adev->res);
324 }
325 
326 static const struct amba_id dynamic_replicator_ids[] = {
327 	{
328 		.id     = 0x000bb909,
329 		.mask   = 0x000fffff,
330 	},
331 	{
332 		/* Coresight SoC-600 */
333 		.id     = 0x000bb9ec,
334 		.mask   = 0x000fffff,
335 	},
336 	{ 0, 0 },
337 };
338 
339 static struct amba_driver dynamic_replicator_driver = {
340 	.drv = {
341 		.name	= "coresight-dynamic-replicator",
342 		.pm	= &replicator_dev_pm_ops,
343 		.suppress_bind_attrs = true,
344 	},
345 	.probe		= dynamic_replicator_probe,
346 	.id_table	= dynamic_replicator_ids,
347 };
348 builtin_amba_driver(dynamic_replicator_driver);
349