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 		pr_warn_once("Uses OBSOLETE CoreSight replicator binding\n");
188 
189 	desc.name = coresight_alloc_device_name(&replicator_devs, dev);
190 	if (!desc.name)
191 		return -ENOMEM;
192 
193 	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
194 	if (!drvdata)
195 		return -ENOMEM;
196 
197 	drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */
198 	if (!IS_ERR(drvdata->atclk)) {
199 		ret = clk_prepare_enable(drvdata->atclk);
200 		if (ret)
201 			return ret;
202 	}
203 
204 	/*
205 	 * Map the device base for dynamic-replicator, which has been
206 	 * validated by AMBA core
207 	 */
208 	if (res) {
209 		base = devm_ioremap_resource(dev, res);
210 		if (IS_ERR(base)) {
211 			ret = PTR_ERR(base);
212 			goto out_disable_clk;
213 		}
214 		drvdata->base = base;
215 		desc.groups = replicator_groups;
216 	}
217 
218 	dev_set_drvdata(dev, drvdata);
219 
220 	pdata = coresight_get_platform_data(dev);
221 	if (IS_ERR(pdata)) {
222 		ret = PTR_ERR(pdata);
223 		goto out_disable_clk;
224 	}
225 	dev->platform_data = pdata;
226 
227 	desc.type = CORESIGHT_DEV_TYPE_LINK;
228 	desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
229 	desc.ops = &replicator_cs_ops;
230 	desc.pdata = dev->platform_data;
231 	desc.dev = dev;
232 
233 	drvdata->csdev = coresight_register(&desc);
234 	if (IS_ERR(drvdata->csdev)) {
235 		ret = PTR_ERR(drvdata->csdev);
236 		goto out_disable_clk;
237 	}
238 
239 	replicator_reset(drvdata);
240 	pm_runtime_put(dev);
241 
242 out_disable_clk:
243 	if (ret && !IS_ERR_OR_NULL(drvdata->atclk))
244 		clk_disable_unprepare(drvdata->atclk);
245 	return ret;
246 }
247 
248 static int static_replicator_probe(struct platform_device *pdev)
249 {
250 	int ret;
251 
252 	pm_runtime_get_noresume(&pdev->dev);
253 	pm_runtime_set_active(&pdev->dev);
254 	pm_runtime_enable(&pdev->dev);
255 
256 	/* Static replicators do not have programming base */
257 	ret = replicator_probe(&pdev->dev, NULL);
258 
259 	if (ret) {
260 		pm_runtime_put_noidle(&pdev->dev);
261 		pm_runtime_disable(&pdev->dev);
262 	}
263 
264 	return ret;
265 }
266 
267 #ifdef CONFIG_PM
268 static int replicator_runtime_suspend(struct device *dev)
269 {
270 	struct replicator_drvdata *drvdata = dev_get_drvdata(dev);
271 
272 	if (drvdata && !IS_ERR(drvdata->atclk))
273 		clk_disable_unprepare(drvdata->atclk);
274 
275 	return 0;
276 }
277 
278 static int replicator_runtime_resume(struct device *dev)
279 {
280 	struct replicator_drvdata *drvdata = dev_get_drvdata(dev);
281 
282 	if (drvdata && !IS_ERR(drvdata->atclk))
283 		clk_prepare_enable(drvdata->atclk);
284 
285 	return 0;
286 }
287 #endif
288 
289 static const struct dev_pm_ops replicator_dev_pm_ops = {
290 	SET_RUNTIME_PM_OPS(replicator_runtime_suspend,
291 			   replicator_runtime_resume, NULL)
292 };
293 
294 static const struct of_device_id static_replicator_match[] = {
295 	{.compatible = "arm,coresight-replicator"},
296 	{.compatible = "arm,coresight-static-replicator"},
297 	{}
298 };
299 
300 #ifdef CONFIG_ACPI
301 static const struct acpi_device_id static_replicator_acpi_ids[] = {
302 	{"ARMHC985", 0}, /* ARM CoreSight Static Replicator */
303 	{}
304 };
305 #endif
306 
307 static struct platform_driver static_replicator_driver = {
308 	.probe          = static_replicator_probe,
309 	.driver         = {
310 		.name   = "coresight-static-replicator",
311 		.of_match_table = of_match_ptr(static_replicator_match),
312 		.acpi_match_table = ACPI_PTR(static_replicator_acpi_ids),
313 		.pm	= &replicator_dev_pm_ops,
314 		.suppress_bind_attrs = true,
315 	},
316 };
317 builtin_platform_driver(static_replicator_driver);
318 
319 static int dynamic_replicator_probe(struct amba_device *adev,
320 				    const struct amba_id *id)
321 {
322 	return replicator_probe(&adev->dev, &adev->res);
323 }
324 
325 static const struct amba_id dynamic_replicator_ids[] = {
326 	{
327 		.id     = 0x000bb909,
328 		.mask   = 0x000fffff,
329 	},
330 	{
331 		/* Coresight SoC-600 */
332 		.id     = 0x000bb9ec,
333 		.mask   = 0x000fffff,
334 	},
335 	{ 0, 0 },
336 };
337 
338 static struct amba_driver dynamic_replicator_driver = {
339 	.drv = {
340 		.name	= "coresight-dynamic-replicator",
341 		.pm	= &replicator_dev_pm_ops,
342 		.suppress_bind_attrs = true,
343 	},
344 	.probe		= dynamic_replicator_probe,
345 	.id_table	= dynamic_replicator_ids,
346 };
347 builtin_amba_driver(dynamic_replicator_driver);
348