]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/armv7/mx6/soc.c
arm: mx6: update temperature calculation code
[karo-tx-uboot.git] / arch / arm / cpu / armv7 / mx6 / soc.c
1 /*
2  * (C) Copyright 2007
3  * Sascha Hauer, Pengutronix
4  *
5  * (C) Copyright 2009 Freescale Semiconductor, Inc.
6  *
7  * SPDX-License-Identifier:     GPL-2.0+
8  */
9
10 #include <common.h>
11 #include <div64.h>
12 #include <asm/errno.h>
13 #include <asm/io.h>
14 #include <asm/arch/imx-regs.h>
15 #include <asm/arch/crm_regs.h>
16 #include <asm/arch/regs-ocotp.h>
17 #include <asm/arch/clock.h>
18 #include <asm/arch/sys_proto.h>
19 #include <asm/imx-common/boot_mode.h>
20 #include <asm/imx-common/dma.h>
21 #include <stdbool.h>
22 #ifdef CONFIG_VIDEO_IPUV3
23 #include <ipu.h>
24 #endif
25
26 DECLARE_GLOBAL_DATA_PTR;
27
28 #ifdef CONFIG_MX6_TEMPERATURE_MIN
29 #define TEMPERATURE_MIN                 CONFIG_MX6_TEMPERATURE_MIN
30 #else
31 #define TEMPERATURE_MIN                 (-40)
32 #endif
33 #ifdef CONFIG_MX6_TEMPERATURE_HOT
34 #define TEMPERATURE_HOT                 CONFIG_MX6_TEMPERATURE_HOT
35 #else
36 #define TEMPERATURE_HOT                 80
37 #endif
38 #ifdef CONFIG_MX6_TEMPERATURE_MAX
39 #define TEMPERATURE_MAX                 CONFIG_MX6_TEMPERATURE_MAX
40 #else
41 #define TEMPERATURE_MAX                 125
42 #endif
43 #define TEMP_AVG_COUNT                  5
44 #define TEMP_WARN_THRESHOLD             5
45
46 #define __data  __attribute__((section(".data")))
47
48 struct scu_regs {
49         u32     ctrl;
50         u32     config;
51         u32     status;
52         u32     invalidate;
53         u32     fpga_rev;
54 };
55
56 #ifdef CONFIG_HW_WATCHDOG
57 #define wdog_base       ((void *)WDOG1_BASE_ADDR)
58 #define WDOG_WCR        0x00
59 #define WCR_WDE         (1 << 2)
60 #define WDOG_WSR        0x02
61
62 void hw_watchdog_reset(void)
63 {
64         if (readw(wdog_base + WDOG_WCR) & WCR_WDE) {
65                 static u16 __data toggle = 0xaaaa;
66                 static int __data first = 1;
67
68                 if (first) {
69                         printf("Watchdog active\n");
70                         first = 0;
71                 }
72                 writew(toggle, wdog_base + WDOG_WSR);
73                 toggle ^= 0xffff;
74         }
75 }
76 #endif
77
78 u32 get_cpu_rev(void)
79 {
80         struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR;
81         u32 reg = readl(&anatop->digprog_sololite);
82         u32 type = ((reg >> 16) & 0xff);
83
84         if (type != MXC_CPU_MX6SL) {
85                 reg = readl(&anatop->digprog);
86                 type = ((reg >> 16) & 0xff);
87                 if (type == MXC_CPU_MX6DL) {
88                         struct scu_regs *scu = (struct scu_regs *)SCU_BASE_ADDR;
89                         u32 cfg = readl(&scu->config) & 3;
90
91                         if (!cfg)
92                                 type = MXC_CPU_MX6SOLO;
93                 }
94         }
95         reg &= 0xff;            /* mx6 silicon revision */
96         return (type << 12) | (reg + 0x10);
97 }
98
99 #ifdef CONFIG_REVISION_TAG
100 u32 __weak get_board_rev(void)
101 {
102         u32 cpurev = get_cpu_rev();
103         u32 type = ((cpurev >> 12) & 0xff);
104         if (type == MXC_CPU_MX6SOLO)
105                 cpurev = (MXC_CPU_MX6DL) << 12 | (cpurev & 0xFFF);
106
107         return cpurev;
108 }
109 #endif
110
111 void init_aips(void)
112 {
113         struct aipstz_regs *aips1, *aips2;
114
115         aips1 = (struct aipstz_regs *)AIPS1_BASE_ADDR;
116         aips2 = (struct aipstz_regs *)AIPS2_BASE_ADDR;
117
118         /*
119          * Set all MPROTx to be non-bufferable, trusted for R/W,
120          * not forced to user-mode.
121          */
122         writel(0x77777777, &aips1->mprot0);
123         writel(0x77777777, &aips1->mprot1);
124         writel(0x77777777, &aips2->mprot0);
125         writel(0x77777777, &aips2->mprot1);
126
127         /*
128          * Set all OPACRx to be non-bufferable, not require
129          * supervisor privilege level for access,allow for
130          * write access and untrusted master access.
131          */
132         writel(0x00000000, &aips1->opacr0);
133         writel(0x00000000, &aips1->opacr1);
134         writel(0x00000000, &aips1->opacr2);
135         writel(0x00000000, &aips1->opacr3);
136         writel(0x00000000, &aips1->opacr4);
137         writel(0x00000000, &aips2->opacr0);
138         writel(0x00000000, &aips2->opacr1);
139         writel(0x00000000, &aips2->opacr2);
140         writel(0x00000000, &aips2->opacr3);
141         writel(0x00000000, &aips2->opacr4);
142 }
143
144 /*
145  * Set the VDDSOC
146  *
147  * Mask out the REG_CORE[22:18] bits (REG2_TRIG) and set
148  * them to the specified millivolt level.
149  * Possible values are from 0.725V to 1.450V in steps of
150  * 0.025V (25mV).
151  */
152 static void set_vddsoc(u32 mv)
153 {
154         struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR;
155         u32 val, reg = readl(&anatop->reg_core);
156
157         if (mv < 725)
158                 val = 0x00;     /* Power gated off */
159         else if (mv > 1450)
160                 val = 0x1F;     /* Power FET switched full on. No regulation */
161         else
162                 val = (mv - 700) / 25;
163
164         /*
165          * Mask out the REG_CORE[22:18] bits (REG2_TRIG)
166          * and set them to the calculated value (0.7V + val * 0.25V)
167          */
168         reg = (reg & ~(0x1F << 18)) | (val << 18);
169         writel(reg, &anatop->reg_core);
170 }
171
172 static u32 __data thermal_calib;
173
174 #define FACTOR0                         10000000
175 #define FACTOR1                         15976
176 #define FACTOR2                         4297157
177
178 int raw_to_celsius(unsigned int raw, unsigned int raw_25c, unsigned int raw_hot,
179                 unsigned int hot_temp)
180 {
181         int temperature;
182
183         if (raw_hot != 0 && hot_temp != 0) {
184                 unsigned int raw_n40c, ratio;
185
186                 ratio = ((raw_25c - raw_hot) * 100) / (hot_temp - 25);
187                 raw_n40c = raw_25c + (13 * ratio) / 20;
188                 if (raw <= raw_n40c)
189                         temperature = (raw_n40c - raw) * 100 / ratio - 40;
190                 else
191                         temperature = TEMPERATURE_MIN;
192         } else {
193                 u64 temp64 = FACTOR0;
194                 unsigned int c1, c2;
195                 /*
196                  * Derived from linear interpolation:
197                  * slope = 0.4297157 - (0.0015976 * 25C fuse)
198                  * slope = (FACTOR2 - FACTOR1 * n1) / FACTOR0
199                  * (Nmeas - n1) / (Tmeas - t1) = slope
200                  * We want to reduce this down to the minimum computation necessary
201                  * for each temperature read.  Also, we want Tmeas in millicelsius
202                  * and we don't want to lose precision from integer division. So...
203                  * Tmeas = (Nmeas - n1) / slope + t1
204                  * milli_Tmeas = 1000 * (Nmeas - n1) / slope + 1000 * t1
205                  * milli_Tmeas = -1000 * (n1 - Nmeas) / slope + 1000 * t1
206                  * Let constant c1 = (-1000 / slope)
207                  * milli_Tmeas = (n1 - Nmeas) * c1 + 1000 * t1
208                  * Let constant c2 = n1 *c1 + 1000 * t1
209                  * milli_Tmeas = c2 - Nmeas * c1
210                  */
211                 temp64 *= 1000;
212                 do_div(temp64, FACTOR1 * raw_25c - FACTOR2);
213                 c1 = temp64;
214                 c2 = raw_25c * c1 + 1000 * 25;
215                 temperature = (c2 - raw * c1) / 1000;
216         }
217         return temperature;
218 }
219
220 int read_cpu_temperature(void)
221 {
222         unsigned int reg, tmp, i;
223         unsigned int raw_25c, raw_hot, hot_temp;
224         int temperature;
225         struct anatop_regs *const anatop = (void *)ANATOP_BASE_ADDR;
226         struct mx6_ocotp_regs *const ocotp_regs = (void *)OCOTP_BASE_ADDR;
227
228         if (!thermal_calib) {
229                 ocotp_clk_enable();
230                 writel(1, &ocotp_regs->hw_ocotp_read_ctrl);
231                 thermal_calib = readl(&ocotp_regs->hw_ocotp_ana1);
232                 writel(0, &ocotp_regs->hw_ocotp_read_ctrl);
233                 ocotp_clk_disable();
234         }
235
236         if (thermal_calib == 0 || thermal_calib == 0xffffffff)
237                 return TEMPERATURE_MIN;
238
239         /* Fuse data layout:
240          * [31:20] sensor value @ 25C
241          * [19:8] sensor value of hot
242          * [7:0] hot temperature value */
243         raw_25c = thermal_calib >> 20;
244         raw_hot = (thermal_calib & 0xfff00) >> 8;
245         hot_temp = thermal_calib & 0xff;
246
247         /* now we only using single measure, every time we measure
248          * the temperature, we will power on/off the anadig module
249          */
250         writel(BM_ANADIG_TEMPSENSE0_POWER_DOWN, &anatop->tempsense0_clr);
251         writel(BM_ANADIG_ANA_MISC0_REFTOP_SELBIASOFF, &anatop->ana_misc0_set);
252
253         /* write measure freq */
254         writel(327, &anatop->tempsense1);
255         writel(BM_ANADIG_TEMPSENSE0_MEASURE_TEMP, &anatop->tempsense0_clr);
256         writel(BM_ANADIG_TEMPSENSE0_FINISHED, &anatop->tempsense0_clr);
257         writel(BM_ANADIG_TEMPSENSE0_MEASURE_TEMP, &anatop->tempsense0_set);
258
259         /* average the temperature value over multiple readings */
260         for (i = 0; i < TEMP_AVG_COUNT; i++) {
261                 static int failed;
262                 int limit = 100;
263
264                 while ((readl(&anatop->tempsense0) &
265                                 BM_ANADIG_TEMPSENSE0_FINISHED) == 0) {
266                         udelay(10000);
267                         if (--limit < 0)
268                                 break;
269                 }
270                 if ((readl(&anatop->tempsense0) &
271                                 BM_ANADIG_TEMPSENSE0_FINISHED) == 0) {
272                         if (!failed) {
273                                 printf("Failed to read temp sensor\n");
274                                 failed = 1;
275                         }
276                         return 0;
277                 }
278                 failed = 0;
279                 reg = (readl(&anatop->tempsense0) &
280                         BM_ANADIG_TEMPSENSE0_TEMP_VALUE) >>
281                         BP_ANADIG_TEMPSENSE0_TEMP_VALUE;
282                 if (i == 0)
283                         tmp = reg;
284                 else
285                         tmp = (tmp * i + reg) / (i + 1);
286                 writel(BM_ANADIG_TEMPSENSE0_FINISHED,
287                         &anatop->tempsense0_clr);
288         }
289
290         temperature = raw_to_celsius(tmp, raw_25c, raw_hot, hot_temp);
291
292         /* power down anatop thermal sensor */
293         writel(BM_ANADIG_TEMPSENSE0_POWER_DOWN, &anatop->tempsense0_set);
294         writel(BM_ANADIG_ANA_MISC0_REFTOP_SELBIASOFF, &anatop->ana_misc0_clr);
295
296         return temperature;
297 }
298
299 int check_cpu_temperature(int boot)
300 {
301         static int __data max_temp;
302         int boot_limit = getenv_ulong("max_boot_temp", 10, TEMPERATURE_HOT);
303         int tmp = read_cpu_temperature();
304         bool first = true;
305
306         if (tmp < TEMPERATURE_MIN || tmp > TEMPERATURE_MAX) {
307                 printf("Temperature:   can't get valid data!\n");
308                 return tmp;
309         }
310
311         if (!boot) {
312                 if (tmp > boot_limit) {
313                         printf("CPU is %d C, too hot, resetting...\n", tmp);
314                         udelay(100000);
315                         reset_cpu(0);
316                 }
317                 if (tmp > max_temp) {
318                         if (tmp > boot_limit - TEMP_WARN_THRESHOLD)
319                                 printf("WARNING: CPU temperature %d C\n", tmp);
320                         max_temp = tmp;
321                 }
322         } else {
323                 printf("Temperature:   %d C, calibration data 0x%x\n",
324                         tmp, thermal_calib);
325                 while (tmp >= boot_limit) {
326                         if (first) {
327                                 printf("CPU is %d C, too hot to boot, waiting...\n",
328                                         tmp);
329                                 first = false;
330                         }
331                         if (ctrlc())
332                                 break;
333                         udelay(50000);
334                         tmp = read_cpu_temperature();
335                         if (tmp > boot_limit - TEMP_WARN_THRESHOLD && tmp != max_temp)
336                                 printf("WARNING: CPU temperature %d C\n", tmp);
337                         max_temp = tmp;
338                 }
339         }
340         return tmp;
341 }
342
343 static void imx_set_wdog_powerdown(bool enable)
344 {
345         struct wdog_regs *wdog1 = (struct wdog_regs *)WDOG1_BASE_ADDR;
346         struct wdog_regs *wdog2 = (struct wdog_regs *)WDOG2_BASE_ADDR;
347
348         /* Write to the PDE (Power Down Enable) bit */
349         writew(enable, &wdog1->wmcr);
350         writew(enable, &wdog2->wmcr);
351 }
352
353 #ifdef CONFIG_ARCH_CPU_INIT
354 int arch_cpu_init(void)
355 {
356         init_aips();
357
358         set_vddsoc(1200);       /* Set VDDSOC to 1.2V */
359
360         imx_set_wdog_powerdown(false); /* Disable PDE bit of WMCR register */
361
362 #ifdef CONFIG_VIDEO_IPUV3
363         gd->arch.ipu_hw_rev = IPUV3_HW_REV_IPUV3H;
364 #endif
365 #ifdef  CONFIG_APBH_DMA
366         /* Timer is required for Initializing APBH DMA */
367         timer_init();
368         mxs_dma_init();
369 #endif
370         return 0;
371 }
372 #endif
373
374 #ifndef CONFIG_SYS_DCACHE_OFF
375 void enable_caches(void)
376 {
377         /* Enable D-cache. I-cache is already enabled in start.S */
378         dcache_enable();
379 }
380 #endif
381
382 #if defined(CONFIG_FEC_MXC)
383 void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
384 {
385         struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
386         struct fuse_bank *bank = &ocotp->bank[4];
387         struct fuse_bank4_regs *fuse =
388                         (struct fuse_bank4_regs *)bank->fuse_regs;
389
390         u32 value = readl(&fuse->mac_addr_high);
391         mac[0] = (value >> 8);
392         mac[1] = value;
393
394         value = readl(&fuse->mac_addr_low);
395         mac[2] = value >> 24;
396         mac[3] = value >> 16;
397         mac[4] = value >> 8;
398         mac[5] = value;
399 }
400 #endif
401
402 void boot_mode_apply(unsigned cfg_val)
403 {
404         unsigned reg;
405         struct src *psrc = (struct src *)SRC_BASE_ADDR;
406         writel(cfg_val, &psrc->gpr9);
407         reg = readl(&psrc->gpr10);
408         if (cfg_val)
409                 reg |= 1 << 28;
410         else
411                 reg &= ~(1 << 28);
412         writel(reg, &psrc->gpr10);
413 }
414 /*
415  * cfg_val will be used for
416  * Boot_cfg4[7:0]:Boot_cfg3[7:0]:Boot_cfg2[7:0]:Boot_cfg1[7:0]
417  * After reset, if GPR10[28] is 1, ROM will copy GPR9[25:0]
418  * to SBMR1, which will determine the boot device.
419  */
420 const struct boot_mode soc_boot_modes[] = {
421         {"normal",      MAKE_CFGVAL(0x00, 0x00, 0x00, 0x00)},
422         /* reserved value should start rom usb */
423         {"usb",         MAKE_CFGVAL(0x01, 0x00, 0x00, 0x00)},
424         {"sata",        MAKE_CFGVAL(0x20, 0x00, 0x00, 0x00)},
425         {"escpi1:0",    MAKE_CFGVAL(0x30, 0x00, 0x00, 0x08)},
426         {"escpi1:1",    MAKE_CFGVAL(0x30, 0x00, 0x00, 0x18)},
427         {"escpi1:2",    MAKE_CFGVAL(0x30, 0x00, 0x00, 0x28)},
428         {"escpi1:3",    MAKE_CFGVAL(0x30, 0x00, 0x00, 0x38)},
429         /* 4 bit bus width */
430         {"esdhc1",      MAKE_CFGVAL(0x40, 0x20, 0x00, 0x00)},
431         {"esdhc2",      MAKE_CFGVAL(0x40, 0x28, 0x00, 0x00)},
432         {"esdhc3",      MAKE_CFGVAL(0x40, 0x30, 0x00, 0x00)},
433         {"esdhc4",      MAKE_CFGVAL(0x40, 0x38, 0x00, 0x00)},
434         {NULL,          0},
435 };
436
437 void s_init(void)
438 {
439 }