root/drivers/hwtracing/intel_th/pti.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pti_width_mode
  2. mode_show
  3. mode_store
  4. freerunning_clock_show
  5. freerunning_clock_store
  6. clock_divider_show
  7. clock_divider_store
  8. intel_th_pti_activate
  9. intel_th_pti_deactivate
  10. read_hw_config
  11. intel_th_pti_probe
  12. intel_th_pti_remove
  13. lpp_dest_show
  14. lpp_dest_store
  15. intel_th_pti_lpp_init
  16. intel_th_pti_lpp_exit

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Intel(R) Trace Hub PTI output driver
   4  *
   5  * Copyright (C) 2014-2016 Intel Corporation.
   6  */
   7 
   8 #define pr_fmt(fmt)     KBUILD_MODNAME ": " fmt
   9 
  10 #include <linux/types.h>
  11 #include <linux/module.h>
  12 #include <linux/device.h>
  13 #include <linux/sizes.h>
  14 #include <linux/printk.h>
  15 #include <linux/slab.h>
  16 #include <linux/mm.h>
  17 #include <linux/io.h>
  18 
  19 #include "intel_th.h"
  20 #include "pti.h"
  21 
  22 struct pti_device {
  23         void __iomem            *base;
  24         struct intel_th_device  *thdev;
  25         unsigned int            mode;
  26         unsigned int            freeclk;
  27         unsigned int            clkdiv;
  28         unsigned int            patgen;
  29         unsigned int            lpp_dest_mask;
  30         unsigned int            lpp_dest;
  31 };
  32 
  33 /* map PTI widths to MODE settings of PTI_CTL register */
  34 static const unsigned int pti_mode[] = {
  35         0, 4, 8, 0, 12, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0,
  36 };
  37 
  38 static int pti_width_mode(unsigned int width)
  39 {
  40         int i;
  41 
  42         for (i = 0; i < ARRAY_SIZE(pti_mode); i++)
  43                 if (pti_mode[i] == width)
  44                         return i;
  45 
  46         return -EINVAL;
  47 }
  48 
  49 static ssize_t mode_show(struct device *dev, struct device_attribute *attr,
  50                          char *buf)
  51 {
  52         struct pti_device *pti = dev_get_drvdata(dev);
  53 
  54         return scnprintf(buf, PAGE_SIZE, "%d\n", pti_mode[pti->mode]);
  55 }
  56 
  57 static ssize_t mode_store(struct device *dev, struct device_attribute *attr,
  58                           const char *buf, size_t size)
  59 {
  60         struct pti_device *pti = dev_get_drvdata(dev);
  61         unsigned long val;
  62         int ret;
  63 
  64         ret = kstrtoul(buf, 10, &val);
  65         if (ret)
  66                 return ret;
  67 
  68         ret = pti_width_mode(val);
  69         if (ret < 0)
  70                 return ret;
  71 
  72         pti->mode = ret;
  73 
  74         return size;
  75 }
  76 
  77 static DEVICE_ATTR_RW(mode);
  78 
  79 static ssize_t
  80 freerunning_clock_show(struct device *dev, struct device_attribute *attr,
  81                        char *buf)
  82 {
  83         struct pti_device *pti = dev_get_drvdata(dev);
  84 
  85         return scnprintf(buf, PAGE_SIZE, "%d\n", pti->freeclk);
  86 }
  87 
  88 static ssize_t
  89 freerunning_clock_store(struct device *dev, struct device_attribute *attr,
  90                         const char *buf, size_t size)
  91 {
  92         struct pti_device *pti = dev_get_drvdata(dev);
  93         unsigned long val;
  94         int ret;
  95 
  96         ret = kstrtoul(buf, 10, &val);
  97         if (ret)
  98                 return ret;
  99 
 100         pti->freeclk = !!val;
 101 
 102         return size;
 103 }
 104 
 105 static DEVICE_ATTR_RW(freerunning_clock);
 106 
 107 static ssize_t
 108 clock_divider_show(struct device *dev, struct device_attribute *attr,
 109                    char *buf)
 110 {
 111         struct pti_device *pti = dev_get_drvdata(dev);
 112 
 113         return scnprintf(buf, PAGE_SIZE, "%d\n", 1u << pti->clkdiv);
 114 }
 115 
 116 static ssize_t
 117 clock_divider_store(struct device *dev, struct device_attribute *attr,
 118                     const char *buf, size_t size)
 119 {
 120         struct pti_device *pti = dev_get_drvdata(dev);
 121         unsigned long val;
 122         int ret;
 123 
 124         ret = kstrtoul(buf, 10, &val);
 125         if (ret)
 126                 return ret;
 127 
 128         if (!is_power_of_2(val) || val > 8 || !val)
 129                 return -EINVAL;
 130 
 131         pti->clkdiv = val;
 132 
 133         return size;
 134 }
 135 
 136 static DEVICE_ATTR_RW(clock_divider);
 137 
 138 static struct attribute *pti_output_attrs[] = {
 139         &dev_attr_mode.attr,
 140         &dev_attr_freerunning_clock.attr,
 141         &dev_attr_clock_divider.attr,
 142         NULL,
 143 };
 144 
 145 static struct attribute_group pti_output_group = {
 146         .attrs  = pti_output_attrs,
 147 };
 148 
 149 static int intel_th_pti_activate(struct intel_th_device *thdev)
 150 {
 151         struct pti_device *pti = dev_get_drvdata(&thdev->dev);
 152         u32 ctl = PTI_EN;
 153 
 154         if (pti->patgen)
 155                 ctl |= pti->patgen << __ffs(PTI_PATGENMODE);
 156         if (pti->freeclk)
 157                 ctl |= PTI_FCEN;
 158         ctl |= pti->mode << __ffs(PTI_MODE);
 159         ctl |= pti->clkdiv << __ffs(PTI_CLKDIV);
 160         ctl |= pti->lpp_dest << __ffs(LPP_DEST);
 161 
 162         iowrite32(ctl, pti->base + REG_PTI_CTL);
 163 
 164         intel_th_trace_enable(thdev);
 165 
 166         return 0;
 167 }
 168 
 169 static void intel_th_pti_deactivate(struct intel_th_device *thdev)
 170 {
 171         struct pti_device *pti = dev_get_drvdata(&thdev->dev);
 172 
 173         intel_th_trace_disable(thdev);
 174 
 175         iowrite32(0, pti->base + REG_PTI_CTL);
 176 }
 177 
 178 static void read_hw_config(struct pti_device *pti)
 179 {
 180         u32 ctl = ioread32(pti->base + REG_PTI_CTL);
 181 
 182         pti->mode       = (ctl & PTI_MODE) >> __ffs(PTI_MODE);
 183         pti->clkdiv     = (ctl & PTI_CLKDIV) >> __ffs(PTI_CLKDIV);
 184         pti->freeclk    = !!(ctl & PTI_FCEN);
 185 
 186         if (!pti_mode[pti->mode])
 187                 pti->mode = pti_width_mode(4);
 188         if (!pti->clkdiv)
 189                 pti->clkdiv = 1;
 190 
 191         if (pti->thdev->output.type == GTH_LPP) {
 192                 if (ctl & LPP_PTIPRESENT)
 193                         pti->lpp_dest_mask |= LPP_DEST_PTI;
 194                 if (ctl & LPP_BSSBPRESENT)
 195                         pti->lpp_dest_mask |= LPP_DEST_EXI;
 196                 if (ctl & LPP_DEST)
 197                         pti->lpp_dest = 1;
 198         }
 199 }
 200 
 201 static int intel_th_pti_probe(struct intel_th_device *thdev)
 202 {
 203         struct device *dev = &thdev->dev;
 204         struct resource *res;
 205         struct pti_device *pti;
 206         void __iomem *base;
 207 
 208         res = intel_th_device_get_resource(thdev, IORESOURCE_MEM, 0);
 209         if (!res)
 210                 return -ENODEV;
 211 
 212         base = devm_ioremap(dev, res->start, resource_size(res));
 213         if (!base)
 214                 return -ENOMEM;
 215 
 216         pti = devm_kzalloc(dev, sizeof(*pti), GFP_KERNEL);
 217         if (!pti)
 218                 return -ENOMEM;
 219 
 220         pti->thdev = thdev;
 221         pti->base = base;
 222 
 223         read_hw_config(pti);
 224 
 225         dev_set_drvdata(dev, pti);
 226 
 227         return 0;
 228 }
 229 
 230 static void intel_th_pti_remove(struct intel_th_device *thdev)
 231 {
 232 }
 233 
 234 static struct intel_th_driver intel_th_pti_driver = {
 235         .probe  = intel_th_pti_probe,
 236         .remove = intel_th_pti_remove,
 237         .activate       = intel_th_pti_activate,
 238         .deactivate     = intel_th_pti_deactivate,
 239         .attr_group     = &pti_output_group,
 240         .driver = {
 241                 .name   = "pti",
 242                 .owner  = THIS_MODULE,
 243         },
 244 };
 245 
 246 static const char * const lpp_dest_str[] = { "pti", "exi" };
 247 
 248 static ssize_t lpp_dest_show(struct device *dev, struct device_attribute *attr,
 249                              char *buf)
 250 {
 251         struct pti_device *pti = dev_get_drvdata(dev);
 252         ssize_t ret = 0;
 253         int i;
 254 
 255         for (i = ARRAY_SIZE(lpp_dest_str) - 1; i >= 0; i--) {
 256                 const char *fmt = pti->lpp_dest == i ? "[%s] " : "%s ";
 257 
 258                 if (!(pti->lpp_dest_mask & BIT(i)))
 259                         continue;
 260 
 261                 ret += scnprintf(buf + ret, PAGE_SIZE - ret,
 262                                  fmt, lpp_dest_str[i]);
 263         }
 264 
 265         if (ret)
 266                 buf[ret - 1] = '\n';
 267 
 268         return ret;
 269 }
 270 
 271 static ssize_t lpp_dest_store(struct device *dev, struct device_attribute *attr,
 272                               const char *buf, size_t size)
 273 {
 274         struct pti_device *pti = dev_get_drvdata(dev);
 275         int i;
 276 
 277         i = sysfs_match_string(lpp_dest_str, buf);
 278         if (i < 0)
 279                 return i;
 280 
 281         if (!(pti->lpp_dest_mask & BIT(i)))
 282                 return -EINVAL;
 283 
 284         pti->lpp_dest = i;
 285         return size;
 286 }
 287 
 288 static DEVICE_ATTR_RW(lpp_dest);
 289 
 290 static struct attribute *lpp_output_attrs[] = {
 291         &dev_attr_mode.attr,
 292         &dev_attr_freerunning_clock.attr,
 293         &dev_attr_clock_divider.attr,
 294         &dev_attr_lpp_dest.attr,
 295         NULL,
 296 };
 297 
 298 static struct attribute_group lpp_output_group = {
 299         .attrs  = lpp_output_attrs,
 300 };
 301 
 302 static struct intel_th_driver intel_th_lpp_driver = {
 303         .probe          = intel_th_pti_probe,
 304         .remove         = intel_th_pti_remove,
 305         .activate       = intel_th_pti_activate,
 306         .deactivate     = intel_th_pti_deactivate,
 307         .attr_group     = &lpp_output_group,
 308         .driver = {
 309                 .name   = "lpp",
 310                 .owner  = THIS_MODULE,
 311         },
 312 };
 313 
 314 static int __init intel_th_pti_lpp_init(void)
 315 {
 316         int err;
 317 
 318         err = intel_th_driver_register(&intel_th_pti_driver);
 319         if (err)
 320                 return err;
 321 
 322         err = intel_th_driver_register(&intel_th_lpp_driver);
 323         if (err) {
 324                 intel_th_driver_unregister(&intel_th_pti_driver);
 325                 return err;
 326         }
 327 
 328         return 0;
 329 }
 330 
 331 module_init(intel_th_pti_lpp_init);
 332 
 333 static void __exit intel_th_pti_lpp_exit(void)
 334 {
 335         intel_th_driver_unregister(&intel_th_pti_driver);
 336         intel_th_driver_unregister(&intel_th_lpp_driver);
 337 }
 338 
 339 module_exit(intel_th_pti_lpp_exit);
 340 
 341 MODULE_LICENSE("GPL v2");
 342 MODULE_DESCRIPTION("Intel(R) Trace Hub PTI/LPP output driver");
 343 MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");

/* [<][>][^][v][top][bottom][index][help] */