b7d7c4146f9a22278e1814cc6103bf1bbe612eaf
[linux-2.6-microblaze.git] / drivers / hwtracing / coresight / coresight-dynamic-replicator.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
4  */
5
6 #include <linux/amba/bus.h>
7 #include <linux/clk.h>
8 #include <linux/coresight.h>
9 #include <linux/device.h>
10 #include <linux/err.h>
11 #include <linux/init.h>
12 #include <linux/io.h>
13 #include <linux/kernel.h>
14 #include <linux/of.h>
15 #include <linux/pm_runtime.h>
16 #include <linux/slab.h>
17
18 #include "coresight-priv.h"
19
20 #define REPLICATOR_IDFILTER0            0x000
21 #define REPLICATOR_IDFILTER1            0x004
22
23 /**
24  * struct replicator_drvdata - specifics associated to a replicator component
25  * @base:       memory mapped base address for this component.
26  * @dev:        the device entity associated with this component
27  * @atclk:      optional clock for the core parts of the replicator.
28  * @csdev:      component vitals needed by the framework
29  */
30 struct replicator_drvdata {
31         void __iomem            *base;
32         struct device           *dev;
33         struct clk              *atclk;
34         struct coresight_device *csdev;
35 };
36
37 /*
38  * dynamic_replicator_reset : Reset the replicator configuration to sane values.
39  */
40 static void dynamic_replicator_reset(struct replicator_drvdata *drvdata)
41 {
42         CS_UNLOCK(drvdata->base);
43
44         if (!coresight_claim_device_unlocked(drvdata->base)) {
45                 writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER0);
46                 writel_relaxed(0xff, drvdata->base + REPLICATOR_IDFILTER1);
47                 coresight_disclaim_device_unlocked(drvdata->base);
48         }
49
50         CS_LOCK(drvdata->base);
51 }
52
53 static int dynamic_replicator_enable(struct replicator_drvdata *drvdata,
54                                      int inport, int outport)
55 {
56         int rc = 0;
57         u32 reg;
58
59         switch (outport) {
60         case 0:
61                 reg = REPLICATOR_IDFILTER0;
62                 break;
63         case 1:
64                 reg = REPLICATOR_IDFILTER1;
65                 break;
66         default:
67                 WARN_ON(1);
68                 return -EINVAL;
69         }
70
71         CS_UNLOCK(drvdata->base);
72
73         if ((readl_relaxed(drvdata->base + REPLICATOR_IDFILTER0) == 0xff) &&
74             (readl_relaxed(drvdata->base + REPLICATOR_IDFILTER1) == 0xff))
75                 rc = coresight_claim_device_unlocked(drvdata->base);
76
77         /* Ensure that the outport is enabled. */
78         if (!rc)
79                 writel_relaxed(0x00, drvdata->base + reg);
80         CS_LOCK(drvdata->base);
81
82         return rc;
83 }
84
85 static int replicator_enable(struct coresight_device *csdev, int inport,
86                              int outport)
87 {
88         int rc = 0;
89         struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
90
91         rc = dynamic_replicator_enable(drvdata, inport, outport);
92         dev_dbg(drvdata->dev, "REPLICATOR enabled\n");
93         return rc;
94 }
95
96 static void dynamic_replicator_disable(struct replicator_drvdata *drvdata,
97                                        int inport, int outport)
98 {
99         u32 reg;
100
101         switch (outport) {
102         case 0:
103                 reg = REPLICATOR_IDFILTER0;
104                 break;
105         case 1:
106                 reg = REPLICATOR_IDFILTER1;
107                 break;
108         default:
109                 WARN_ON(1);
110                 return;
111         }
112
113         CS_UNLOCK(drvdata->base);
114
115         /* disable the flow of ATB data through port */
116         writel_relaxed(0xff, drvdata->base + reg);
117
118         if ((readl_relaxed(drvdata->base + REPLICATOR_IDFILTER0) == 0xff) &&
119             (readl_relaxed(drvdata->base + REPLICATOR_IDFILTER1) == 0xff))
120                 coresight_disclaim_device_unlocked(drvdata->base);
121         CS_LOCK(drvdata->base);
122 }
123
124 static void replicator_disable(struct coresight_device *csdev, int inport,
125                                int outport)
126 {
127         struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
128
129         dynamic_replicator_disable(drvdata, inport, outport);
130         dev_dbg(drvdata->dev, "REPLICATOR disabled\n");
131 }
132
133 static const struct coresight_ops_link replicator_link_ops = {
134         .enable         = replicator_enable,
135         .disable        = replicator_disable,
136 };
137
138 static const struct coresight_ops replicator_cs_ops = {
139         .link_ops       = &replicator_link_ops,
140 };
141
142 #define coresight_replicator_reg(name, offset) \
143         coresight_simple_reg32(struct replicator_drvdata, name, offset)
144
145 coresight_replicator_reg(idfilter0, REPLICATOR_IDFILTER0);
146 coresight_replicator_reg(idfilter1, REPLICATOR_IDFILTER1);
147
148 static struct attribute *replicator_mgmt_attrs[] = {
149         &dev_attr_idfilter0.attr,
150         &dev_attr_idfilter1.attr,
151         NULL,
152 };
153
154 static const struct attribute_group replicator_mgmt_group = {
155         .attrs = replicator_mgmt_attrs,
156         .name = "mgmt",
157 };
158
159 static const struct attribute_group *replicator_groups[] = {
160         &replicator_mgmt_group,
161         NULL,
162 };
163
164 static int replicator_probe(struct device *dev, struct resource *res)
165 {
166         int ret = 0;
167         struct coresight_platform_data *pdata = NULL;
168         struct replicator_drvdata *drvdata;
169         struct coresight_desc desc = { 0 };
170         struct device_node *np = dev->of_node;
171         void __iomem *base;
172
173         if (np) {
174                 pdata = of_get_coresight_platform_data(dev, np);
175                 if (IS_ERR(pdata))
176                         return PTR_ERR(pdata);
177                 dev->platform_data = pdata;
178         }
179
180         drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
181         if (!drvdata)
182                 return -ENOMEM;
183
184         drvdata->dev = dev;
185         drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */
186         if (!IS_ERR(drvdata->atclk)) {
187                 ret = clk_prepare_enable(drvdata->atclk);
188                 if (ret)
189                         return ret;
190         }
191
192         /*
193          * Map the device base for dynamic-replicator, which has been
194          * validated by AMBA core
195          */
196         if (res) {
197                 base = devm_ioremap_resource(dev, res);
198                 if (IS_ERR(base)) {
199                         ret = PTR_ERR(base);
200                         goto out_disable_clk;
201                 }
202                 drvdata->base = base;
203                 desc.groups = replicator_groups;
204         }
205
206         dev_set_drvdata(dev, drvdata);
207
208         desc.type = CORESIGHT_DEV_TYPE_LINK;
209         desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
210         desc.ops = &replicator_cs_ops;
211         desc.pdata = dev->platform_data;
212         desc.dev = dev;
213         drvdata->csdev = coresight_register(&desc);
214
215         if (IS_ERR(drvdata->csdev)) {
216                 ret = PTR_ERR(drvdata->csdev);
217                 goto out_disable_clk;
218         }
219
220         dynamic_replicator_reset(drvdata);
221         pm_runtime_put(dev);
222
223 out_disable_clk:
224         if (ret && !IS_ERR_OR_NULL(drvdata->atclk))
225                 clk_disable_unprepare(drvdata->atclk);
226         return ret;
227 }
228
229 static int dynamic_replicator_probe(struct amba_device *adev,
230                                     const struct amba_id *id)
231 {
232         return replicator_probe(&adev->dev, &adev->res);
233 }
234
235 #ifdef CONFIG_PM
236 static int replicator_runtime_suspend(struct device *dev)
237 {
238         struct replicator_drvdata *drvdata = dev_get_drvdata(dev);
239
240         if (drvdata && !IS_ERR(drvdata->atclk))
241                 clk_disable_unprepare(drvdata->atclk);
242
243         return 0;
244 }
245
246 static int replicator_runtime_resume(struct device *dev)
247 {
248         struct replicator_drvdata *drvdata = dev_get_drvdata(dev);
249
250         if (drvdata && !IS_ERR(drvdata->atclk))
251                 clk_prepare_enable(drvdata->atclk);
252
253         return 0;
254 }
255 #endif
256
257 static const struct dev_pm_ops replicator_dev_pm_ops = {
258         SET_RUNTIME_PM_OPS(replicator_runtime_suspend,
259                            replicator_runtime_resume,
260                            NULL)
261 };
262
263 static const struct amba_id dynamic_replicator_ids[] = {
264         {
265                 .id     = 0x000bb909,
266                 .mask   = 0x000fffff,
267         },
268         {
269                 /* Coresight SoC-600 */
270                 .id     = 0x000bb9ec,
271                 .mask   = 0x000fffff,
272         },
273         { 0, 0 },
274 };
275
276 static struct amba_driver dynamic_replicator_driver = {
277         .drv = {
278                 .name   = "coresight-dynamic-replicator",
279                 .pm     = &replicator_dev_pm_ops,
280                 .suppress_bind_attrs = true,
281         },
282         .probe          = dynamic_replicator_probe,
283         .id_table       = dynamic_replicator_ids,
284 };
285 builtin_amba_driver(dynamic_replicator_driver);