diff options
Diffstat (limited to 'drivers/hwtracing/intel_th/pti.c')
-rw-r--r-- | drivers/hwtracing/intel_th/pti.c | 115 |
1 files changed, 110 insertions, 5 deletions
diff --git a/drivers/hwtracing/intel_th/pti.c b/drivers/hwtracing/intel_th/pti.c index 35738b5bfccd..e96a1fcb57b2 100644 --- a/drivers/hwtracing/intel_th/pti.c +++ b/drivers/hwtracing/intel_th/pti.c @@ -1,7 +1,7 @@ /* * Intel(R) Trace Hub PTI output driver * - * Copyright (C) 2014-2015 Intel Corporation. + * Copyright (C) 2014-2016 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -34,6 +34,8 @@ struct pti_device { unsigned int freeclk; unsigned int clkdiv; unsigned int patgen; + unsigned int lpp_dest_mask; + unsigned int lpp_dest; }; /* map PTI widths to MODE settings of PTI_CTL register */ @@ -163,6 +165,7 @@ static int intel_th_pti_activate(struct intel_th_device *thdev) ctl |= PTI_FCEN; ctl |= pti->mode << __ffs(PTI_MODE); ctl |= pti->clkdiv << __ffs(PTI_CLKDIV); + ctl |= pti->lpp_dest << __ffs(LPP_DEST); iowrite32(ctl, pti->base + REG_PTI_CTL); @@ -192,6 +195,15 @@ static void read_hw_config(struct pti_device *pti) pti->mode = pti_width_mode(4); if (!pti->clkdiv) pti->clkdiv = 1; + + if (pti->thdev->output.type == GTH_LPP) { + if (ctl & LPP_PTIPRESENT) + pti->lpp_dest_mask |= LPP_DEST_PTI; + if (ctl & LPP_BSSBPRESENT) + pti->lpp_dest_mask |= LPP_DEST_EXI; + if (ctl & LPP_DEST) + pti->lpp_dest = 1; + } } static int intel_th_pti_probe(struct intel_th_device *thdev) @@ -239,10 +251,103 @@ static struct intel_th_driver intel_th_pti_driver = { }, }; -module_driver(intel_th_pti_driver, - intel_th_driver_register, - intel_th_driver_unregister); +static const char * const lpp_dest_str[] = { "pti", "exi" }; + +static ssize_t lpp_dest_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct pti_device *pti = dev_get_drvdata(dev); + ssize_t ret = 0; + int i; + + for (i = ARRAY_SIZE(lpp_dest_str) - 1; i >= 0; i--) { + const char *fmt = pti->lpp_dest == i ? "[%s] " : "%s "; + + if (!(pti->lpp_dest_mask & BIT(i))) + continue; + + ret += scnprintf(buf + ret, PAGE_SIZE - ret, + fmt, lpp_dest_str[i]); + } + + if (ret) + buf[ret - 1] = '\n'; + + return ret; +} + +static ssize_t lpp_dest_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + struct pti_device *pti = dev_get_drvdata(dev); + ssize_t ret = -EINVAL; + int i; + + for (i = 0; i < ARRAY_SIZE(lpp_dest_str); i++) + if (sysfs_streq(buf, lpp_dest_str[i])) + break; + + if (i < ARRAY_SIZE(lpp_dest_str) && pti->lpp_dest_mask & BIT(i)) { + pti->lpp_dest = i; + ret = size; + } + + return ret; +} + +static DEVICE_ATTR_RW(lpp_dest); + +static struct attribute *lpp_output_attrs[] = { + &dev_attr_mode.attr, + &dev_attr_freerunning_clock.attr, + &dev_attr_clock_divider.attr, + &dev_attr_lpp_dest.attr, + NULL, +}; + +static struct attribute_group lpp_output_group = { + .attrs = lpp_output_attrs, +}; + +static struct intel_th_driver intel_th_lpp_driver = { + .probe = intel_th_pti_probe, + .remove = intel_th_pti_remove, + .activate = intel_th_pti_activate, + .deactivate = intel_th_pti_deactivate, + .attr_group = &lpp_output_group, + .driver = { + .name = "lpp", + .owner = THIS_MODULE, + }, +}; + +static int __init intel_th_pti_lpp_init(void) +{ + int err; + + err = intel_th_driver_register(&intel_th_pti_driver); + if (err) + return err; + + err = intel_th_driver_register(&intel_th_lpp_driver); + if (err) { + intel_th_driver_unregister(&intel_th_pti_driver); + return err; + } + + return 0; +} + +module_init(intel_th_pti_lpp_init); + +static void __exit intel_th_pti_lpp_exit(void) +{ + intel_th_driver_unregister(&intel_th_pti_driver); + intel_th_driver_unregister(&intel_th_lpp_driver); +} + +module_exit(intel_th_pti_lpp_exit); MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Intel(R) Trace Hub PTI output driver"); +MODULE_DESCRIPTION("Intel(R) Trace Hub PTI/LPP output driver"); MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>"); |