summaryrefslogtreecommitdiff
path: root/sys-kernel/linux-image-redcore/files/5.5-02-hwmon-add-zenpower-module.patch
diff options
context:
space:
mode:
Diffstat (limited to 'sys-kernel/linux-image-redcore/files/5.5-02-hwmon-add-zenpower-module.patch')
-rw-r--r--sys-kernel/linux-image-redcore/files/5.5-02-hwmon-add-zenpower-module.patch693
1 files changed, 0 insertions, 693 deletions
diff --git a/sys-kernel/linux-image-redcore/files/5.5-02-hwmon-add-zenpower-module.patch b/sys-kernel/linux-image-redcore/files/5.5-02-hwmon-add-zenpower-module.patch
deleted file mode 100644
index d155d386..00000000
--- a/sys-kernel/linux-image-redcore/files/5.5-02-hwmon-add-zenpower-module.patch
+++ /dev/null
@@ -1,693 +0,0 @@
-diff -Naur linux-5.5.5/drivers/hwmon/Kconfig linux-5.5.5-p/drivers/hwmon/Kconfig
---- linux-5.5.5/drivers/hwmon/Kconfig 2020-02-23 19:55:09.002053939 +0100
-+++ linux-5.5.5-p/drivers/hwmon/Kconfig 2020-02-23 19:52:32.184058339 +0100
-@@ -295,6 +295,17 @@
- This driver can also be built as a module. If so, the module
- will be called k10temp.
-
-+config SENSORS_ZENPOWER
-+ tristate "AMD Family 17h+ temperature and power sensor"
-+ depends on X86 && PCI && AMD_NB
-+ help
-+ If you say yes here you get support for the temperature and power
-+ sensor(s) inside your CPU. Supported are later revisions of
-+ the AMD Family 17h microarchitectures.
-+
-+ This driver can also be built as a module. If so, the module
-+ will be called zenpower.
-+
- config SENSORS_FAM15H_POWER
- tristate "AMD Family 15h processor power"
- depends on X86 && PCI && CPU_SUP_AMD
-diff -Naur linux-5.5.5/drivers/hwmon/Makefile linux-5.5.5-p/drivers/hwmon/Makefile
---- linux-5.5.5/drivers/hwmon/Makefile 2020-02-19 19:54:14.000000000 +0100
-+++ linux-5.5.5-p/drivers/hwmon/Makefile 2020-02-23 19:49:35.639936556 +0100
-@@ -87,6 +87,7 @@
- obj-$(CONFIG_SENSORS_JC42) += jc42.o
- obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o
- obj-$(CONFIG_SENSORS_K10TEMP) += k10temp.o
-+obj-$(CONFIG_SENSORS_ZENPOWER) += zenpower.o
- obj-$(CONFIG_SENSORS_LINEAGE) += lineage-pem.o
- obj-$(CONFIG_SENSORS_LOCHNAGAR) += lochnagar-hwmon.o
- obj-$(CONFIG_SENSORS_LM63) += lm63.o
-diff -Naur linux-5.5.5/drivers/hwmon/zenpower.c linux-5.5.5-p/drivers/hwmon/zenpower.c
---- linux-5.5.5/drivers/hwmon/zenpower.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-5.5.5-p/drivers/hwmon/zenpower.c 2020-02-23 19:48:10.473395027 +0100
-@@ -0,0 +1,657 @@
-+/*
-+ * Zenpower - Driver for reading temperature, voltage, current and power for AMD 17h CPUs
-+ *
-+ * Copyright (c) 2018-2020 Ondrej Čerman
-+ *
-+ * This driver is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License; either
-+ * version 2 of the License, or (at your option) any later version.
-+ *
-+ * This driver is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-+ * See the GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this driver; if not, see <http://www.gnu.org/licenses/>.
-+ *
-+ */
-+
-+/*
-+ * based on k10temp by Clemens Ladisch
-+ *
-+ * Docs:
-+ * - https://www.kernel.org/doc/Documentation/hwmon/hwmon-kernel-api.txt
-+ * - https://developer.amd.com/wp-content/resources/56255_3_03.PDF
-+ *
-+ * Sources:
-+ * - Temp monitoring is from k10temp
-+ * - SVI address and voltage formula is from LibreHardwareMonitor
-+ * - Current formulas and CCD temp addresses were discovered experimentally
-+ */
-+
-+#include <linux/hwmon.h>
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include <asm/amd_nb.h>
-+
-+MODULE_DESCRIPTION("AMD ZEN family CPU Sensors Driver");
-+MODULE_AUTHOR("Ondrej Čerman");
-+MODULE_LICENSE("GPL");
-+MODULE_VERSION("0.1.9");
-+
-+
-+#ifndef PCI_DEVICE_ID_AMD_17H_DF_F3
-+#define PCI_DEVICE_ID_AMD_17H_DF_F3 0x1463
-+#endif
-+
-+#ifndef PCI_DEVICE_ID_AMD_17H_M10H_DF_F3
-+#define PCI_DEVICE_ID_AMD_17H_M10H_DF_F3 0x15eb
-+#endif
-+
-+#ifndef PCI_DEVICE_ID_AMD_17H_M30H_DF_F3
-+#define PCI_DEVICE_ID_AMD_17H_M30H_DF_F3 0x1493
-+#endif
-+
-+#ifndef PCI_DEVICE_ID_AMD_17H_M70H_DF_F3
-+#define PCI_DEVICE_ID_AMD_17H_M70H_DF_F3 0x1443
-+#endif
-+
-+#define F17H_M01H_REPORTED_TEMP_CTRL 0x00059800
-+#define F17H_M01H_SVI 0x0005A000
-+#define F17H_M01H_SVI_TEL_PLANE0 (F17H_M01H_SVI + 0xC)
-+#define F17H_M01H_SVI_TEL_PLANE1 (F17H_M01H_SVI + 0x10)
-+#define F17H_M30H_SVI_TEL_PLANE0 (F17H_M01H_SVI + 0x14)
-+#define F17H_M30H_SVI_TEL_PLANE1 (F17H_M01H_SVI + 0x10)
-+#define F17H_M70H_SVI_TEL_PLANE0 (F17H_M01H_SVI + 0x10)
-+#define F17H_M70H_SVI_TEL_PLANE1 (F17H_M01H_SVI + 0xC)
-+#define F17H_M70H_CCD_TEMP(x) (0x00059954 + ((x) * 4))
-+
-+#define F17H_TEMP_ADJUST_MASK 0x80000
-+
-+#ifndef HWMON_CHANNEL_INFO
-+#define HWMON_CHANNEL_INFO(stype, ...) \
-+ (&(struct hwmon_channel_info) { \
-+ .type = hwmon_##stype, \
-+ .config = (u32 []) { \
-+ __VA_ARGS__, 0 \
-+ } \
-+ })
-+#endif
-+
-+struct zenpower_data {
-+ struct pci_dev *pdev;
-+ void (*read_amdsmn_addr)(struct pci_dev *pdev, u16 node_id, u32 address, u32 *regval);
-+ u32 svi_core_addr;
-+ u32 svi_soc_addr;
-+ u16 node_id;
-+ u8 cpu_id;
-+ u8 nodes_per_cpu;
-+ int temp_offset;
-+ bool zen2;
-+ bool kernel_smn_support;
-+ bool amps_visible;
-+ bool ccd_visible[8];
-+};
-+
-+struct tctl_offset {
-+ u8 model;
-+ char const *id;
-+ int offset;
-+};
-+
-+static const struct tctl_offset tctl_offset_table[] = {
-+ { 0x17, "AMD Ryzen 5 1600X", 20000 },
-+ { 0x17, "AMD Ryzen 7 1700X", 20000 },
-+ { 0x17, "AMD Ryzen 7 1800X", 20000 },
-+ { 0x17, "AMD Ryzen 7 2700X", 10000 },
-+ { 0x17, "AMD Ryzen Threadripper 19", 27000 }, /* 19{00,20,50}X */
-+ { 0x17, "AMD Ryzen Threadripper 29", 27000 }, /* 29{20,50,70,90}[W]X */
-+};
-+
-+static DEFINE_MUTEX(nb_smu_ind_mutex);
-+static bool multicpu = false;
-+
-+static umode_t zenpower_is_visible(const void *rdata,
-+ enum hwmon_sensor_types type,
-+ u32 attr, int channel)
-+{
-+ const struct zenpower_data *data = rdata;
-+
-+ switch (type) {
-+ case hwmon_temp:
-+ if (channel >= 2 && data->ccd_visible[channel-2] == false) // Tccd1-8
-+ return 0;
-+ break;
-+
-+ case hwmon_curr:
-+ case hwmon_power:
-+ if (data->amps_visible == false)
-+ return 0;
-+ if (channel == 0 && data->svi_core_addr == 0)
-+ return 0;
-+ if (channel == 1 && data->svi_soc_addr == 0)
-+ return 0;
-+ break;
-+
-+ case hwmon_in:
-+ if (channel == 0) // fake item to align different indexing,
-+ return 0; // see note at zenpower_info
-+ if (channel == 1 && data->svi_core_addr == 0)
-+ return 0;
-+ if (channel == 2 && data->svi_soc_addr == 0)
-+ return 0;
-+ break;
-+
-+ default:
-+ break;
-+ }
-+
-+ return 0444;
-+}
-+
-+static u32 plane_to_vcc(u32 p)
-+{
-+ u32 vdd_cor;
-+ vdd_cor = (p >> 16) & 0xff;
-+ // U = 1550 - 6.25 * vddcor
-+
-+ return 1550 - ((625 * vdd_cor) / 100);
-+}
-+
-+static u32 get_core_current(u32 plane, bool zen2)
-+{
-+ u32 idd_cor, fc;
-+ idd_cor = plane & 0xff;
-+
-+ // I = 1039.211 * iddcor
-+ // I = 658.823 * iddcor
-+ fc = zen2 ? 658823 : 1039211;
-+
-+ return (fc * idd_cor) / 1000;
-+}
-+
-+static u32 get_soc_current(u32 plane, bool zen2)
-+{
-+ u32 idd_cor, fc;
-+ idd_cor = plane & 0xff;
-+
-+ // I = 360.772 * iddcor
-+ // I = 294.3 * iddcor
-+ fc = zen2 ? 294300 : 360772;
-+
-+ return (fc * idd_cor) / 1000;
-+}
-+
-+static unsigned int get_ctl_temp(struct zenpower_data *data)
-+{
-+ unsigned int temp;
-+ u32 regval;
-+
-+ data->read_amdsmn_addr(data->pdev, data->node_id,
-+ F17H_M01H_REPORTED_TEMP_CTRL, &regval);
-+ temp = (regval >> 21) * 125;
-+ if (regval & F17H_TEMP_ADJUST_MASK)
-+ temp -= 49000;
-+ return temp;
-+}
-+
-+static unsigned int get_ccd_temp(struct zenpower_data *data, u32 ccd_addr)
-+{
-+ u32 regval;
-+ data->read_amdsmn_addr(data->pdev, data->node_id, ccd_addr, &regval);
-+
-+ return (regval & 0xfff) * 125 - 305000;
-+}
-+
-+int static debug_addrs_arr[] = {
-+ F17H_M01H_SVI + 0x8, F17H_M01H_SVI + 0xC, F17H_M01H_SVI + 0x10,
-+ F17H_M01H_SVI + 0x14, 0x000598BC, 0x0005994C, F17H_M70H_CCD_TEMP(0),
-+ F17H_M70H_CCD_TEMP(1), F17H_M70H_CCD_TEMP(2), F17H_M70H_CCD_TEMP(3),
-+ F17H_M70H_CCD_TEMP(4), F17H_M70H_CCD_TEMP(5), F17H_M70H_CCD_TEMP(6),
-+ F17H_M70H_CCD_TEMP(7)
-+};
-+
-+static ssize_t debug_data_show(struct device *dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ int i, len = 0;
-+ struct zenpower_data *data = dev_get_drvdata(dev);
-+ u32 smndata;
-+
-+ len += sprintf(buf + len, "KERN_SUP: %d\n", data->kernel_smn_support);
-+ len += sprintf(buf + len, "NODE%d; CPU%d; ", data->node_id, data->cpu_id);
-+ len += sprintf(buf + len, "N/CPU: %d\n", data->nodes_per_cpu);
-+
-+ for (i = 0; i < ARRAY_SIZE(debug_addrs_arr); i++){
-+ data->read_amdsmn_addr(data->pdev, data->node_id, debug_addrs_arr[i], &smndata);
-+ len += sprintf(buf + len, "%08x = %08x\n", debug_addrs_arr[i], smndata);
-+ }
-+
-+ return len;
-+}
-+
-+static int zenpower_read(struct device *dev, enum hwmon_sensor_types type,
-+ u32 attr, int channel, long *val)
-+{
-+ struct zenpower_data *data = dev_get_drvdata(dev);
-+ u32 plane;
-+
-+ switch (type) {
-+
-+ // Temperatures
-+ case hwmon_temp:
-+ switch (attr) {
-+ case hwmon_temp_input:
-+ switch (channel) {
-+ case 0: // Tdie
-+ *val = get_ctl_temp(data) - data->temp_offset;
-+ break;
-+ case 1: // Tctl
-+ *val = get_ctl_temp(data);
-+ break;
-+ case 2 ... 9: // Tccd1-8
-+ *val = get_ccd_temp(data, F17H_M70H_CCD_TEMP(channel-2));
-+ break;
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+ break;
-+
-+ case hwmon_temp_max: // Tdie max
-+ // source: https://www.amd.com/en/products/cpu/amd-ryzen-7-3700x
-+ // other cpus have also same* Tmax on AMD website
-+ // * = when taking into consideration a tctl offset
-+ *val = 95 * 1000;
-+ break;
-+
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+ break;
-+
-+ // Voltage
-+ case hwmon_in:
-+ if (channel == 0)
-+ return -EOPNOTSUPP;
-+ channel -= 1; // hwmon_in have different indexing, see note at zenpower_info
-+ // fall through
-+ // Power / Current
-+ case hwmon_curr:
-+ case hwmon_power:
-+ if (attr != hwmon_in_input && attr != hwmon_curr_input &&
-+ attr != hwmon_power_input) {
-+ return -EOPNOTSUPP;
-+ }
-+
-+ switch (channel) {
-+ case 0: // Core SVI2
-+ data->read_amdsmn_addr(data->pdev, data->node_id,
-+ data->svi_core_addr, &plane);
-+ break;
-+ case 1: // SoC SVI2
-+ data->read_amdsmn_addr(data->pdev, data->node_id,
-+ data->svi_soc_addr, &plane);
-+ break;
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+
-+ switch (type) {
-+ case hwmon_in:
-+ *val = plane_to_vcc(plane);
-+ break;
-+ case hwmon_curr:
-+ *val = (channel == 0) ?
-+ get_core_current(plane, data->zen2):
-+ get_soc_current(plane, data->zen2);
-+ break;
-+ case hwmon_power:
-+ *val = (channel == 0) ?
-+ get_core_current(plane, data->zen2) * plane_to_vcc(plane):
-+ get_soc_current(plane, data->zen2) * plane_to_vcc(plane);
-+ break;
-+ default:
-+ break;
-+ }
-+ break;
-+
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+
-+ return 0;
-+}
-+
-+static const char *zenpower_temp_label[][10] = {
-+ {
-+ "Tdie",
-+ "Tctl",
-+ "Tccd1",
-+ "Tccd2",
-+ "Tccd3",
-+ "Tccd4",
-+ "Tccd5",
-+ "Tccd6",
-+ "Tccd7",
-+ "Tccd8",
-+ },
-+ {
-+ "cpu0 Tdie",
-+ "cpu0 Tctl",
-+ "cpu0 Tccd1",
-+ "cpu0 Tccd2",
-+ "cpu0 Tccd3",
-+ "cpu0 Tccd4",
-+ "cpu0 Tccd5",
-+ "cpu0 Tccd6",
-+ "cpu0 Tccd7",
-+ "cpu0 Tccd8",
-+ },
-+ {
-+ "cpu1 Tdie",
-+ "cpu1 Tctl",
-+ "cpu1 Tccd1",
-+ "cpu1 Tccd2",
-+ "cpu1 Tccd3",
-+ "cpu1 Tccd4",
-+ "cpu1 Tccd5",
-+ "cpu1 Tccd6",
-+ "cpu1 Tccd7",
-+ "cpu1 Tccd8",
-+ }
-+};
-+
-+static const char *zenpower_in_label[][3] = {
-+ {
-+ "",
-+ "SVI2_Core",
-+ "SVI2_SoC",
-+ },
-+ {
-+ "",
-+ "cpu0 SVI2_Core",
-+ "cpu0 SVI2_SoC",
-+ },
-+ {
-+ "",
-+ "cpu1 SVI2_Core",
-+ "cpu1 SVI2_SoC",
-+ }
-+};
-+
-+static const char *zenpower_curr_label[][2] = {
-+ {
-+ "SVI2_C_Core",
-+ "SVI2_C_SoC",
-+ },
-+ {
-+ "cpu0 SVI2_C_Core",
-+ "cpu0 SVI2_C_SoC",
-+ },
-+ {
-+ "cpu1 SVI2_C_Core",
-+ "cpu1 SVI2_C_SoC",
-+ }
-+};
-+
-+static const char *zenpower_power_label[][2] = {
-+ {
-+ "SVI2_P_Core",
-+ "SVI2_P_SoC",
-+ },
-+ {
-+ "cpu0 SVI2_P_Core",
-+ "cpu0 SVI2_P_SoC",
-+ },
-+ {
-+ "cpu1 SVI2_P_Core",
-+ "cpu1 SVI2_P_SoC",
-+ }
-+};
-+
-+static int zenpower_read_labels(struct device *dev,
-+ enum hwmon_sensor_types type, u32 attr,
-+ int channel, const char **str)
-+{
-+ struct zenpower_data *data;
-+ u8 i = 0;
-+
-+ if (multicpu) {
-+ data = dev_get_drvdata(dev);
-+ if (data->cpu_id <= 1)
-+ i = data->cpu_id + 1;
-+ }
-+
-+ switch (type) {
-+ case hwmon_temp:
-+ *str = zenpower_temp_label[i][channel];
-+ break;
-+ case hwmon_in:
-+ *str = zenpower_in_label[i][channel];
-+ break;
-+ case hwmon_curr:
-+ *str = zenpower_curr_label[i][channel];
-+ break;
-+ case hwmon_power:
-+ *str = zenpower_power_label[i][channel];
-+ break;
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+
-+ return 0;
-+}
-+
-+static void kernel_smn_read(struct pci_dev *pdev, u16 node_id, u32 address, u32 *regval)
-+{
-+ amd_smn_read(node_id, address, regval);
-+}
-+
-+// fallback method from k10temp
-+// may return inaccurate results on multi-die chips
-+static void nb_index_read(struct pci_dev *pdev, u16 node_id, u32 address, u32 *regval)
-+{
-+ mutex_lock(&nb_smu_ind_mutex);
-+ pci_bus_write_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0x60, address);
-+ pci_bus_read_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0x64, regval);
-+ mutex_unlock(&nb_smu_ind_mutex);
-+}
-+
-+static const struct hwmon_channel_info *zenpower_info[] = {
-+ HWMON_CHANNEL_INFO(temp,
-+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_LABEL, // Tdie
-+ HWMON_T_INPUT | HWMON_T_LABEL, // Tctl
-+ HWMON_T_INPUT | HWMON_T_LABEL, // Tccd1
-+ HWMON_T_INPUT | HWMON_T_LABEL, // Tccd2
-+ HWMON_T_INPUT | HWMON_T_LABEL, // Tccd3
-+ HWMON_T_INPUT | HWMON_T_LABEL, // Tccd4
-+ HWMON_T_INPUT | HWMON_T_LABEL, // Tccd5
-+ HWMON_T_INPUT | HWMON_T_LABEL, // Tccd6
-+ HWMON_T_INPUT | HWMON_T_LABEL, // Tccd7
-+ HWMON_T_INPUT | HWMON_T_LABEL), // Tccd8
-+
-+ HWMON_CHANNEL_INFO(in,
-+ HWMON_I_LABEL, // everything is using 1 based indexing except
-+ // hwmon_in - that is using 0 based indexing
-+ // let's make fake item so corresponding SVI2 data is
-+ // associated with same index
-+ HWMON_I_INPUT | HWMON_I_LABEL, // Core Voltage (SVI2)
-+ HWMON_I_INPUT | HWMON_I_LABEL), // SoC Voltage (SVI2)
-+
-+ HWMON_CHANNEL_INFO(curr,
-+ HWMON_C_INPUT | HWMON_C_LABEL, // Core Current (SVI2)
-+ HWMON_C_INPUT | HWMON_C_LABEL), // SoC Current (SVI2)
-+
-+ HWMON_CHANNEL_INFO(power,
-+ HWMON_P_INPUT | HWMON_P_LABEL, // Core Power (SVI2)
-+ HWMON_P_INPUT | HWMON_P_LABEL), // SoC Power (SVI2)
-+
-+ NULL
-+};
-+
-+static const struct hwmon_ops zenpower_hwmon_ops = {
-+ .is_visible = zenpower_is_visible,
-+ .read = zenpower_read,
-+ .read_string = zenpower_read_labels,
-+};
-+
-+static const struct hwmon_chip_info zenpower_chip_info = {
-+ .ops = &zenpower_hwmon_ops,
-+ .info = zenpower_info,
-+};
-+
-+static DEVICE_ATTR_RO(debug_data);
-+
-+static struct attribute *zenpower_attrs[] = {
-+ &dev_attr_debug_data.attr,
-+ NULL
-+};
-+
-+static const struct attribute_group zenpower_group = {
-+ .attrs = zenpower_attrs
-+};
-+__ATTRIBUTE_GROUPS(zenpower);
-+
-+static int zenpower_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct zenpower_data *data;
-+ struct device *hwmon_dev;
-+ int i, ccd_check = 0;
-+ bool multinode;
-+ u8 node_of_cpu;
-+ u32 val;
-+
-+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
-+ if (!data)
-+ return -ENOMEM;
-+
-+ data->zen2 = false;
-+ data->pdev = pdev;
-+ data->temp_offset = 0;
-+ data->read_amdsmn_addr = nb_index_read;
-+ data->kernel_smn_support = false;
-+ data->svi_core_addr = false;
-+ data->svi_soc_addr = false;
-+ data->amps_visible = false;
-+ data->node_id = 0;
-+ for (i = 0; i < 8; i++) {
-+ data->ccd_visible[i] = false;
-+ }
-+
-+ for (id = amd_nb_misc_ids; id->vendor; id++) {
-+ if (pdev->vendor == id->vendor && pdev->device == id->device) {
-+ data->kernel_smn_support = true;
-+ data->read_amdsmn_addr = kernel_smn_read;
-+ break;
-+ }
-+ }
-+
-+ if (data->kernel_smn_support) {
-+ data->node_id = amd_pci_dev_to_node_id(pdev);
-+ }
-+
-+ // CPUID_Fn8000001E_ECX [Node Identifiers] (Core::X86::Cpuid::NodeId)
-+ // 10:8 NodesPerProcessor
-+ data->nodes_per_cpu = 1 + ((cpuid_ecx(0x8000001E) >> 8) & 0b111);
-+ multinode = (data->nodes_per_cpu > 1);
-+
-+ node_of_cpu = data->node_id % data->nodes_per_cpu;
-+ data->cpu_id = data->node_id / data->nodes_per_cpu;
-+
-+ if (data->cpu_id > 0)
-+ multicpu = true;
-+
-+ if (boot_cpu_data.x86 == 0x17) {
-+ switch (boot_cpu_data.x86_model) {
-+ case 0x1: // Zen
-+ case 0x8: // Zen+
-+ data->amps_visible = true;
-+
-+ if (multinode) { // Threadripper / EPYC
-+ if (node_of_cpu == 0) {
-+ data->svi_soc_addr = F17H_M01H_SVI_TEL_PLANE0;
-+ }
-+ if (node_of_cpu == 1) {
-+ data->svi_core_addr = F17H_M01H_SVI_TEL_PLANE0;
-+ }
-+ }
-+ else { // Ryzen
-+ data->svi_core_addr = F17H_M01H_SVI_TEL_PLANE0;
-+ data->svi_soc_addr = F17H_M01H_SVI_TEL_PLANE1;
-+ }
-+ ccd_check = 4;
-+ break;
-+
-+ case 0x11: // Zen APU
-+ case 0x18: // Zen+ APU
-+ data->amps_visible = true;
-+ data->svi_core_addr = F17H_M01H_SVI_TEL_PLANE0;
-+ data->svi_soc_addr = F17H_M01H_SVI_TEL_PLANE1;
-+ break;
-+
-+ case 0x31: // Zen2 Threadripper/EPYC
-+ data->zen2 = true;
-+ data->amps_visible = true;
-+ data->svi_core_addr = F17H_M30H_SVI_TEL_PLANE0;
-+ data->svi_soc_addr = F17H_M30H_SVI_TEL_PLANE1;
-+ ccd_check = 8;
-+ break;
-+
-+ case 0x71: // Zen2 Ryzen
-+ data->zen2 = true;
-+ data->amps_visible = true;
-+ data->svi_core_addr = F17H_M70H_SVI_TEL_PLANE0;
-+ data->svi_soc_addr = F17H_M70H_SVI_TEL_PLANE1;
-+ ccd_check = 8;
-+ break;
-+
-+ default:
-+ data->svi_core_addr = F17H_M01H_SVI_TEL_PLANE0;
-+ data->svi_soc_addr = F17H_M01H_SVI_TEL_PLANE1;
-+ break;
-+ }
-+ }
-+
-+ for (i = 0; i < ccd_check; i++) {
-+ data->read_amdsmn_addr(pdev, data->node_id,
-+ F17H_M70H_CCD_TEMP(i), &val);
-+ if ((val & 0xfff) > 0) {
-+ data->ccd_visible[i] = true;
-+ }
-+ }
-+
-+ for (i = 0; i < ARRAY_SIZE(tctl_offset_table); i++) {
-+ const struct tctl_offset *entry = &tctl_offset_table[i];
-+
-+ if (boot_cpu_data.x86 == entry->model &&
-+ strstr(boot_cpu_data.x86_model_id, entry->id)) {
-+ data->temp_offset = entry->offset;
-+ break;
-+ }
-+ }
-+
-+ hwmon_dev = devm_hwmon_device_register_with_info(
-+ dev, "zenpower", data, &zenpower_chip_info, zenpower_groups
-+ );
-+
-+ return PTR_ERR_OR_ZERO(hwmon_dev);
-+}
-+
-+static const struct pci_device_id zenpower_id_table[] = {
-+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) },
-+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3) },
-+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) },
-+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) },
-+ {}
-+};
-+MODULE_DEVICE_TABLE(pci, zenpower_id_table);
-+
-+static struct pci_driver zenpower_driver = {
-+ .name = "zenpower",
-+ .id_table = zenpower_id_table,
-+ .probe = zenpower_probe,
-+};
-+
-+module_pci_driver(zenpower_driver);