--- /dev/null
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * intel_tcc.c - Library for Intel TCC (thermal control circuitry) MSR access
+ * Copyright (c) 2022, Intel Corporation.
+ */
+
+#include <linux/errno.h>
+#include <linux/intel_tcc.h>
+#include <asm/msr.h>
+
+/**
+ * intel_tcc_get_tjmax() - returns the default TCC activation Temperature
+ * @cpu: cpu that the MSR should be run on, nagative value means any cpu.
+ *
+ * Get the TjMax value, which is the default thermal throttling or TCC
+ * activation temperature in degrees C.
+ *
+ * Return: Tjmax value in degrees C on success, negative error code otherwise.
+ */
+int intel_tcc_get_tjmax(int cpu)
+{
+       u32 low, high;
+       int val, err;
+
+       if (cpu < 0)
+               err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &low, &high);
+       else
+               err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &low, &high);
+       if (err)
+               return err;
+
+       val = (low >> 16) & 0xff;
+
+       return val ? val : -ENODATA;
+}
+EXPORT_SYMBOL_NS_GPL(intel_tcc_get_tjmax, INTEL_TCC);
+
+/**
+ * intel_tcc_get_offset() - returns the TCC Offset value to Tjmax
+ * @cpu: cpu that the MSR should be run on, nagative value means any cpu.
+ *
+ * Get the TCC offset value to Tjmax. The effective thermal throttling or TCC
+ * activation temperature equals "Tjmax" - "TCC Offset", in degrees C.
+ *
+ * Return: Tcc offset value in degrees C on success, negative error code otherwise.
+ */
+int intel_tcc_get_offset(int cpu)
+{
+       u32 low, high;
+       int err;
+
+       if (cpu < 0)
+               err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &low, &high);
+       else
+               err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &low, &high);
+       if (err)
+               return err;
+
+       return (low >> 24) & 0x3f;
+}
+EXPORT_SYMBOL_NS_GPL(intel_tcc_get_offset, INTEL_TCC);
+
+/**
+ * intel_tcc_set_offset() - set the TCC offset value to Tjmax
+ * @cpu: cpu that the MSR should be run on, nagative value means any cpu.
+ * @offset: TCC offset value in degree C
+ *
+ * Set the TCC Offset value to Tjmax. The effective thermal throttling or TCC
+ * activation temperature equals "Tjmax" - "TCC Offset", in degree C.
+ *
+ * Return: On success returns 0, negative error code otherwise.
+ */
+
+int intel_tcc_set_offset(int cpu, int offset)
+{
+       u32 low, high;
+       int err;
+
+       if (offset < 0 || offset > 0x3f)
+               return -EINVAL;
+
+       if (cpu < 0)
+               err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &low, &high);
+       else
+               err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &low, &high);
+       if (err)
+               return err;
+
+       /* MSR Locked */
+       if (low & BIT(31))
+               return -EPERM;
+
+       low &= ~(0x3f << 24);
+       low |= offset << 24;
+
+       if (cpu < 0)
+               return wrmsr_safe(MSR_IA32_TEMPERATURE_TARGET, low, high);
+       else
+               return wrmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, low, high);
+}
+EXPORT_SYMBOL_NS_GPL(intel_tcc_set_offset, INTEL_TCC);
+
+/**
+ * intel_tcc_get_temp() - returns the current temperature
+ * @cpu: cpu that the MSR should be run on, nagative value means any cpu.
+ * @pkg: true: Package Thermal Sensor. false: Core Thermal Sensor.
+ *
+ * Get the current temperature returned by the CPU core/package level
+ * thermal sensor, in degrees C.
+ *
+ * Return: Temperature in degrees C on success, negative error code otherwise.
+ */
+int intel_tcc_get_temp(int cpu, bool pkg)
+{
+       u32 low, high;
+       u32 msr = pkg ? MSR_IA32_PACKAGE_THERM_STATUS : MSR_IA32_THERM_STATUS;
+       int tjmax, temp, err;
+
+       tjmax = intel_tcc_get_tjmax(cpu);
+       if (tjmax < 0)
+               return tjmax;
+
+       if (cpu < 0)
+               err = rdmsr_safe(msr, &low, &high);
+       else
+               err = rdmsr_safe_on_cpu(cpu, msr, &low, &high);
+       if (err)
+               return err;
+
+       /* Temperature is beyond the valid thermal sensor range */
+       if (!(low & BIT(31)))
+               return -ENODATA;
+
+       temp = tjmax - ((low >> 16) & 0x7f);
+
+       /* Do not allow negative CPU temperature */
+       return temp >= 0 ? temp : -ENODATA;
+}
+EXPORT_SYMBOL_NS_GPL(intel_tcc_get_temp, INTEL_TCC);