intel_th: pti: Support Low Power Path output port type
The Low Power Path (LPP) output port type, looks mostly like PTI to the software, with a few additional bits in the control register. This extends the PTI driver to support LPP ports as well. Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
This commit is contained in:
parent
92758af39a
commit
f77d22bc12
@ -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>");
|
||||
|
@ -23,7 +23,15 @@ enum {
|
||||
#define PTI_EN BIT(0)
|
||||
#define PTI_FCEN BIT(1)
|
||||
#define PTI_MODE 0xf0
|
||||
#define LPP_PTIPRESENT BIT(8)
|
||||
#define LPP_BSSBPRESENT BIT(9)
|
||||
#define PTI_CLKDIV 0x000f0000
|
||||
#define PTI_PATGENMODE 0x00f00000
|
||||
#define LPP_DEST BIT(25)
|
||||
#define LPP_BSSBACT BIT(30)
|
||||
#define LPP_LPPBUSY BIT(31)
|
||||
|
||||
#define LPP_DEST_PTI BIT(0)
|
||||
#define LPP_DEST_EXI BIT(1)
|
||||
|
||||
#endif /* __INTEL_TH_STH_H__ */
|
||||
|
Loading…
Reference in New Issue
Block a user