diff options
author | Ye Li <ye.li@nxp.com> | 2016-11-14 17:34:42 +0800 |
---|---|---|
committer | Ye Li <ye.li@nxp.com> | 2016-11-22 17:49:31 +0800 |
commit | 0d655abeb5ca1420162e06418d09bcb175072eab (patch) | |
tree | 9ca34b087fdc0f74d6e8d61ac5f2c8d9efca5f44 | |
parent | 305b43f4f97dc3f1c6988a50c267af479bb2d89c (diff) | |
download | u-boot-imx-0d655abeb5ca1420162e06418d09bcb175072eab.zip u-boot-imx-0d655abeb5ca1420162e06418d09bcb175072eab.tar.gz u-boot-imx-0d655abeb5ca1420162e06418d09bcb175072eab.tar.bz2 |
MLK-13450-6 mx7ulp: Add soc level initialization codes and functions
Implement soc level functions to get cpu rev, reset cause, enable cache,
etc. We will disable the wdog and init clocks in s_init at very early u-boot
phase.
Since the we are seeking the way to get chip id for mx7ulp, the get_cpu_rev
is hard coded to a fixed value. This may change in future.
Signed-off-by: Ye Li <ye.li@nxp.com>
Signed-off-by: Shenwei Wang <shenwei.wang@nxp.com>
-rw-r--r-- | arch/arm/cpu/armv7/mx7ulp/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/mx7ulp/soc.c | 297 | ||||
-rw-r--r-- | arch/arm/include/asm/arch-mx7ulp/sys_proto.h | 24 |
3 files changed, 322 insertions, 1 deletions
diff --git a/arch/arm/cpu/armv7/mx7ulp/Makefile b/arch/arm/cpu/armv7/mx7ulp/Makefile index 6f37e8c..0248ea8 100644 --- a/arch/arm/cpu/armv7/mx7ulp/Makefile +++ b/arch/arm/cpu/armv7/mx7ulp/Makefile @@ -5,4 +5,4 @@ # # -obj-y := clock.o iomux.o pcc.o scg.o +obj-y := soc.o clock.o iomux.o pcc.o scg.o diff --git a/arch/arm/cpu/armv7/mx7ulp/soc.c b/arch/arm/cpu/armv7/mx7ulp/soc.c new file mode 100644 index 0000000..5caa8dd --- /dev/null +++ b/arch/arm/cpu/armv7/mx7ulp/soc.c @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/imx-regs.h> +#include <asm/arch/sys_proto.h> + +static char *get_reset_cause(char *); + +u32 get_cpu_rev(void) +{ + /* Temporally hard code the CPU rev to 0x73, rev 1.0. Fix it later */ + return (0x73 << 12) | (1 << 4); +} + +#ifdef CONFIG_REVISION_TAG +u32 __weak get_board_rev(void) +{ + return get_cpu_rev(); +} +#endif + +enum bt_mode get_boot_mode(void) +{ + u32 bt0_cfg = 0; + + bt0_cfg = readl(CMC0_RBASE + 0x40); + bt0_cfg &= (BT0CFG_LPBOOT_MASK | BT0CFG_DUALBOOT_MASK); + + if (!(bt0_cfg & BT0CFG_LPBOOT_MASK)) { + /* No low power boot */ + if (bt0_cfg & BT0CFG_DUALBOOT_MASK) + return DUAL_BOOT; + else + return SINGLE_BOOT; + } + + return LOW_POWER_BOOT; +} + +int arch_cpu_init(void) +{ + return 0; +} + +#ifndef CONFIG_SYS_DCACHE_OFF +void enable_caches(void) +{ +#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH) + enum dcache_option option = DCACHE_WRITETHROUGH; +#else + enum dcache_option option = DCACHE_WRITEBACK; +#endif + + /* Avoid random hang when download by usb */ + invalidate_dcache_all(); + + /* Enable D-cache. I-cache is already enabled in start.S */ + dcache_enable(); + + /* Enable caching on OCRAM and ROM */ + mmu_set_region_dcache_behaviour(CORE_B_ROM_BASE, + CORE_B_ROM_SIZE, + option); + mmu_set_region_dcache_behaviour(OCRAM_0_BASE, + SZ_128K + SZ_128K, + option); +} +#endif + +#ifdef CONFIG_BOARD_POSTCLK_INIT +int board_postclk_init(void) +{ + return 0; +} +#endif + +#define UNLOCK_WORD0 0xC520 /* 1st unlock word */ +#define UNLOCK_WORD1 0xD928 /* 2nd unlock word */ +#define REFRESH_WORD0 0xA602 /* 1st refresh word */ +#define REFRESH_WORD1 0xB480 /* 2nd refresh word */ + +static void disable_wdog(u32 wdog_base) +{ + writel(UNLOCK_WORD0, (wdog_base + 0x04)); + writel(UNLOCK_WORD1, (wdog_base + 0x04)); + writel(0x0, (wdog_base + 0x0C)); /* Set WIN to 0 */ + writel(0x400, (wdog_base + 0x08)); /* Set timeout to default 0x400 */ + writel(0x120, (wdog_base + 0x00)); /* Disable it and set update */ + + writel(REFRESH_WORD0, (wdog_base + 0x04)); /* Refresh the CNT */ + writel(REFRESH_WORD1, (wdog_base + 0x04)); +} + +void init_wdog(void) +{ + /* + * ROM will configure WDOG1, disable it or enable it depending on FUSE. + * The update bit is set for reconfigurable. We have to use unlock sequence to + * reconfigure it. + * + * WDOG2 is not touched by ROM, so it will have default value which is enabled. + * We can directly configure it. To simplify the codes, we still use same reconfigure + * process as WDOG1. Because the update bit is not set for WDOG2, the unlock sequence + * won't take effect really. It actually directly configure the wdog. + * + * In this function, we will disable both WDOG1 and WDOG2, and set update bit + * for both. So that kernel can reconfigure them. + */ + disable_wdog(WDG1_RBASE); + disable_wdog(WDG2_RBASE); +} + + +void s_init(void) +{ + /* Disable wdog */ + init_wdog(); + + /* clock configuration. */ + clock_init(); + + return; +} + +void reset_misc(void) +{ +} + +#ifndef CONFIG_ULP_WATCHDOG +void reset_cpu(ulong addr) +{ + setbits_le32(SIM0_RBASE, SIM_SOPT1_A7_SW_RESET); + while (1) + ; +} +#endif + +#if defined(CONFIG_DISPLAY_CPUINFO) +const char *get_imx_type(u32 imxtype) +{ +#ifdef CONFIG_MXC_OCOTP + + u8 uid[8]; + u32 val; + + struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; + struct fuse_bank *bank = &ocotp->bank[0]; + struct fuse_bank1_regs *fuse = + (struct fuse_bank1_regs *)bank->fuse_regs; + + val = readl(&fuse->cfg0); + *uid = val & 0xFF; + *(uid + 1) = (val & 0xFF00) >> 8; + + val = readl(&fuse->cfg1); + *(uid + 2) = val & 0xFF; + *(uid + 3) = (val & 0xFF00) >> 8; + + val = readl(&fuse->cfg2); + *(uid + 4) = val & 0xFF; + *(uid + 5) = (val & 0xFF00) >> 8; + + val = readl(&fuse->cfg3); + *(uid + 6) = val & 0xFF; + *(uid + 7) = (val & 0xFF00) >> 8; + + debug("UID = %02X %02X %02X %02X %02X %02X %02X %02X\r\n", + uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6], uid[7]); + +#endif + return "7ULP"; +} + +int print_cpuinfo(void) +{ + u32 cpurev; + char cause[18]; + + cpurev = get_cpu_rev(); + + { + printf("CPU: Freescale i.MX%s rev%d.%d at %d MHz\n", + get_imx_type((cpurev & 0xFF000) >> 12), + (cpurev & 0x000F0) >> 4, + (cpurev & 0x0000F) >> 0, + mxc_get_clock(MXC_ARM_CLK) / 1000000); + } + + printf("Reset cause: %s\n", get_reset_cause(cause)); + + printf("Boot mode: "); + switch (get_boot_mode()) { + case LOW_POWER_BOOT: + printf("Low power boot\n"); + break; + case DUAL_BOOT: + printf("Dual boot\n"); + break; + case SINGLE_BOOT: + default: + printf("Single boot\n"); + break; + } + + return 0; +} +#endif + +#define CMC_SRS_TAMPER (1 << 31) +#define CMC_SRS_SECURITY (1 << 30) +#define CMC_SRS_TZWDG (1 << 29) +#define CMC_SRS_JTAG_RST (1 << 28) +#define CMC_SRS_CORE1 (1 << 16) +#define CMC_SRS_LOCKUP (1 << 15) +#define CMC_SRS_SW (1 << 14) +#define CMC_SRS_WDG (1 << 13) +#define CMC_SRS_PIN_RESET (1 << 8) +#define CMC_SRS_WARM (1 << 4) +#define CMC_SRS_HVD (1 << 3) +#define CMC_SRS_LVD (1 << 2) +#define CMC_SRS_POR (1 << 1) +#define CMC_SRS_WUP (1 << 0) + +static char *get_reset_cause(char *ret) +{ + u32 cause1, cause = 0, srs = 0; + u32 *reg_ssrs = (u32 *) (SRC_BASE_ADDR + 0x28); + u32 *reg_srs = (u32 *) (SRC_BASE_ADDR + 0x20); + + if (!ret) + return "null"; + + srs = readl(reg_srs); + cause1 = readl(reg_ssrs); + writel(cause1, reg_ssrs); + + cause = cause1 & (CMC_SRS_POR | CMC_SRS_WUP | CMC_SRS_WARM); + + switch (cause) { + case CMC_SRS_POR: + sprintf(ret, "%s-%X", "POR", cause1); + break; + case CMC_SRS_WUP: + sprintf(ret, "%s-%X", "WUP", cause1); + break; + case CMC_SRS_WARM: + cause = cause1 & (CMC_SRS_WDG | CMC_SRS_SW | + CMC_SRS_JTAG_RST); + switch (cause) { + case CMC_SRS_WDG: + sprintf(ret, "%s-%X", "WARM-WDG", cause1); + break; + case CMC_SRS_SW: + sprintf(ret, "%s-%X", "WARM-SW", cause1); + break; + case CMC_SRS_JTAG_RST: + sprintf(ret, "%s-%X", "WARM-JTAG", cause1); + break; + default: + sprintf(ret, "%s-%X", "WARM-UNKN", cause1); + break; + } + break; + default: + sprintf(ret, "%s-%X", "UNKN", cause1); + break; + } + + debug("[%X] SRS[%X] %X - ", cause1, srs, srs^cause1); + return ret; +} + +#ifdef CONFIG_ENV_IS_IN_MMC +__weak int board_mmc_get_env_dev(int devno) +{ + return CONFIG_SYS_MMC_ENV_DEV; +} + +int mmc_get_env_dev(void) +{ + int devno = 0; + u32 bt1_cfg = 0; + + /* If not boot from sd/mmc, use default value */ + if (get_boot_mode() == LOW_POWER_BOOT) + return CONFIG_SYS_MMC_ENV_DEV; + + bt1_cfg = readl(CMC1_RBASE + 0x40); + devno = (bt1_cfg >> 9) & 0x7; + + return board_mmc_get_env_dev(devno); +} +#endif diff --git a/arch/arm/include/asm/arch-mx7ulp/sys_proto.h b/arch/arm/include/asm/arch-mx7ulp/sys_proto.h new file mode 100644 index 0000000..ec5c017 --- /dev/null +++ b/arch/arm/include/asm/arch-mx7ulp/sys_proto.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _SYS_PROTO_H_ +#define _SYS_PROTO_H_ + +#define BT0CFG_LPBOOT_MASK 0x1 +#define BT0CFG_DUALBOOT_MASK 0x2 + +enum bt_mode { + LOW_POWER_BOOT, /* LP_BT = 1 */ + DUAL_BOOT, /* LP_BT = 0, DUAL_BT = 1 */ + SINGLE_BOOT /* LP_BT = 0, DUAL_BT = 0 */ +}; + +u32 get_cpu_rev(void); + +int mmc_get_env_dev(void); +void board_late_mmc_env_init(void); + +#endif |