]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - arch/arm/cpu/armv7/mx6/soc.c
arm: mx6: use imx6_thermal driver
[karo-tx-uboot.git] / arch / arm / cpu / armv7 / mx6 / soc.c
index f49dd37bf29d88307c652f6840988f8c2ada9375..08f2cdbe7fcd6ef31e23556696deaff1d3d5ff4e 100644 (file)
@@ -8,24 +8,26 @@
  */
 
 #include <common.h>
-#include <stdbool.h>
-#include <dm.h>
 #include <div64.h>
 #include <ipu.h>
-#include <imx_thermal.h>
+#include <fuse.h>
+#include <thermal.h>
 #include <asm/armv7.h>
 #include <asm/bootm.h>
 #include <asm/pl310.h>
 #include <asm/errno.h>
 #include <asm/io.h>
 #include <asm/arch/imx-regs.h>
-#include <asm/arch/crm_regs.h>
-#include <asm/arch/regs-ocotp.h>
 #include <asm/arch/clock.h>
-#include <asm/arch/mxc_hdmi.h>
+#include <asm/arch/regs-ocotp.h>
 #include <asm/arch/sys_proto.h>
 #include <asm/imx-common/boot_mode.h>
 #include <asm/imx-common/dma.h>
+#include <stdbool.h>
+#include <asm/arch/mxc_hdmi.h>
+#include <asm/arch/crm_regs.h>
+#include <dm.h>
+#include <imx_thermal.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -87,11 +89,12 @@ u32 get_cpu_rev(void)
        struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR;
        u32 reg = readl(&anatop->digprog_sololite);
        u32 type = ((reg >> 16) & 0xff);
+       u32 major, cfg = 0;
 
        if (type != MXC_CPU_MX6SL) {
                reg = readl(&anatop->digprog);
                struct scu_regs *scu = (struct scu_regs *)SCU_BASE_ADDR;
-               u32 cfg = readl(&scu->config) & 3;
+               cfg = readl(&scu->config) & 3;
                type = ((reg >> 16) & 0xff);
                if (type == MXC_CPU_MX6DL) {
                        if (!cfg)
@@ -104,8 +107,16 @@ u32 get_cpu_rev(void)
                }
 
        }
+       major = ((reg >> 8) & 0xff);
+       if ((major >= 1) &&
+           ((type == MXC_CPU_MX6Q) || (type == MXC_CPU_MX6D))) {
+               major--;
+               type = MXC_CPU_MX6QP;
+               if (cfg == 1)
+                       type = MXC_CPU_MX6DP;
+       }
        reg &= 0xff;            /* mx6 silicon revision */
-       return (type << 12) | (reg + 0x10);
+       return (type << 12) | (reg + (0x10 * (major + 1)));
 }
 
 /*
@@ -120,13 +131,12 @@ u32 get_cpu_rev(void)
 
 u32 get_cpu_speed_grade_hz(void)
 {
-       struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
-       struct fuse_bank *bank = &ocotp->bank[0];
-       struct fuse_bank0_regs *fuse =
-               (struct fuse_bank0_regs *)bank->fuse_regs;
        uint32_t val;
 
-       val = readl(&fuse->cfg3);
+       if (fuse_read(0, 3, &val)) {
+               printf("Failed to read speed_grade fuse\n");
+               return 0;
+       }
        val >>= OCOTP_CFG3_SPEED_SHIFT;
        val &= 0x3;
 
@@ -149,6 +159,43 @@ u32 get_cpu_speed_grade_hz(void)
        return 0;
 }
 
+/*
+ * OCOTP_MEM0[7:6] (see Fusemap Description Table offset 0x480)
+ * defines a 2-bit Temperature Grade
+ *
+ * return temperature grade and min/max temperature in celcius
+ */
+#define OCOTP_MEM0_TEMP_SHIFT          6
+
+u32 get_cpu_temp_grade(int *minc, int *maxc)
+{
+       uint32_t val;
+
+       if (fuse_read(1, 0, &val)) {
+               printf("Failed to read temp_grade fuse\n");
+               val = 0;
+       }
+       val >>= OCOTP_MEM0_TEMP_SHIFT;
+       val &= 0x3;
+
+       if (minc && maxc) {
+               if (val == TEMP_AUTOMOTIVE) {
+                       *minc = -40;
+                       *maxc = 125;
+               } else if (val == TEMP_INDUSTRIAL) {
+                       *minc = -40;
+                       *maxc = 105;
+               } else if (val == TEMP_EXTCOMMERCIAL) {
+                       *minc = -20;
+                       *maxc = 105;
+               } else {
+                       *minc = 0;
+                       *maxc = 95;
+               }
+       }
+       return val;
+}
+
 #ifdef CONFIG_REVISION_TAG
 u32 __weak get_board_rev(void)
 {
@@ -290,140 +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) {
-               ocotp_clk_enable();
-               writel(1, &ocotp_regs->hw_ocotp_read_ctrl);
-               thermal_calib = readl(&ocotp_regs->hw_ocotp_ana1);
-               writel(0, &ocotp_regs->hw_ocotp_read_ctrl);
-               ocotp_clk_disable();
-       }
-
-       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;
@@ -431,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);
                }
@@ -441,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;
@@ -465,11 +402,10 @@ static void imx_set_wdog_powerdown(bool enable)
 {
        struct wdog_regs *wdog1 = (struct wdog_regs *)WDOG1_BASE_ADDR;
        struct wdog_regs *wdog2 = (struct wdog_regs *)WDOG2_BASE_ADDR;
-
-#ifdef CONFIG_MX6SX
        struct wdog_regs *wdog3 = (struct wdog_regs *)WDOG3_BASE_ADDR;
-       writew(enable, &wdog3->wmcr);
-#endif
+
+       if (is_cpu_type(MXC_CPU_MX6SX) || is_cpu_type(MXC_CPU_MX6UL))
+               writew(enable, &wdog3->wmcr);
 
        /* Write to the PDE (Power Down Enable) bit */
        writew(enable, &wdog1->wmcr);
@@ -491,9 +427,12 @@ static void set_ahb_rate(u32 val)
 static void clear_mmdc_ch_mask(void)
 {
        struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
+       u32 reg;
+       reg = readl(&mxc_ccm->ccdr);
 
        /* Clear MMDC channel mask */
-       writel(0, &mxc_ccm->ccdr);
+       reg &= ~(MXC_CCM_CCDR_MMDC_CH1_HS_MASK | MXC_CCM_CCDR_MMDC_CH0_HS_MASK);
+       writel(reg, &mxc_ccm->ccdr);
 }
 
 static void init_bandgap(void)
@@ -618,20 +557,31 @@ void enable_caches(void)
 #if defined(CONFIG_FEC_MXC)
 void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
 {
-       struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
-       struct fuse_bank *bank = &ocotp->bank[4];
-       struct fuse_bank4_regs *fuse =
-                       (struct fuse_bank4_regs *)bank->fuse_regs;
-
-       u32 value = readl(&fuse->mac_addr_high);
-       mac[0] = (value >> 8);
-       mac[1] = value;
-
-       value = readl(&fuse->mac_addr_low);
-       mac[2] = value >> 24;
-       mac[3] = value >> 16;
-       mac[4] = value >> 8;
-       mac[5] = value;
+       unsigned int mac0, mac1;
+
+       memset(mac, 0, 6);
+       if (dev_id < 0 || dev_id > 2)
+               return;
+
+       if (fuse_read(4, 2, &mac0)) {
+               printf("Failed to read MAC0 fuse\n");
+               return;
+       }
+       if (fuse_read(4, 3, &mac1)) {
+               printf("Failed to read MAC1 fuse\n");
+               return;
+       }
+       mac[0] = mac1 >> 8;
+       mac[1] = mac1;
+       mac[2] = mac0 >> 24;
+       mac[3] = mac0 >> 16;
+       if (dev_id == 0) {
+               mac[4] = mac0 >> 8;
+               mac[5] = mac0;
+       } else {
+               mac[4] = mac1 >> 24;
+               mac[5] = mac1 >> 16;
+       }
 }
 #endif
 
@@ -678,7 +628,7 @@ void s_init(void)
        u32 mask528;
        u32 reg, periph1, periph2;
 
-       if (is_cpu_type(MXC_CPU_MX6SX))
+       if (is_cpu_type(MXC_CPU_MX6SX) || is_cpu_type(MXC_CPU_MX6UL))
                return;
 
        /* Due to hardware limitation, on MX6Q we need to gate/ungate all PFDs