From: Lothar Waßmann Date: Mon, 19 Oct 2015 10:28:12 +0000 (+0200) Subject: arm: mx6: use imx6_thermal driver X-Git-Tag: KARO-TX6UL-2015-10-23~14 X-Git-Url: https://git.kernelconcepts.de/?p=karo-tx-uboot.git;a=commitdiff_plain;h=a83c6285388b5aa22980d96a70fff7d111d971fd arm: mx6: use imx6_thermal driver --- diff --git a/arch/arm/cpu/armv7/mx6/soc.c b/arch/arm/cpu/armv7/mx6/soc.c index 2f30d46067..08f2cdbe7f 100644 --- a/arch/arm/cpu/armv7/mx6/soc.c +++ b/arch/arm/cpu/armv7/mx6/soc.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -336,139 +337,28 @@ static int set_ldo_voltage(enum ldo_reg ldo, u32 mv) return 0; } -static u32 __data thermal_calib; - -#define FACTOR0 10000000 -#define FACTOR1 15976 -#define FACTOR2 4297157 - -int raw_to_celsius(unsigned int raw, unsigned int raw_25c, unsigned int raw_hot, - unsigned int hot_temp) -{ - int temperature; - - if (raw_hot != 0 && hot_temp != 0) { - unsigned int raw_n40c, ratio; - - ratio = ((raw_25c - raw_hot) * 100) / (hot_temp - 25); - raw_n40c = raw_25c + (13 * ratio) / 20; - if (raw <= raw_n40c) - temperature = (raw_n40c - raw) * 100 / ratio - 40; - else - temperature = TEMPERATURE_MIN; - } else { - u64 temp64 = FACTOR0; - unsigned int c1, c2; - /* - * Derived from linear interpolation: - * slope = 0.4297157 - (0.0015976 * 25C fuse) - * slope = (FACTOR2 - FACTOR1 * n1) / FACTOR0 - * (Nmeas - n1) / (Tmeas - t1) = slope - * We want to reduce this down to the minimum computation necessary - * for each temperature read. Also, we want Tmeas in millicelsius - * and we don't want to lose precision from integer division. So... - * Tmeas = (Nmeas - n1) / slope + t1 - * milli_Tmeas = 1000 * (Nmeas - n1) / slope + 1000 * t1 - * milli_Tmeas = -1000 * (n1 - Nmeas) / slope + 1000 * t1 - * Let constant c1 = (-1000 / slope) - * milli_Tmeas = (n1 - Nmeas) * c1 + 1000 * t1 - * Let constant c2 = n1 *c1 + 1000 * t1 - * milli_Tmeas = c2 - Nmeas * c1 - */ - temp64 *= 1000; - do_div(temp64, FACTOR1 * raw_25c - FACTOR2); - c1 = temp64; - c2 = raw_25c * c1 + 1000 * 25; - temperature = (c2 - raw * c1) / 1000; - } - return temperature; -} - -int read_cpu_temperature(void) -{ - unsigned int reg, tmp, i; - unsigned int raw_25c, raw_hot, hot_temp; - int temperature; - struct anatop_regs *const anatop = (void *)ANATOP_BASE_ADDR; - struct mx6_ocotp_regs *const ocotp_regs = (void *)OCOTP_BASE_ADDR; - - if (!thermal_calib) { - if (fuse_read(1, 6, &thermal_calib) != 0) { - printf("Failed to read thermal calibration data\n"); - thermal_calib = ~0; - } - } - - if (thermal_calib == 0 || thermal_calib == 0xffffffff) - return TEMPERATURE_MIN; - - /* Fuse data layout: - * [31:20] sensor value @ 25C - * [19:8] sensor value of hot - * [7:0] hot temperature value */ - raw_25c = thermal_calib >> 20; - raw_hot = (thermal_calib & 0xfff00) >> 8; - hot_temp = thermal_calib & 0xff; - - /* now we only using single measure, every time we measure - * the temperature, we will power on/off the anadig module - */ - writel(BM_ANADIG_TEMPSENSE0_POWER_DOWN, &anatop->tempsense0_clr); - writel(BM_ANADIG_ANA_MISC0_REFTOP_SELBIASOFF, &anatop->ana_misc0_set); - - /* write measure freq */ - writel(327, &anatop->tempsense1); - writel(BM_ANADIG_TEMPSENSE0_MEASURE_TEMP, &anatop->tempsense0_clr); - writel(BM_ANADIG_TEMPSENSE0_FINISHED, &anatop->tempsense0_clr); - writel(BM_ANADIG_TEMPSENSE0_MEASURE_TEMP, &anatop->tempsense0_set); - - /* average the temperature value over multiple readings */ - for (i = 0; i < TEMP_AVG_COUNT; i++) { - static int failed; - int limit = 100; - - while ((readl(&anatop->tempsense0) & - BM_ANADIG_TEMPSENSE0_FINISHED) == 0) { - udelay(10000); - if (--limit < 0) - break; - } - if ((readl(&anatop->tempsense0) & - BM_ANADIG_TEMPSENSE0_FINISHED) == 0) { - if (!failed) { - printf("Failed to read temp sensor\n"); - failed = 1; - } - return 0; - } - failed = 0; - reg = (readl(&anatop->tempsense0) & - BM_ANADIG_TEMPSENSE0_TEMP_VALUE) >> - BP_ANADIG_TEMPSENSE0_TEMP_VALUE; - if (i == 0) - tmp = reg; - else - tmp = (tmp * i + reg) / (i + 1); - writel(BM_ANADIG_TEMPSENSE0_FINISHED, - &anatop->tempsense0_clr); - } - - temperature = raw_to_celsius(tmp, raw_25c, raw_hot, hot_temp); - - /* power down anatop thermal sensor */ - writel(BM_ANADIG_TEMPSENSE0_POWER_DOWN, &anatop->tempsense0_set); - writel(BM_ANADIG_ANA_MISC0_REFTOP_SELBIASOFF, &anatop->ana_misc0_clr); - - return temperature; -} - int check_cpu_temperature(int boot) { + int ret; static int __data max_temp; int boot_limit = getenv_ulong("max_boot_temp", 10, TEMPERATURE_HOT); - int tmp = read_cpu_temperature(); + int tmp; + struct udevice *dev; bool first = true; + if (uclass_get_device_by_name(UCLASS_THERMAL, "imx_thermal", &dev)) { + if (first) { + printf("No thermal device found; cannot read CPU temperature\n"); + first = false; + } + return 0; + } + + ret = thermal_get_temp(dev, &tmp); + if (ret) { + printf("Failed to read temperature: %d\n", ret); + return TEMPERATURE_MAX; + } if (tmp < TEMPERATURE_MIN || tmp > TEMPERATURE_MAX) { printf("Temperature: can't get valid data!\n"); return tmp; @@ -476,7 +366,7 @@ int check_cpu_temperature(int boot) if (!boot) { if (tmp > boot_limit) { - printf("CPU is %d C, too hot, resetting...\n", tmp); + printf("CPU is %d C; too hot, resetting...\n", tmp); udelay(100000); reset_cpu(0); } @@ -486,18 +376,20 @@ int check_cpu_temperature(int boot) max_temp = tmp; } } else { - printf("Temperature: %d C, calibration data 0x%x\n", - tmp, thermal_calib); while (tmp >= boot_limit) { if (first) { - printf("CPU is %d C, too hot to boot, waiting...\n", + printf("CPU is %d C; too hot to boot, waiting...\n", tmp); first = false; } if (ctrlc()) break; udelay(50000); - tmp = read_cpu_temperature(); + ret = thermal_get_temp(dev, &tmp); + if (ret < 0) { + printf("Failed to read temperature: %d\n", ret); + return TEMPERATURE_MAX; + } if (tmp > boot_limit - TEMP_WARN_THRESHOLD && tmp != max_temp) printf("WARNING: CPU temperature %d C\n", tmp); max_temp = tmp; diff --git a/arch/arm/include/asm/arch-mx6/sys_proto.h b/arch/arm/include/asm/arch-mx6/sys_proto.h index 4e1f7b9dfb..bcd3dd458b 100644 --- a/arch/arm/include/asm/arch-mx6/sys_proto.h +++ b/arch/arm/include/asm/arch-mx6/sys_proto.h @@ -47,6 +47,5 @@ int mxs_wait_mask_clr(struct mxs_register_32 *reg, uint32_t mask, unsigned int timeout); -int read_cpu_temperature(void); int check_cpu_temperature(int boot); #endif diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 3c6b36d1cf..ece7257077 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -5,3 +5,10 @@ config DM_THERMAL temperature sensors to permit warnings, speed throttling or even automatic power-off when the temperature gets too high or low. Other devices may be discrete but connected on a suitable bus. + +config IMX6_THERMAL + bool "Driver for i.MX6 thermal sensor" + depends on ARCH_MX6 + help + Enable support for the thermal sensor inside the i.MX6 SoC. + diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c index 3c6c9679f9..de9aaf80d5 100644 --- a/drivers/thermal/imx_thermal.c +++ b/drivers/thermal/imx_thermal.c @@ -46,7 +46,7 @@ static int read_cpu_temperature(struct udevice *dev) int temperature; unsigned int reg, n_meas; const struct imx_thermal_plat *pdata = dev_get_platdata(dev); - struct anatop_regs *anatop = (struct anatop_regs *)pdata->regs; + struct anatop_regs *anatop = pdata->regs; struct thermal_data *priv = dev_get_priv(dev); u32 fuse = priv->fuse; int t1, n1; @@ -93,10 +93,7 @@ static int read_cpu_temperature(struct udevice *dev) writel(MISC0_REFTOP_SELBIASOFF, &anatop->ana_misc0_set); /* setup measure freq */ - reg = readl(&anatop->tempsense1); - reg &= ~TEMPSENSE1_MEASURE_FREQ; - reg |= MEASURE_FREQ; - writel(reg, &anatop->tempsense1); + writel(MEASURE_FREQ, &anatop->tempsense1); /* start the measurement process */ writel(TEMPSENSE0_MEASURE_TEMP, &anatop->tempsense0_clr); @@ -104,9 +101,16 @@ static int read_cpu_temperature(struct udevice *dev) writel(TEMPSENSE0_MEASURE_TEMP, &anatop->tempsense0_set); /* make sure that the latest temp is valid */ - while ((readl(&anatop->tempsense0) & - TEMPSENSE0_FINISHED) == 0) - udelay(10000); + const int max_loops = 30; + int loops = 0; + + while (((reg = readl(&anatop->tempsense0)) & TEMPSENSE0_FINISHED) == 0) { + udelay(5); + if (++loops >= max_loops) + break; + } + if ((readl(&anatop->tempsense0) & TEMPSENSE0_FINISHED) == 0) + return 0; /* read temperature count */ reg = readl(&anatop->tempsense0); @@ -115,7 +119,7 @@ static int read_cpu_temperature(struct udevice *dev) writel(TEMPSENSE0_FINISHED, &anatop->tempsense0_clr); /* milli_Tmeas = c2 - Nmeas * c1 */ - temperature = (long)(c2 - n_meas * c1)/1000; + temperature = (long)(c2 - n_meas * c1) / 1000; /* power down anatop thermal sensor */ writel(TEMPSENSE0_POWER_DOWN, &anatop->tempsense0_set); @@ -149,18 +153,26 @@ static const struct dm_thermal_ops imx_thermal_ops = { static int imx_thermal_probe(struct udevice *dev) { + int ret; unsigned int fuse = ~0; - const struct imx_thermal_plat *pdata = dev_get_platdata(dev); struct thermal_data *priv = dev_get_priv(dev); /* Read Temperature calibration data fuse */ - fuse_read(pdata->fuse_bank, pdata->fuse_word, &fuse); + if ((ret = fuse_read(pdata->fuse_bank, pdata->fuse_word, &fuse))) { + printf("Failed to read temp calib fuse: %d\n", ret); + return ret; + } /* Check for valid fuse */ if (fuse == 0 || fuse == ~0) { - printf("CPU: Thermal invalid data, fuse: 0x%x\n", fuse); - return -EPERM; + static int first = 1; + + if (first) { + printf("CPU: Thermal invalid data, fuse: %#10x\n", fuse); + first = 0; + } + return -EINVAL; } /* set critical cooling temp */