soc/mediatek/mt8196: Add thermal driver

Add thermal driver to support LVTS (Low Voltage Thermal Sensor).

BUG=b:317009620
TEST=Check temperatures read from each sensors.
[INFO ]  [LVTS_MSR] ts0 msr_all=14104, msr_temp=16644, temp=35694
[INFO ]  lvts_tscpu_thermal_read_tc_temp order 0 ts_name 0 temp 35694 rg_temp 35697(36554)
[INFO ]  [LVTS_MSR] ts1 msr_all=14116, msr_temp=16662, temp=36088
[INFO ]  lvts_tscpu_thermal_read_tc_temp order 1 ts_name 1 temp 36088 rg_temp 36091(36958)
[INFO ]  [LVTS_MSR] ts2 msr_all=140f6, msr_temp=16630, temp=35387
[INFO ]  lvts_tscpu_thermal_read_tc_temp order 2 ts_name 2 temp 35387 rg_temp 35390(36240)
[INFO ]  [LVTS_MSR] ts3 msr_all=14105, msr_temp=16645, temp=35716
[INFO ]  lvts_tscpu_thermal_read_tc_temp order 3 ts_name 3 temp 35716 rg_temp 35718(36576)
[INFO ]  [LVTS_MSR] ts4 msr_all=14129, msr_temp=16681, temp=36504
[INFO ]  lvts_tscpu_thermal_read_tc_temp order 0 ts_name 4 temp 36504 rg_temp 36507(37384)
[INFO ]  [LVTS_MSR] ts5 msr_all=1412d, msr_temp=16685, temp=36592
[INFO ]  lvts_tscpu_thermal_read_tc_temp order 1 ts_name 5 temp 36592 rg_temp 36595(37474)
[INFO ]  [LVTS_MSR] ts6 msr_all=140eb, msr_temp=16619, temp=35146
[INFO ]  lvts_tscpu_thermal_read_tc_temp order 2 ts_name 6 temp 35146 rg_temp 35149(35993)
[INFO ]  [LVTS_MSR] ts7 msr_all=14126, msr_temp=16678, temp=36438
[INFO ]  lvts_tscpu_thermal_read_tc_temp order 3 ts_name 7 temp 36438 rg_temp 36442(37317)

Signed-off-by: Zhaoqing Jiu <zhaoqing.jiu@mediatek.corp-partner.google.com>
Change-Id: Ieef94a6909e4da82461351bcb9292e9d01db3362
Reviewed-on: https://review.coreboot.org/c/coreboot/+/86017
Reviewed-by: Yu-Ping Wu <yupingso@google.com>
Reviewed-by: Yidi Lin <yidilin@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Jarried Lin 2024-11-11 11:39:02 +08:00 committed by Yidi Lin
commit c0f0be625b
7 changed files with 1008 additions and 0 deletions

View file

@ -9,5 +9,6 @@ DECLARE_REGION(dram_dma)
DECLARE_REGION(resv_mem_optee)
DECLARE_REGION(resv_mem_gpu)
DECLARE_REGION(resv_mem_gpueb)
DECLARE_REGION(mcufw_reserved)
#endif /* _SOC_MEDIATEK_COMMON_SYMBOLS_H_ */

View file

@ -46,6 +46,8 @@ romstage-y += ../common/pmif_clk.c pmif_clk.c
romstage-y += ../common/pmif.c pmif_init.c
romstage-y += pmif_spmi.c
romstage-y += srclken_rc.c
romstage-y += thermal.c
romstage-y += thermal_sram.c
ramstage-$(CONFIG_ARM64_USE_ARM_TRUSTED_FIRMWARE) += ../common/bl31.c
ramstage-y += ../common/dpm_v2.c

View file

@ -104,6 +104,7 @@ enum {
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,

View file

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

View file

@ -0,0 +1,242 @@
/* 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
/* 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 */

View file

@ -0,0 +1,692 @@
/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
#include <assert.h>
#include <console/console.h>
#include <delay.h>
#include <soc/thermal.h>
#include <soc/thermal_internal.h>
#define LVTS_DEVICE_ACCESS_DELAY_US 3
#define CHECK_DEVICE_ACCESS_RETRY_CNT 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_RETRY_CNT 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,
},
};
static uint32_t golden_temp;
static uint32_t ts_edata[L_TS_LVTS_NUM];
static uint8_t 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_RETRY_CNT,
!(read32(&tc->regs->lvts_config_0) & DEVICE_ACCESS_START_BIT), udelay(2))) {
printk(BIOS_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 + 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 - (golden_temp * 500) + coff_a;
assert(temp1 > 0);
msr_raw = ((coff_a << 14) / temp1) & 0xFFFF;
printk(BIOS_DEBUG, "%s: msr_raw=%u, temp_mc=%d\n", __func__, msr_raw, temp_mc);
return msr_raw;
}
static void lvts_efuse_setting(void)
{
int i, 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 = ts_edata[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 |= (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;
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 ((op_cali[i] & (1 << 5)) != 0) {
cali_0 = (op_cali[i] & 0xf) << 4;
cali_1 = ((op_cali[i] >> 4) & 1) << 4;
} else {
cali_0 = (op_cali[i] & 0xf);
cali_1 = ((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: %#x, %d: %#x, %d: %#x, %d: %#x, %d: %#x, %d: %#x, %d: %#x\n",
0, temp[0], 1, temp[1], 2, temp[2], 3, temp[3], 4, temp[4], 5, temp[5], 6, temp[6]);
golden_temp = temp[0] & GENMASK(7, 0);
ts_edata[L_TS_LVTS11_0] = (temp[1] & GENMASK(31, 16)) >> 16;
ts_edata[L_TS_LVTS11_1] = temp[1] & GENMASK(15, 0);
ts_edata[L_TS_LVTS11_2] = (temp[2] & GENMASK(31, 16)) >> 16;
ts_edata[L_TS_LVTS11_3] = temp[2] & GENMASK(15, 0);
ts_edata[L_TS_LVTS12_0] = (temp[3] & GENMASK(31, 16)) >> 16;
ts_edata[L_TS_LVTS12_1] = temp[3] & GENMASK(15, 0);
ts_edata[L_TS_LVTS12_2] = (temp[4] & GENMASK(31, 16)) >> 16;
ts_edata[L_TS_LVTS12_3] = temp[4] & GENMASK(15, 0);
op_cali[LVTS_AP_CONTROLLER0] = (temp[5] & GENMASK(29, 24)) >> 24;
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");
golden_temp = DEFAULT_EFUSE_GOLDEN_TEMP;
for (i = 0; i < L_TS_LVTS_NUM; i++)
ts_edata[i] = DEFAULT_EFUSE_COUNT;
for (i = 0; i < LVTS_CONTROLLER_NUM; i++)
op_cali[i] = 0;
}
printk(BIOS_INFO, "[lvts_cal] golden_temp = %d\n", golden_temp);
printk(BIOS_INFO, "[lvts_cal] num:ts_edata ");
for (i = 0; i < L_TS_LVTS_NUM; i++)
printk(BIOS_INFO, "%d:%d ", i, ts_edata[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, op_cali[j]);
printk(BIOS_INFO, "\n");
write32(&lvts_tscpu_g_tc[LVTS_AP_CONTROLLER0].regs->lvtsspare[1], 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 until
* HW init is done, because 0 msr raw will translate to 28x'C
* and then 28x'C will trigger a SW reset.
*
* If HW init finishes, this msr raw will not be 0,
* system can report normal temperature.
* If wait over 60 times zero, this means something wrong with HW.
*/
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_RETRY_CNT,
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();
}

View file

@ -0,0 +1,61 @@
/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
#include <arch/cache.h>
#include <soc/thermal_internal.h>
#include <string.h>
/* SRAM for Thermal */
#define THERMAL_SRAM_BASE (_mcufw_reserved + 0x1000)
#define THERMAL_SRAM_LEN 0x400
static void thermal_cls_sram(void)
{
int i = 0;
const uint32_t pattern = 0x27BC86AA;
uint32_t *buff = (uint32_t *)THERMAL_SRAM_BASE;
for (i = 0; i < THERMAL_SRAM_LEN / sizeof(*buff); i++) {
*buff = pattern;
buff++;
}
dcache_clean_invalidate_by_mva((void *)THERMAL_SRAM_BASE, THERMAL_SRAM_LEN);
}
/* SRAM for Thermal state */
#define THERMAL_STAT_SRAM_BASE ((uintptr_t)_sram + 0x0001A800)
#define THERMAL_STAT_SRAM_LEN 0x400
static void thermal_stat_cls_sram(void)
{
int i = 0;
const uint32_t pattern = 0xFFFFFFFF;
uint32_t *buff = (uint32_t *)THERMAL_STAT_SRAM_BASE;
for (i = 0; i < THERMAL_STAT_SRAM_LEN / sizeof(*buff); 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;
const uint32_t pattern = 0xFFFFFFFF;
uint32_t *buff = (uint32_t *)GPU_THERMAL_STAT_SRAM_BASE;
for (i = 0; i < GPU_THERMAL_STAT_SRAM_LEN / sizeof(*buff); 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();
}