diff --git a/src/soc/qualcomm/common/Kconfig b/src/soc/qualcomm/common/Kconfig index 98760cec63..373ba51c40 100644 --- a/src/soc/qualcomm/common/Kconfig +++ b/src/soc/qualcomm/common/Kconfig @@ -54,4 +54,11 @@ config SOC_QUALCOMM_QCLIB_SKIP_MMU_TOGGLE flushes and TLB invalidations associated with mmu_disable() and mmu_enable() calls. +config SOC_QUALCOMM_DEBUG_TSENS + bool + default n + help + When enabled, a call to monitor TSENS will dump the sensor data on + the debug console. + endif diff --git a/src/soc/qualcomm/common/include/soc/qcom_tsens.h b/src/soc/qualcomm/common/include/soc/qcom_tsens.h new file mode 100644 index 0000000000..6bb82a5e30 --- /dev/null +++ b/src/soc/qualcomm/common/include/soc/qcom_tsens.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _SOC_QUALCOMM_TSENS_H_ +#define _SOC_QUALCOMM_TSENS_H_ + +#include +#include +#include + +#define TM_SN_STATUS_OFF 0x00a0 +#define SN_STATUS_VALID (1 << 21) +#define SN_STATUS_TEMP_MASK 0xFFF + +struct tsens_controller { + const char *name; + uintptr_t tm_base; + uintptr_t srot_base; + uint32_t sensor_count; +}; + +enum sensor_type { + TYPE_TSENS +}; + +struct thermal_zone_map { + const char *label; + enum sensor_type type; + const void *ctrl; + int hw_id; + int threshold; +}; + +/* + * Iterates through all defined zones and checks thresholds. + */ +void qcom_tsens_monitor_all(bool *has_crossed_threshold); + +/* External Data (Defined in SoC file) */ +extern const struct thermal_zone_map qcom_thermal_zones[]; + +#endif /* _SOC_QUALCOMM_TSENS_H_ */ diff --git a/src/soc/qualcomm/common/tsens.c b/src/soc/qualcomm/common/tsens.c new file mode 100644 index 0000000000..12f5ecdc5b --- /dev/null +++ b/src/soc/qualcomm/common/tsens.c @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include +#include +#include + +#if CONFIG(SOC_QUALCOMM_DEBUG_TSENS) +#define thermal_printk(fmt, ...) printk(BIOS_INFO, fmt, ##__VA_ARGS__) +#else +#define thermal_printk(fmt, ...) do { (void)(fmt); } while (0) +#endif + +static int read_tsens(const struct thermal_zone_map *zone, int *out) +{ + if (!zone) + return -1; + + const struct tsens_controller *ctrl = (const struct tsens_controller *)zone->ctrl; + if (!ctrl || (zone->hw_id >= (int)ctrl->sensor_count)) + return -1; + + uintptr_t status_addr = ctrl->tm_base + TM_SN_STATUS_OFF + (zone->hw_id * 4); + + uint32_t status = read32p(status_addr); + if (!(status & SN_STATUS_VALID)) + return -2; + + /* Sign extend 12-bit temperature and scale to milli C */ + *out = ((int32_t)((status & SN_STATUS_TEMP_MASK) << 20) >> 20) * 100; + return 0; +} + +void qcom_tsens_monitor_all(bool *has_crossed_threshold) +{ + if (!has_crossed_threshold) + return; + + *has_crossed_threshold = false; + + thermal_printk("\n------------------ Thermal Sensor State --------------------\n"); + thermal_printk("%-15s | %-10s | %-8s | %-10s\n", "Zone", "Type", "Temp (C)", "Status"); + thermal_printk("------------------------------------------------------------\n"); + + for (const struct thermal_zone_map *zone = qcom_thermal_zones; zone->label != NULL; zone++) { + int data = 0, status = -1; + const char *type_str = "UNK"; + (void)type_str; + + if (zone->type == TYPE_TSENS) { + type_str = "SoC"; + status = read_tsens(zone, &data); + } + + if (status == 0) { + thermal_printk("%-15s | %-10s | %3d.%1d | ", + zone->label, type_str, data / 1000, (data % 1000) / 100); + + if (data >= zone->threshold) { + *has_crossed_threshold = true; + thermal_printk("EXCEEDED\n"); + if (!CONFIG(SOC_QUALCOMM_DEBUG_TSENS)) + return; + } else { + thermal_printk("OK\n"); + } + } else { + thermal_printk("%-15s | %-10s | [ERR %d] | -\n", zone->label, type_str, status); + } + } +}