| // 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; |
| } |