diff -Naur linux-5.12/drivers/hwmon/k10temp.c linux-5.12-p/drivers/hwmon/k10temp.c --- linux-5.12/drivers/hwmon/k10temp.c 2021-04-25 22:49:08.000000000 +0200 +++ linux-5.12-p/drivers/hwmon/k10temp.c 2021-04-26 15:49:17.205409281 +0200 @@ -11,6 +11,13 @@ * convert raw register values is from https://github.com/ocerman/zenpower. * The information is not confirmed from chip datasheets, but experiments * suggest that it provides reasonable temperature values. + * - Register addresses to read chip voltage and current are also from + * https://github.com/ocerman/zenpower, and not confirmed from chip + * datasheets. Current calibration is board specific and not typically + * shared by board vendors. For this reason, current values are + * normalized to report 1A/LSB for core current and and 0.25A/LSB for SoC + * current. Reported values can be adjusted using the sensors configuration + * file. */ #include @@ -80,17 +87,34 @@ /* F17h thermal registers through SMN */ #define F17H_M01H_SVI_TEL_PLANE0 (ZEN_SVI_BASE + 0xc) #define F17H_M01H_SVI_TEL_PLANE1 (ZEN_SVI_BASE + 0x10) + +/* ZEN2 SP3/TR */ #define F17H_M31H_SVI_TEL_PLANE0 (ZEN_SVI_BASE + 0x14) #define F17H_M31H_SVI_TEL_PLANE1 (ZEN_SVI_BASE + 0x10) +/* ZEN2 Ryzen Desktop */ +#define F17H_M71H_SVI_TEL_PLANE0 (ZEN_SVI_BASE + 0x10) +#define F17H_M71H_SVI_TEL_PLANE1 (ZEN_SVI_BASE + 0xc) + +/* Renoir is different */ +#define F17H_RN_SVI 0x0006F000 +#define F17H_RN_SVI_TEL_PLANE0 (F17H_RN_SVI + 0x38) +#define F17H_RN_SVI_TEL_PLANE1 (F17H_RN_SVI + 0x3C) + +/* fixme: figure these */ #define F17H_M01H_CFACTOR_ICORE 1000000 /* 1A / LSB */ #define F17H_M01H_CFACTOR_ISOC 250000 /* 0.25A / LSB */ #define F17H_M31H_CFACTOR_ICORE 1000000 /* 1A / LSB */ #define F17H_M31H_CFACTOR_ISOC 310000 /* 0.31A / LSB */ /* F19h thermal registers through SMN */ -#define F19H_M01_SVI_TEL_PLANE0 (ZEN_SVI_BASE + 0x14) -#define F19H_M01_SVI_TEL_PLANE1 (ZEN_SVI_BASE + 0x10) +/* ZEN3 SP3/TR */ +#define F19H_M01H_SVI_TEL_PLANE0 (ZEN_SVI_BASE + 0x14) +#define F19H_M01H_SVI_TEL_PLANE1 (ZEN_SVI_BASE + 0x10) + +/* ZEN3 Ryzen Desktop */ +#define F19H_M21H_SVI_TEL_PLANE0 (ZEN_SVI_BASE + 0x10) +#define F19H_M21H_SVI_TEL_PLANE1 (ZEN_SVI_BASE + 0xc) #define F19H_M01H_CFACTOR_ICORE 1000000 /* 1A / LSB */ #define F19H_M01H_CFACTOR_ISOC 310000 /* 0.31A / LSB */ @@ -102,7 +126,10 @@ int temp_offset; u32 temp_adjust_mask; u32 show_temp; + u32 svi_addr[2]; bool is_zen; + bool show_current; + int cfactor[2]; }; #define TCTL_BIT 0 @@ -127,6 +154,16 @@ { 0x17, "AMD Ryzen Threadripper 29", 27000 }, /* 29{20,50,70,90}[W]X */ }; +static bool is_threadripper(void) +{ + return strstr(boot_cpu_data.x86_model_id, "Threadripper"); +} + +static bool is_epyc(void) +{ + return strstr(boot_cpu_data.x86_model_id, "EPYC"); +} + static void read_htcreg_pci(struct pci_dev *pdev, u32 *regval) { pci_read_config_dword(pdev, REG_HARDWARE_THERMAL_CONTROL, regval); @@ -191,6 +228,16 @@ "Tccd8", }; +static const char *k10temp_in_label[] = { + "Vcore", + "Vsoc", +}; + +static const char *k10temp_curr_label[] = { + "Icore", + "Isoc", +}; + static int k10temp_read_labels(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, const char **str) @@ -199,6 +246,50 @@ case hwmon_temp: *str = k10temp_temp_label[channel]; break; + case hwmon_in: + *str = k10temp_in_label[channel]; + break; + case hwmon_curr: + *str = k10temp_curr_label[channel]; + break; + default: + return -EOPNOTSUPP; + } + return 0; +} + +static int k10temp_read_curr(struct device *dev, u32 attr, int channel, + long *val) +{ + struct k10temp_data *data = dev_get_drvdata(dev); + u32 regval; + + switch (attr) { + case hwmon_curr_input: + amd_smn_read(amd_pci_dev_to_node_id(data->pdev), + data->svi_addr[channel], ®val); + *val = DIV_ROUND_CLOSEST(data->cfactor[channel] * + (regval & 0xff), + 1000); + break; + default: + return -EOPNOTSUPP; + } + return 0; +} + +static int k10temp_read_in(struct device *dev, u32 attr, int channel, long *val) +{ + struct k10temp_data *data = dev_get_drvdata(dev); + u32 regval; + + switch (attr) { + case hwmon_in_input: + amd_smn_read(amd_pci_dev_to_node_id(data->pdev), + data->svi_addr[channel], ®val); + regval = (regval >> 16) & 0xff; + *val = DIV_ROUND_CLOSEST(155000 - regval * 625, 100); + break; default: return -EOPNOTSUPP; } @@ -257,6 +348,10 @@ switch (type) { case hwmon_temp: return k10temp_read_temp(dev, attr, channel, val); + case hwmon_in: + return k10temp_read_in(dev, attr, channel, val); + case hwmon_curr: + return k10temp_read_curr(dev, attr, channel, val); default: return -EOPNOTSUPP; } @@ -305,6 +400,11 @@ return 0; } break; + case hwmon_in: + case hwmon_curr: + if (!data->show_current) + return 0; + break; default: return 0; } @@ -430,16 +530,43 @@ data->is_zen = true; switch (boot_cpu_data.x86_model) { + /* FIXME: those looks wrong too */ case 0x1: /* Zen */ case 0x8: /* Zen+ */ case 0x11: /* Zen APU */ case 0x18: /* Zen+ APU */ + data->show_current = !is_threadripper() && !is_epyc(); + data->svi_addr[0] = F17H_M01H_SVI_TEL_PLANE0; + data->svi_addr[1] = F17H_M01H_SVI_TEL_PLANE1; + data->cfactor[0] = F17H_M01H_CFACTOR_ICORE; + data->cfactor[1] = F17H_M01H_CFACTOR_ISOC; k10temp_get_ccd_support(pdev, data, 4); break; - case 0x31: /* Zen2 Threadripper */ - case 0x71: /* Zen2 */ + case 0x31: /* Zen2 SP3/TR */ + data->show_current = !is_threadripper() && !is_epyc(); + data->cfactor[0] = F17H_M31H_CFACTOR_ICORE; + data->cfactor[1] = F17H_M31H_CFACTOR_ISOC; + data->svi_addr[0] = F17H_M31H_SVI_TEL_PLANE0; + data->svi_addr[1] = F17H_M31H_SVI_TEL_PLANE1; k10temp_get_ccd_support(pdev, data, 8); break; + case 0x60: /* Renoir APUs */ + data->show_current = true; + /* FIXME */ + data->cfactor[0] = F17H_M31H_CFACTOR_ICORE; + data->cfactor[1] = F17H_M31H_CFACTOR_ISOC; + data->svi_addr[0] = F17H_RN_SVI_TEL_PLANE0; + data->svi_addr[1] = F17H_RN_SVI_TEL_PLANE1; + k10temp_get_ccd_support(pdev, data, 4); /* probably not needed */ + break; + case 0x71: /* ZEN2 Ryzen Desktop */ + data->show_current = true; + data->cfactor[0] = F17H_M31H_CFACTOR_ICORE; + data->cfactor[1] = F17H_M31H_CFACTOR_ISOC; + data->svi_addr[0] = F17H_M71H_SVI_TEL_PLANE0; + data->svi_addr[1] = F17H_M71H_SVI_TEL_PLANE1; + k10temp_get_ccd_support(pdev, data, 4); + break; } } else if (boot_cpu_data.x86 == 0x19) { data->temp_adjust_mask = ZEN_CUR_TEMP_RANGE_SEL_MASK; @@ -449,9 +576,21 @@ switch (boot_cpu_data.x86_model) { case 0x0 ... 0x1: /* Zen3 SP3/TR */ - case 0x21: /* Zen3 Ryzen Desktop */ + data->show_current = true; + data->svi_addr[0] = F19H_M01H_SVI_TEL_PLANE0; + data->svi_addr[1] = F19H_M01H_SVI_TEL_PLANE1; + data->cfactor[0] = F19H_M01H_CFACTOR_ICORE; + data->cfactor[1] = F19H_M01H_CFACTOR_ISOC; k10temp_get_ccd_support(pdev, data, 8); break; + case 0x21: /* ZEN3 Ryzen Desktop */ + data->show_current = true; + data->svi_addr[0] = F19H_M21H_SVI_TEL_PLANE0; + data->svi_addr[1] = F19H_M21H_SVI_TEL_PLANE1; + data->cfactor[0] = F19H_M01H_CFACTOR_ICORE; + data->cfactor[1] = F19H_M01H_CFACTOR_ISOC; + k10temp_get_ccd_support(pdev, data, 2); + break; } } else { data->read_htcreg = read_htcreg_pci;