1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * processor thermal device platform temperature controls 4 * Copyright (c) 2025, Intel Corporation. 5 */ 6 7 /* 8 * Platform temperature controls hardware interface 9 * 10 * The hardware control interface is via MMIO offsets in the processor 11 * thermal device MMIO space. There are three instances of MMIO registers. 12 * All registers are 64 bit wide with RW access. 13 * 14 * Name: PLATFORM_TEMPERATURE_CONTROL 15 * Offsets: 0x5B20, 0x5B28, 0x5B30 16 * 17 * Bits Description 18 * 7:0 TARGET_TEMP : Target temperature limit to which the control 19 * mechanism is regulating. Units: 0.5C. 20 * 8:8 ENABLE: Read current enable status of the feature or enable 21 * feature. 22 * 11:9 GAIN: Sets the aggressiveness of control loop from 0 to 7 23 * 7 graceful, favors performance at the expense of temperature 24 * overshoots 25 * 0 aggressive, favors tight regulation over performance 26 * 12:12 TEMPERATURE_OVERRIDE_EN 27 * When set, hardware will use TEMPERATURE_OVERRIDE values instead 28 * of reading from corresponding sensor. 29 * 15:13 RESERVED 30 * 23:16 MIN_PERFORMANCE_LEVEL: Minimum Performance level below which the 31 * there will be no throttling. 0 - all levels of throttling allowed 32 * including survivability actions. 255 - no throttling allowed. 33 * 31:24 TEMPERATURE_OVERRIDE: Allows SW to override the input temperature. 34 * hardware will use this value instead of the sensor temperature. 35 * Units: 0.5C. 36 * 63:32 RESERVED 37 */ 38 39 #include <linux/kernel.h> 40 #include <linux/module.h> 41 #include <linux/pci.h> 42 #include "processor_thermal_device.h" 43 44 struct mmio_reg { 45 int bits; 46 u16 mask; 47 u16 shift; 48 u16 units; 49 }; 50 51 #define MAX_ATTR_GROUP_NAME_LEN 32 52 #define PTC_MAX_ATTRS 3 53 54 struct ptc_data { 55 u32 offset; 56 struct attribute_group ptc_attr_group; 57 struct attribute *ptc_attrs[PTC_MAX_ATTRS]; 58 struct device_attribute temperature_target_attr; 59 struct device_attribute enable_attr; 60 char group_name[MAX_ATTR_GROUP_NAME_LEN]; 61 }; 62 63 static const struct mmio_reg ptc_mmio_regs[] = { 64 { 8, 0xFF, 0, 500}, /* temperature_target, units 0.5C*/ 65 { 1, 0x01, 8, 0}, /* enable */ 66 { 3, 0x7, 9, 0}, /* gain */ 67 { 8, 0xFF, 16, 0}, /* min_performance_level */ 68 { 1, 0x1, 12, 0}, /* temperature_override_enable */ 69 { 8, 0xFF, 24, 500}, /* temperature_override, units 0.5C */ 70 }; 71 72 #define PTC_MAX_INSTANCES 3 73 74 /* Unique offset for each PTC instance */ 75 static u32 ptc_offsets[PTC_MAX_INSTANCES] = {0x5B20, 0x5B28, 0x5B30}; 76 77 /* These will represent sysfs attribute names */ 78 static const char * const ptc_strings[] = { 79 "temperature_target", 80 "enable", 81 NULL 82 }; 83 84 /* Lock to protect concurrent read/write and read-modify-write */ 85 static DEFINE_MUTEX(ptc_lock); 86 87 static ssize_t ptc_mmio_show(struct ptc_data *data, struct device *dev, 88 struct device_attribute *attr, char *buf) 89 { 90 struct pci_dev *pdev = to_pci_dev(dev); 91 struct proc_thermal_device *proc_priv; 92 const struct mmio_reg *mmio_regs; 93 int ret, units; 94 u64 reg_val; 95 96 proc_priv = pci_get_drvdata(pdev); 97 mmio_regs = ptc_mmio_regs; 98 ret = match_string(ptc_strings, -1, attr->attr.name); 99 if (ret < 0) 100 return ret; 101 102 units = mmio_regs[ret].units; 103 104 guard(mutex)(&ptc_lock); 105 106 reg_val = readq((void __iomem *) (proc_priv->mmio_base + data->offset)); 107 ret = (reg_val >> mmio_regs[ret].shift) & mmio_regs[ret].mask; 108 if (units) 109 ret *= units; 110 111 return sysfs_emit(buf, "%d\n", ret); 112 } 113 114 #define PTC_SHOW(suffix)\ 115 static ssize_t suffix##_show(struct device *dev,\ 116 struct device_attribute *attr,\ 117 char *buf)\ 118 {\ 119 struct ptc_data *data = container_of(attr, struct ptc_data, suffix##_attr);\ 120 return ptc_mmio_show(data, dev, attr, buf);\ 121 } 122 123 static void ptc_mmio_write(struct pci_dev *pdev, u32 offset, int index, u32 value) 124 { 125 struct proc_thermal_device *proc_priv; 126 u64 mask, reg_val; 127 128 proc_priv = pci_get_drvdata(pdev); 129 130 mask = GENMASK_ULL(ptc_mmio_regs[index].shift + ptc_mmio_regs[index].bits - 1, 131 ptc_mmio_regs[index].shift); 132 133 guard(mutex)(&ptc_lock); 134 135 reg_val = readq((void __iomem *) (proc_priv->mmio_base + offset)); 136 reg_val &= ~mask; 137 reg_val |= (value << ptc_mmio_regs[index].shift); 138 writeq(reg_val, (void __iomem *) (proc_priv->mmio_base + offset)); 139 } 140 141 static int ptc_store(struct ptc_data *data, struct device *dev, struct device_attribute *attr, 142 const char *buf, size_t count) 143 { 144 struct pci_dev *pdev = to_pci_dev(dev); 145 unsigned int input; 146 int ret; 147 148 ret = kstrtouint(buf, 10, &input); 149 if (ret) 150 return ret; 151 152 ret = match_string(ptc_strings, -1, attr->attr.name); 153 if (ret < 0) 154 return ret; 155 156 if (ptc_mmio_regs[ret].units) 157 input /= ptc_mmio_regs[ret].units; 158 159 if (input > ptc_mmio_regs[ret].mask) 160 return -EINVAL; 161 162 ptc_mmio_write(pdev, data->offset, ret, input); 163 164 return count; 165 } 166 167 #define PTC_STORE(suffix)\ 168 static ssize_t suffix##_store(struct device *dev,\ 169 struct device_attribute *attr,\ 170 const char *buf, size_t count)\ 171 {\ 172 struct ptc_data *data = container_of(attr, struct ptc_data, suffix##_attr);\ 173 return ptc_store(data, dev, attr, buf, count);\ 174 } 175 176 PTC_SHOW(temperature_target); 177 PTC_STORE(temperature_target); 178 PTC_SHOW(enable); 179 PTC_STORE(enable); 180 181 #define ptc_init_attribute(_name)\ 182 do {\ 183 sysfs_attr_init(&data->_name##_attr.attr);\ 184 data->_name##_attr.show = _name##_show;\ 185 data->_name##_attr.store = _name##_store;\ 186 data->_name##_attr.attr.name = #_name;\ 187 data->_name##_attr.attr.mode = 0644;\ 188 } while (0) 189 190 static int ptc_create_groups(struct pci_dev *pdev, int instance, struct ptc_data *data) 191 { 192 int ret, index = 0; 193 194 ptc_init_attribute(temperature_target); 195 ptc_init_attribute(enable); 196 197 data->ptc_attrs[index++] = &data->temperature_target_attr.attr; 198 data->ptc_attrs[index++] = &data->enable_attr.attr; 199 data->ptc_attrs[index] = NULL; 200 201 snprintf(data->group_name, MAX_ATTR_GROUP_NAME_LEN, 202 "ptc_%d_control", instance); 203 data->ptc_attr_group.name = data->group_name; 204 data->ptc_attr_group.attrs = data->ptc_attrs; 205 206 ret = sysfs_create_group(&pdev->dev.kobj, &data->ptc_attr_group); 207 208 return ret; 209 } 210 211 static struct ptc_data ptc_instance[PTC_MAX_INSTANCES]; 212 213 int proc_thermal_ptc_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv) 214 { 215 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_PTC) { 216 int i; 217 218 for (i = 0; i < PTC_MAX_INSTANCES; i++) { 219 ptc_instance[i].offset = ptc_offsets[i]; 220 ptc_create_groups(pdev, i, &ptc_instance[i]); 221 } 222 } 223 224 return 0; 225 } 226 EXPORT_SYMBOL_GPL(proc_thermal_ptc_add); 227 228 void proc_thermal_ptc_remove(struct pci_dev *pdev) 229 { 230 struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev); 231 232 if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_PTC) { 233 int i; 234 235 for (i = 0; i < PTC_MAX_INSTANCES; i++) 236 sysfs_remove_group(&pdev->dev.kobj, &ptc_instance[i].ptc_attr_group); 237 } 238 } 239 EXPORT_SYMBOL_GPL(proc_thermal_ptc_remove); 240 241 MODULE_IMPORT_NS("INT340X_THERMAL"); 242 MODULE_LICENSE("GPL"); 243 MODULE_DESCRIPTION("Processor Thermal PTC Interface"); 244