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