coresight: tmc: making prepare/unprepare functions generic
[firefly-linux-kernel-4.4.55.git] / drivers / hwtracing / coresight / coresight-tmc.c
1 /* Copyright (c) 2012, The Linux Foundation. All rights reserved.
2  *
3  * Description: CoreSight Trace Memory Controller driver
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 and
7  * only version 2 as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  */
14
15 #include <linux/kernel.h>
16 #include <linux/init.h>
17 #include <linux/types.h>
18 #include <linux/device.h>
19 #include <linux/io.h>
20 #include <linux/err.h>
21 #include <linux/fs.h>
22 #include <linux/miscdevice.h>
23 #include <linux/uaccess.h>
24 #include <linux/slab.h>
25 #include <linux/dma-mapping.h>
26 #include <linux/spinlock.h>
27 #include <linux/pm_runtime.h>
28 #include <linux/of.h>
29 #include <linux/coresight.h>
30 #include <linux/amba/bus.h>
31
32 #include "coresight-priv.h"
33 #include "coresight-tmc.h"
34
35 void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata)
36 {
37         /* Ensure formatter, unformatter and hardware fifo are empty */
38         if (coresight_timeout(drvdata->base,
39                               TMC_STS, TMC_STS_TMCREADY_BIT, 1)) {
40                 dev_err(drvdata->dev,
41                         "timeout observed when probing at offset %#x\n",
42                         TMC_STS);
43         }
44 }
45
46 void tmc_flush_and_stop(struct tmc_drvdata *drvdata)
47 {
48         u32 ffcr;
49
50         ffcr = readl_relaxed(drvdata->base + TMC_FFCR);
51         ffcr |= TMC_FFCR_STOP_ON_FLUSH;
52         writel_relaxed(ffcr, drvdata->base + TMC_FFCR);
53         ffcr |= BIT(TMC_FFCR_FLUSHMAN_BIT);
54         writel_relaxed(ffcr, drvdata->base + TMC_FFCR);
55         /* Ensure flush completes */
56         if (coresight_timeout(drvdata->base,
57                               TMC_FFCR, TMC_FFCR_FLUSHMAN_BIT, 0)) {
58                 dev_err(drvdata->dev,
59                         "timeout observed when probing at offset %#x\n",
60                         TMC_FFCR);
61         }
62
63         tmc_wait_for_tmcready(drvdata);
64 }
65
66 void tmc_enable_hw(struct tmc_drvdata *drvdata)
67 {
68         writel_relaxed(TMC_CTL_CAPT_EN, drvdata->base + TMC_CTL);
69 }
70
71 void tmc_disable_hw(struct tmc_drvdata *drvdata)
72 {
73         writel_relaxed(0x0, drvdata->base + TMC_CTL);
74 }
75
76 static int tmc_read_prepare(struct tmc_drvdata *drvdata)
77 {
78         int ret = 0;
79
80         switch (drvdata->config_type) {
81         case TMC_CONFIG_TYPE_ETB:
82         case TMC_CONFIG_TYPE_ETF:
83                 ret = tmc_read_prepare_etb(drvdata);
84                 break;
85         case TMC_CONFIG_TYPE_ETR:
86                 ret = tmc_read_prepare_etr(drvdata);
87                 break;
88         default:
89                 ret = -EINVAL;
90         }
91
92         if (!ret)
93                 dev_info(drvdata->dev, "TMC read start\n");
94
95         return ret;
96 }
97
98 static void tmc_read_unprepare(struct tmc_drvdata *drvdata)
99 {
100         int ret = 0;
101
102         switch (drvdata->config_type) {
103         case TMC_CONFIG_TYPE_ETB:
104         case TMC_CONFIG_TYPE_ETF:
105                 ret = tmc_read_unprepare_etb(drvdata);
106                 break;
107         case TMC_CONFIG_TYPE_ETR:
108                 ret = tmc_read_unprepare_etr(drvdata);
109                 break;
110         default:
111                 ret = -EINVAL;
112         }
113
114         if (!ret)
115                 dev_info(drvdata->dev, "TMC read end\n");
116 }
117
118 static int tmc_open(struct inode *inode, struct file *file)
119 {
120         struct tmc_drvdata *drvdata = container_of(file->private_data,
121                                                    struct tmc_drvdata, miscdev);
122         int ret = 0;
123
124         if (drvdata->read_count++)
125                 goto out;
126
127         ret = tmc_read_prepare(drvdata);
128         if (ret)
129                 return ret;
130 out:
131         nonseekable_open(inode, file);
132
133         dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__);
134         return 0;
135 }
136
137 static ssize_t tmc_read(struct file *file, char __user *data, size_t len,
138                         loff_t *ppos)
139 {
140         struct tmc_drvdata *drvdata = container_of(file->private_data,
141                                                    struct tmc_drvdata, miscdev);
142         char *bufp = drvdata->buf + *ppos;
143
144         if (*ppos + len > drvdata->size)
145                 len = drvdata->size - *ppos;
146
147         if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
148                 if (bufp == (char *)(drvdata->vaddr + drvdata->size))
149                         bufp = drvdata->vaddr;
150                 else if (bufp > (char *)(drvdata->vaddr + drvdata->size))
151                         bufp -= drvdata->size;
152                 if ((bufp + len) > (char *)(drvdata->vaddr + drvdata->size))
153                         len = (char *)(drvdata->vaddr + drvdata->size) - bufp;
154         }
155
156         if (copy_to_user(data, bufp, len)) {
157                 dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__);
158                 return -EFAULT;
159         }
160
161         *ppos += len;
162
163         dev_dbg(drvdata->dev, "%s: %zu bytes copied, %d bytes left\n",
164                 __func__, len, (int)(drvdata->size - *ppos));
165         return len;
166 }
167
168 static int tmc_release(struct inode *inode, struct file *file)
169 {
170         struct tmc_drvdata *drvdata = container_of(file->private_data,
171                                                    struct tmc_drvdata, miscdev);
172
173         if (--drvdata->read_count) {
174                 if (drvdata->read_count < 0) {
175                         dev_err(drvdata->dev, "mismatched close\n");
176                         drvdata->read_count = 0;
177                 }
178                 goto out;
179         }
180
181         tmc_read_unprepare(drvdata);
182 out:
183         dev_dbg(drvdata->dev, "%s: released\n", __func__);
184         return 0;
185 }
186
187 static const struct file_operations tmc_fops = {
188         .owner          = THIS_MODULE,
189         .open           = tmc_open,
190         .read           = tmc_read,
191         .release        = tmc_release,
192         .llseek         = no_llseek,
193 };
194
195 #define coresight_tmc_simple_func(name, offset)                 \
196         coresight_simple_func(struct tmc_drvdata, name, offset)
197
198 coresight_tmc_simple_func(rsz, TMC_RSZ);
199 coresight_tmc_simple_func(sts, TMC_STS);
200 coresight_tmc_simple_func(rrp, TMC_RRP);
201 coresight_tmc_simple_func(rwp, TMC_RWP);
202 coresight_tmc_simple_func(trg, TMC_TRG);
203 coresight_tmc_simple_func(ctl, TMC_CTL);
204 coresight_tmc_simple_func(ffsr, TMC_FFSR);
205 coresight_tmc_simple_func(ffcr, TMC_FFCR);
206 coresight_tmc_simple_func(mode, TMC_MODE);
207 coresight_tmc_simple_func(pscr, TMC_PSCR);
208 coresight_tmc_simple_func(devid, CORESIGHT_DEVID);
209
210 static struct attribute *coresight_tmc_mgmt_attrs[] = {
211         &dev_attr_rsz.attr,
212         &dev_attr_sts.attr,
213         &dev_attr_rrp.attr,
214         &dev_attr_rwp.attr,
215         &dev_attr_trg.attr,
216         &dev_attr_ctl.attr,
217         &dev_attr_ffsr.attr,
218         &dev_attr_ffcr.attr,
219         &dev_attr_mode.attr,
220         &dev_attr_pscr.attr,
221         &dev_attr_devid.attr,
222         NULL,
223 };
224
225 ssize_t trigger_cntr_show(struct device *dev,
226                           struct device_attribute *attr, char *buf)
227 {
228         struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
229         unsigned long val = drvdata->trigger_cntr;
230
231         return sprintf(buf, "%#lx\n", val);
232 }
233
234 static ssize_t trigger_cntr_store(struct device *dev,
235                              struct device_attribute *attr,
236                              const char *buf, size_t size)
237 {
238         int ret;
239         unsigned long val;
240         struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
241
242         ret = kstrtoul(buf, 16, &val);
243         if (ret)
244                 return ret;
245
246         drvdata->trigger_cntr = val;
247         return size;
248 }
249 static DEVICE_ATTR_RW(trigger_cntr);
250
251 static struct attribute *coresight_tmc_attrs[] = {
252         &dev_attr_trigger_cntr.attr,
253         NULL,
254 };
255
256 static const struct attribute_group coresight_tmc_group = {
257         .attrs = coresight_tmc_attrs,
258 };
259
260 static const struct attribute_group coresight_tmc_mgmt_group = {
261         .attrs = coresight_tmc_mgmt_attrs,
262         .name = "mgmt",
263 };
264
265 const struct attribute_group *coresight_tmc_groups[] = {
266         &coresight_tmc_group,
267         &coresight_tmc_mgmt_group,
268         NULL,
269 };
270
271 static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
272 {
273         int ret = 0;
274         u32 devid;
275         void __iomem *base;
276         struct device *dev = &adev->dev;
277         struct coresight_platform_data *pdata = NULL;
278         struct tmc_drvdata *drvdata;
279         struct resource *res = &adev->res;
280         struct coresight_desc *desc;
281         struct device_node *np = adev->dev.of_node;
282
283         if (np) {
284                 pdata = of_get_coresight_platform_data(dev, np);
285                 if (IS_ERR(pdata))
286                         return PTR_ERR(pdata);
287                 adev->dev.platform_data = pdata;
288         }
289
290         drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
291         if (!drvdata)
292                 return -ENOMEM;
293
294         drvdata->dev = &adev->dev;
295         dev_set_drvdata(dev, drvdata);
296
297         /* Validity for the resource is already checked by the AMBA core */
298         base = devm_ioremap_resource(dev, res);
299         if (IS_ERR(base))
300                 return PTR_ERR(base);
301
302         drvdata->base = base;
303
304         spin_lock_init(&drvdata->spinlock);
305
306         devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID);
307         drvdata->config_type = BMVAL(devid, 6, 7);
308
309         if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
310                 if (np)
311                         ret = of_property_read_u32(np,
312                                                    "arm,buffer-size",
313                                                    &drvdata->size);
314                 if (ret)
315                         drvdata->size = SZ_1M;
316         } else {
317                 drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4;
318         }
319
320         pm_runtime_put(&adev->dev);
321
322         if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
323                 drvdata->vaddr = dma_alloc_coherent(dev, drvdata->size,
324                                                 &drvdata->paddr, GFP_KERNEL);
325                 if (!drvdata->vaddr)
326                         return -ENOMEM;
327
328                 memset(drvdata->vaddr, 0, drvdata->size);
329                 drvdata->buf = drvdata->vaddr;
330         } else {
331                 drvdata->buf = devm_kzalloc(dev, drvdata->size, GFP_KERNEL);
332                 if (!drvdata->buf)
333                         return -ENOMEM;
334         }
335
336         desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
337         if (!desc) {
338                 ret = -ENOMEM;
339                 goto err_devm_kzalloc;
340         }
341
342         desc->pdata = pdata;
343         desc->dev = dev;
344         desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
345         desc->groups = coresight_tmc_groups;
346
347         if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
348                 desc->type = CORESIGHT_DEV_TYPE_SINK;
349                 desc->ops = &tmc_etb_cs_ops;
350         } else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
351                 desc->type = CORESIGHT_DEV_TYPE_SINK;
352                 desc->ops = &tmc_etr_cs_ops;
353         } else {
354                 desc->type = CORESIGHT_DEV_TYPE_LINKSINK;
355                 desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO;
356                 desc->ops = &tmc_etf_cs_ops;
357         }
358
359         drvdata->csdev = coresight_register(desc);
360         if (IS_ERR(drvdata->csdev)) {
361                 ret = PTR_ERR(drvdata->csdev);
362                 goto err_devm_kzalloc;
363         }
364
365         drvdata->miscdev.name = pdata->name;
366         drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
367         drvdata->miscdev.fops = &tmc_fops;
368         ret = misc_register(&drvdata->miscdev);
369         if (ret)
370                 goto err_misc_register;
371
372         return 0;
373
374 err_misc_register:
375         coresight_unregister(drvdata->csdev);
376 err_devm_kzalloc:
377         if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
378                 dma_free_coherent(dev, drvdata->size,
379                                 drvdata->vaddr, drvdata->paddr);
380         return ret;
381 }
382
383 static struct amba_id tmc_ids[] = {
384         {
385                 .id     = 0x0003b961,
386                 .mask   = 0x0003ffff,
387         },
388         { 0, 0},
389 };
390
391 static struct amba_driver tmc_driver = {
392         .drv = {
393                 .name   = "coresight-tmc",
394                 .owner  = THIS_MODULE,
395                 .suppress_bind_attrs = true,
396         },
397         .probe          = tmc_probe,
398         .id_table       = tmc_ids,
399 };
400 builtin_amba_driver(tmc_driver);