| /* | |
| * common/cmd_cpu_temp.c | |
| * | |
| * Copyright (C) 2015 Amlogic, Inc. All rights reserved. | |
| * | |
| * This program is free software; you can redistribute it and/or modify | |
| * it under the terms of the GNU General Public License as published by | |
| * the Free Software Foundation; either version 2 of the License, or | |
| * (at your option) any later version. | |
| * | |
| * This program is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
| * more details. | |
| * | |
| * You should have received a copy of the GNU General Public License along | |
| * with this program; if not, write to the Free Software Foundation, Inc., | |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
| */ | |
| #include <common.h> | |
| #include <asm/io.h> | |
| #include <asm/arch/efuse.h> | |
| #include <command.h> | |
| #include <asm/arch/secure_apb.h> | |
| #include <asm/arch/mailbox.h> | |
| #include <asm/arch/thermal.h> | |
| #include <asm/cpu_id.h> | |
| #ifdef CONFIG_AML_MESON_TXHD | |
| #define NEW_THERMAL_MODE 1 | |
| #endif | |
| #ifdef CONFIG_AML_MESON_G12A | |
| #define R1P1_TSENSOR_MODE 1 | |
| #endif | |
| //#define HHI_SAR_CLK_CNTL 0xc883c000+0xf6*4 //0xc883c3d8 | |
| int temp_base = 27; | |
| #define NUM 30 | |
| uint32_t vref_en = 0; | |
| uint32_t trim = 0; | |
| int saradc_vref = -1; | |
| #define MANUAL_POWER 1 //not use vref, use 1.8V power | |
| int r1p1_read_entry(void); | |
| int r1p1_trim_entry(int tempbase, int tempver); | |
| static int get_tsc(int temp) | |
| { | |
| int vmeasure, TS_C; | |
| switch (get_cpu_id().family_id) { | |
| case MESON_CPU_MAJOR_ID_GXBB: | |
| case MESON_CPU_MAJOR_ID_GXTVBB: | |
| /*TS_C = (adc-435)/8.25+16*/ | |
| vmeasure = temp - (435 + (temp_base - 27) * 3.4); | |
| printf("vmeasure=%d\n", vmeasure); | |
| TS_C = ((vmeasure) / 8.25) + 16; | |
| break; | |
| case MESON_CPU_MAJOR_ID_GXL: | |
| case MESON_CPU_MAJOR_ID_GXM: | |
| case MESON_CPU_MAJOR_ID_GXLX: | |
| if (vref_en) { | |
| /*TS_C = 16-(adc-1655)/37.6*/ | |
| vmeasure = temp - (1655 + (temp_base - 27) * 15.3); | |
| printf("vmeasure=%d\n", vmeasure); | |
| TS_C = 16 - ((vmeasure) / 37.6); | |
| break; | |
| } else { | |
| /*TS_C = 16-(adc-1778)/42*/ | |
| vmeasure = temp - (1778 + (temp_base - 27) * 17); | |
| printf("vmeasure=%d\n", vmeasure); | |
| TS_C = 16 - ((vmeasure) / 42); | |
| break; | |
| } | |
| case MESON_CPU_MAJOR_ID_TXL: | |
| /*TS_C = 16-(adc-1530)/40*/ | |
| vmeasure = temp - (1530 + (temp_base - 27) * 15.5); | |
| printf("vmeasure=%d\n", vmeasure); | |
| TS_C = 16-((vmeasure)/40); | |
| break; | |
| case MESON_CPU_MAJOR_ID_TXLX: | |
| case MESON_CPU_MAJOR_ID_AXG: | |
| case MESON_CPU_MAJOR_ID_TXHD: | |
| /*TS_C = 16-(adc-1750)/42*/ | |
| vmeasure = temp - (1750 + (temp_base - 27) * 17); | |
| printf("vmeasure=%d\n", vmeasure); | |
| TS_C = 16 - ((vmeasure) / 42); | |
| break; | |
| default: | |
| printf("cpu family id not support!!!\n"); | |
| return -1; | |
| } | |
| if (TS_C > 31) | |
| TS_C = 31; | |
| else if (TS_C < 0) | |
| TS_C = 0; | |
| printf("TS_C=%d\n", TS_C); | |
| return TS_C; | |
| } | |
| static int adc_init_chan6(void) | |
| { | |
| #ifdef MANUAL_POWER | |
| int ver = (readl(SEC_AO_SEC_SD_CFG12) >> 24) & 0xff; | |
| #endif | |
| switch (get_cpu_id().family_id) { | |
| case MESON_CPU_MAJOR_ID_GXBB: | |
| case MESON_CPU_MAJOR_ID_GXTVBB: | |
| writel(0x002c2000, SAR_ADC_REG11);/*bit20: test mode disabled*/ | |
| writel(0x00000006, SAR_ADC_CHAN_LIST); | |
| writel(0x00003000, SAR_ADC_AVG_CNTL); | |
| writel(0xc3a8500a, SAR_ADC_REG3); | |
| writel(0x010a000a, SAR_ADC_DELAY); | |
| writel(0x03eb1a0c, SAR_ADC_AUX_SW); | |
| writel(0x008c000c, SAR_ADC_CHAN_10_SW); | |
| writel(0x030e030c, SAR_ADC_DETECT_IDLE_SW); | |
| writel(0x0c00c400, SAR_ADC_DELTA_10); | |
| writel(0x00000114, SAR_CLK_CNTL); /* Clock */ | |
| writel(readl(0xc110868c) | (0x1 << 28), SAR_ADC_REG3); | |
| break; | |
| case MESON_CPU_MAJOR_ID_GXL: | |
| case MESON_CPU_MAJOR_ID_GXM: | |
| case MESON_CPU_MAJOR_ID_GXLX: | |
| writel(0x002c2060, SAR_ADC_REG11);/*bit20 disabled*/ | |
| writel(0x00000006, SAR_ADC_CHAN_LIST);/*channel 6*/ | |
| writel(0x00003000, SAR_ADC_AVG_CNTL); | |
| writel(0xc8a8500a, SAR_ADC_REG3);/*bit27:0*/ | |
| writel(0x010a000a, SAR_ADC_DELAY); | |
| writel(0x03eb1a0c, SAR_ADC_AUX_SW); | |
| writel(0x008c000c, SAR_ADC_CHAN_10_SW); | |
| writel(0x030e030c, SAR_ADC_DETECT_IDLE_SW); | |
| writel(0x0c00c400, SAR_ADC_DELTA_10); | |
| writel(0x00000114, SAR_CLK_CNTL);/*Clock*/ | |
| break; | |
| case MESON_CPU_MAJOR_ID_TXL: | |
| writel(0x00000006, SAR_ADC_CHAN_LIST);/*channel 6*/ | |
| writel(0x00003000, SAR_ADC_AVG_CNTL); | |
| writel(0xc8a8500a, SAR_ADC_REG3);/*bit27:1 disable*/ | |
| writel(0x010a000a, SAR_ADC_DELAY); | |
| writel(0x03eb1a0c, SAR_ADC_AUX_SW); | |
| writel(0x008c000c, SAR_ADC_CHAN_10_SW); | |
| writel(0x030e030c, SAR_ADC_DETECT_IDLE_SW); | |
| writel(0x0c00c400, SAR_ADC_DELTA_10); | |
| writel(0x00000110, SAR_CLK_CNTL);/*Clock*/ | |
| writel(0x002c2060, SAR_ADC_REG11);/*bit20 disabled*/ | |
| break; | |
| case MESON_CPU_MAJOR_ID_TXLX: | |
| writel(0x00000006, SAR_ADC_CHAN_LIST);/*channel 6*/ | |
| writel(0x00003000, SAR_ADC_AVG_CNTL); | |
| writel(0xc8a8500a, SAR_ADC_REG3);/*bit27:1 disable*/ | |
| writel(0x010a000a, SAR_ADC_DELAY); | |
| writel(0x03eb1a0c, SAR_ADC_AUX_SW); | |
| writel(0x008c000c, SAR_ADC_CHAN_10_SW); | |
| writel(0x030e030c, SAR_ADC_DETECT_IDLE_SW); | |
| writel(0x0c00c400, SAR_ADC_DELTA_10); | |
| writel(0x00000110, SAR_CLK_CNTL);/*Clock*/ | |
| writel(0x002c2060, SAR_ADC_REG11);/*bit20 disabled*/ | |
| #ifndef MANUAL_POWER | |
| if (ver != 0xa0) | |
| #endif | |
| writel(readl(SAR_ADC_REG11) | 0x1, SAR_ADC_REG11);/*manual trim use 1.8V*/ | |
| break; | |
| case MESON_CPU_MAJOR_ID_AXG: | |
| case MESON_CPU_MAJOR_ID_TXHD: | |
| writel(0x00000006, SAR_ADC_CHAN_LIST);/*channel 6*/ | |
| writel(0x00003000, SAR_ADC_AVG_CNTL); | |
| writel(0xc8a8500a, SAR_ADC_REG3);/*bit27:1 disable*/ | |
| writel(0x010a000a, SAR_ADC_DELAY); | |
| writel(0x03eb1a0c, SAR_ADC_AUX_SW); | |
| writel(0x008c000c, SAR_ADC_CHAN_10_SW); | |
| writel(0x030e030c, SAR_ADC_DETECT_IDLE_SW); | |
| writel(0x0c00c400, SAR_ADC_DELTA_10); | |
| writel(0x00000110, SAR_CLK_CNTL);/*Clock*/ | |
| writel(0x002c2060, SAR_ADC_REG11);/*bit20 disabled*/ | |
| #ifdef MANUAL_POWER | |
| if ((ver != 0x9) || (ver != 0xa) || (ver != 0xb))/*ft trim no use 1.8v*/ | |
| #endif | |
| writel(readl(SAR_ADC_REG11) | 0x1, SAR_ADC_REG11);/*manual trim use 1.8V*/ | |
| break; | |
| default: | |
| printf("cpu family id not support!!!\n"); | |
| return -1; | |
| } | |
| return 0; | |
| } | |
| static int get_adc_sample(int chan) | |
| { | |
| unsigned value; | |
| int count = 0; | |
| if (!(readl(SAR_CLK_CNTL) & (1 << 8)))/*check and open clk*/ | |
| writel(readl(SAR_CLK_CNTL) | (1 << 8), SAR_CLK_CNTL); | |
| if (!(readl(SAR_BUS_CLK_EN) & (1 << EN_BIT)))/*check and open clk*/ | |
| writel(readl(SAR_BUS_CLK_EN) | (1 << EN_BIT), HHI_GCLK_MPEG2); | |
| /*adc reg4 bit14~15: read adc sample value flag*/ | |
| /*0x21a4: bit14: kernel bit15: bl30*/ | |
| for (; count <= 100; count++) { | |
| if (count == 100) { | |
| printf("%s: get flag timeout!\n",__func__); | |
| return -1; | |
| } | |
| if (!((readl(SAR_ADC_DELAY) >> 14) & 3)) { | |
| writel(readl(SAR_ADC_DELAY) | (FLAG_BUSY_BL30), | |
| SAR_ADC_DELAY); | |
| if (((readl(SAR_ADC_DELAY) >> 14) & 3) != 0x2) | |
| /*maybe kernel set flag, try again*/ | |
| writel(readl(SAR_ADC_DELAY) & (~(FLAG_BUSY_BL30)), | |
| SAR_ADC_DELAY); | |
| else | |
| break;/*set bl30 read flag ok*/ | |
| } else{/*kernel set flag, clear bl30 flag and wait*/ | |
| writel(readl(SAR_ADC_DELAY) & (~(FLAG_BUSY_BL30)), | |
| SAR_ADC_DELAY); | |
| udelay(20); | |
| } | |
| } | |
| #ifndef CONFIG_CHIP_AML_GXB | |
| /* if thermal VREF(5 bits) is not zero, write it to SAR_ADC_REG13[13:9] | |
| * and set SAR_ADC_REG13[8]:0, chipid >= GXL | |
| */ | |
| if (get_cpu_id().family_id >= MESON_CPU_MAJOR_ID_GXL) { | |
| saradc_vref = (readl(SAR_ADC_REG13) >> 8) & 0x3f; /*back up SAR_ADC_REG13[13:8]*/ | |
| if ((readl(AO_SEC_SD_CFG12) >> 19) & 0x1f) { /*thermal VREF*/ | |
| writel(((readl(SAR_ADC_REG13)) & (~(0x3f << 8))) /*SAR_ADC_REG13[8]:0*/ | |
| |(((readl(AO_SEC_SD_CFG12) >> 19) & 0x1f) << 9), /*SAR_ADC_REG13[13:9]*/ | |
| SAR_ADC_REG13); | |
| vref_en = 1; | |
| } else if ((get_cpu_id().family_id >= MESON_CPU_MAJOR_ID_TXL)&& | |
| ((trim == 1)|| | |
| ((((readl(SEC_AO_SEC_SD_CFG12)) >> 24) & 0xff) == 0xc0))) { | |
| writel(((readl(SAR_ADC_REG13)) & (~(0x3f << 8))) /*SAR_ADC_REG13[13:8]:0*/ | |
| | (0x1e << 8), /*SAR_ADC_REG13[13:8]:[0x1e]*/ | |
| SAR_ADC_REG13); | |
| } else { | |
| writel((readl(SAR_ADC_REG13)) & (~(0x3f << 8)), SAR_ADC_REG13); | |
| } | |
| } | |
| #endif | |
| writel(0x00000006, SAR_ADC_CHAN_LIST);/*channel 6*/ | |
| writel(0xc000c | (0x6 << 23) | (0x6 << 7), SAR_ADC_DETECT_IDLE_SW);/*channel 6*/ | |
| writel((readl(SAR_ADC_REG0) & (~(1 << 0))), SAR_ADC_REG0); | |
| writel((readl(SAR_ADC_REG0)|(1 << 0)), SAR_ADC_REG0); | |
| writel((readl(SAR_ADC_REG0)|(1 << 2)), SAR_ADC_REG0);/*start sample*/ | |
| count = 0; | |
| do { | |
| udelay(20); | |
| count++; | |
| } while ((readl(SAR_ADC_REG0) & (0x7 << 28)) | |
| && (count < 100));/*finish sample?*/ | |
| if (count == 100) { | |
| writel(readl(SAR_ADC_REG3) & (~(1 << 29)), SAR_ADC_REG3); | |
| printf("%s: wait finish sample timeout!\n",__func__); | |
| return -1; | |
| } | |
| value = readl(SAR_ADC_FIFO_RD); | |
| #ifndef CONFIG_CHIP_AML_GXB | |
| if (saradc_vref >= 0) /*write back SAR_ADC_REG13[13:8]*/ | |
| writel(((readl(SAR_ADC_REG13)) & (~(0x3f << 8))) | | |
| ((saradc_vref & 0x3f) << 8), | |
| SAR_ADC_REG13); | |
| #endif | |
| writel(readl(SAR_ADC_DELAY) & (~(FLAG_BUSY_BL30)), SAR_ADC_DELAY); | |
| if (((value >> 12) & 0x7) == 0x6) | |
| value = value & SAMPLE_BIT_MASK; | |
| else{ | |
| value = -1; | |
| printf("%s:sample value err! ch:%d, flag:%d\n", __func__, | |
| ((value>>12) & 0x7), ((readl(SAR_ADC_DELAY) >> 14) & 3)); | |
| } | |
| return value; | |
| } | |
| static unsigned int get_cpu_temp(int tsc, int flag) | |
| { | |
| unsigned value; | |
| if (flag) { | |
| value = readl(SAR_ADC_REG11); | |
| writel(((value&(~(0x1f << 14))) | ((tsc & 0x1f) << 14)), SAR_ADC_REG11); | |
| /* bit[14-18]:tsc */ | |
| } else{ | |
| value = readl(SAR_ADC_REG11); | |
| writel(((value&(~(0x1f << 14))) | (0x10 << 14)), SAR_ADC_REG11); | |
| /* bit[14-18]:0x16 */ | |
| } | |
| return get_adc_sample(6); | |
| } | |
| void quicksort(int a[], int numsize) | |
| { | |
| int i = 0, j = numsize - 1; | |
| int val = a[0]; | |
| if (numsize > 1) { | |
| while (i < j) { | |
| for (; j > i; j--) | |
| if (a[j] < val) { | |
| a[i] = a[j]; | |
| break; | |
| } | |
| for (; i < j; i++) | |
| if (a[i] > val) { | |
| a[j] = a[i]; | |
| break; | |
| } | |
| } | |
| a[i] = val; | |
| quicksort(a, i); | |
| quicksort(a + i + 1, numsize - 1 - i); | |
| } | |
| } | |
| static unsigned do_read_calib_data(int *flag, int *temp, int *TS_C) | |
| { | |
| char buf[2]; | |
| unsigned ret; | |
| *flag = 0; | |
| buf[0] = 0; buf[1] = 0; | |
| char flagbuf; | |
| ret = readl(AO_SEC_SD_CFG12); | |
| flagbuf = (ret >> 24) & 0xff; | |
| if (((int)flagbuf != 0xA0) && ((int)flagbuf != 0x40) | |
| && ((int)flagbuf != 0xC0) | |
| && ((int)flagbuf != 0x05) && ((int)flagbuf != 0x06) | |
| && ((int)flagbuf != 0x07) && ((int)flagbuf != 0x09) | |
| && ((int)flagbuf != 0x0a) && ((int)flagbuf != 0x0b) | |
| && ((int)flagbuf != 0x0d) && ((int)flagbuf != 0x0e) | |
| && ((int)flagbuf != 0x0f) | |
| ) { | |
| if (flagbuf) | |
| printf("thermal ver flag error!\n"); | |
| printf("flagbuf is 0x%x!\n", flagbuf); | |
| return 0; | |
| } | |
| buf[0] = (ret) & 0xff; | |
| buf[1] = (ret >> 8) & 0xff; | |
| *temp = buf[1]; | |
| *temp = (*temp << 8) | buf[0]; | |
| *TS_C = *temp & 0x1f; | |
| *flag = (*temp & 0x8000) >> 15; | |
| *temp = (*temp & 0x7fff) >> 5; | |
| if ((get_cpu_id().family_id == MESON_CPU_MAJOR_ID_GXBB) | |
| &&(0x40 == (int)flagbuf))/*ver2*/ | |
| *TS_C = 16; | |
| if (get_cpu_id().family_id >= MESON_CPU_MAJOR_ID_GXL) | |
| *temp = (*temp) << 2; /*adc 12bit sample*/ | |
| printf("adc=%d,TS_C=%d,flag=%d\n", *temp, *TS_C, *flag); | |
| return ret; | |
| } | |
| #if defined(NEW_THERMAL_MODE) | |
| static unsigned int do_read_calib_data1(unsigned int *ver, unsigned int *u_efuse) | |
| { | |
| char buf[2]; | |
| unsigned ret; | |
| buf[0] = 0; buf[1] = 0; | |
| ret = readl(AO_SEC_GP_CFG10); | |
| *ver = (ret >> 24) & 0xff; | |
| if ((*ver != 0x05) && ((int)*ver != 0x06) | |
| && ((int)*ver != 0x07) && ((int)*ver != 0x0d) | |
| && ((int)*ver != 0x0e) && ((int)*ver != 0x0f) | |
| && ((int)*ver != 0x09) && ((int)*ver != 0x0a) | |
| && ((int)*ver != 0x0b)) { | |
| if (ver) | |
| printf("thermal ver flag error!\n"); | |
| printf("ver is 0x%x!\n", *ver); | |
| return 0; | |
| } | |
| buf[0] = (ret) & 0xff; | |
| buf[1] = (ret >> 8) & 0xff; | |
| *u_efuse = buf[1]; | |
| *u_efuse = (*u_efuse << 8) | buf[0]; | |
| return ret; | |
| } | |
| #endif | |
| #if defined(NEW_THERMAL_MODE) | |
| static int write_trim1(void) | |
| { | |
| unsigned int ret,ver, u_efuse;//, ret; | |
| unsigned int signbit; | |
| unsigned long value,tmp1,tmp2; | |
| int family_id; | |
| family_id = get_cpu_id().family_id; | |
| switch (get_cpu_id().family_id) { | |
| case MESON_CPU_MAJOR_ID_TXHD: | |
| writel(1 << 7 | (0x30), HHI_TS_CLK_CNTL); /*clk:0.5M*/ | |
| writel(0x50ab, TS_CFG_REG);/*0x50ab is enable the new thermal mudule*/ | |
| break; | |
| default: | |
| printf("cpu xxxx family id not support!!! id: %d\n", family_id); | |
| return -1; | |
| } | |
| mdelay(5); /*at least 4.2ms*/ | |
| ret = do_read_calib_data1(&ver, &u_efuse); | |
| if (ret) { | |
| printf("This chip has trimmed!!!\n"); | |
| return -1; | |
| } | |
| value = readl(TS_YOUT); | |
| printf("value: 0x%lx\n",value); | |
| value = value & (0xffff);/*maybe the value need to read more times*/ | |
| printf("temp_base: %d\n",temp_base); | |
| printf("YOUT: 0x%lx\n", value); | |
| if ((value < 0x18a9) || (value > 0x31c0)) { /*-20~125 ideal yout*/ | |
| printf("%s : YOUT: 0x%lx out of range! ERROR! \n",__func__,value); | |
| return -1; | |
| } | |
| /* T = (727.8*(5.05*Yout)/((1<<16)+4.05*Yout)) - 274.7 */ | |
| /* u_efuse = u_ideal - u_real */ | |
| tmp1 = ((temp_base * 10 + 2747) * (1 << 16)) / 7278; /*ideal u*/ | |
| printf("%s : tmp1: 0x%lx\n", __func__, tmp1); | |
| tmp2 = (505 * value * (1 << 16)) / ((1 << 16) * 100 + 405 * 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; | |
| printf("%s : u_efuse: 0x%x\n", __func__, u_efuse); | |
| ret = thermal_calibration(2, u_efuse); | |
| return ret; | |
| } | |
| #endif | |
| static int write_trim0(void) | |
| { | |
| int temp = 0; | |
| int temp1[NUM]; | |
| char buf[2]; | |
| unsigned int data; | |
| int i, TS_C; | |
| int ret; | |
| int flag; | |
| memset(temp1, 0, NUM); | |
| ret = adc_init_chan6(); | |
| if (ret) | |
| goto err; | |
| ret = do_read_calib_data(&flag, &temp, &TS_C); | |
| if (ret) { | |
| printf("chip has trimed!!!\n"); | |
| return -1; | |
| } else { | |
| printf("chip is not triming! triming now......\n"); | |
| flag = 0; | |
| temp = 0; | |
| TS_C = 0; | |
| trim = 1; | |
| } | |
| for (i = 0; i < NUM; i++) { | |
| udelay(10000); | |
| /*adc sample value*/ | |
| temp1[i] = get_cpu_temp(16, 0); | |
| } | |
| printf("raw data\n"); | |
| for (i = 0; i < NUM; i++) | |
| printf("%d ", temp1[i]); | |
| printf("\nsort data\n"); | |
| quicksort(temp1, NUM); | |
| for (i = 0; i < NUM; i++) | |
| printf("%d ", temp1[i]); | |
| printf("\n"); | |
| for (i = 2; i < NUM - 2; i++) | |
| temp += temp1[i]; | |
| temp = temp / (NUM - 4); | |
| printf("the adc cpu adc=%d\n", temp); | |
| /**********************************/ | |
| TS_C = get_tsc(temp); | |
| if ((TS_C == 31) || (TS_C <= 0)) { | |
| printf("TS_C: %d NO Trim! Bad chip!Please check!!!\n", TS_C); | |
| goto err; | |
| } | |
| /**********************************/ | |
| temp = 0; | |
| memset(temp1, 0, NUM); | |
| /* flag=1; */ | |
| for (i = 0; i < NUM; i++) { | |
| udelay(10000); | |
| temp1[i] = get_cpu_temp(TS_C, 1); | |
| } | |
| printf("use triming data\n"); | |
| quicksort(temp1, NUM); | |
| for (i = 0; i < NUM; i++) | |
| printf("%d ", temp1[i]); | |
| printf("\n"); | |
| for (i = 2; i < NUM-2; i++) | |
| temp += temp1[i]; | |
| temp = temp / (NUM - 4); | |
| printf("the adc cpu adc=%d\n", temp); | |
| /**************recalculate to 27******/ | |
| switch (get_cpu_id().family_id) { | |
| case MESON_CPU_MAJOR_ID_GXBB: | |
| case MESON_CPU_MAJOR_ID_GXTVBB: | |
| temp = temp - 3.4 * (temp_base - 27); | |
| break; | |
| case MESON_CPU_MAJOR_ID_GXL:/*12bit*/ | |
| case MESON_CPU_MAJOR_ID_GXM: | |
| case MESON_CPU_MAJOR_ID_GXLX: | |
| if (vref_en) { | |
| temp = temp - 15.3*(temp_base - 27); | |
| temp = temp >> 2;/*efuse only 10bit adc*/ | |
| break; | |
| } else { | |
| temp = temp - 17 * (temp_base - 27); | |
| temp = temp >> 2;/*efuse only 10bit adc*/ | |
| break; | |
| } | |
| case MESON_CPU_MAJOR_ID_TXL: | |
| temp = temp - 15.5 * (temp_base - 27); | |
| temp = temp >> 2;/*efuse only 10bit adc*/ | |
| break; | |
| case MESON_CPU_MAJOR_ID_TXLX: | |
| case MESON_CPU_MAJOR_ID_AXG: | |
| case MESON_CPU_MAJOR_ID_TXHD: | |
| temp = temp - 17 * (temp_base - 27); | |
| temp = temp >> 2;/*efuse only 10bit adc*/ | |
| break; | |
| default: | |
| printf("cpu family id not support, thermal0!!!\n"); | |
| goto err; | |
| } | |
| /**********************************/ | |
| temp = ((temp << 5) | (TS_C & 0x1f)) & 0xffff; | |
| /* write efuse tsc,flag */ | |
| buf[0] = (char)(temp & 0xff); | |
| buf[1] = (char)((temp >> 8) & 0xff); | |
| buf[1] |= 0x80; | |
| printf("buf[0]=%x,buf[1]=%x\n", buf[0], buf[1]); | |
| data = buf[1] << 8 | buf[0]; | |
| ret = thermal_calibration(0, data); | |
| return ret; | |
| err: | |
| return -1; | |
| } | |
| static int do_write_trim(cmd_tbl_t *cmdtp, int flag1, | |
| int argc, char * const argv[]) | |
| { | |
| #if defined(NEW_THERMAL_MODE) | |
| unsigned int choose = simple_strtoul(argv[1], NULL, 10); | |
| #endif | |
| int ret; | |
| #if defined(NEW_THERMAL_MODE) | |
| if (choose == 1) { | |
| printf("%s: will trim thermal1.....\n",__func__); | |
| ret = write_trim1(); | |
| } else | |
| #endif | |
| { | |
| printf("%s: will trim thermal0.....\n",__func__); | |
| ret = write_trim0(); | |
| } | |
| return ret; | |
| } | |
| static int read_temp0(void) | |
| { | |
| int temp; | |
| int TS_C; | |
| int flag, adc, count, tempa; | |
| unsigned ret; | |
| flag = 0; | |
| char buf[100] = {}; | |
| setenv("tempa", " "); | |
| adc_init_chan6(); | |
| ret = do_read_calib_data(&flag, &temp, &TS_C); | |
| if (ret) { | |
| adc = 0; | |
| count = 0; | |
| while (count < 64) { | |
| adc += get_cpu_temp(TS_C, flag); | |
| count++; | |
| udelay(200); | |
| } | |
| adc /= count; | |
| tempa = 0; | |
| printf("adc=%d\n", adc); | |
| if (flag) { | |
| switch (get_cpu_id().family_id) { | |
| case MESON_CPU_MAJOR_ID_GXBB: | |
| case MESON_CPU_MAJOR_ID_GXTVBB: | |
| tempa = (10 * (adc-temp)) / 34 + 27; | |
| break; | |
| case MESON_CPU_MAJOR_ID_GXL: | |
| case MESON_CPU_MAJOR_ID_GXM: | |
| case MESON_CPU_MAJOR_ID_GXLX: | |
| if (vref_en)/*thermal VREF*/ | |
| tempa = (10 * (adc - temp)) / 153 + 27; | |
| else | |
| tempa = (10 * (adc - temp)) / 171 + 27; | |
| break; | |
| case MESON_CPU_MAJOR_ID_TXL: | |
| tempa = (10 * (adc - temp)) / 155 + 27; | |
| break; | |
| case MESON_CPU_MAJOR_ID_TXLX: | |
| case MESON_CPU_MAJOR_ID_AXG: | |
| case MESON_CPU_MAJOR_ID_TXHD: | |
| tempa = (adc - temp) / 17 + 27; | |
| break; | |
| default: | |
| printf("cpu family id not support!!!\n"); | |
| return -1; | |
| } | |
| printf("tempa=%d\n", tempa); | |
| sprintf(buf, "%d", tempa); | |
| setenv("tempa", buf); | |
| memset(buf, 0, sizeof(buf)); | |
| sprintf(buf, "temp:%d, adc:%d, tsc:%d, dout:%d", tempa, adc, TS_C, temp); | |
| setenv("err_info_tempa", buf); | |
| } else { | |
| printf("This chip is not trimmed\n"); | |
| sprintf(buf, "%s", "This chip is not trimmed"); | |
| setenv("err_info_tempa", buf); | |
| return -1; | |
| } | |
| } else { | |
| printf("read calibrated data failed\n"); | |
| sprintf(buf, "%s", "read calibrated data failed"); | |
| setenv("err_info_tempa", buf); | |
| return -1; | |
| } | |
| return 0; | |
| } | |
| #if defined(NEW_THERMAL_MODE) | |
| static int read_temp1(void) | |
| { | |
| unsigned int ret; | |
| unsigned long value,tmp; | |
| unsigned int ver, u_efuse; //tmp for debug | |
| int family_id; | |
| int cur_temp; | |
| family_id = get_cpu_id().family_id; | |
| switch (get_cpu_id().family_id) { | |
| case MESON_CPU_MAJOR_ID_TXHD: | |
| writel(1 << 7 | (0x30), HHI_TS_CLK_CNTL); /*clk:0.5M*/ | |
| writel(0x50ab, TS_CFG_REG);/*0x50ab is enable the new thermal mudule*/ | |
| break; | |
| default: | |
| printf("cpu xxxx family id not support!!! id: %d\n", family_id); | |
| return -1; | |
| } | |
| mdelay(5); /*at least 4.2ms*/ | |
| ret = do_read_calib_data1(&ver,&u_efuse); | |
| if (!ret) { | |
| printf("This chip is not trimmed\n"); | |
| return -1; | |
| } | |
| value = readl(TS_YOUT); | |
| value = value & (0xffff); | |
| printf("YOUT: 0x%lx\n", value); | |
| printf("u_efuse: 0x%x\n", u_efuse); | |
| /* T = 727.8*(u_real+u_efuse/(1<<16)) - 274.7 */ | |
| /* u_readl = (5.05*YOUT)/((1<<16)+ 4.05*YOUT) */ | |
| tmp = (value * 505) * (1 << 16) / (100 * (1 << 16) + 405 * value); | |
| if (u_efuse & 0x8000) | |
| cur_temp = ((tmp - (u_efuse & (0x7fff))) * 7278 / (1 << 16) - 2747) / 10; | |
| else | |
| cur_temp = ((tmp + u_efuse) * 7278 / (1 << 16) - 2747) / 10; | |
| printf("newtemp: %d\n", cur_temp); | |
| return cur_temp; | |
| } | |
| #endif | |
| static int do_read_temp(cmd_tbl_t *cmdtp, int flag1, | |
| int argc, char * const argv[]) | |
| { | |
| #if defined(R1P1_TSENSOR_MODE) | |
| printf("read temp\n"); | |
| r1p1_read_entry(); | |
| return 0; | |
| #endif | |
| #if defined(NEW_THERMAL_MODE) | |
| printf("read new and old temp\n"); | |
| read_temp1(); | |
| #endif | |
| read_temp0(); | |
| return 0; | |
| } | |
| static int do_write_version(cmd_tbl_t *cmdtp, int flag1, | |
| int argc, char * const argv[]) | |
| { | |
| int ret; | |
| unsigned int val = simple_strtoul(argv[1], NULL, 16); | |
| ret = thermal_calibration(1, val); | |
| return ret; | |
| } | |
| static int do_set_trim_base(cmd_tbl_t *cmdtp, int flag1, | |
| int argc, char * const argv[]) | |
| { | |
| int temp = simple_strtoul(argv[1], NULL, 10); | |
| temp_base = temp; | |
| printf("set base temperature: %d\n", temp_base); | |
| return 0; | |
| } | |
| static int do_temp_triming(cmd_tbl_t *cmdtp, int flag1, | |
| int argc, char * const argv[]) | |
| { | |
| int cmd_result = -1; | |
| int temp; | |
| #if defined (CONFIG_AML_MESON_AXG) || defined (CONFIG_AML_MESON_TXHD) || (R1P1_TSENSOR_MODE) | |
| unsigned int ver; | |
| int ret = -1; | |
| #endif | |
| if (argc < 2) | |
| return CMD_RET_USAGE; | |
| temp = simple_strtoul(argv[1], NULL, 10); | |
| temp_base = temp; | |
| printf("set base temperature: %d\n", temp_base); | |
| switch (get_cpu_id().family_id) { | |
| case MESON_CPU_MAJOR_ID_GXBB: | |
| case MESON_CPU_MAJOR_ID_GXTVBB: | |
| case MESON_CPU_MAJOR_ID_GXL: | |
| case MESON_CPU_MAJOR_ID_GXM: | |
| case MESON_CPU_MAJOR_ID_TXL: | |
| case MESON_CPU_MAJOR_ID_TXLX: | |
| case MESON_CPU_MAJOR_ID_GXLX: | |
| cmd_result = run_command("write_trim", 0); | |
| if (cmd_result == CMD_RET_SUCCESS) { | |
| /*FB calibration v5: 1010 0000*/ | |
| /*manual calibration v2: 0100 0000*/ | |
| printf("manual calibration v3: 1100 0000\n"); | |
| cmd_result = run_command("write_version 0xc0", 0); | |
| if (cmd_result != CMD_RET_SUCCESS) | |
| printf("write version error!!!\n"); | |
| } else { | |
| printf("trim FAIL!!!Please check!!!\n"); | |
| return -1; | |
| } | |
| run_command("read_temp", 0); | |
| break; | |
| #ifdef CONFIG_AML_MESON_AXG | |
| case MESON_CPU_MAJOR_ID_AXG: | |
| if (argc <3) { | |
| printf("too little args for AXG temp triming!!\n"); | |
| return CMD_RET_USAGE; | |
| } | |
| ver = simple_strtoul(argv[2], NULL, 10); | |
| printf("ver: %d\n", ver); | |
| switch (ver) { | |
| case 0x5: | |
| case 0xd: /*thermal0*/ | |
| cmd_result = run_command("write_trim", 0); | |
| if (cmd_result != CMD_RET_SUCCESS) { | |
| printf("trim FAIL!!!Please check!!!\n"); | |
| return -1; | |
| } else | |
| ret = 0; | |
| break; | |
| default: | |
| printf("thermal version not support!!!Please check!\n"); | |
| return -1; | |
| } | |
| printf("trim thermal data ok\n"); | |
| if (!ret) { //write data ok | |
| char str[20]; | |
| sprintf(str, "write_version 0x%x", ver); | |
| cmd_result = run_command(str, 0); | |
| if (cmd_result == CMD_RET_SUCCESS) | |
| printf("write thermal version ok\n"); | |
| else { | |
| printf("trim FAIL!!!Please check version!!!\n"); | |
| return -1; | |
| } | |
| } | |
| break; | |
| #endif | |
| #ifdef CONFIG_AML_MESON_TXHD | |
| case MESON_CPU_MAJOR_ID_TXHD: | |
| if (argc <3) { | |
| printf("too little args for txhd temp triming!!\n"); | |
| return CMD_RET_USAGE; | |
| } | |
| ver = simple_strtoul(argv[2], NULL, 10); | |
| printf("ver: %d\n", ver); | |
| switch (ver) { | |
| case 0x6: | |
| case 0xe: /*thermal1*/ | |
| if (get_cpu_id().chip_rev != 0x7) { | |
| cmd_result = run_command("write_trim 1", 0); | |
| if (cmd_result != CMD_RET_SUCCESS) { | |
| printf("trim FAIL!!!Please check!!!\n"); | |
| return -1; | |
| } else | |
| ret = 0; | |
| } else | |
| printf("chip version: 0x%x not support!!!Please check!\n", | |
| get_cpu_id().chip_rev); | |
| break; | |
| case 0x5: | |
| case 0xd: /*thermal0*/ | |
| cmd_result = run_command("write_trim", 0); | |
| if (cmd_result != CMD_RET_SUCCESS) { | |
| printf("trim FAIL!!!Please check!!!\n"); | |
| return -1; | |
| } else | |
| ret = 0; | |
| break; | |
| case 0x7: | |
| case 0xf: | |
| if (get_cpu_id().chip_rev != 0x7) { | |
| cmd_result = run_command("write_trim 1", 0); | |
| if (cmd_result != CMD_RET_SUCCESS) { | |
| printf("trim FAIL!!!Please check!!!\n"); | |
| return -1; | |
| } else { | |
| ret = 0; | |
| cmd_result = run_command("write_trim", 0); | |
| if (cmd_result != CMD_RET_SUCCESS) { | |
| printf("trim FAIL!!!Please check!!!\n"); | |
| return -1; | |
| } else | |
| ret = 0; | |
| } | |
| } else | |
| printf("chip version: 0x%x not support!!!Please check!\n", | |
| get_cpu_id().chip_rev); | |
| break; | |
| default: | |
| printf("thermal version not support!!!Please check!\n"); | |
| return -1; | |
| } | |
| printf("trim thermal data ok\n"); | |
| if (!ret) { //write data ok | |
| char str[20]; | |
| sprintf(str, "write_version 0x%x", ver); | |
| cmd_result = run_command(str, 0); | |
| if (cmd_result == CMD_RET_SUCCESS) | |
| printf("write thermal version ok\n"); | |
| else { | |
| printf("trim FAIL!!!Please check version!!!\n"); | |
| return -1; | |
| } | |
| } | |
| break; | |
| #endif | |
| #if defined(R1P1_TSENSOR_MODE) | |
| case MESON_CPU_MAJOR_ID_G12A: | |
| if (argc <3) { | |
| printf("too little args for txhd temp triming!!\n"); | |
| return CMD_RET_USAGE; | |
| } | |
| ver = simple_strtoul(argv[2], NULL, 16); | |
| ret = r1p1_trim_entry(temp_base, ver); | |
| return ret; | |
| break; | |
| #endif | |
| default: | |
| printf("cpu family id not support!!!\n"); | |
| return -1; | |
| } | |
| return 0; | |
| } | |
| #ifdef R1P1_TSENSOR_MODE | |
| int r1p1_codetotemp(unsigned long value, unsigned int u_efuse, | |
| int ts_b, int ts_a, int ts_m, int ts_n) | |
| { | |
| unsigned long tmp; | |
| int cur_temp; | |
| /* T = 727.8*(u_real+u_efuse/(1<<16)) - 274.7 */ | |
| /* u_readl = (5.05*YOUT)/((1<<16)+ 4.05*YOUT) */ | |
| tmp = (value * ts_m) * (1 << 16) / (100 * (1 << 16) + ts_n * value); | |
| printf("u_efuse 0x%x, tmp: %ld\n", u_efuse, tmp); | |
| if (u_efuse & 0x8000) { | |
| cur_temp = ((tmp - (u_efuse & (0x7fff))) * ts_a / (1 << 16) - ts_b) / 10; | |
| } else { | |
| cur_temp = ((tmp + u_efuse) * ts_a / (1 << 16) - ts_b) / 10; | |
| } | |
| return cur_temp; | |
| } | |
| int r1p1_temp_read(int type) | |
| { | |
| unsigned int ret, u_efuse, regdata;//, ret; | |
| unsigned int value_ts, value_all_ts; | |
| int family_id; | |
| int tmp; | |
| int i, ts_a, ts_b, ts_m, ts_n, cnt; | |
| char buf[2]; | |
| family_id = get_cpu_id().family_id; | |
| switch (family_id) { | |
| case MESON_CPU_MAJOR_ID_G12A: | |
| ts_b = 3159; | |
| ts_a = 9411; | |
| ts_m = 424; | |
| ts_n = 324; | |
| switch (type) { | |
| case 1: | |
| /*enable thermal1*/ | |
| regdata = 0x62b;/*enable control*/ | |
| writel(regdata, TS_PLL_CFG_REG1); | |
| regdata = 0x130;/*enable tsclk*/ | |
| writel(regdata, HHI_TS_CLK_CNTL); | |
| ret = readl(AO_SEC_GP_CFG10);/*thermal1 cali data in reg CFG10*/ | |
| 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 <= NUM; i ++) { | |
| udelay(5000); | |
| value_ts = readl(TS_PLL_STAT0) & 0xffff; | |
| if ((value_ts >= 0x18a9) && (value_ts <= 0x32a6)) { | |
| 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("tsensor read temp is zero\n"); | |
| return -1; | |
| } | |
| tmp = r1p1_codetotemp(value_ts, u_efuse, ts_b, ts_a, ts_m, ts_n); | |
| printf("temp1: %d\n", tmp); | |
| break; | |
| case 2: | |
| /*enable thermal2*/ | |
| regdata = 0x62b;/*enable control*/ | |
| writel(regdata,TS_DDR_CFG_REG1); | |
| regdata = 0x130;/*enable tsclk*/ | |
| writel(regdata,HHI_TS_CLK_CNTL); | |
| mdelay(5); | |
| ret = readl(AO_SEC_SD_CFG12);/*thermal1 cali data in reg CFG10*/ | |
| 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_DDR_STAT0) & 0xffff; | |
| } | |
| for (i = 0; i <= NUM; i ++) { | |
| udelay(5000); | |
| value_ts = readl(TS_DDR_STAT0) & 0xffff; | |
| if ((value_ts >= 0x18a9) && (value_ts <= 0x32a6)) { | |
| value_all_ts += value_ts; | |
| cnt ++; | |
| } | |
| } | |
| value_ts = value_all_ts / cnt; | |
| printf("ddr tsensor avg: 0x%x\n", value_ts); | |
| if (value_ts == 0) { | |
| printf("tsensor read temp is zero\n"); | |
| return -1; | |
| } | |
| tmp = r1p1_codetotemp(value_ts, u_efuse, ts_b, ts_a, ts_m, ts_n); | |
| printf("temp2: %d\n", tmp); | |
| break; | |
| default: | |
| printf("r1p1 tsensor trim type not support\n"); | |
| } | |
| } | |
| return 0; | |
| } | |
| int r1p1_read_entry(void) | |
| { | |
| unsigned int ret, ver;//, ret; | |
| int family_id; | |
| family_id = get_cpu_id().family_id; | |
| switch (family_id) { | |
| case MESON_CPU_MAJOR_ID_G12A: | |
| ret = readl(AO_SEC_GP_CFG10); | |
| ver = (ret >> 24) & 0xff; | |
| if ((ver & 0x80) == 0) { | |
| printf("tsensor no trimmed, ver:0x%x\n", ver); | |
| return -1; | |
| } | |
| ver = (ver & 0xf) >> 2; | |
| switch (ver) { | |
| case 0x2: | |
| r1p1_temp_read(1); | |
| r1p1_temp_read(2); | |
| printf("read the thermal1 and thermal2\n"); | |
| break; | |
| case 0x0: | |
| case 0x1: | |
| case 0x3: | |
| printf("temp type no support\n"); | |
| break; | |
| default: | |
| printf("thermal version not support!!!Please check!\n"); | |
| return -1; | |
| } | |
| } | |
| return 0; | |
| } | |
| unsigned int r1p1_temptocode(unsigned long value, int tempbase, | |
| int ts_b, int ts_a, int ts_m, int ts_n) | |
| { | |
| unsigned long tmp1, tmp2, u_efuse, signbit; | |
| /* T = (727.8*(5.05*Yout)/((1<<16)+4.05*Yout)) - 274.7 */ | |
| /* u_efuse = u_ideal - u_real */ | |
| 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, regdata, index_ts, index_ver;//, ret; | |
| unsigned int value_ts, value_all_ts; | |
| int family_id; | |
| int i, ts_a, ts_b, ts_m, ts_n, cnt; | |
| family_id = get_cpu_id().family_id; | |
| printf("r1p1 temp trim type: 0x%x, familyid: %d\n", type, family_id); | |
| switch (family_id) { | |
| case MESON_CPU_MAJOR_ID_G12A: | |
| ts_b = 3159; | |
| ts_a = 9411; | |
| ts_m = 424; | |
| ts_n = 324; | |
| switch (type) { | |
| case 0: | |
| index_ver = 5; | |
| if (thermal_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*/ | |
| regdata = 0x62b;/*enable control*/ | |
| writel(regdata, TS_PLL_CFG_REG1); | |
| regdata = 0x130;/*enable tsclk*/ | |
| writel(regdata, HHI_TS_CLK_CNTL); | |
| for (i = 0; i <= 10; i ++) { | |
| udelay(50); | |
| value_ts = readl(TS_PLL_STAT0) & 0xffff; | |
| } | |
| for (i = 0; i <= NUM; i ++) { | |
| udelay(5000); | |
| value_ts = readl(TS_PLL_STAT0) & 0xffff; | |
| printf("pll tsensor read: 0x%x\n", value_ts); | |
| if ((value_ts >= 0x18a9) && (value_ts <= 0x32a6)) { | |
| 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, ts_b, ts_a, ts_m, ts_n); | |
| printf("pll ts efuse:%d\n", u_efuse); | |
| printf("pll ts efuse:0x%x, index: %d\n", u_efuse, index_ts); | |
| if (thermal_calibration(index_ts, u_efuse) < 0) { | |
| printf("pll tsensor thermal_calibration send error\n"); | |
| return -1; | |
| } | |
| break; | |
| case 2: | |
| value_ts = 0; | |
| value_all_ts = 0; | |
| index_ts = 7; | |
| cnt = 0; | |
| /*enable thermal2*/ | |
| regdata = 0x62b;/*enable control*/ | |
| writel(regdata, TS_DDR_CFG_REG1); | |
| regdata = 0x130;/*enable tsclk*/ | |
| writel(regdata, HHI_TS_CLK_CNTL); | |
| for (i = 0; i <= 10; i ++) { | |
| udelay(50); | |
| value_ts = readl(TS_DDR_STAT0) & 0xffff; | |
| } | |
| for (i = 0; i <= NUM; i ++) { | |
| udelay(5000); | |
| value_ts = readl(TS_DDR_STAT0) & 0xffff; | |
| printf("ddr tsensor read: 0x%x\n", value_ts); | |
| if ((value_ts >= 0x18a9) && (value_ts <= 0x32a6)) { | |
| value_all_ts += value_ts; | |
| cnt ++; | |
| } | |
| } | |
| value_ts = value_all_ts / cnt; | |
| printf("ddr tsensor avg: 0x%x\n", value_ts); | |
| if (value_ts == 0) { | |
| printf("ddr tsensor read temp is zero\n"); | |
| return -1; | |
| } | |
| u_efuse = r1p1_temptocode(value_ts, tempbase, ts_b, ts_a, ts_m, ts_n); | |
| printf("pll ts efuse:%d\n", u_efuse); | |
| printf("pll ts efuse:0x%x, index: %d\n", u_efuse, index_ts); | |
| if (thermal_calibration(index_ts, u_efuse) < 0) { | |
| printf("ddr tsensor thermal_calibration send error\n"); | |
| return -1; | |
| } | |
| break; | |
| default: | |
| printf("r1p1 tsensor trim type not support\n"); | |
| return -1; | |
| break; | |
| } | |
| } | |
| return 0; | |
| } | |
| int r1p1_trim_entry(int tempbase, int tempver) | |
| { | |
| unsigned int ret, ver; | |
| int family_id; | |
| family_id = get_cpu_id().family_id; | |
| switch (family_id) { | |
| case MESON_CPU_MAJOR_ID_G12A: | |
| ret = readl(AO_SEC_GP_CFG10); | |
| ver = (ret >> 24) & 0xff; | |
| if (ver & 0x80) { | |
| printf("tsensor has trimmed, ver:0x%x\n", ver); | |
| printf("tsensor cali data: 0x%x, 0x%x\n", | |
| readl(AO_SEC_GP_CFG10), readl(AO_SEC_SD_CFG12)); | |
| return -1; | |
| } | |
| printf("tsensor input trim tempver, tempver:0x%x\n", tempver); | |
| switch (tempver) { | |
| case 0x88: | |
| r1p1_temp_trim(tempbase, tempver, 1); | |
| r1p1_temp_trim(tempbase, tempver, 2); | |
| r1p1_temp_trim(tempbase, tempver, 0); | |
| printf("triming the thermal1 and thermal2 by sw\n"); | |
| break; | |
| case 0x89: | |
| r1p1_temp_trim(tempbase, tempver, 1); | |
| r1p1_temp_trim(tempbase, tempver, 2); | |
| r1p1_temp_trim(tempbase, tempver, 0); | |
| printf("triming the thermal1 and thermal2 by sw\n"); | |
| break; | |
| case 0x8b: | |
| r1p1_temp_trim(tempbase, tempver, 1); | |
| r1p1_temp_trim(tempbase, tempver, 2); | |
| r1p1_temp_trim(tempbase, tempver, 0); | |
| printf("triming the thermal1 and thermal2 by slt\n"); | |
| break; | |
| default: | |
| printf("thermal version not support!!!Please check!\n"); | |
| return -1; | |
| } | |
| } | |
| return 0; | |
| } | |
| #endif | |
| U_BOOT_CMD( | |
| write_trim, 5, 0, do_write_trim, | |
| "cpu temp-system", | |
| "write_trim data" | |
| ); | |
| U_BOOT_CMD( | |
| read_temp, 5, 0, do_read_temp, | |
| "cpu temp-system", | |
| "read_temp pos" | |
| ); | |
| U_BOOT_CMD( | |
| write_version, 5, 0, do_write_version, | |
| "cpu temp-system", | |
| "write_flag" | |
| ); | |
| static char temp_trim_help_text[] = | |
| "temp_triming x [ver]\n" | |
| " - for manual trimming chip\n" | |
| " - x: [decimal]the temperature of the chip surface\n" | |
| " - [ver]: [decimal]only for New thermal sensor\n" | |
| " BBT: OPS socket board, which can change chips\n" | |
| " online: reference boards witch chip mounted\n" | |
| " AXG or TXHD:\n" | |
| " 5 (0101)b: BBT, thermal0\n" | |
| " 6 (0110)b: BBT, thermal1\n" | |
| " 7 (0111)b: BBT, thermal01\n" | |
| " 13 (1101)b: online, thermal0\n" | |
| " 14 (1110)b: online, thermal1\n" | |
| " 15 (1111)b: online, thermal01\n" | |
| " G12A:\n" | |
| " 88 (10001000)b: BBT-SW, thermal1 thermal2, valid thermal cali data\n" | |
| " 89 (10001001)b: BBT-OPS, thermal1 thermal2, valid thermal cali data\n" | |
| " 8b (10001001)b: SLT, thermal1 thermal2, valid thermal cali data\n"; | |
| U_BOOT_CMD( | |
| temp_triming, 5, 1, do_temp_triming, | |
| "cpu temp-system", | |
| temp_trim_help_text | |
| ); | |
| U_BOOT_CMD( | |
| set_trim_base, 5, 1, do_set_trim_base, | |
| "cpu temp-system", | |
| "set triming base temp" | |
| ); |