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