]> git.kernelconcepts.de Git - karo-tx-uboot.git/commitdiff
arm: mx6: use imx6_thermal driver
authorLothar Waßmann <LW@KARO-electronics.de>
Mon, 19 Oct 2015 10:28:12 +0000 (12:28 +0200)
committerLothar Waßmann <LW@KARO-electronics.de>
Mon, 19 Oct 2015 10:28:12 +0000 (12:28 +0200)
arch/arm/cpu/armv7/mx6/soc.c
arch/arm/include/asm/arch-mx6/sys_proto.h
drivers/thermal/Kconfig
drivers/thermal/imx_thermal.c

index 2f30d46067fef5d0a61dc26bb0661fe3467f2bee..08f2cdbe7fcd6ef31e23556696deaff1d3d5ff4e 100644 (file)
@@ -11,6 +11,7 @@
 #include <div64.h>
 #include <ipu.h>
 #include <fuse.h>
+#include <thermal.h>
 #include <asm/armv7.h>
 #include <asm/bootm.h>
 #include <asm/pl310.h>
@@ -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;
index 4e1f7b9dfb1b5f80b84eb627eff34d4593c88848..bcd3dd458b37c3bb5d586c889c4c1a06227ac723 100644 (file)
@@ -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
index 3c6b36d1cfd0dc10a617ff44613ccad311e3c90e..ece72570778a249b029c497381bff401ca304524 100644 (file)
@@ -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.
+
index 3c6c9679f97a89b30a30caf8b8bafb9238a41213..de9aaf80d5498fa4bdee18b1a4f86d7839f44d05 100644 (file)
@@ -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 */