soc/qualcomm/common: Add Qualcomm TSENS support

Introduce a generic driver for the Qualcomm Temperature Sensor (TSENS)
V2 hardware block. This driver provides the infrastructure to read
temperature data from hardware status registers and monitor them
against software-defined thresholds.

The driver sign-extends the 12-bit raw temperature values and scales
the output to millidegrees Celsius for accurate monitoring.

TEST=Verify all x1p42100 thermal zones are readable on Google/Quartz.

Change-Id: I826df3f86edc30ac57d84f672b487a8b9b51728a
Signed-off-by: Kapil Porwal <kapilporwal@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/91609
Reviewed-by: Subrata Banik <subratabanik@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Kapil Porwal 2026-03-09 18:01:37 +05:30 committed by Subrata Banik
commit 53529b1d93
3 changed files with 120 additions and 0 deletions

View file

@ -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

View file

@ -0,0 +1,41 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _SOC_QUALCOMM_TSENS_H_
#define _SOC_QUALCOMM_TSENS_H_
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#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_ */

View file

@ -0,0 +1,72 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <arch/mmio.h>
#include <commonlib/bsd/stdlib.h>
#include <device/mmio.h>
#include <soc/addressmap.h>
#include <soc/qcom_tsens.h>
#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);
}
}
}