Jarried Lin has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/86017?usp=email )
Change subject: soc/mediatek/mt8196: Add thermal driver ......................................................................
soc/mediatek/mt8196: Add thermal driver
Add thermal driver to support LVTS (Low Voltage Thermal Sensor).
TEST=Check temperatures read from each sensors. BUG=b:317009620
Signed-off-by: Zhaoqing Jiu zhaoqing.jiu@mediatek.corp-partner.google.com Change-Id: Ieef94a6909e4da82461351bcb9292e9d01db3362 --- M src/soc/mediatek/mt8196/Makefile.mk M src/soc/mediatek/mt8196/include/soc/addressmap.h A src/soc/mediatek/mt8196/include/soc/thermal.h A src/soc/mediatek/mt8196/include/soc/thermal_internal.h A src/soc/mediatek/mt8196/mt_thermal.c A src/soc/mediatek/mt8196/mt_thermal_sram_init.c 6 files changed, 1,042 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/17/86017/1
diff --git a/src/soc/mediatek/mt8196/Makefile.mk b/src/soc/mediatek/mt8196/Makefile.mk index a287949..cf2d591 100644 --- a/src/soc/mediatek/mt8196/Makefile.mk +++ b/src/soc/mediatek/mt8196/Makefile.mk @@ -45,6 +45,8 @@ romstage-y += ../common/pmif.c pmif_init.c romstage-y += pmif_spmi.c romstage-y += srclken_rc.c +romstage-y += mt_thermal.c +romstage-y += mt_thermal_sram_init.c
ramstage-$(CONFIG_ARM64_USE_ARM_TRUSTED_FIRMWARE) += ../common/bl31.c ramstage-y += ../common/dpm_v2.c diff --git a/src/soc/mediatek/mt8196/include/soc/addressmap.h b/src/soc/mediatek/mt8196/include/soc/addressmap.h index 1ec3c86..441b8f7 100644 --- a/src/soc/mediatek/mt8196/include/soc/addressmap.h +++ b/src/soc/mediatek/mt8196/include/soc/addressmap.h @@ -102,6 +102,7 @@ APINFRA_MEM_CTRL_AO_DEBUG_BASE = IO_PHYS + 0x04125000, APIFRBUS_AO_MEM_REG_BASE = IO_PHYS + 0x04126000, THERM_CTRL_BASE = IO_PHYS + 0x04414000, + INFRACFG_AO_SEC_BASE = IO_PHYS + 0x04461000, VOTE_BASE = IO_PHYS + 0x04500000, DBG_TRACKER_BASE = IO_PHYS + 0x04780000, INFRA_TRACKER_BASE = IO_PHYS + 0x047A0000, diff --git a/src/soc/mediatek/mt8196/include/soc/thermal.h b/src/soc/mediatek/mt8196/include/soc/thermal.h new file mode 100644 index 0000000..6d2b523 --- /dev/null +++ b/src/soc/mediatek/mt8196/include/soc/thermal.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ + +#ifndef SOC_MEDIATEK_MT8196_THERMAL_H +#define SOC_MEDIATEK_MT8196_THERMAL_H + +void thermal_sram_init(void); +void thermal_init(void); + +#endif /* SOC_MEDIATEK_MT8196_THERMAL_H */ diff --git a/src/soc/mediatek/mt8196/include/soc/thermal_internal.h b/src/soc/mediatek/mt8196/include/soc/thermal_internal.h new file mode 100644 index 0000000..dd185a0 --- /dev/null +++ b/src/soc/mediatek/mt8196/include/soc/thermal_internal.h @@ -0,0 +1,260 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ + +#ifndef SOC_MEDIATEK_MT8196_THERMAL_INTERNAL_H +#define SOC_MEDIATEK_MT8196_THERMAL_INTERNAL_H + +#include <console/console.h> +#include <device/mmio.h> +#include <soc/addressmap.h> +#include <soc/symbols.h> +#include <soc/thermal.h> +#include <stddef.h> + +#define LVTS_MAGIC 0x0000555 +#define MAX_TS_NUMBER 4 +/* + * module LVTS Plan + *===================================================== + * Dsu0, Core3, Core7_0/1 LVTS1-0, LVTS1-1, LVTS1-2, LVTS1-3 + * Core4_0/1, Core1, Core2 LVTS2-0, LVTS2-1, LVTS2-2, LVTS2-3 + * Dsu2, Dsu1, Core6_0/1 LVTS3-0, LVTS3-1, LVTS3-2, LVTS3-3 + * Dsu3, Core0, Core5_0/1 LVTS4-0, LVTS4-1, LVTS4-2, LVTS4-3 + * APUa LVTS5-0, LVTS5-1, LVTS5-2, LVTS5-3 + * GPUa LVTS7-0, LVTS7-1 + * SOC-TOP LVTS11-0, LVTS11-1, LVTS11-2, LVTS11-3 + * SOC-BOT LVTS12-0, LVTS12-1, LVTS12-2, LVTS12-3 + * MD-AP LVTS13-0, LVTS13-1, LVTS13-2, LVTS13-3 + * SOC-ADCT LVTS14-0, LVTS14-3 + * ptp_therm_ctrl_AP Base address: 0x1441_4000, 0x1441_4100, + * 0x1441_4200 + * ptp_therm_ctrl_MCU Base address: 0x0C23_0000, 0x0C23_0100, + * 0x0C23_0200, 0x0C23_0300, + */ + +/* private thermal sensor enum */ +enum lvts_sensor { + L_TS_LVTS11_0 = 0, /* LVTS11-0 SOC-TOP */ + L_TS_LVTS11_1, /* LVTS11-1 SOC-TOP */ + L_TS_LVTS11_2, /* LVTS11-2 SOC-TOP */ + L_TS_LVTS11_3, /* LVTS11-3 SOC-TOP */ + L_TS_LVTS12_0, /* LVTS12-0 SOC-BOT */ + L_TS_LVTS12_1, /* LVTS12-1 SOC-BOT */ + L_TS_LVTS12_2, /* LVTS12-2 SOC-BOT */ + L_TS_LVTS12_3, /* LVTS12-3 SOC-BOT */ + L_TS_LVTS13_0, /* LVTS13-0 MD-AP */ + L_TS_LVTS13_1, /* LVTS13-1 MD-AP */ + L_TS_LVTS13_2, /* LVTS13-2 MD-AP */ + L_TS_LVTS13_3, /* LVTS13-3 MD-AP */ + L_TS_LVTS14_0, /* LVTS14-0 SOC-ADCT */ + L_TS_LVTS14_3, /* LVTS14-3 SOC-ADCT */ + L_TS_LVTS_NUM, +}; + +enum lvts_tc { + LVTS_AP_CONTROLLER0 = 0, + LVTS_AP_CONTROLLER1, + LVTS_AP_CONTROLLER2, + LVTS_AP_CONTROLLER3, + LVTS_CONTROLLER_NUM, +}; + +enum lvts_tc_offset { + TS_OFFSET_AP_CONTROLLER0 = 0, + TS_OFFSET_AP_CONTROLLER1 = 0x100, + TS_OFFSET_AP_CONTROLLER2 = 0x200, + TS_OFFSET_AP_CONTROLLER3 = 0x300, +}; + +enum sensor_switch_status { + SEN_OFF, + SEN_ON, +}; + +enum controller_switch_status { + CTRL_OFF, + CTRL_ON, +}; + +struct lvts_thermal_controller_speed { + uint32_t group_interval_delay; + uint32_t period_unit; + uint32_t filter_interval_delay; + uint32_t sensor_interval_delay; +}; + +struct lvts_thermal_controller { + enum lvts_sensor ts[MAX_TS_NUMBER]; + enum sensor_switch_status sensor_on_off[MAX_TS_NUMBER]; + enum controller_switch_status ctrl_on_off; + size_t ts_number; + int reboot_temperature; + int dominator_ts_idx; + struct lvts_thermal_controller_speed speed; + struct mtk_thermal_controller_regs *regs; +}; + +/* LVTS Thermal Controller Register Definition */ +static struct mtk_thermal_controller_regs *const + mtk_lvts_ap_controller0 = (void *)(THERM_CTRL_BASE + TS_OFFSET_AP_CONTROLLER0); +static struct mtk_thermal_controller_regs *const + mtk_lvts_ap_controller1 = (void *)(THERM_CTRL_BASE + TS_OFFSET_AP_CONTROLLER1); +static struct mtk_thermal_controller_regs *const + mtk_lvts_ap_controller2 = (void *)(THERM_CTRL_BASE + TS_OFFSET_AP_CONTROLLER2); +static struct mtk_thermal_controller_regs *const + mtk_lvts_ap_controller3 = (void *)(THERM_CTRL_BASE + TS_OFFSET_AP_CONTROLLER3); + +struct mtk_thermal_controller_regs { + u32 lvtsmonctl0_0; + u32 lvtsmonctl1_0; + u32 lvtsmonctl2_0; + u32 lvtsmonint_0; + u32 lvtsmonintsts_0; + u32 lvtsmonidet0_0; + u32 lvtsmonidet1_0; + u32 lvtsmonidet2_0; + u32 lvtsmonidet3_0; + u32 lvtsh2nthre_0; + u32 lvtshthre_0; + u32 lvtscthre_0; + u32 lvtsoffseth_0; + u32 lvtsoffsetl_0; + u32 lvtsmsrctl0_0; + u32 lvtsmsrctl1_0; + u32 lvtstssel_0; + u32 lvtsdeviceto_0; + u32 lvtscalscale_0; + u32 lvts_id_0; + u32 lvts_config_0; + u32 lvtsedata[4]; + u32 reserved0[1]; + u32 lvtsgslope_0; + u32 lvtsmsroft_0; + u32 lvtsatp[4]; + u32 reserved1[4]; + u32 lvtsmsr[4]; + u32 lvtsimmd[4]; + u32 lvtsrdata[4]; + u32 lvtsprotctl_0; + u32 lvtsprotta_0; + u32 lvtsprottb_0; + u32 lvtsprottc_0; + u32 reserved2[1]; + u32 lvtstemp[4]; + u32 lvtsclken_0; + u32 lvtsdbgsel_0; + u32 lvtsdbgsig_0; + u32 lvtsspare[4]; +}; + +check_member(mtk_thermal_controller_regs, lvtsmonctl0_0, 0x000); +check_member(mtk_thermal_controller_regs, lvtsmonctl1_0, 0x004); +check_member(mtk_thermal_controller_regs, lvtsmonctl2_0, 0x008); +check_member(mtk_thermal_controller_regs, lvtsmonint_0, 0x00c); +check_member(mtk_thermal_controller_regs, lvtsmonintsts_0, 0x010); +check_member(mtk_thermal_controller_regs, lvtsmonidet0_0, 0x014); +check_member(mtk_thermal_controller_regs, lvtsmonidet1_0, 0x018); +check_member(mtk_thermal_controller_regs, lvtsmonidet2_0, 0x01c); +check_member(mtk_thermal_controller_regs, lvtsmonidet3_0, 0x020); +check_member(mtk_thermal_controller_regs, lvtsh2nthre_0, 0x024); +check_member(mtk_thermal_controller_regs, lvtshthre_0, 0x028); +check_member(mtk_thermal_controller_regs, lvtscthre_0, 0x02c); +check_member(mtk_thermal_controller_regs, lvtsoffseth_0, 0x030); +check_member(mtk_thermal_controller_regs, lvtsoffsetl_0, 0x034); +check_member(mtk_thermal_controller_regs, lvtsmsrctl0_0, 0x038); +check_member(mtk_thermal_controller_regs, lvtsmsrctl1_0, 0x03c); +check_member(mtk_thermal_controller_regs, lvtstssel_0, 0x040); +check_member(mtk_thermal_controller_regs, lvtsdeviceto_0, 0x044); +check_member(mtk_thermal_controller_regs, lvtscalscale_0, 0x048); +check_member(mtk_thermal_controller_regs, lvts_id_0, 0x04c); +check_member(mtk_thermal_controller_regs, lvts_config_0, 0x050); +check_member(mtk_thermal_controller_regs, lvtsedata, 0x054); +check_member(mtk_thermal_controller_regs, lvtsgslope_0, 0x068); +check_member(mtk_thermal_controller_regs, lvtsmsroft_0, 0x06c); +check_member(mtk_thermal_controller_regs, lvtsatp, 0x070); +check_member(mtk_thermal_controller_regs, lvtsmsr, 0x090); +check_member(mtk_thermal_controller_regs, lvtsimmd, 0x0a0); +check_member(mtk_thermal_controller_regs, lvtsrdata, 0x0b0); +check_member(mtk_thermal_controller_regs, lvtsprotctl_0, 0x0c0); +check_member(mtk_thermal_controller_regs, lvtsprotta_0, 0x0c4); +check_member(mtk_thermal_controller_regs, lvtsprottb_0, 0x0c8); +check_member(mtk_thermal_controller_regs, lvtsprottc_0, 0x0cc); +check_member(mtk_thermal_controller_regs, lvtstemp, 0x0d4); +check_member(mtk_thermal_controller_regs, lvtsclken_0, 0x0e4); +check_member(mtk_thermal_controller_regs, lvtsdbgsel_0, 0x0e8); +check_member(mtk_thermal_controller_regs, lvtsdbgsig_0, 0x0ec); +check_member(mtk_thermal_controller_regs, lvtsspare, 0x0f0); + +#define LDO_ON_SETTING 0x1108 + +#define AP_RST_SET (INFRACFG_AO_SEC_BASE + 0xf30) +#define AP_RST_CLR (INFRACFG_AO_SEC_BASE + 0xf34) + +#define LVTS_COF_T_SLP_GLD 358830 +#define LVTS_COF_COUNT_R_GLD 34389 +#define LVTS_COF_T_CONST_OFS 0 + +#define DEFAULT_EFUSE_GOLDEN_TEMP 60 +#define DEFAULT_EFUSE_COUNT 34389 +#define DEFAULT_EFUSE_COUNT_RC 24173 + +#define HIGH_OFFSET3_INT_EN BIT(25) +#define HIGH_OFFSET2_INT_EN BIT(13) +#define HIGH_OFFSET1_INT_EN BIT(8) +#define HIGH_OFFSET0_INT_EN BIT(3) + +#define LOW_OFFSET3_INT_EN BIT(24) +#define LOW_OFFSET2_INT_EN BIT(12) +#define LOW_OFFSET1_INT_EN BIT(7) +#define LOW_OFFSET0_INT_EN BIT(2) + +#define HOT_INT3_EN BIT(23) +#define HOT_INT2_EN BIT(11) +#define HOT_INT1_EN BIT(6) +#define HOT_INT0_EN BIT(1) + +#define COLD_INT3_EN BIT(22) +#define COLD_INT2_EN BIT(10) +#define COLD_INT1_EN BIT(5) +#define COLD_INT0_EN BIT(0) + +#define STAGE3_INT_EN BIT(31) + +#define DEVICE_ACCESS_START_BIT BIT(24) + +#define CPU_LVTS_RESET_ADDR (MCUCFG_BASE + 0x610) + +/* chip dependent */ +#define LVTS_ADDRESS_INDEX_0 (EFUSEC_BASE + 0x334) +#define LVTS_ADDRESS_INDEX_1 (EFUSEC_BASE + 0x338) +#define LVTS_ADDRESS_INDEX_2 (EFUSEC_BASE + 0x33C) +#define LVTS_ADDRESS_INDEX_3 (EFUSEC_BASE + 0x340) +#define LVTS_ADDRESS_INDEX_4 (EFUSEC_BASE + 0x344) +#define LVTS_ADDRESS_INDEX_5 (EFUSEC_BASE + 0x348) +#define LVTS_ADDRESS_INDEX_6 (EFUSEC_BASE + 0x34C) +#define LVTS_ADDRESS_INDEX_7 (EFUSEC_BASE + 0x350) +#define LVTS_ADDRESS_INDEX_8 (EFUSEC_BASE + 0x354) +#define LVTS_ADDRESS_INDEX_9 (EFUSEC_BASE + 0x358) +#define LVTS_ADDRESS_INDEX_10 (EFUSEC_BASE + 0x35C) +#define LVTS_ADDRESS_INDEX_11 (EFUSEC_BASE + 0x360) +#define LVTS_ADDRESS_INDEX_12 (EFUSEC_BASE + 0x364) +#define LVTS_ADDRESS_INDEX_13 (EFUSEC_BASE + 0x368) +#define LVTS_ADDRESS_INDEX_14 (EFUSEC_BASE + 0x36C) +#define LVTS_ADDRESS_INDEX_15 (EFUSEC_BASE + 0x370) +#define LVTS_ADDRESS_INDEX_16 (EFUSEC_BASE + 0x374) +#define LVTS_ADDRESS_INDEX_17 (EFUSEC_BASE + 0x378) +#define LVTS_ADDRESS_INDEX_18 (EFUSEC_BASE + 0x37C) +#define LVTS_ADDRESS_INDEX_19 (EFUSEC_BASE + 0x380) +#define LVTS_ADDRESS_INDEX_20 (EFUSEC_BASE + 0x384) +#define LVTS_ADDRESS_INDEX_21 (EFUSEC_BASE + 0x388) +#define LVTS_ADDRESS_INDEX_22 (EFUSEC_BASE + 0x38C) +#define LVTS_ADDRESS_INDEX_23 (EFUSEC_BASE + 0x390) +#define LVTS_ADDRESS_INDEX_24 (EFUSEC_BASE + 0x394) +#define LVTS_ADDRESS_INDEX_25 (EFUSEC_BASE + 0x398) +#define LVTS_ADDRESS_INDEX_26 (EFUSEC_BASE + 0x39C) +#define LVTS_ADDRESS_INDEX_27 (EFUSEC_BASE + 0x3A0) +#define LVTS_ADDRESS_INDEX_28 (EFUSEC_BASE + 0x3A4) +#define LVTS_ADDRESS_INDEX_29 (EFUSEC_BASE + 0x3A8) +#define LVTS_ADDRESS_INDEX_30 (EFUSEC_BASE + 0x3AC) +#define LVTS_ADDRESS_INDEX_31 (EFUSEC_BASE + 0x3B0) + +#endif /* SOC_MEDIATEK_MT8196_THERMAL_INTERNAL_H */ diff --git a/src/soc/mediatek/mt8196/mt_thermal.c b/src/soc/mediatek/mt8196/mt_thermal.c new file mode 100644 index 0000000..a9f2b0a --- /dev/null +++ b/src/soc/mediatek/mt8196/mt_thermal.c @@ -0,0 +1,706 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <assert.h> +#include <delay.h> +#include <soc/thermal.h> +#include <soc/thermal_internal.h> +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#define LVTS_DEVICE_ACCESS_DELAY_US 3 +#define CHECK_DEVICE_ACCESS_TIMES 100 +#define THERMAL_LVTS_MSR_OFT 64552 +#define LVTS_READ_ID_DELAY_US 3 +#define LVTS_READ_ID_RETRY_CNT 5 +#define LVTS_SINGLE_SENSE_MODE_EN BIT(9) +#define CHECK_SENSING_POINTS_IDLE_TIMES 100 +#define LVTS_DEVICE_WRITE_CONFIG 0x8103 +#define LVTS_DEVICE_READ_CONFIG 0x8502 +#define LVTS_SENSOR_POINT_SELECTION_SETTING 0x13121110 +#define LVTS_CALCULATION_SCALING_RULE 0x00000300 + +/* + * module LVTS Plan + *===================================================== + * Dsu0, Core3, Core7_0/1 LVTS1-0, LVTS1-1, LVTS1-2, LVTS1-3 + * Core4_0/1, Core1, Core2 LVTS2-0, LVTS2-1, LVTS2-2, LVTS2-3 + * Dsu2, Dsu1, Core6_0/1 LVTS3-0, LVTS3-1, LVTS3-2, LVTS3-3 + * Dsu3, Core0, Core5_0/1 LVTS4-0, LVTS4-1, LVTS4-2, LVTS4-3 + * APUa LVTS5-0, LVTS5-1, LVTS5-2, LVTS5-3 + * GPUa LVTS7-0, LVTS7-1 + * SOC-TOP LVTS11-0, LVTS11-1, LVTS11-2, LVTS11-3 + * SOC-BOT LVTS12-0, LVTS12-1, LVTS12-2, LVTS12-3 + * MD-AP LVTS13-0, LVTS13-1, LVTS13-2, LVTS13-3 + * SOC-ADCT LVTS14-0, LVTS14-3 + * ptp_therm_ctrl_AP Base address: 0x1441_4000, 0x1441_4100, + * 0x1441_4200 + * ptp_therm_ctrl_MCU Base address: 0x0C23_0000, 0x0C23_0100, + * 0x0C23_0200, 0x0C23_0300, + */ +static const struct lvts_thermal_controller lvts_tscpu_g_tc[LVTS_CONTROLLER_NUM] = { + [LVTS_AP_CONTROLLER0] = { /* SOC-TOP */ + .ts = {L_TS_LVTS11_0, L_TS_LVTS11_1, L_TS_LVTS11_2, L_TS_LVTS11_3}, + .sensor_on_off = {SEN_ON, SEN_ON, SEN_ON, SEN_ON}, + .ctrl_on_off = CTRL_ON, + .ts_number = 4, + .reboot_temperature = 118800, + .dominator_ts_idx = 0, + .speed = { + .group_interval_delay = 0x7fff, + .period_unit = 0x001, + .filter_interval_delay = 0x001, + .sensor_interval_delay = 0x001, + }, + .regs = mtk_lvts_ap_controller0, + }, + [LVTS_AP_CONTROLLER1] = { /* SOC-BOT */ + .ts = {L_TS_LVTS12_0, L_TS_LVTS12_1, L_TS_LVTS12_2, L_TS_LVTS12_3}, + .sensor_on_off = {SEN_ON, SEN_ON, SEN_ON, SEN_ON}, + .ctrl_on_off = CTRL_ON, + .ts_number = 4, + .reboot_temperature = 118800, + .dominator_ts_idx = 0, + .speed = { + .group_interval_delay = 0x7fff, + .period_unit = 0x001, + .filter_interval_delay = 0x001, + .sensor_interval_delay = 0x001, + }, + .regs = mtk_lvts_ap_controller1, + }, + [LVTS_AP_CONTROLLER2] = { /* MD-AP */ + .ts = {L_TS_LVTS13_0, L_TS_LVTS13_1, L_TS_LVTS13_2, L_TS_LVTS13_3}, + .sensor_on_off = {SEN_ON, SEN_ON, SEN_ON, SEN_ON}, + .ctrl_on_off = CTRL_OFF, + .ts_number = 4, + .reboot_temperature = 118800, + .dominator_ts_idx = 0, + .speed = { + .group_interval_delay = 0x7fff, + .period_unit = 0x001, + .filter_interval_delay = 0x001, + .sensor_interval_delay = 0x001, + }, + .regs = mtk_lvts_ap_controller2, + }, + [LVTS_AP_CONTROLLER3] = { /* SOC-ADCT */ + .ts = {L_TS_LVTS14_0, L_TS_LVTS14_3}, + .sensor_on_off = {SEN_ON, SEN_ON}, + .ctrl_on_off = CTRL_OFF, + .ts_number = 2, + .reboot_temperature = 118800, + .dominator_ts_idx = 0, + .speed = { + .group_interval_delay = 0x7fff, + .period_unit = 0x001, + .filter_interval_delay = 0x001, + .sensor_interval_delay = 0x001, + }, + .regs = mtk_lvts_ap_controller3, + }, +}; + +/*============================================================= + * Local variable definition + *============================================================= + */ +static uint32_t g_golden_temp; +static uint32_t g_count_r[L_TS_LVTS_NUM]; +static uint8_t g_op_cali[LVTS_CONTROLLER_NUM]; + +static int lvts_write_device(uint16_t config, uint8_t dev_reg_idx, uint8_t data, int tc_num) +{ + const struct lvts_thermal_controller *tc = &lvts_tscpu_g_tc[tc_num]; + uint32_t config_data = (config << 16) | (dev_reg_idx << 8) | data; + + write32(&tc->regs->lvts_config_0, config_data); + + /* + * LVTS Device Register Setting takes 1us (by 26MHz clock source) + * interface latency to access. + * So we set 2~3 us delay could guarantee access complete. + */ + udelay(LVTS_DEVICE_ACCESS_DELAY_US); + + /* + * Check ASIF bus status for transaction finished + * Wait until DEVICE_ACCESS_START = 0 + */ + if (!retry(CHECK_DEVICE_ACCESS_TIMES, + read32(&tc->regs->lvts_config_0) & DEVICE_ACCESS_START_BIT, udelay(2))) { + printk(BIOS_INFO, "write err: DEVICE_ACCESS_START didn't ready, reg0x%x\n", + dev_reg_idx); + } + + return 1; +} + +static int lvts_raw_to_temp(uint16_t msr_raw, enum lvts_sensor ts_name) +{ + /* In millidegree Celsius */ + int temp_mc; + int64_t temp1, coff_a; + + coff_a = LVTS_COF_T_SLP_GLD; + + temp1 = (coff_a * msr_raw) / (1 << 14); + temp_mc = temp1 + g_golden_temp * 500 - coff_a; + + return temp_mc; +} + +/* + * The return value is NOT the same as the argument `msr_raw` of lvts_raw_to_temp. + * Instead, it is equal to "(1 << 28) / msr_raw". + */ +static uint16_t lvts_temp_to_raw(int temp_mc, enum lvts_sensor ts_name) +{ + uint32_t msr_raw = 0; + int64_t coff_a = 0; + int64_t temp1; + + coff_a = LVTS_COF_T_SLP_GLD; + + temp1 = (int64_t)temp_mc - (g_golden_temp * 500) + coff_a; + assert(temp1 >= 0); + msr_raw = ((coff_a << 14) / temp1) & 0xFFFF; + + printk(BIOS_INFO, "%s: msr_raw=%u, temp_mc=%d\n", __func__, msr_raw, temp_mc); + + return msr_raw; +} + +static void lvts_efuse_setting(void) +{ + uint32_t i; + uint32_t j, s_index; + uint32_t efuse_data; + uint32_t val_0, val_1; + + printk(BIOS_INFO, "%s\n", __func__); + + for (i = 0; i < ARRAY_SIZE(lvts_tscpu_g_tc); i++) { + const struct lvts_thermal_controller *tc = &lvts_tscpu_g_tc[i]; + if (tc->ctrl_on_off == CTRL_OFF) + continue; + + val_0 = 0; + val_1 = 0; + for (j = 0; j < tc->ts_number; j++) { + if (tc->sensor_on_off[j] == SEN_OFF) + continue; + + s_index = tc->ts[j]; + + efuse_data = g_count_r[s_index] + THERMAL_LVTS_MSR_OFT; + + switch (j) { + case 0: + write32(&tc->regs->lvtsedata[0], efuse_data); + printk(BIOS_INFO, "efuse LVTSEDATA00_%d %#x\n", i, + read32(&tc->regs->lvtsedata[0])); + val_0 |= ((LVTS_COF_T_SLP_GLD + 500) / 1000); + break; + + case 1: + write32(&tc->regs->lvtsedata[1], efuse_data); + printk(BIOS_INFO, "efuse LVTSEDATA01_%d %#x\n", i, + read32(&tc->regs->lvtsedata[1])); + val_0 |= (((LVTS_COF_T_SLP_GLD + 500) / 1000) << 10); + break; + case 2: + write32(&tc->regs->lvtsedata[2], efuse_data); + printk(BIOS_INFO, "efuse LVTSEDATA02_%d %#x\n", i, + read32(&tc->regs->lvtsedata[2])); + val_1 |= ((LVTS_COF_T_SLP_GLD + 500) / 1000); + break; + case 3: + write32(&tc->regs->lvtsedata[3], efuse_data); + printk(BIOS_INFO, "efuse LVTSEDATA03_%d %#x\n", i, + read32(&tc->regs->lvtsedata[3])); + val_1 |= (((LVTS_COF_T_SLP_GLD + 500) / 1000) << 10); + break; + default: + printk(BIOS_ERR, "%s, illegal ts order : %d!!\n", __func__, j); + break; + } + } + val_0 |= (g_golden_temp << 20); + printk(BIOS_INFO, "%s, spare setting: %#x, %#x\n", __func__, val_0, val_1); + write32(&tc->regs->lvtsmsroft_0, THERMAL_LVTS_MSR_OFT); + write32(&tc->regs->lvtsspare[1], val_0); + write32(&tc->regs->lvtsspare[2], val_1); + } +} + +static void lvts_device_identification(void) +{ + uint32_t dev_id, data; + int i; + + printk(BIOS_INFO, "===== %s begin ======\n", __func__); + for (i = 0; i < ARRAY_SIZE(lvts_tscpu_g_tc); i++) { + const struct lvts_thermal_controller *tc = &lvts_tscpu_g_tc[i]; + if (tc->ctrl_on_off == CTRL_OFF) + continue; + + /* Enable LVTS_CTRL Clock */ + write32(&tc->regs->lvtsclken_0, 0x00000001); + + /* Turn On LDO & set DIV_MODE and wait 10 us */ + write32(&tc->regs->lvtsgslope_0, LDO_ON_SETTING); + udelay(10); + + /* Reset All Devices */ + lvts_write_device(LVTS_DEVICE_WRITE_CONFIG, 0xFF, 0xFF, i); + + /* Read back Dev_ID with Update */ + lvts_write_device(LVTS_DEVICE_READ_CONFIG, 0xFC, 0x55, i); + + dev_id = 0x8B + i; + + if (!retry(LVTS_READ_ID_RETRY_CNT, + (data = read32(&tc->regs->lvts_id_0) & GENMASK(7, 0)) == dev_id, + udelay(LVTS_READ_ID_DELAY_US))) + printk(BIOS_ERR, + "LVTS_TC_%d read timeout, addr:0x%lx, Device ID should be 0x%x, but 0x%x\n", + i, (uintptr_t)(&tc->regs->lvts_id_0), dev_id, data); + } +} + +static void lvts_device_enable_init_all_devices(void) +{ + int i; + uint8_t cali_0, cali_1; + + printk(BIOS_INFO, "%s\n", __func__); + + for (i = 0; i < ARRAY_SIZE(lvts_tscpu_g_tc); i++) { + const struct lvts_thermal_controller *tc = &lvts_tscpu_g_tc[i]; + if (tc->ctrl_on_off == CTRL_OFF) + continue; + + /* Stop Counting (RG_TSFM_ST=0) */ + lvts_write_device(LVTS_DEVICE_WRITE_CONFIG, 0x03, 0x00, i); + + /* Set Bandgap Calibration */ + if ((g_op_cali[i] & (1 << 5)) != 0) { + cali_0 = (g_op_cali[i] & 0xf) << 4; + cali_1 = ((g_op_cali[i] >> 4) & 1) << 4; + } else { + cali_0 = (g_op_cali[i] & 0xf); + cali_1 = ((g_op_cali[i] >> 4) & 1) << 3; + } + cali_1 |= 0xA0; + + lvts_write_device(LVTS_DEVICE_WRITE_CONFIG, 0x20, cali_0, i); + lvts_write_device(LVTS_DEVICE_WRITE_CONFIG, 0x21, cali_1, i); + } +} + +static void lvts_thermal_cal_prepare(void) +{ + uint32_t temp[7]; + int i, j; + bool efuse_calibrated = false; + + temp[0] = read32p(LVTS_ADDRESS_INDEX_0); + temp[1] = read32p(LVTS_ADDRESS_INDEX_12); + temp[2] = read32p(LVTS_ADDRESS_INDEX_13); + temp[3] = read32p(LVTS_ADDRESS_INDEX_14); + temp[4] = read32p(LVTS_ADDRESS_INDEX_15); + temp[5] = read32p(LVTS_ADDRESS_INDEX_27); + temp[6] = read32p(LVTS_ADDRESS_INDEX_28); + + printk(BIOS_INFO, + "[lvts_cali] %d: 0x%x, %d: 0x%x, %d: 0x%x, %d: 0x%x, %d: 0x%x, %d: 0x%x, %d: 0x%x\n", + 0, temp[0], 1, temp[1], 2, temp[2], 3, temp[3], 4, temp[4], 5, temp[5], 6, temp[6]); + + g_golden_temp = temp[0] & GENMASK(7, 0); + + g_count_r[L_TS_LVTS11_0] = (temp[1] & GENMASK(31, 16)) >> 16; + g_count_r[L_TS_LVTS11_1] = temp[1] & GENMASK(15, 0); + g_count_r[L_TS_LVTS11_2] = (temp[2] & GENMASK(31, 16)) >> 16; + g_count_r[L_TS_LVTS11_3] = temp[2] & GENMASK(15, 0); + g_count_r[L_TS_LVTS12_0] = (temp[3] & GENMASK(31, 16)) >> 16; + g_count_r[L_TS_LVTS12_1] = temp[3] & GENMASK(15, 0); + g_count_r[L_TS_LVTS12_2] = (temp[4] & GENMASK(31, 16)) >> 16; + g_count_r[L_TS_LVTS12_3] = temp[4] & GENMASK(15, 0); + g_op_cali[LVTS_AP_CONTROLLER0] = (temp[5] & GENMASK(29, 24)) >> 24; + g_op_cali[LVTS_AP_CONTROLLER1] = (temp[6] & GENMASK(29, 24)) >> 24; + + for (i = 0; i < ARRAY_SIZE(temp); i++) { + if (temp[i] != 0) { + efuse_calibrated = true; + break; + } + } + + if (!efuse_calibrated) { + /* It means all efuse data are equal to 0 */ + printk(BIOS_ERR, "[lvts_cal] This sample is not calibrated; Use fake efuse\n"); + g_golden_temp = DEFAULT_EFUSE_GOLDEN_TEMP; + for (i = 0; i < L_TS_LVTS_NUM; i++) + g_count_r[i] = DEFAULT_EFUSE_COUNT; + + for (i = 0; i < LVTS_CONTROLLER_NUM; i++) + g_op_cali[i] = 0; + } + printk(BIOS_INFO, "[lvts_cal] g_golden_temp = %d\n", g_golden_temp); + + printk(BIOS_INFO, "[lvts_cal] num:g_count_r "); + for (i = 0; i < L_TS_LVTS_NUM; i++) + printk(BIOS_INFO, "%d:%d ", i, g_count_r[i]); + printk(BIOS_INFO, "\n"); + + printk(BIOS_INFO, "num:op_cali "); + for (j = 0; j < LVTS_CONTROLLER_NUM; j++) + printk(BIOS_INFO, "%d:0x%x ", j, g_op_cali[j]); + + printk(BIOS_INFO, "\n"); + + write32(&lvts_tscpu_g_tc[LVTS_AP_CONTROLLER0].regs->lvtsspare[1], g_golden_temp); +} + +static int lvts_read_tc_raw_and_temp(void *msr_reg, enum lvts_sensor ts_name) +{ + int temp; + uint32_t msr_data; + uint16_t msr_raw; + + msr_data = read32(msr_reg); + msr_raw = msr_data & 0xFFFF; + + if (msr_raw > 0) { + temp = lvts_raw_to_temp(msr_raw, ts_name); + } else { + /* + * 26111 is magic num + * this is to keep system alive for a while + * to wait HW init done, + * because 0 msr raw will translates to 28x'C + * and then 28x'C will trigger a SW reset. + * + * if HW init finish, this msr raw will not be 0, + * system can report normal temperature. + * if wait over 60 times zero, this means something + * wrong with HW, must trigger BUG on and dump useful + * register for debug. + */ + + temp = 26111; + } + + printk(BIOS_INFO, "[LVTS_MSR] ts%d msr_all=%x, msr_temp=%d, temp=%d\n", ts_name, + msr_data, msr_raw, temp); + + return temp; +} + +static void lvts_tscpu_thermal_read_tc_temp(const struct lvts_thermal_controller *tc, int order) +{ + uint32_t rg_temp; + enum lvts_sensor ts_name = tc->ts[order]; + int temperature; + + ASSERT(order < ARRAY_SIZE(tc->regs->lvtsatp)); + + temperature = lvts_read_tc_raw_and_temp(&tc->regs->lvtsatp[order], ts_name); + rg_temp = read32(&tc->regs->lvtstemp[order]) & 0x7FFFFF; + + printk(BIOS_INFO, "%s order %d ts_name %d temp %d rg_temp %d(%d)\n", __func__, order, + ts_name, temperature, (rg_temp * 1000 / 1024), rg_temp); +} + +static void read_all_tc_lvts_temperature(void) +{ + int i, j; + + for (i = 0; i < ARRAY_SIZE(lvts_tscpu_g_tc); i++) { + const struct lvts_thermal_controller *tc = &lvts_tscpu_g_tc[i]; + if (tc->ctrl_on_off == CTRL_OFF) + continue; + + for (j = 0; j < tc->ts_number; j++) + lvts_tscpu_thermal_read_tc_temp(tc, j); + } +} + +static void lvts_enable_sensing_points(const struct lvts_thermal_controller *tc) +{ + int i; + + printk(BIOS_INFO, "===== %s begin ======\n", __func__); + uint32_t value = LVTS_SINGLE_SENSE_MODE_EN; + + for (i = 0; i < tc->ts_number; i++) { + if (tc->sensor_on_off[i] == SEN_ON) + value |= BIT(i); + } + + write32(&tc->regs->lvtsmonctl0_0, value); + + printk(BIOS_INFO, "%s, value in LVTSMONCTL0_0 = %#x\n", __func__, value); +} + +/* + * disable ALL periodoc temperature sensing point + */ +static void lvts_disable_all_sensing_points(void) +{ + int i = 0; + + printk(BIOS_INFO, "%s\n", __func__); + + for (i = 0; i < ARRAY_SIZE(lvts_tscpu_g_tc); i++) { + const struct lvts_thermal_controller *tc = &lvts_tscpu_g_tc[i]; + if (tc->ctrl_on_off == CTRL_OFF) + continue; + write32(&tc->regs->lvtsmonctl0_0, LVTS_SINGLE_SENSE_MODE_EN); + } +} + +static int lvts_check_all_sensing_points_idle(void) +{ + uint32_t mask, temp; + int i; + + mask = BIT(10) | BIT(7) | BIT(0); + for (i = 0; i < ARRAY_SIZE(lvts_tscpu_g_tc); i++) { + const struct lvts_thermal_controller *tc = &lvts_tscpu_g_tc[i]; + if (tc->ctrl_on_off == CTRL_OFF) + continue; + + temp = read32(&tc->regs->lvtsmsrctl1_0); + if ((temp & mask) != 0) + return -1; + } + + return 0; +} + +static void lvts_wait_all_sensing_points_idle(void) +{ + if (!retry(CHECK_SENSING_POINTS_IDLE_TIMES, + lvts_check_all_sensing_points_idle() == 0, + udelay(2))) + printk(BIOS_ERR, "%s timeout\n", __func__); +} + +static void lvts_enable_all_sensing_points(void) +{ + int i = 0; + + printk(BIOS_INFO, "%s\n", __func__); + + for (i = 0; i < ARRAY_SIZE(lvts_tscpu_g_tc); i++) { + const struct lvts_thermal_controller *tc = &lvts_tscpu_g_tc[i]; + if (tc->ctrl_on_off == CTRL_OFF) + continue; + + lvts_enable_sensing_points(tc); + } +} + +static void lvts_set_init_flag(void) +{ + int i; + + printk(BIOS_INFO, "%s\n", __func__); + + /* write init done flag to inform kernel */ + + for (i = 0; i < ARRAY_SIZE(lvts_tscpu_g_tc); i++) { + const struct lvts_thermal_controller *tc = &lvts_tscpu_g_tc[i]; + if (tc->ctrl_on_off == CTRL_OFF) + continue; + + printk(BIOS_INFO, "%s %d:%zu, tc_base_addr:%p\n", __func__, i, + tc->ts_number, tc->regs); + + write32(&tc->regs->lvtsspare[0], LVTS_MAGIC); + } +} + +static void lvts_configure_polling_speed_and_filter(const struct lvts_thermal_controller *tc) +{ + uint32_t lvts_mon_ctl1, lvts_mon_ctl2; + + lvts_mon_ctl1 = (((tc->speed.group_interval_delay << 17) & GENMASK(31, 17)) | + (tc->speed.period_unit & GENMASK(9, 0))); + + lvts_mon_ctl2 = (((tc->speed.filter_interval_delay << 16) & GENMASK(25, 16)) | + (tc->speed.sensor_interval_delay & GENMASK(9, 0))); + + /* + * Calculate period unit in Module clock x 256, and the Module clock + * will be changed to 26M when Infrasys enters Sleep mode. + */ + + /* + * bus clock 66M counting unit is + * 12 * 1/66M * 256 = 12 * 3.879us = 46.545 us + */ + write32(&tc->regs->lvtsmonctl1_0, lvts_mon_ctl1); + /* + * filt interval is 1 * 46.545us = 46.545us, + * sen interval is 429 * 46.545us = 19.968ms + */ + write32(&tc->regs->lvtsmonctl2_0, lvts_mon_ctl2); + + /* temperature sampling control, 1 sample */ + write32(&tc->regs->lvtsmsrctl0_0, 0); + + udelay(1); + printk(BIOS_INFO, "%s, LVTSMONCTL1_0= 0x%x,LVTSMONCTL2_0= 0x%x,LVTSMSRCTL0_0= 0x%x\n", + __func__, read32(&tc->regs->lvtsmonctl1_0), read32(&tc->regs->lvtsmonctl2_0), + read32(&tc->regs->lvtsmsrctl0_0)); +} + +static void lvts_tscpu_thermal_initial_all_tc(void) +{ + uint32_t i = 0; + + printk(BIOS_INFO, "%s\n", __func__); + + for (i = 0; i < ARRAY_SIZE(lvts_tscpu_g_tc); i++) { + const struct lvts_thermal_controller *tc = &lvts_tscpu_g_tc[i]; + if (tc->ctrl_on_off == CTRL_OFF) + continue; + + /* set sensor index of LVTS */ + write32(&tc->regs->lvtstssel_0, LVTS_SENSOR_POINT_SELECTION_SETTING); + /* set calculation scale rules */ + write32(&tc->regs->lvtscalscale_0, LVTS_CALCULATION_SCALING_RULE); + + lvts_configure_polling_speed_and_filter(tc); + } + +} + +static void lvts_tscpu_reset_thermal(void) +{ + /* Enable thermal control software reset */ + write32p(AP_RST_SET, BIT(11)); + + /* Clear thermal control software reset */ + write32p(AP_RST_CLR, BIT(11)); +} + +static void lvts_set_tc_trigger_hw_protect(const struct lvts_thermal_controller *tc) +{ + int d_index, i; + uint32_t raw_high; + uint16_t raw; + enum lvts_sensor ts_name; + + if (tc->dominator_ts_idx < tc->ts_number) { + d_index = tc->dominator_ts_idx; + } else { + printk(BIOS_ERR, "LVTS, dominator_ts_idx %d >= ts_number %zu; use idx 0\n", + tc->dominator_ts_idx, tc->ts_number); + d_index = 0; + } + + ts_name = tc->ts[d_index]; + + printk(BIOS_INFO, "%s, the dominator ts_name is %d\n", __func__, ts_name); + + /* Maximum of 4 sensing points */ + raw_high = 0; + for (i = 0; i < tc->ts_number; i++) { + ts_name = tc->ts[i]; + raw = lvts_temp_to_raw(tc->reboot_temperature, ts_name); + raw_high = MAX(raw_high, raw); + } + + setbits32(&tc->regs->lvtsprotctl_0, 0x3FFF); + /* disable trigger SPM interrupt */ + write32(&tc->regs->lvtsmonint_0, 0); + + clrsetbits32(&tc->regs->lvtsprotctl_0, 0xF << 16, BIT(16)); + + write32(&tc->regs->lvtsprottc_0, raw_high); + + /* enable trigger Hot SPM interrupt */ + write32(&tc->regs->lvtsmonint_0, STAGE3_INT_EN); + + clrbits32(&tc->regs->lvtsprotctl_0, 0xFFFF); +} + +static void lvts_config_all_tc_hw_protect(void) +{ + int i = 0; + + printk(BIOS_INFO, "===== %s begin ======\n", __func__); + + for (i = 0; i < ARRAY_SIZE(lvts_tscpu_g_tc); i++) { + const struct lvts_thermal_controller *tc = &lvts_tscpu_g_tc[i]; + if (tc->ctrl_on_off == CTRL_OFF) + continue; + + lvts_set_tc_trigger_hw_protect(tc); + } +} + +static bool lvts_lk_init_check(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(lvts_tscpu_g_tc); i++) { + const struct lvts_thermal_controller *tc = &lvts_tscpu_g_tc[i]; + if (tc->ctrl_on_off == CTRL_OFF) + continue; + + /* Check LVTS device ID */ + if ((read32(&tc->regs->lvtsspare[0]) & GENMASK(11, 0)) != LVTS_MAGIC) + return false; + } + + return true; +} + +static void lvts_thermal_init(void) +{ + printk(BIOS_INFO, "===== %s begin ======\n", __func__); + + if (lvts_lk_init_check()) + return; + + lvts_tscpu_reset_thermal(); + + lvts_thermal_cal_prepare(); + lvts_device_identification(); + lvts_device_enable_init_all_devices(); + lvts_efuse_setting(); + + lvts_disable_all_sensing_points(); + lvts_wait_all_sensing_points_idle(); + lvts_tscpu_thermal_initial_all_tc(); + lvts_config_all_tc_hw_protect(); + lvts_enable_all_sensing_points(); + + lvts_set_init_flag(); + + printk(BIOS_INFO, "%s: thermal initialized\n", __func__); + + read_all_tc_lvts_temperature(); +} + +static void reset_cpu_lvts(void) +{ + write32p(CPU_LVTS_RESET_ADDR, 1); + udelay(10); + write32p(CPU_LVTS_RESET_ADDR, 0); + + printk(BIOS_INFO, "%s done\n", __func__); +} + +void thermal_init(void) +{ + reset_cpu_lvts(); + lvts_thermal_init(); + thermal_sram_init(); +} diff --git a/src/soc/mediatek/mt8196/mt_thermal_sram_init.c b/src/soc/mediatek/mt8196/mt_thermal_sram_init.c new file mode 100644 index 0000000..e0308e7 --- /dev/null +++ b/src/soc/mediatek/mt8196/mt_thermal_sram_init.c @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <arch/cache.h> +#include <soc/thermal_internal.h> +#include <string.h> + +/* SRAM for Thermal */ +#define THERMAL_SRAM_BASE ((uintptr_t)_sram + 0x00014000) +#define THERMAL_SRAM_LEN 0x400 +#define THERMAL_ATC_SRAM_BASE (THERMAL_SRAM_BASE + 0x280) +#define THERMAL_ATC_SRAM_LEN (24 * 4) + +static void thermal_cls_sram(void) +{ + int i = 0; + uint32_t pattern = 0x27bc86aa; + uint32_t *buff = (uint32_t *)THERMAL_SRAM_BASE; + for (i = 0; i < THERMAL_SRAM_LEN / 4; i++) { + *buff = pattern; + buff++; + } + dcache_clean_invalidate_by_mva((void *)THERMAL_ATC_SRAM_BASE, THERMAL_ATC_SRAM_LEN); +} + +/* SRAM for Thermal state */ +#define THERMAL_STAT_SRAM_BASE ((uintptr_t)_sram + 0x0001A800) +#define THERMAL_STAT_SRAM_LEN 0x400 +#define THERMAL_STAT_BUF_LENGTH 0x1000 + +static void thermal_stat_cls_sram(void) +{ + int i = 0; + uint32_t pattern = 0xffffffff; + uint32_t *buff = (uint32_t *)THERMAL_STAT_SRAM_BASE; + for (i = 0; i < THERMAL_STAT_SRAM_LEN / 4; i++) { + *buff = pattern; + buff++; + } + dcache_clean_invalidate_by_mva((void *)THERMAL_STAT_SRAM_BASE, THERMAL_STAT_SRAM_LEN); +} + +/* SRAM for GPU Thermal state */ +#define GPU_THERMAL_STAT_SRAM_BASE ((uintptr_t)_sram + 0x00017C00) +#define GPU_THERMAL_STAT_SRAM_LEN 0x400 + +static void thermal_gpu_stat_cls_sram(void) +{ + int i = 0; + uint32_t pattern = 0xffffffff; + uint32_t *buff = (uint32_t *)GPU_THERMAL_STAT_SRAM_BASE; + for (i = 0; i < GPU_THERMAL_STAT_SRAM_LEN / 4; i++) { + *buff = pattern; + buff++; + } + dcache_clean_invalidate_by_mva((void *)GPU_THERMAL_STAT_SRAM_BASE, + GPU_THERMAL_STAT_SRAM_LEN); +} + +void thermal_sram_init(void) +{ + thermal_cls_sram(); + thermal_stat_cls_sram(); + thermal_gpu_stat_cls_sram(); +}