ntb: remove unneeded DRIVER_LICENSE #defines
[linux/fpc-iii.git] / drivers / hwtracing / intel_th / pti.c
blobe96a1fcb57b201f52ed74344d8e0b0439da4cf9e
1 /*
2 * Intel(R) Trace Hub PTI output driver
4 * Copyright (C) 2014-2016 Intel Corporation.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
16 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18 #include <linux/types.h>
19 #include <linux/module.h>
20 #include <linux/device.h>
21 #include <linux/sizes.h>
22 #include <linux/printk.h>
23 #include <linux/slab.h>
24 #include <linux/mm.h>
25 #include <linux/io.h>
27 #include "intel_th.h"
28 #include "pti.h"
30 struct pti_device {
31 void __iomem *base;
32 struct intel_th_device *thdev;
33 unsigned int mode;
34 unsigned int freeclk;
35 unsigned int clkdiv;
36 unsigned int patgen;
37 unsigned int lpp_dest_mask;
38 unsigned int lpp_dest;
41 /* map PTI widths to MODE settings of PTI_CTL register */
42 static const unsigned int pti_mode[] = {
43 0, 4, 8, 0, 12, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0,
46 static int pti_width_mode(unsigned int width)
48 int i;
50 for (i = 0; i < ARRAY_SIZE(pti_mode); i++)
51 if (pti_mode[i] == width)
52 return i;
54 return -EINVAL;
57 static ssize_t mode_show(struct device *dev, struct device_attribute *attr,
58 char *buf)
60 struct pti_device *pti = dev_get_drvdata(dev);
62 return scnprintf(buf, PAGE_SIZE, "%d\n", pti_mode[pti->mode]);
65 static ssize_t mode_store(struct device *dev, struct device_attribute *attr,
66 const char *buf, size_t size)
68 struct pti_device *pti = dev_get_drvdata(dev);
69 unsigned long val;
70 int ret;
72 ret = kstrtoul(buf, 10, &val);
73 if (ret)
74 return ret;
76 ret = pti_width_mode(val);
77 if (ret < 0)
78 return ret;
80 pti->mode = ret;
82 return size;
85 static DEVICE_ATTR_RW(mode);
87 static ssize_t
88 freerunning_clock_show(struct device *dev, struct device_attribute *attr,
89 char *buf)
91 struct pti_device *pti = dev_get_drvdata(dev);
93 return scnprintf(buf, PAGE_SIZE, "%d\n", pti->freeclk);
96 static ssize_t
97 freerunning_clock_store(struct device *dev, struct device_attribute *attr,
98 const char *buf, size_t size)
100 struct pti_device *pti = dev_get_drvdata(dev);
101 unsigned long val;
102 int ret;
104 ret = kstrtoul(buf, 10, &val);
105 if (ret)
106 return ret;
108 pti->freeclk = !!val;
110 return size;
113 static DEVICE_ATTR_RW(freerunning_clock);
115 static ssize_t
116 clock_divider_show(struct device *dev, struct device_attribute *attr,
117 char *buf)
119 struct pti_device *pti = dev_get_drvdata(dev);
121 return scnprintf(buf, PAGE_SIZE, "%d\n", 1u << pti->clkdiv);
124 static ssize_t
125 clock_divider_store(struct device *dev, struct device_attribute *attr,
126 const char *buf, size_t size)
128 struct pti_device *pti = dev_get_drvdata(dev);
129 unsigned long val;
130 int ret;
132 ret = kstrtoul(buf, 10, &val);
133 if (ret)
134 return ret;
136 if (!is_power_of_2(val) || val > 8 || !val)
137 return -EINVAL;
139 pti->clkdiv = val;
141 return size;
144 static DEVICE_ATTR_RW(clock_divider);
146 static struct attribute *pti_output_attrs[] = {
147 &dev_attr_mode.attr,
148 &dev_attr_freerunning_clock.attr,
149 &dev_attr_clock_divider.attr,
150 NULL,
153 static struct attribute_group pti_output_group = {
154 .attrs = pti_output_attrs,
157 static int intel_th_pti_activate(struct intel_th_device *thdev)
159 struct pti_device *pti = dev_get_drvdata(&thdev->dev);
160 u32 ctl = PTI_EN;
162 if (pti->patgen)
163 ctl |= pti->patgen << __ffs(PTI_PATGENMODE);
164 if (pti->freeclk)
165 ctl |= PTI_FCEN;
166 ctl |= pti->mode << __ffs(PTI_MODE);
167 ctl |= pti->clkdiv << __ffs(PTI_CLKDIV);
168 ctl |= pti->lpp_dest << __ffs(LPP_DEST);
170 iowrite32(ctl, pti->base + REG_PTI_CTL);
172 intel_th_trace_enable(thdev);
174 return 0;
177 static void intel_th_pti_deactivate(struct intel_th_device *thdev)
179 struct pti_device *pti = dev_get_drvdata(&thdev->dev);
181 intel_th_trace_disable(thdev);
183 iowrite32(0, pti->base + REG_PTI_CTL);
186 static void read_hw_config(struct pti_device *pti)
188 u32 ctl = ioread32(pti->base + REG_PTI_CTL);
190 pti->mode = (ctl & PTI_MODE) >> __ffs(PTI_MODE);
191 pti->clkdiv = (ctl & PTI_CLKDIV) >> __ffs(PTI_CLKDIV);
192 pti->freeclk = !!(ctl & PTI_FCEN);
194 if (!pti_mode[pti->mode])
195 pti->mode = pti_width_mode(4);
196 if (!pti->clkdiv)
197 pti->clkdiv = 1;
199 if (pti->thdev->output.type == GTH_LPP) {
200 if (ctl & LPP_PTIPRESENT)
201 pti->lpp_dest_mask |= LPP_DEST_PTI;
202 if (ctl & LPP_BSSBPRESENT)
203 pti->lpp_dest_mask |= LPP_DEST_EXI;
204 if (ctl & LPP_DEST)
205 pti->lpp_dest = 1;
209 static int intel_th_pti_probe(struct intel_th_device *thdev)
211 struct device *dev = &thdev->dev;
212 struct resource *res;
213 struct pti_device *pti;
214 void __iomem *base;
216 res = intel_th_device_get_resource(thdev, IORESOURCE_MEM, 0);
217 if (!res)
218 return -ENODEV;
220 base = devm_ioremap(dev, res->start, resource_size(res));
221 if (!base)
222 return -ENOMEM;
224 pti = devm_kzalloc(dev, sizeof(*pti), GFP_KERNEL);
225 if (!pti)
226 return -ENOMEM;
228 pti->thdev = thdev;
229 pti->base = base;
231 read_hw_config(pti);
233 dev_set_drvdata(dev, pti);
235 return 0;
238 static void intel_th_pti_remove(struct intel_th_device *thdev)
242 static struct intel_th_driver intel_th_pti_driver = {
243 .probe = intel_th_pti_probe,
244 .remove = intel_th_pti_remove,
245 .activate = intel_th_pti_activate,
246 .deactivate = intel_th_pti_deactivate,
247 .attr_group = &pti_output_group,
248 .driver = {
249 .name = "pti",
250 .owner = THIS_MODULE,
254 static const char * const lpp_dest_str[] = { "pti", "exi" };
256 static ssize_t lpp_dest_show(struct device *dev, struct device_attribute *attr,
257 char *buf)
259 struct pti_device *pti = dev_get_drvdata(dev);
260 ssize_t ret = 0;
261 int i;
263 for (i = ARRAY_SIZE(lpp_dest_str) - 1; i >= 0; i--) {
264 const char *fmt = pti->lpp_dest == i ? "[%s] " : "%s ";
266 if (!(pti->lpp_dest_mask & BIT(i)))
267 continue;
269 ret += scnprintf(buf + ret, PAGE_SIZE - ret,
270 fmt, lpp_dest_str[i]);
273 if (ret)
274 buf[ret - 1] = '\n';
276 return ret;
279 static ssize_t lpp_dest_store(struct device *dev, struct device_attribute *attr,
280 const char *buf, size_t size)
282 struct pti_device *pti = dev_get_drvdata(dev);
283 ssize_t ret = -EINVAL;
284 int i;
286 for (i = 0; i < ARRAY_SIZE(lpp_dest_str); i++)
287 if (sysfs_streq(buf, lpp_dest_str[i]))
288 break;
290 if (i < ARRAY_SIZE(lpp_dest_str) && pti->lpp_dest_mask & BIT(i)) {
291 pti->lpp_dest = i;
292 ret = size;
295 return ret;
298 static DEVICE_ATTR_RW(lpp_dest);
300 static struct attribute *lpp_output_attrs[] = {
301 &dev_attr_mode.attr,
302 &dev_attr_freerunning_clock.attr,
303 &dev_attr_clock_divider.attr,
304 &dev_attr_lpp_dest.attr,
305 NULL,
308 static struct attribute_group lpp_output_group = {
309 .attrs = lpp_output_attrs,
312 static struct intel_th_driver intel_th_lpp_driver = {
313 .probe = intel_th_pti_probe,
314 .remove = intel_th_pti_remove,
315 .activate = intel_th_pti_activate,
316 .deactivate = intel_th_pti_deactivate,
317 .attr_group = &lpp_output_group,
318 .driver = {
319 .name = "lpp",
320 .owner = THIS_MODULE,
324 static int __init intel_th_pti_lpp_init(void)
326 int err;
328 err = intel_th_driver_register(&intel_th_pti_driver);
329 if (err)
330 return err;
332 err = intel_th_driver_register(&intel_th_lpp_driver);
333 if (err) {
334 intel_th_driver_unregister(&intel_th_pti_driver);
335 return err;
338 return 0;
341 module_init(intel_th_pti_lpp_init);
343 static void __exit intel_th_pti_lpp_exit(void)
345 intel_th_driver_unregister(&intel_th_pti_driver);
346 intel_th_driver_unregister(&intel_th_lpp_driver);
349 module_exit(intel_th_pti_lpp_exit);
351 MODULE_LICENSE("GPL v2");
352 MODULE_DESCRIPTION("Intel(R) Trace Hub PTI/LPP output driver");
353 MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");