linux/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * processor thermal device RFIM control
   4 * Copyright (c) 2020, Intel Corporation.
   5 */
   6
   7#include <linux/kernel.h>
   8#include <linux/module.h>
   9#include <linux/pci.h>
  10#include "processor_thermal_device.h"
  11
  12struct mmio_reg {
  13        int read_only;
  14        u32 offset;
  15        int bits;
  16        u16 mask;
  17        u16 shift;
  18};
  19
  20/* These will represent sysfs attribute names */
  21static const char * const fivr_strings[] = {
  22        "vco_ref_code_lo",
  23        "vco_ref_code_hi",
  24        "spread_spectrum_pct",
  25        "spread_spectrum_clk_enable",
  26        "rfi_vco_ref_code",
  27        "fivr_fffc_rev",
  28        NULL
  29};
  30
  31static const struct mmio_reg tgl_fivr_mmio_regs[] = {
  32        { 0, 0x5A18, 3, 0x7, 12}, /* vco_ref_code_lo */
  33        { 0, 0x5A18, 8, 0xFF, 16}, /* vco_ref_code_hi */
  34        { 0, 0x5A08, 8, 0xFF, 0}, /* spread_spectrum_pct */
  35        { 0, 0x5A08, 1, 0x1, 8}, /* spread_spectrum_clk_enable */
  36        { 1, 0x5A10, 12, 0xFFF, 0}, /* rfi_vco_ref_code */
  37        { 1, 0x5A14, 2, 0x3, 1}, /* fivr_fffc_rev */
  38};
  39
  40/* These will represent sysfs attribute names */
  41static const char * const dvfs_strings[] = {
  42        "rfi_restriction_run_busy",
  43        "rfi_restriction_err_code",
  44        "rfi_restriction_data_rate",
  45        "rfi_restriction_data_rate_base",
  46        "ddr_data_rate_point_0",
  47        "ddr_data_rate_point_1",
  48        "ddr_data_rate_point_2",
  49        "ddr_data_rate_point_3",
  50        "rfi_disable",
  51        NULL
  52};
  53
  54static const struct mmio_reg adl_dvfs_mmio_regs[] = {
  55        { 0, 0x5A38, 1, 0x1, 31}, /* rfi_restriction_run_busy */
  56        { 0, 0x5A38, 7, 0x7F, 24}, /* rfi_restriction_err_code */
  57        { 0, 0x5A38, 8, 0xFF, 16}, /* rfi_restriction_data_rate */
  58        { 0, 0x5A38, 16, 0xFFFF, 0}, /* rfi_restriction_data_rate_base */
  59        { 0, 0x5A30, 10, 0x3FF, 0}, /* ddr_data_rate_point_0 */
  60        { 0, 0x5A30, 10, 0x3FF, 10}, /* ddr_data_rate_point_1 */
  61        { 0, 0x5A30, 10, 0x3FF, 20}, /* ddr_data_rate_point_2 */
  62        { 0, 0x5A30, 10, 0x3FF, 30}, /* ddr_data_rate_point_3 */
  63        { 0, 0x5A40, 1, 0x1, 0}, /* rfi_disable */
  64};
  65
  66#define RFIM_SHOW(suffix, table)\
  67static ssize_t suffix##_show(struct device *dev,\
  68                              struct device_attribute *attr,\
  69                              char *buf)\
  70{\
  71        struct proc_thermal_device *proc_priv;\
  72        struct pci_dev *pdev = to_pci_dev(dev);\
  73        const struct mmio_reg *mmio_regs;\
  74        const char **match_strs;\
  75        u32 reg_val;\
  76        int ret;\
  77\
  78        proc_priv = pci_get_drvdata(pdev);\
  79        if (table) {\
  80                match_strs = (const char **)dvfs_strings;\
  81                mmio_regs = adl_dvfs_mmio_regs;\
  82        } else { \
  83                match_strs = (const char **)fivr_strings;\
  84                mmio_regs = tgl_fivr_mmio_regs;\
  85        } \
  86        \
  87        ret = match_string(match_strs, -1, attr->attr.name);\
  88        if (ret < 0)\
  89                return ret;\
  90        reg_val = readl((void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\
  91        ret = (reg_val >> mmio_regs[ret].shift) & mmio_regs[ret].mask;\
  92        return sprintf(buf, "%u\n", ret);\
  93}
  94
  95#define RFIM_STORE(suffix, table)\
  96static ssize_t suffix##_store(struct device *dev,\
  97                               struct device_attribute *attr,\
  98                               const char *buf, size_t count)\
  99{\
 100        struct proc_thermal_device *proc_priv;\
 101        struct pci_dev *pdev = to_pci_dev(dev);\
 102        unsigned int input;\
 103        const char **match_strs;\
 104        const struct mmio_reg *mmio_regs;\
 105        int ret, err;\
 106        u32 reg_val;\
 107        u32 mask;\
 108\
 109        proc_priv = pci_get_drvdata(pdev);\
 110        if (table) {\
 111                match_strs = (const char **)dvfs_strings;\
 112                mmio_regs = adl_dvfs_mmio_regs;\
 113        } else { \
 114                match_strs = (const char **)fivr_strings;\
 115                mmio_regs = tgl_fivr_mmio_regs;\
 116        } \
 117        \
 118        ret = match_string(match_strs, -1, attr->attr.name);\
 119        if (ret < 0)\
 120                return ret;\
 121        if (mmio_regs[ret].read_only)\
 122                return -EPERM;\
 123        err = kstrtouint(buf, 10, &input);\
 124        if (err)\
 125                return err;\
 126        mask = GENMASK(mmio_regs[ret].shift + mmio_regs[ret].bits - 1, mmio_regs[ret].shift);\
 127        reg_val = readl((void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\
 128        reg_val &= ~mask;\
 129        reg_val |= (input << mmio_regs[ret].shift);\
 130        writel(reg_val, (void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\
 131        return count;\
 132}
 133
 134RFIM_SHOW(vco_ref_code_lo, 0)
 135RFIM_SHOW(vco_ref_code_hi, 0)
 136RFIM_SHOW(spread_spectrum_pct, 0)
 137RFIM_SHOW(spread_spectrum_clk_enable, 0)
 138RFIM_SHOW(rfi_vco_ref_code, 0)
 139RFIM_SHOW(fivr_fffc_rev, 0)
 140
 141RFIM_STORE(vco_ref_code_lo, 0)
 142RFIM_STORE(vco_ref_code_hi, 0)
 143RFIM_STORE(spread_spectrum_pct, 0)
 144RFIM_STORE(spread_spectrum_clk_enable, 0)
 145RFIM_STORE(rfi_vco_ref_code, 0)
 146RFIM_STORE(fivr_fffc_rev, 0)
 147
 148static DEVICE_ATTR_RW(vco_ref_code_lo);
 149static DEVICE_ATTR_RW(vco_ref_code_hi);
 150static DEVICE_ATTR_RW(spread_spectrum_pct);
 151static DEVICE_ATTR_RW(spread_spectrum_clk_enable);
 152static DEVICE_ATTR_RW(rfi_vco_ref_code);
 153static DEVICE_ATTR_RW(fivr_fffc_rev);
 154
 155static struct attribute *fivr_attrs[] = {
 156        &dev_attr_vco_ref_code_lo.attr,
 157        &dev_attr_vco_ref_code_hi.attr,
 158        &dev_attr_spread_spectrum_pct.attr,
 159        &dev_attr_spread_spectrum_clk_enable.attr,
 160        &dev_attr_rfi_vco_ref_code.attr,
 161        &dev_attr_fivr_fffc_rev.attr,
 162        NULL
 163};
 164
 165static const struct attribute_group fivr_attribute_group = {
 166        .attrs = fivr_attrs,
 167        .name = "fivr"
 168};
 169
 170RFIM_SHOW(rfi_restriction_run_busy, 1)
 171RFIM_SHOW(rfi_restriction_err_code, 1)
 172RFIM_SHOW(rfi_restriction_data_rate, 1)
 173RFIM_SHOW(ddr_data_rate_point_0, 1)
 174RFIM_SHOW(ddr_data_rate_point_1, 1)
 175RFIM_SHOW(ddr_data_rate_point_2, 1)
 176RFIM_SHOW(ddr_data_rate_point_3, 1)
 177RFIM_SHOW(rfi_disable, 1)
 178
 179RFIM_STORE(rfi_restriction_run_busy, 1)
 180RFIM_STORE(rfi_restriction_err_code, 1)
 181RFIM_STORE(rfi_restriction_data_rate, 1)
 182RFIM_STORE(rfi_disable, 1)
 183
 184static DEVICE_ATTR_RW(rfi_restriction_run_busy);
 185static DEVICE_ATTR_RW(rfi_restriction_err_code);
 186static DEVICE_ATTR_RW(rfi_restriction_data_rate);
 187static DEVICE_ATTR_RO(ddr_data_rate_point_0);
 188static DEVICE_ATTR_RO(ddr_data_rate_point_1);
 189static DEVICE_ATTR_RO(ddr_data_rate_point_2);
 190static DEVICE_ATTR_RO(ddr_data_rate_point_3);
 191static DEVICE_ATTR_RW(rfi_disable);
 192
 193static ssize_t rfi_restriction_store(struct device *dev,
 194                                     struct device_attribute *attr,
 195                                     const char *buf, size_t count)
 196{
 197        u16 cmd_id = 0x0008;
 198        u32 cmd_resp;
 199        u32 input;
 200        int ret;
 201
 202        ret = kstrtou32(buf, 10, &input);
 203        if (ret)
 204                return ret;
 205
 206        ret = processor_thermal_send_mbox_cmd(to_pci_dev(dev), cmd_id, input, &cmd_resp);
 207        if (ret)
 208                return ret;
 209
 210        return count;
 211}
 212
 213static ssize_t rfi_restriction_show(struct device *dev,
 214                                    struct device_attribute *attr,
 215                                    char *buf)
 216{
 217        u16 cmd_id = 0x0007;
 218        u32 cmd_resp;
 219        int ret;
 220
 221        ret = processor_thermal_send_mbox_cmd(to_pci_dev(dev), cmd_id, 0, &cmd_resp);
 222        if (ret)
 223                return ret;
 224
 225        return sprintf(buf, "%u\n", cmd_resp);
 226}
 227
 228static ssize_t ddr_data_rate_show(struct device *dev,
 229                                  struct device_attribute *attr,
 230                                  char *buf)
 231{
 232        u16 cmd_id = 0x0107;
 233        u32 cmd_resp;
 234        int ret;
 235
 236        ret = processor_thermal_send_mbox_cmd(to_pci_dev(dev), cmd_id, 0, &cmd_resp);
 237        if (ret)
 238                return ret;
 239
 240        return sprintf(buf, "%u\n", cmd_resp);
 241}
 242
 243static DEVICE_ATTR_RW(rfi_restriction);
 244static DEVICE_ATTR_RO(ddr_data_rate);
 245
 246static struct attribute *dvfs_attrs[] = {
 247        &dev_attr_rfi_restriction_run_busy.attr,
 248        &dev_attr_rfi_restriction_err_code.attr,
 249        &dev_attr_rfi_restriction_data_rate.attr,
 250        &dev_attr_ddr_data_rate_point_0.attr,
 251        &dev_attr_ddr_data_rate_point_1.attr,
 252        &dev_attr_ddr_data_rate_point_2.attr,
 253        &dev_attr_ddr_data_rate_point_3.attr,
 254        &dev_attr_rfi_disable.attr,
 255        &dev_attr_ddr_data_rate.attr,
 256        &dev_attr_rfi_restriction.attr,
 257        NULL
 258};
 259
 260static const struct attribute_group dvfs_attribute_group = {
 261        .attrs = dvfs_attrs,
 262        .name = "dvfs"
 263};
 264
 265int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
 266{
 267        int ret;
 268
 269        if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) {
 270                ret = sysfs_create_group(&pdev->dev.kobj, &fivr_attribute_group);
 271                if (ret)
 272                        return ret;
 273        }
 274
 275        if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS) {
 276                ret = sysfs_create_group(&pdev->dev.kobj, &dvfs_attribute_group);
 277                if (ret && proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) {
 278                        sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group);
 279                        return ret;
 280                }
 281        }
 282
 283        return 0;
 284}
 285EXPORT_SYMBOL_GPL(proc_thermal_rfim_add);
 286
 287void proc_thermal_rfim_remove(struct pci_dev *pdev)
 288{
 289        struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);
 290
 291        if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR)
 292                sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group);
 293
 294        if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS)
 295                sysfs_remove_group(&pdev->dev.kobj, &dvfs_attribute_group);
 296}
 297EXPORT_SYMBOL_GPL(proc_thermal_rfim_remove);
 298
 299MODULE_LICENSE("GPL v2");
 300