blob: d03739118359d44393549fa507154d8f438350ec [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <common.h>
#include <asm/io.h>
#include <command.h>
#include <asm/arch/secure_apb.h>
#include <asm/arch/mailbox.h>
#include <asm/arch/tsensor.h>
#include <asm/arch/bl31_apis.h>
#include <linux/arm-smccc.h>
int tsensor_tz_calibration(unsigned int type, unsigned int data)
{
int ret;
register long x0 asm("x0") = TSENSOR_CALI_SET;
register long x1 asm("x1") = type;
register long x2 asm("x2") = data;
register long x3 asm("x3") = 0;
do {
asm volatile(
__asmeq("%0", "x0")
__asmeq("%1", "x1")
__asmeq("%2", "x2")
__asmeq("%3", "x3")
"smc #0\n"
: "+r" (x0)
: "r" (x1), "r" (x2), "r" (x3));
} while (0);
ret = x0;
if (!ret)
return -1;
else
return 0;
}
int thermal_cali_data_read(uint32_t type, uint32_t *outbuf, int32_t size)
{
long sharemem_output_base = 0;
struct arm_smccc_res res;
sharemem_output_base = get_sharemem_info(GET_SHARE_MEM_OUTPUT_BASE);
arm_smccc_smc(TSENSOR_CALI_READ, type, 0, 0, 0, 0, 0, 0, &res);
flush_cache(sharemem_output_base, size);
memcpy((void *)outbuf, (void *)sharemem_output_base, size);
return 0;
}
int r1p1_codetotemp(unsigned long value, unsigned int u_efuse)
{
int64_t temp;
temp = (value * ts_m) * (1 << 16) / (100 * (1 << 16) + ts_n * value);
if (u_efuse & 0x8000) {
temp = ((temp - (u_efuse & 0x7fff)) * ts_a / (1 << 16) - ts_b) / 10;
} else {
temp = ((temp + (u_efuse & 0x7fff)) * ts_a / (1 << 16) - ts_b) / 10;
}
return temp;
}
int r1p1_temp_read(int type)
{
uint32_t ret;
unsigned int u_efuse;
unsigned int value_ts, value_all_ts;
int tmp = -1;
int i, cnt;
char buf[2];
switch (type) {
case 1:
/*enable thermal1*/
writel(T_CONTROL_DATA, TS_PLL_CFG_REG1);
writel(T_TSCLK_DATA, CLKCTRL_TS_CLK_CTRL);
thermal_cali_data_read(1, &ret, 4);
printf("type: ret = %x\n", ret);
mdelay(5);
buf[0] = (ret) & 0xff;
buf[1] = (ret >> 8) & 0xff;
u_efuse = buf[1];
u_efuse = (u_efuse << 8) | buf[0];
value_ts = 0;
value_all_ts = 0;
cnt = 0;
for (i = 0; i <= 10; i ++) {
udelay(50);
value_ts = readl(TS_PLL_STAT0) & 0xffff;
}
for (i = 0; i <= T_AVG_NUM; i ++) {
udelay(T_DLY_TIME);
value_ts = readl(TS_PLL_STAT0) & 0xffff;
if ((value_ts >= T_VALUE_MIN) &&
(value_ts <= T_VALUE_MAX)) {
value_all_ts += value_ts;
cnt ++;
}
}
value_ts = value_all_ts / cnt;
printf("pll tsensor avg: 0x%x, u_efuse: 0x%x\n", value_ts, u_efuse);
if (value_ts == 0) {
printf("pll tsensor read temp is zero\n");
return -1;
}
tmp = r1p1_codetotemp(value_ts, u_efuse);
printf("temp1: %d\n", tmp);
break;
default:
printf("r1p1 tsensor trim type not support\n");
return -1;
}
return tmp;
}
unsigned int r1p1_temptocode(unsigned long value, int tempbase)
{
unsigned long tmp1, tmp2, u_efuse, signbit;
printf("a b m n: %d, %d, %d, %d\n", ts_a, ts_b, ts_m, ts_n);
tmp1 = ((tempbase * 10 + ts_b) * (1 << 16)) / ts_a; /*ideal u*/
printf("%s : tmp1: 0x%lx\n", __func__, tmp1);
tmp2 = (ts_m * value * (1 << 16)) / ((1 << 16) * 100 + ts_n * value);
printf("%s : tmp2: 0x%lx\n", __func__, tmp2);
signbit = ((tmp1 > tmp2) ? 0 : 1);
u_efuse = (tmp1 > tmp2) ? (tmp1 - tmp2) : (tmp2 - tmp1);
u_efuse = (signbit << 15) | u_efuse;
return u_efuse;
}
int r1p1_temp_trim(int tempbase, int tempver, int type)
{
unsigned int u_efuse, index_ts, index_ver;
unsigned int value_ts, value_all_ts;
int i, cnt;
printf("r1p1 temp trim type: 0x%x\n", type);
switch (type) {
case 0:
index_ver = 5;
tempver = tempver & 0x3;
if (tsensor_tz_calibration(index_ver, tempver) < 0)
printf("version tsensor thermal_calibration send error\n");
break;
case 1:
value_ts = 0;
value_all_ts = 0;
index_ts = 6;
cnt = 0;
/*enable thermal1*/
writel(T_CONTROL_DATA, TS_PLL_CFG_REG1);
writel(T_TSCLK_DATA, CLKCTRL_TS_CLK_CTRL);
for (i = 0; i <= 10; i ++) {
udelay(50);
value_ts = readl(TS_PLL_STAT0) & 0xffff;
}
for (i = 0; i <= T_AVG_NUM; i ++) {
udelay(T_DLY_TIME);
value_ts = readl(TS_PLL_STAT0) & 0xffff;
printf("pll tsensor read: 0x%x\n", value_ts);
if ((value_ts >= T_VALUE_MIN) &&
(value_ts <= T_VALUE_MAX)) {
value_all_ts += value_ts;
cnt ++;
}
}
value_ts = value_all_ts / cnt;
printf("pll tsensor avg: 0x%x\n", value_ts);
if (value_ts == 0) {
printf("pll tsensor read temp is zero\n");
return -1;
}
u_efuse = r1p1_temptocode(value_ts, tempbase);
printf("ts efuse:%d\n", u_efuse);
if (u_efuse & 0x8000)
u_efuse = u_efuse | 0x4000;
u_efuse = u_efuse | 0x8000;
printf("ts efuse:0x%x, index: %d\n", u_efuse, index_ts);
if (tsensor_tz_calibration(index_ts, u_efuse) < 0) {
printf("pll tsensor thermal_calibration send error\n");
return -1;
}
break;
default:
printf("r1p1 tsensor trim type not support\n");
return -1;
break;
}
return 0;
}
int temp_read_entry(void)
{
unsigned int ret, ver;
uint32_t data = 0;
thermal_cali_data_read(1, &data, 4);
ver = (data >> 24) & 0xff;
if (0 == (ver & T_VER_MASK)) {
printf("tsensor no trimmed: calidata:0x%x\n", data);
return -1;
}
ret = (ver & 0xf) >> 2;
switch (ret) {
case 0x0:
printf("temp type no support\n");
break;
case 0x2:
printf("temp type no support\n");
break;
case 0x1:
r1p1_temp_read(1);
printf("read the thermal\n");
break;
case 0x3:
printf("temp type no support\n");
return -1;
break;
default:
printf("thermal version not support!!!Please check!\n");
return -1;
}
return 0;
}
int temp_trim_entry(int tempbase, int tempver)
{
unsigned int ver;
uint32_t data;
thermal_cali_data_read(1, &data, 4);
ver = (data >> 24) & 0xff;
if (ver & T_VER_MASK) {
printf("tsensor trimmed: cali data: 0x%x\n", data);
return -1;
}
printf("tsensor input trim tempver, tempver:0x%x\n", tempver);
switch (tempver) {
case 0x84:
r1p1_temp_trim(tempbase, tempver, 1);
r1p1_temp_trim(tempbase, tempver, 0);
printf("triming the thermal by bbt-sw\n");
break;
case 0x85:
r1p1_temp_trim(tempbase, tempver, 1);
r1p1_temp_trim(tempbase, tempver, 0);
printf("triming the thermal by bbt-ops\n");
break;
case 0x87:
r1p1_temp_trim(tempbase, tempver, 1);
r1p1_temp_trim(tempbase, tempver, 0);
printf("triming the thermal by slt\n");
break;
default:
printf("thermal version not support!!!Please check!\n");
return -1;
}
return 0;
}
int temp_cooling_entry(void)
{
#ifdef CONFIG_AML_TSENSOR_COOL
int temp;
while (1) {
temp = r1p1_temp_read(1);
if (temp <= CONFIG_HIGH_TEMP_COOL) {
printf("device cool done\n");
break;
}
mdelay(2000);
printf("warning: temp %d over %d, cooling\n", temp,
CONFIG_HIGH_TEMP_COOL);
}
#endif
return 0;
}