X-Git-Url: https://git.kernelconcepts.de/?p=karo-tx-uboot.git;a=blobdiff_plain;f=arch%2Farm%2Fcpu%2Farmv7%2Fmx6%2Fsoc.c;h=0a9182dcc32f150673f540e5455c6faee6abecf4;hp=fc436fbee7c971978a896cdf24ce75648260dd86;hb=e3eef1834ea6cf0f881d2582c706694fb751f018;hpb=d6639d10dbfa42dc888f8917012550b632a88959 diff --git a/arch/arm/cpu/armv7/mx6/soc.c b/arch/arm/cpu/armv7/mx6/soc.c index fc436fbee7..0a9182dcc3 100644 --- a/arch/arm/cpu/armv7/mx6/soc.c +++ b/arch/arm/cpu/armv7/mx6/soc.c @@ -4,34 +4,32 @@ * * (C) Copyright 2009 Freescale Semiconductor, Inc. * - * See file CREDITS for list of people who contributed to this - * project. - * - * 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., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include +#include +#include #include #include #include #include #include +#ifdef CONFIG_VIDEO_IPUV3 +#include +#endif + +DECLARE_GLOBAL_DATA_PTR; + +#define TEMPERATURE_MIN -40 +#define TEMPERATURE_HOT 80 +#define TEMPERATURE_MAX 125 +#define REG_VALUE_TO_CEL(ratio, raw) ((raw_n40c - raw) * 100 / ratio - 40) + +#define __data __attribute__((section(".data"))) struct scu_regs { u32 ctrl; @@ -41,6 +39,28 @@ struct scu_regs { u32 fpga_rev; }; +#ifdef CONFIG_HW_WATCHDOG +#define wdog_base ((void *)WDOG1_BASE_ADDR) +#define WDOG_WCR 0x00 +#define WCR_WDE (1 << 2) +#define WDOG_WSR 0x02 + +void hw_watchdog_reset(void) +{ + if (readw(wdog_base + WDOG_WCR) & WCR_WDE) { + static u16 __data toggle = 0xaaaa; + static int __data first = 1; + + if (first) { + printf("Watchdog active\n"); + first = 0; + } + writew(toggle, wdog_base + WDOG_WSR); + toggle ^= 0xffff; + } +} +#endif + u32 get_cpu_rev(void) { struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR; @@ -115,7 +135,7 @@ void init_aips(void) * Possible values are from 0.725V to 1.450V in steps of * 0.025V (25mV). */ -void set_vddsoc(u32 mv) +static void set_vddsoc(u32 mv) { struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR; u32 val, reg = readl(&anatop->reg_core); @@ -135,6 +155,116 @@ void set_vddsoc(u32 mv) writel(reg, &anatop->reg_core); } +static u32 __data thermal_calib; + +int read_cpu_temperature(void) +{ + unsigned int reg, tmp, i; + unsigned int raw_25c, raw_hot, hot_temp, raw_n40c, ratio; + 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; + + ratio = ((raw_25c - raw_hot) * 100) / (hot_temp - 25); + raw_n40c = raw_25c + (13 * ratio) / 20; + + /* now we only using single measure, every time we measure + the temperature, we will power on/down 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 */ + reg = readl(&anatop->tempsense1); + reg &= ~BM_ANADIG_TEMPSENSE1_MEASURE_FREQ; + reg |= 327; + writel(reg, &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); + + tmp = 0; + /* read five times of temperature values to get average*/ + for (i = 0; i < 5; i++) { + while ((readl(&anatop->tempsense0) & + BM_ANADIG_TEMPSENSE0_FINISHED) == 0) + udelay(10000); + reg = readl(&anatop->tempsense0); + tmp += (reg & BM_ANADIG_TEMPSENSE0_TEMP_VALUE) >> + BP_ANADIG_TEMPSENSE0_TEMP_VALUE; + writel(BM_ANADIG_TEMPSENSE0_FINISHED, + &anatop->tempsense0_clr); + } + + tmp = tmp / 5; + if (tmp <= raw_n40c) + temperature = REG_VALUE_TO_CEL(ratio, tmp); + else + temperature = TEMPERATURE_MIN; + + /* 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) +{ + static int __data max_temp; + int boot_limit = TEMPERATURE_HOT; + int tmp = read_cpu_temperature(); + + if (tmp < TEMPERATURE_MIN || tmp > TEMPERATURE_MAX) { + printf("Temperature: can't get valid data!\n"); + return tmp; + } + + while (tmp >= boot_limit) { + if (boot) { + printf("CPU is %d C, too hot to boot, waiting...\n", + tmp); + udelay(5000000); + tmp = read_cpu_temperature(); + boot_limit = TEMPERATURE_HOT - 1; + } else { + printf("CPU is %d C, too hot, resetting...\n", + tmp); + udelay(1000000); + reset_cpu(0); + } + } + + if (boot) { + printf("Temperature: %d C, calibration data 0x%x\n", + tmp, thermal_calib); + } else if (tmp > max_temp) { + if (tmp > TEMPERATURE_HOT - 5) + printf("WARNING: CPU temperature %d C\n", tmp); + max_temp = tmp; + } + return tmp; +} + static void imx_set_wdog_powerdown(bool enable) { struct wdog_regs *wdog1 = (struct wdog_regs *)WDOG1_BASE_ADDR; @@ -145,6 +275,7 @@ static void imx_set_wdog_powerdown(bool enable) writew(enable, &wdog2->wmcr); } +#ifdef CONFIG_ARCH_CPU_INIT int arch_cpu_init(void) { init_aips(); @@ -153,13 +284,17 @@ int arch_cpu_init(void) imx_set_wdog_powerdown(false); /* Disable PDE bit of WMCR register */ -#ifdef CONFIG_APBH_DMA - /* Start APBH DMA */ +#ifdef CONFIG_VIDEO_IPUV3 + gd->arch.ipu_hw_rev = IPUV3_HW_REV_IPUV3H; +#endif +#ifdef CONFIG_APBH_DMA + /* Timer is required for Initializing APBH DMA */ + timer_init(); mxs_dma_init(); #endif - return 0; } +#endif #ifndef CONFIG_SYS_DCACHE_OFF void enable_caches(void) @@ -179,14 +314,13 @@ void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) u32 value = readl(&fuse->mac_addr_high); mac[0] = (value >> 8); - mac[1] = value ; + mac[1] = value; value = readl(&fuse->mac_addr_low); - mac[2] = value >> 24 ; - mac[3] = value >> 16 ; - mac[4] = value >> 8 ; - mac[5] = value ; - + mac[2] = value >> 24; + mac[3] = value >> 16; + mac[4] = value >> 8; + mac[5] = value; } #endif