diff options
Diffstat (limited to 'arch/arm/cpu')
29 files changed, 1368 insertions, 33 deletions
diff --git a/arch/arm/cpu/arm720t/start.S b/arch/arm/cpu/arm720t/start.S index ec8e88d..0bb3441 100644 --- a/arch/arm/cpu/arm720t/start.S +++ b/arch/arm/cpu/arm720t/start.S @@ -9,7 +9,6 @@ #include <asm-offsets.h> #include <config.h> -#include <asm/hardware.h> /* ************************************************************************* diff --git a/arch/arm/cpu/arm946es/cpu.c b/arch/arm/cpu/arm946es/cpu.c index e20e5a8..5d864b9 100644 --- a/arch/arm/cpu/arm946es/cpu.c +++ b/arch/arm/cpu/arm946es/cpu.c @@ -53,7 +53,7 @@ static void cache_flush (void) asm ("mcr p15, 0, %0, c7, c6, 0": :"r" (i)); } -#ifndef CONFIG_INTEGRATOR +#ifndef CONFIG_ARCH_INTEGRATOR __attribute__((noreturn)) void reset_cpu(ulong addr __attribute__((unused))) { @@ -63,4 +63,4 @@ __attribute__((noreturn)) void reset_cpu(ulong addr __attribute__((unused))) ; } -#endif /* #ifdef CONFIG_INTEGRATOR */ +#endif /* #ifdef CONFIG_ARCH_INTEGRATOR */ diff --git a/arch/arm/cpu/armv7/ls102xa/clock.c b/arch/arm/cpu/armv7/ls102xa/clock.c index 8f80c61..7a337e1 100644 --- a/arch/arm/cpu/armv7/ls102xa/clock.c +++ b/arch/arm/cpu/armv7/ls102xa/clock.c @@ -20,7 +20,7 @@ void get_sys_info(struct sys_info *sys_info) { struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); #ifdef CONFIG_FSL_IFC - struct fsl_ifc *ifc_regs = (void *)CONFIG_SYS_IFC_ADDR; + struct fsl_ifc ifc_regs = {(void *)CONFIG_SYS_IFC_ADDR, (void *)NULL}; u32 ccr; #endif struct ccsr_clk *clk = (void *)(CONFIG_SYS_FSL_LS1_CLK_ADDR); @@ -74,7 +74,7 @@ void get_sys_info(struct sys_info *sys_info) } #if defined(CONFIG_FSL_IFC) - ccr = in_be32(&ifc_regs->ifc_ccr); + ccr = in_be32(&ifc_regs.gregs->ifc_ccr); ccr = ((ccr & IFC_CCR_CLK_DIV_MASK) >> IFC_CCR_CLK_DIV_SHIFT) + 1; sys_info->freq_localbus = sys_info->freq_systembus / ccr; diff --git a/arch/arm/cpu/armv7/omap-common/boot-common.c b/arch/arm/cpu/armv7/omap-common/boot-common.c index f2f6897..bbc6bed 100644 --- a/arch/arm/cpu/armv7/omap-common/boot-common.c +++ b/arch/arm/cpu/armv7/omap-common/boot-common.c @@ -162,3 +162,13 @@ void arch_preboot_os(void) ahci_reset((void __iomem *)DWC_AHSATA_BASE); } #endif + +#if defined(CONFIG_CMD_FASTBOOT) && !defined(CONFIG_ENV_IS_NOWHERE) +int fb_set_reboot_flag(void) +{ + printf("Setting reboot to fastboot flag ...\n"); + setenv("dofastboot", "1"); + saveenv(); + return 0; +} +#endif diff --git a/arch/arm/cpu/armv7/omap-common/utils.c b/arch/arm/cpu/armv7/omap-common/utils.c index 1696c2d..df5f817 100644 --- a/arch/arm/cpu/armv7/omap-common/utils.c +++ b/arch/arm/cpu/armv7/omap-common/utils.c @@ -60,3 +60,16 @@ void __weak usb_fake_mac_from_die_id(u32 *id) eth_setenv_enetaddr("usbethaddr", device_mac); } } + +void __weak usb_set_serial_num_from_die_id(u32 *id) +{ + char serialno[72]; + uint32_t serialno_lo, serialno_hi; + + if (!getenv("serial#")) { + serialno_hi = id[0]; + serialno_lo = id[1]; + sprintf(serialno, "%08x%08x", serialno_hi, serialno_lo); + setenv("serial#", serialno); + } +} diff --git a/arch/arm/cpu/armv7/omap5/prcm-regs.c b/arch/arm/cpu/armv7/omap5/prcm-regs.c index 440bb40..f80d36d 100644 --- a/arch/arm/cpu/armv7/omap5/prcm-regs.c +++ b/arch/arm/cpu/armv7/omap5/prcm-regs.c @@ -440,6 +440,10 @@ struct omap_sys_ctrl_regs const dra7xx_ctrl = { .control_emif1_sdram_config_ext = 0x4AE0C144, .control_emif2_sdram_config_ext = 0x4AE0C148, .control_wkup_ldovbb_mpu_voltage_ctrl = 0x4AE0C158, + .control_std_fuse_die_id_0 = 0x4AE0C200, + .control_std_fuse_die_id_1 = 0x4AE0C208, + .control_std_fuse_die_id_2 = 0x4AE0C20C, + .control_std_fuse_die_id_3 = 0x4AE0C210, .control_padconf_mode = 0x4AE0C5A0, .control_xtal_oscillator = 0x4AE0C5A4, .control_i2c_2 = 0x4AE0C5A8, diff --git a/arch/arm/cpu/armv7/vf610/generic.c b/arch/arm/cpu/armv7/vf610/generic.c index 92aaad9..1bb9b8e 100644 --- a/arch/arm/cpu/armv7/vf610/generic.c +++ b/arch/arm/cpu/armv7/vf610/generic.c @@ -18,6 +18,8 @@ DECLARE_GLOBAL_DATA_PTR; #endif +static char soc_type[] = "xx0"; + #ifdef CONFIG_MXC_OCOTP void enable_ocotp_clk(unsigned char enable) { @@ -284,14 +286,37 @@ static char *get_reset_cause(void) int print_cpuinfo(void) { - printf("CPU: Freescale Vybrid VF610 at %d MHz\n", - mxc_get_clock(MXC_ARM_CLK) / 1000000); + printf("CPU: Freescale Vybrid VF%s at %d MHz\n", + soc_type, mxc_get_clock(MXC_ARM_CLK) / 1000000); printf("Reset cause: %s\n", get_reset_cause()); return 0; } #endif +int arch_cpu_init(void) +{ + struct mscm *mscm = (struct mscm *)MSCM_BASE_ADDR; + + soc_type[0] = mscm->cpxcount ? '6' : '5'; /*Dual Core => VF6x0 */ + soc_type[1] = mscm->cpxcfg1 ? '1' : '0'; /* L2 Cache => VFx10 */ + + return 0; +} + +#ifdef CONFIG_ARCH_MISC_INIT +int arch_misc_init(void) +{ + char soc[6]; + + strcat(soc, "vf"); + strcat(soc, soc_type); + setenv("soc", soc); + + return 0; +} +#endif + int cpu_eth_init(bd_t *bis) { int rc = -ENODEV; @@ -317,3 +342,19 @@ int get_clocks(void) #endif 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 + dcache_enable(); + icache_enable(); + + /* Enable caching on OCRAM */ + mmu_set_region_dcache_behaviour(IRAM_BASE_ADDR, IRAM_SIZE, option); +} +#endif diff --git a/arch/arm/cpu/armv7m/Makefile b/arch/arm/cpu/armv7m/Makefile new file mode 100644 index 0000000..b662e03 --- /dev/null +++ b/arch/arm/cpu/armv7m/Makefile @@ -0,0 +1,11 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +extra-y := start.o +obj-y += cpu.o + +obj-$(CONFIG_STM32F4) += stm32f4/ diff --git a/arch/arm/cpu/armv7m/config.mk b/arch/arm/cpu/armv7m/config.mk new file mode 100644 index 0000000..0b31e44 --- /dev/null +++ b/arch/arm/cpu/armv7m/config.mk @@ -0,0 +1,8 @@ +# +# (C) Copyright 2015 +# Kamil Lulko, <rev13@wp.pl> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +PLATFORM_CPPFLAGS += -march=armv7-m -mthumb diff --git a/arch/arm/cpu/armv7m/cpu.c b/arch/arm/cpu/armv7m/cpu.c new file mode 100644 index 0000000..d3ab862 --- /dev/null +++ b/arch/arm/cpu/armv7m/cpu.c @@ -0,0 +1,35 @@ +/* + * (C) Copyright 2010,2011 + * Vladimir Khusainov, Emcraft Systems, vlad@emcraft.com + * + * (C) Copyright 2015 + * Kamil Lulko, <rev13@wp.pl> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/armv7m.h> + +/* + * This is called right before passing control to + * the Linux kernel point. + */ +int cleanup_before_linux(void) +{ + return 0; +} + +/* + * Perform the low-level reset. + */ +void reset_cpu(ulong addr) +{ + /* + * Perform reset but keep priority group unchanged. + */ + writel((V7M_AIRCR_VECTKEY << V7M_AIRCR_VECTKEY_SHIFT) + | (V7M_SCB->aircr & V7M_AIRCR_PRIGROUP_MSK) + | V7M_AIRCR_SYSRESET, &V7M_SCB->aircr); +} diff --git a/arch/arm/cpu/armv7m/start.S b/arch/arm/cpu/armv7m/start.S new file mode 100644 index 0000000..e05e984 --- /dev/null +++ b/arch/arm/cpu/armv7m/start.S @@ -0,0 +1,15 @@ +/* + * (C) Copyright 2015 + * Kamil Lulko, <rev13@wp.pl> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +.globl reset +.type reset, %function +reset: + b _main + +.globl c_runtime_cpu_setup +c_runtime_cpu_setup: + mov pc, lr diff --git a/arch/arm/cpu/armv7m/stm32f4/Makefile b/arch/arm/cpu/armv7m/stm32f4/Makefile new file mode 100644 index 0000000..e982830 --- /dev/null +++ b/arch/arm/cpu/armv7m/stm32f4/Makefile @@ -0,0 +1,11 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# (C) Copyright 2015 +# Kamil Lulko, <rev13@wp.pl> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y += soc.o clock.o timer.o flash.o diff --git a/arch/arm/cpu/armv7m/stm32f4/clock.c b/arch/arm/cpu/armv7m/stm32f4/clock.c new file mode 100644 index 0000000..2eded1f --- /dev/null +++ b/arch/arm/cpu/armv7m/stm32f4/clock.c @@ -0,0 +1,209 @@ +/* + * (C) Copyright 2015 + * Kamil Lulko, <rev13@wp.pl> + * + * (C) Copyright 2014 + * STMicroelectronics + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/stm32.h> + +#define RCC_CR_HSION (1 << 0) +#define RCC_CR_HSEON (1 << 16) +#define RCC_CR_HSERDY (1 << 17) +#define RCC_CR_HSEBYP (1 << 18) +#define RCC_CR_CSSON (1 << 19) +#define RCC_CR_PLLON (1 << 24) +#define RCC_CR_PLLRDY (1 << 25) + +#define RCC_PLLCFGR_PLLM_MASK 0x3F +#define RCC_PLLCFGR_PLLN_MASK 0x7FC0 +#define RCC_PLLCFGR_PLLP_MASK 0x30000 +#define RCC_PLLCFGR_PLLQ_MASK 0xF000000 +#define RCC_PLLCFGR_PLLSRC (1 << 22) +#define RCC_PLLCFGR_PLLN_SHIFT 6 +#define RCC_PLLCFGR_PLLP_SHIFT 16 +#define RCC_PLLCFGR_PLLQ_SHIFT 24 + +#define RCC_CFGR_AHB_PSC_MASK 0xF0 +#define RCC_CFGR_APB1_PSC_MASK 0x1C00 +#define RCC_CFGR_APB2_PSC_MASK 0xE000 +#define RCC_CFGR_SW0 (1 << 0) +#define RCC_CFGR_SW1 (1 << 1) +#define RCC_CFGR_SW_MASK 0x3 +#define RCC_CFGR_SW_HSI 0 +#define RCC_CFGR_SW_HSE RCC_CFGR_SW0 +#define RCC_CFGR_SW_PLL RCC_CFGR_SW1 +#define RCC_CFGR_SWS0 (1 << 2) +#define RCC_CFGR_SWS1 (1 << 3) +#define RCC_CFGR_SWS_MASK 0xC +#define RCC_CFGR_SWS_HSI 0 +#define RCC_CFGR_SWS_HSE RCC_CFGR_SWS0 +#define RCC_CFGR_SWS_PLL RCC_CFGR_SWS1 +#define RCC_CFGR_HPRE_SHIFT 4 +#define RCC_CFGR_PPRE1_SHIFT 10 +#define RCC_CFGR_PPRE2_SHIFT 13 + +#define RCC_APB1ENR_PWREN (1 << 28) + +#define PWR_CR_VOS0 (1 << 14) +#define PWR_CR_VOS1 (1 << 15) +#define PWR_CR_VOS_MASK 0xC000 +#define PWR_CR_VOS_SCALE_MODE_1 (PWR_CR_VOS0 | PWR_CR_VOS1) +#define PWR_CR_VOS_SCALE_MODE_2 (PWR_CR_VOS1) +#define PWR_CR_VOS_SCALE_MODE_3 (PWR_CR_VOS0) + +#define FLASH_ACR_WS(n) n +#define FLASH_ACR_PRFTEN (1 << 8) +#define FLASH_ACR_ICEN (1 << 9) +#define FLASH_ACR_DCEN (1 << 10) + +struct pll_psc { + u8 pll_m; + u16 pll_n; + u8 pll_p; + u8 pll_q; + u8 ahb_psc; + u8 apb1_psc; + u8 apb2_psc; +}; + +#define AHB_PSC_1 0 +#define AHB_PSC_2 0x8 +#define AHB_PSC_4 0x9 +#define AHB_PSC_8 0xA +#define AHB_PSC_16 0xB +#define AHB_PSC_64 0xC +#define AHB_PSC_128 0xD +#define AHB_PSC_256 0xE +#define AHB_PSC_512 0xF + +#define APB_PSC_1 0 +#define APB_PSC_2 0x4 +#define APB_PSC_4 0x5 +#define APB_PSC_8 0x6 +#define APB_PSC_16 0x7 + +#if !defined(CONFIG_STM32_HSE_HZ) +#error "CONFIG_STM32_HSE_HZ not defined!" +#else +#if (CONFIG_STM32_HSE_HZ == 8000000) +struct pll_psc pll_psc_168 = { + .pll_m = 8, + .pll_n = 336, + .pll_p = 2, + .pll_q = 7, + .ahb_psc = AHB_PSC_1, + .apb1_psc = APB_PSC_4, + .apb2_psc = APB_PSC_2 +}; +#else +#error "No PLL/Prescaler configuration for given CONFIG_STM32_HSE_HZ exists" +#endif +#endif + +int configure_clocks(void) +{ + /* Reset RCC configuration */ + setbits_le32(&STM32_RCC->cr, RCC_CR_HSION); + writel(0, &STM32_RCC->cfgr); /* Reset CFGR */ + clrbits_le32(&STM32_RCC->cr, (RCC_CR_HSEON | RCC_CR_CSSON + | RCC_CR_PLLON)); + writel(0x24003010, &STM32_RCC->pllcfgr); /* Reset value from RM */ + clrbits_le32(&STM32_RCC->cr, RCC_CR_HSEBYP); + writel(0, &STM32_RCC->cir); /* Disable all interrupts */ + + /* Configure for HSE+PLL operation */ + setbits_le32(&STM32_RCC->cr, RCC_CR_HSEON); + while (!(readl(&STM32_RCC->cr) & RCC_CR_HSERDY)) + ; + + /* Enable high performance mode, System frequency up to 168 MHz */ + setbits_le32(&STM32_RCC->apb1enr, RCC_APB1ENR_PWREN); + writel(PWR_CR_VOS_SCALE_MODE_1, &STM32_PWR->cr); + + setbits_le32(&STM32_RCC->cfgr, (( + pll_psc_168.ahb_psc << RCC_CFGR_HPRE_SHIFT) + | (pll_psc_168.apb1_psc << RCC_CFGR_PPRE1_SHIFT) + | (pll_psc_168.apb2_psc << RCC_CFGR_PPRE2_SHIFT))); + + writel(pll_psc_168.pll_m + | (pll_psc_168.pll_n << RCC_PLLCFGR_PLLN_SHIFT) + | (((pll_psc_168.pll_p >> 1) - 1) << RCC_PLLCFGR_PLLP_SHIFT) + | (pll_psc_168.pll_q << RCC_PLLCFGR_PLLQ_SHIFT), + &STM32_RCC->pllcfgr); + setbits_le32(&STM32_RCC->pllcfgr, RCC_PLLCFGR_PLLSRC); + + setbits_le32(&STM32_RCC->cr, RCC_CR_PLLON); + + while (!(readl(&STM32_RCC->cr) & RCC_CR_PLLRDY)) + ; + + /* 5 wait states, Prefetch enabled, D-Cache enabled, I-Cache enabled */ + writel(FLASH_ACR_WS(5) | FLASH_ACR_PRFTEN | FLASH_ACR_ICEN + | FLASH_ACR_DCEN, &STM32_FLASH->acr); + + clrbits_le32(&STM32_RCC->cfgr, (RCC_CFGR_SW0 | RCC_CFGR_SW1)); + setbits_le32(&STM32_RCC->cfgr, RCC_CFGR_SW_PLL); + + while ((readl(&STM32_RCC->cfgr) & RCC_CFGR_SWS_MASK) != + RCC_CFGR_SWS_PLL) + ; + + return 0; +} + +unsigned long clock_get(enum clock clck) +{ + u32 sysclk = 0; + u32 shift = 0; + /* Prescaler table lookups for clock computation */ + u8 ahb_psc_table[16] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9 + }; + u8 apb_psc_table[8] = { + 0, 0, 0, 0, 1, 2, 3, 4 + }; + + if ((readl(&STM32_RCC->cfgr) & RCC_CFGR_SWS_MASK) == + RCC_CFGR_SWS_PLL) { + u16 pllm, plln, pllp; + pllm = (readl(&STM32_RCC->pllcfgr) & RCC_PLLCFGR_PLLM_MASK); + plln = ((readl(&STM32_RCC->pllcfgr) & RCC_PLLCFGR_PLLN_MASK) + >> RCC_PLLCFGR_PLLN_SHIFT); + pllp = ((((readl(&STM32_RCC->pllcfgr) & RCC_PLLCFGR_PLLP_MASK) + >> RCC_PLLCFGR_PLLP_SHIFT) + 1) << 1); + sysclk = ((CONFIG_STM32_HSE_HZ / pllm) * plln) / pllp; + } + + switch (clck) { + case CLOCK_CORE: + return sysclk; + break; + case CLOCK_AHB: + shift = ahb_psc_table[( + (readl(&STM32_RCC->cfgr) & RCC_CFGR_AHB_PSC_MASK) + >> RCC_CFGR_HPRE_SHIFT)]; + return sysclk >>= shift; + break; + case CLOCK_APB1: + shift = apb_psc_table[( + (readl(&STM32_RCC->cfgr) & RCC_CFGR_APB1_PSC_MASK) + >> RCC_CFGR_PPRE1_SHIFT)]; + return sysclk >>= shift; + break; + case CLOCK_APB2: + shift = apb_psc_table[( + (readl(&STM32_RCC->cfgr) & RCC_CFGR_APB2_PSC_MASK) + >> RCC_CFGR_PPRE2_SHIFT)]; + return sysclk >>= shift; + break; + default: + return 0; + break; + } +} diff --git a/arch/arm/cpu/armv7m/stm32f4/flash.c b/arch/arm/cpu/armv7m/stm32f4/flash.c new file mode 100644 index 0000000..e5c6111 --- /dev/null +++ b/arch/arm/cpu/armv7m/stm32f4/flash.c @@ -0,0 +1,143 @@ +/* + * (C) Copyright 2015 + * Kamil Lulko, <rev13@wp.pl> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/stm32.h> + +#define STM32_FLASH_KEY1 0x45670123 +#define STM32_FLASH_KEY2 0xCDEF89AB + +flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; + +const u32 sect_sz_kb[CONFIG_SYS_MAX_FLASH_SECT] = { + [0 ... 3] = 16 * 1024, + [4] = 64 * 1024, + [5 ... 11] = 128 * 1024 +}; + +static void stm32f4_flash_lock(u8 lock) +{ + if (lock) { + setbits_le32(&STM32_FLASH->cr, STM32_FLASH_CR_LOCK); + } else { + writel(STM32_FLASH_KEY1, &STM32_FLASH->key); + writel(STM32_FLASH_KEY2, &STM32_FLASH->key); + } +} + +unsigned long flash_init(void) +{ + unsigned long total_size = 0; + u8 i, j; + + for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { + flash_info[i].flash_id = FLASH_STM32F4; + flash_info[i].sector_count = CONFIG_SYS_MAX_FLASH_SECT; + flash_info[i].start[0] = CONFIG_SYS_FLASH_BASE + (i << 20); + flash_info[i].size = sect_sz_kb[0]; + for (j = 1; j < CONFIG_SYS_MAX_FLASH_SECT; j++) { + flash_info[i].start[j] = flash_info[i].start[j - 1] + + (sect_sz_kb[j - 1]); + flash_info[i].size += sect_sz_kb[j]; + } + total_size += flash_info[i].size; + } + + return total_size; +} + +void flash_print_info(flash_info_t *info) +{ + int i; + + if (info->flash_id == FLASH_UNKNOWN) { + printf("missing or unknown FLASH type\n"); + return; + } else if (info->flash_id == FLASH_STM32F4) { + printf("STM32F4 Embedded Flash\n"); + } + + printf(" Size: %ld MB in %d Sectors\n", + info->size >> 20, info->sector_count); + + printf(" Sector Start Addresses:"); + for (i = 0; i < info->sector_count; ++i) { + if ((i % 5) == 0) + printf("\n "); + printf(" %08lX%s", + info->start[i], + info->protect[i] ? " (RO)" : " "); + } + printf("\n"); + return; +} + +int flash_erase(flash_info_t *info, int first, int last) +{ + u8 bank = 0xFF; + int i; + + for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { + if (info == &flash_info[i]) { + bank = i; + break; + } + } + if (bank == 0xFF) + return -1; + + stm32f4_flash_lock(0); + + for (i = first; i <= last; i++) { + while (readl(&STM32_FLASH->sr) & STM32_FLASH_SR_BSY) + ; + + if (bank == 0) { + setbits_le32(&STM32_FLASH->cr, + (i << STM32_FLASH_CR_SNB_OFFSET)); + } else if (bank == 1) { + setbits_le32(&STM32_FLASH->cr, + ((0x10 | i) << STM32_FLASH_CR_SNB_OFFSET)); + } else { + stm32f4_flash_lock(1); + return -1; + } + setbits_le32(&STM32_FLASH->cr, STM32_FLASH_CR_SER); + setbits_le32(&STM32_FLASH->cr, STM32_FLASH_CR_STRT); + + while (readl(&STM32_FLASH->sr) & STM32_FLASH_SR_BSY) + ; + + clrbits_le32(&STM32_FLASH->cr, STM32_FLASH_CR_SER); + stm32f4_flash_lock(1); + } + + return 0; +} + +int write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt) +{ + ulong i; + + while (readl(&STM32_FLASH->sr) & STM32_FLASH_SR_BSY) + ; + + stm32f4_flash_lock(0); + + setbits_le32(&STM32_FLASH->cr, STM32_FLASH_CR_PG); + /* To make things simple use byte writes only */ + for (i = 0; i < cnt; i++) { + *(uchar *)(addr + i) = src[i]; + while (readl(&STM32_FLASH->sr) & STM32_FLASH_SR_BSY) + ; + } + clrbits_le32(&STM32_FLASH->cr, STM32_FLASH_CR_PG); + stm32f4_flash_lock(1); + + return 0; +} diff --git a/arch/arm/cpu/armv7m/stm32f4/soc.c b/arch/arm/cpu/armv7m/stm32f4/soc.c new file mode 100644 index 0000000..202a126 --- /dev/null +++ b/arch/arm/cpu/armv7m/stm32f4/soc.c @@ -0,0 +1,37 @@ +/* + * (C) Copyright 2015 + * Kamil Lulko, <rev13@wp.pl> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/armv7m.h> +#include <asm/arch/stm32.h> + +u32 get_cpu_rev(void) +{ + return 0; +} + +int arch_cpu_init(void) +{ + configure_clocks(); + + /* + * Configure the memory protection unit (MPU) to allow full access to + * the whole 4GB address space. + */ + writel(0, &V7M_MPU->rnr); + writel(0, &V7M_MPU->rbar); + writel((V7M_MPU_RASR_AP_RW_RW | V7M_MPU_RASR_SIZE_4GB + | V7M_MPU_RASR_EN), &V7M_MPU->rasr); + writel(V7M_MPU_CTRL_ENABLE | V7M_MPU_CTRL_HFNMIENA, &V7M_MPU->ctrl); + + return 0; +} + +void s_init(void) +{ +} diff --git a/arch/arm/cpu/armv7m/stm32f4/timer.c b/arch/arm/cpu/armv7m/stm32f4/timer.c new file mode 100644 index 0000000..102ae6d --- /dev/null +++ b/arch/arm/cpu/armv7m/stm32f4/timer.c @@ -0,0 +1,118 @@ +/* + * (C) Copyright 2015 + * Kamil Lulko, <rev13@wp.pl> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/armv7m.h> +#include <asm/arch/stm32.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define STM32_TIM2_BASE (STM32_APB1PERIPH_BASE + 0x0000) + +#define RCC_APB1ENR_TIM2EN (1 << 0) + +struct stm32_tim2_5 { + u32 cr1; + u32 cr2; + u32 smcr; + u32 dier; + u32 sr; + u32 egr; + u32 ccmr1; + u32 ccmr2; + u32 ccer; + u32 cnt; + u32 psc; + u32 arr; + u32 reserved1; + u32 ccr1; + u32 ccr2; + u32 ccr3; + u32 ccr4; + u32 reserved2; + u32 dcr; + u32 dmar; + u32 or; +}; + +#define TIM_CR1_CEN (1 << 0) + +#define TIM_EGR_UG (1 << 0) + +int timer_init(void) +{ + struct stm32_tim2_5 *tim = (struct stm32_tim2_5 *)STM32_TIM2_BASE; + + setbits_le32(&STM32_RCC->apb1enr, RCC_APB1ENR_TIM2EN); + + if (clock_get(CLOCK_AHB) == clock_get(CLOCK_APB1)) + writel((clock_get(CLOCK_APB1) / CONFIG_SYS_HZ_CLOCK) - 1, + &tim->psc); + else + writel(((clock_get(CLOCK_APB1) * 2) / CONFIG_SYS_HZ_CLOCK) - 1, + &tim->psc); + + writel(0xFFFFFFFF, &tim->arr); + writel(TIM_CR1_CEN, &tim->cr1); + setbits_le32(&tim->egr, TIM_EGR_UG); + + gd->arch.tbl = 0; + gd->arch.tbu = 0; + gd->arch.lastinc = 0; + + return 0; +} + +ulong get_timer(ulong base) +{ + return (get_ticks() / (CONFIG_SYS_HZ_CLOCK / CONFIG_SYS_HZ)) - base; +} + +unsigned long long get_ticks(void) +{ + struct stm32_tim2_5 *tim = (struct stm32_tim2_5 *)STM32_TIM2_BASE; + u32 now; + + now = readl(&tim->cnt); + + if (now >= gd->arch.lastinc) + gd->arch.tbl += (now - gd->arch.lastinc); + else + gd->arch.tbl += (0xFFFFFFFF - gd->arch.lastinc) + now; + + gd->arch.lastinc = now; + + return gd->arch.tbl; +} + +void reset_timer(void) +{ + struct stm32_tim2_5 *tim = (struct stm32_tim2_5 *)STM32_TIM2_BASE; + + gd->arch.lastinc = readl(&tim->cnt); + gd->arch.tbl = 0; +} + +/* delay x useconds */ +void __udelay(ulong usec) +{ + unsigned long long start; + + start = get_ticks(); /* get current timestamp */ + while ((get_ticks() - start) < usec) + ; /* loop till time has passed */ +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk(void) +{ + return CONFIG_SYS_HZ_CLOCK; +} diff --git a/arch/arm/cpu/armv8/fsl-lsch3/Makefile b/arch/arm/cpu/armv8/fsl-lsch3/Makefile index f920eeb..9f7815b 100644 --- a/arch/arm/cpu/armv8/fsl-lsch3/Makefile +++ b/arch/arm/cpu/armv8/fsl-lsch3/Makefile @@ -6,6 +6,8 @@ obj-y += cpu.o obj-y += lowlevel.o +obj-y += soc.o obj-y += speed.o +obj-$(CONFIG_SYS_HAS_SERDES) += fsl_lsch3_serdes.o ls2085a_serdes.o obj-$(CONFIG_MP) += mp.o obj-$(CONFIG_OF_LIBFDT) += fdt.o diff --git a/arch/arm/cpu/armv8/fsl-lsch3/README b/arch/arm/cpu/armv8/fsl-lsch3/README index cc47466..37f07fb 100644 --- a/arch/arm/cpu/armv8/fsl-lsch3/README +++ b/arch/arm/cpu/armv8/fsl-lsch3/README @@ -8,3 +8,141 @@ Freescale LayerScape with Chassis Generation 3 This architecture supports Freescale ARMv8 SoCs with Chassis generation 3, for example LS2085A. + +Flash Layout +============ + +(1) A typical layout of various images (including Linux and other firmware images) + is shown below considering a 32MB NOR flash device present on most + pre-silicon platforms (simulator and emulator): + + ------------------------- + | FIT Image | + | (linux + DTB + RFS) | + ------------------------- ----> 0x0120_0000 + | Debug Server FW | + ------------------------- ----> 0x00C0_0000 + | AIOP FW | + ------------------------- ----> 0x0070_0000 + | MC FW | + ------------------------- ----> 0x006C_0000 + | MC DPL Blob | + ------------------------- ----> 0x0020_0000 + | BootLoader + Env| + ------------------------- ----> 0x0000_1000 + | PBI | + ------------------------- ----> 0x0000_0080 + | RCW | + ------------------------- ----> 0x0000_0000 + + 32-MB NOR flash layout for pre-silicon platforms (simulator and emulator) + +(2) A typical layout of various images (including Linux and other firmware images) + is shown below considering a 128MB NOR flash device present on QDS and RDB + boards: + ----------------------------------------- ----> 0x5_8800_0000 --- + | .. Unused .. (7M) | | + ----------------------------------------- ----> 0x5_8790_0000 | + | FIT Image (linux + DTB + RFS) (40M) | | + ----------------------------------------- ----> 0x5_8510_0000 | + | PHY firmware (2M) | | + ----------------------------------------- ----> 0x5_84F0_0000 | 64K + | Debug Server FW (2M) | | Alt + ----------------------------------------- ----> 0x5_84D0_0000 | Bank + | AIOP FW (4M) | | + ----------------------------------------- ----> 0x5_8490_0000 (vbank4) + | MC DPC Blob (1M) | | + ----------------------------------------- ----> 0x5_8480_0000 | + | MC DPL Blob (1M) | | + ----------------------------------------- ----> 0x5_8470_0000 | + | MC FW (4M) | | + ----------------------------------------- ----> 0x5_8430_0000 | + | BootLoader Environment (1M) | | + ----------------------------------------- ----> 0x5_8420_0000 | + | BootLoader (1M) | | + ----------------------------------------- ----> 0x5_8410_0000 | + | RCW and PBI (1M) | | + ----------------------------------------- ----> 0x5_8400_0000 --- + | .. Unused .. (7M) | | + ----------------------------------------- ----> 0x5_8390_0000 | + | FIT Image (linux + DTB + RFS) (40M) | | + ----------------------------------------- ----> 0x5_8110_0000 | + | PHY firmware (2M) | | + ----------------------------------------- ----> 0x5_80F0_0000 | 64K + | Debug Server FW (2M) | | Bank + ----------------------------------------- ----> 0x5_80D0_0000 | + | AIOP FW (4M) | | + ----------------------------------------- ----> 0x5_8090_0000 (vbank0) + | MC DPC Blob (1M) | | + ----------------------------------------- ----> 0x5_8080_0000 | + | MC DPL Blob (1M) | | + ----------------------------------------- ----> 0x5_8070_0000 | + | MC FW (4M) | | + ----------------------------------------- ----> 0x5_8030_0000 | + | BootLoader Environment (1M) | | + ----------------------------------------- ----> 0x5_8020_0000 | + | BootLoader (1M) | | + ----------------------------------------- ----> 0x5_8010_0000 | + | RCW and PBI (1M) | | + ----------------------------------------- ----> 0x5_8000_0000 --- + + 128-MB NOR flash layout for QDS and RDB boards + +Environment Variables +===================== +mcboottimeout: MC boot timeout in milliseconds. If this variable is not defined + the value CONFIG_SYS_LS_MC_BOOT_TIMEOUT_MS will be assumed. + +mcmemsize: MC DRAM block size. If this variable is not defined, the value + CONFIG_SYS_LS_MC_DRAM_BLOCK_MIN_SIZE will be assumed. + +Booting from NAND +------------------- +Booting from NAND requires two images, RCW and u-boot-with-spl.bin. +The difference between NAND boot RCW image and NOR boot image is the PBI +command sequence. Below is one example for PBI commands for QDS which uses +NAND device with 2KB/page, block size 128KB. + +1) CCSR 4-byte write to 0x00e00404, data=0x00000000 +2) CCSR 4-byte write to 0x00e00400, data=0x1800a000 +The above two commands set bootloc register to 0x00000000_1800a000 where +the u-boot code will be running in OCRAM. + +3) Block Copy: SRC=0x0107, SRC_ADDR=0x00020000, DEST_ADDR=0x1800a000, +BLOCK_SIZE=0x00014000 +This command copies u-boot image from NAND device into OCRAM. The values need +to adjust accordingly. + +SRC should match the cfg_rcw_src, the reset config pins. It depends + on the NAND device. See reference manual for cfg_rcw_src. +SRC_ADDR is the offset of u-boot-with-spl.bin image in NAND device. In + the example above, 128KB. For easy maintenance, we put it at + the beginning of next block from RCW. +DEST_ADDR is fixed at 0x1800a000, matching bootloc set above. +BLOCK_SIZE is the size to be copied by PBI. + +RCW image should be written to the beginning of NAND device. Example of using +u-boot command + +nand write <rcw image in memory> 0 <size of rcw image> + +To form the NAND image, build u-boot with NAND config, for example, +ls2085aqds_nand_defconfig. The image needed is u-boot-with-spl.bin. +The u-boot image should be written to match SRC_ADDR, in above example 0x20000. + +nand write <u-boot image in memory> 200000 <size of u-boot image> + +With these two images in NAND device, the board can boot from NAND. + +Another example for RDB boards, + +1) CCSR 4-byte write to 0x00e00404, data=0x00000000 +2) CCSR 4-byte write to 0x00e00400, data=0x1800a000 +3) Block Copy: SRC=0x0119, SRC_ADDR=0x00080000, DEST_ADDR=0x1800a000, +BLOCK_SIZE=0x00014000 + +nand write <rcw image in memory> 0 <size of rcw image> +nand write <u-boot image in memory> 80000 <size of u-boot image> + +Notice the difference from QDS is SRC, SRC_ADDR and the offset of u-boot image +to match board NAND device with 4KB/page, block size 512KB. diff --git a/arch/arm/cpu/armv8/fsl-lsch3/cpu.c b/arch/arm/cpu/armv8/fsl-lsch3/cpu.c index 4997487..6714577 100644 --- a/arch/arm/cpu/armv8/fsl-lsch3/cpu.c +++ b/arch/arm/cpu/armv8/fsl-lsch3/cpu.c @@ -10,7 +10,12 @@ #include <asm/armv8/mmu.h> #include <asm/io.h> #include <asm/arch-fsl-lsch3/immap_lsch3.h> +#include <fsl_debug_server.h> #include <fsl-mc/fsl_mc.h> +#include <asm/arch/fsl_serdes.h> +#ifdef CONFIG_FSL_ESDHC +#include <fsl_esdhc.h> +#endif #include "cpu.h" #include "mp.h" #include "speed.h" @@ -24,8 +29,9 @@ DECLARE_GLOBAL_DATA_PTR; * levels of translation tables here to cover 40-bit address space. * We use 4KB granule size, with 40 bits physical address, T0SZ=24 * Level 0 IA[39], table address @0 - * Level 1 IA[31:30], table address @01000, 0x2000 - * Level 2 IA[29:21], table address @0x3000 + * Level 1 IA[31:30], table address @0x1000, 0x2000 + * Level 2 IA[29:21], table address @0x3000, 0x4000 + * Address above 0x5000 is free for other purpose. */ #define SECTION_SHIFT_L0 39UL @@ -60,12 +66,12 @@ static inline void early_mmu_setup(void) { int el; u64 i; - u64 section_l1t0, section_l1t1, section_l2; + u64 section_l1t0, section_l1t1, section_l2t0, section_l2t1; u64 *level0_table = (u64 *)CONFIG_SYS_FSL_OCRAM_BASE; u64 *level1_table_0 = (u64 *)(CONFIG_SYS_FSL_OCRAM_BASE + 0x1000); u64 *level1_table_1 = (u64 *)(CONFIG_SYS_FSL_OCRAM_BASE + 0x2000); - u64 *level2_table = (u64 *)(CONFIG_SYS_FSL_OCRAM_BASE + 0x3000); - + u64 *level2_table_0 = (u64 *)(CONFIG_SYS_FSL_OCRAM_BASE + 0x3000); + u64 *level2_table_1 = (u64 *)(CONFIG_SYS_FSL_OCRAM_BASE + 0x4000); level0_table[0] = (u64)level1_table_0 | PMD_TYPE_TABLE; @@ -79,21 +85,25 @@ static inline void early_mmu_setup(void) */ section_l1t0 = 0; section_l1t1 = BLOCK_SIZE_L0; - section_l2 = 0; + section_l2t0 = 0; + section_l2t1 = CONFIG_SYS_FLASH_BASE; for (i = 0; i < 512; i++) { set_pgtable_section(level1_table_0, i, section_l1t0, MT_DEVICE_NGNRNE); set_pgtable_section(level1_table_1, i, section_l1t1, MT_NORMAL); - set_pgtable_section(level2_table, i, section_l2, + set_pgtable_section(level2_table_0, i, section_l2t0, + MT_DEVICE_NGNRNE); + set_pgtable_section(level2_table_1, i, section_l2t1, MT_DEVICE_NGNRNE); section_l1t0 += BLOCK_SIZE_L1; section_l1t1 += BLOCK_SIZE_L1; - section_l2 += BLOCK_SIZE_L2; + section_l2t0 += BLOCK_SIZE_L2; + section_l2t1 += BLOCK_SIZE_L2; } level1_table_0[0] = - (u64)level2_table | PMD_TYPE_TABLE; + (u64)level2_table_0 | PMD_TYPE_TABLE; level1_table_0[1] = 0x40000000 | PMD_SECT_AF | PMD_TYPE_SECT | PMD_ATTRINDX(MT_DEVICE_NGNRNE); @@ -104,17 +114,34 @@ static inline void early_mmu_setup(void) 0xc0000000 | PMD_SECT_AF | PMD_TYPE_SECT | PMD_ATTRINDX(MT_NORMAL); - /* Rewrite table to enable cache */ - set_pgtable_section(level2_table, + /* Rewerite table to enable cache for OCRAM */ + set_pgtable_section(level2_table_0, CONFIG_SYS_FSL_OCRAM_BASE >> SECTION_SHIFT_L2, CONFIG_SYS_FSL_OCRAM_BASE, MT_NORMAL); - for (i = CONFIG_SYS_IFC_BASE >> SECTION_SHIFT_L2; - i < (CONFIG_SYS_IFC_BASE + CONFIG_SYS_IFC_SIZE) - >> SECTION_SHIFT_L2; i++) { - section_l2 = i << SECTION_SHIFT_L2; - set_pgtable_section(level2_table, i, - section_l2, MT_NORMAL); + +#if defined(CONFIG_SYS_NOR0_CSPR_EARLY) && defined(CONFIG_SYS_NOR_AMASK_EARLY) + /* Rewrite table to enable cache for two entries (4MB) */ + section_l2t1 = CONFIG_SYS_IFC_BASE; + set_pgtable_section(level2_table_0, + section_l2t1 >> SECTION_SHIFT_L2, + section_l2t1, + MT_NORMAL); + section_l2t1 += BLOCK_SIZE_L2; + set_pgtable_section(level2_table_0, + section_l2t1 >> SECTION_SHIFT_L2, + section_l2t1, + MT_NORMAL); +#endif + + /* Create a mapping for 256MB IFC region to final flash location */ + level1_table_0[CONFIG_SYS_FLASH_BASE >> SECTION_SHIFT_L1] = + (u64)level2_table_1 | PMD_TYPE_TABLE; + section_l2t1 = CONFIG_SYS_IFC_BASE; + for (i = 0; i < 0x10000000 >> SECTION_SHIFT_L2; i++) { + set_pgtable_section(level2_table_1, i, + section_l2t1, MT_DEVICE_NGNRNE); + section_l2t1 += BLOCK_SIZE_L2; } el = current_el(); @@ -347,6 +374,7 @@ u32 fsl_qoriq_core_to_type(unsigned int core) #ifdef CONFIG_DISPLAY_CPUINFO int print_cpuinfo(void) { + struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); struct sys_info sysinfo; char buf[32]; unsigned int i, core; @@ -370,21 +398,40 @@ int print_cpuinfo(void) printf(" DP-DDR: %-4s MHz", strmhz(buf, sysinfo.freq_ddrbus2)); puts("\n"); + /* Display the RCW, so that no one gets confused as to what RCW + * we're actually using for this boot. + */ + puts("Reset Configuration Word (RCW):"); + for (i = 0; i < ARRAY_SIZE(gur->rcwsr); i++) { + u32 rcw = in_le32(&gur->rcwsr[i]); + + if ((i % 4) == 0) + printf("\n %02x:", i * 4); + printf(" %08x", rcw); + } + puts("\n"); + return 0; } #endif +#ifdef CONFIG_FSL_ESDHC +int cpu_mmc_init(bd_t *bis) +{ + return fsl_esdhc_mmc_init(bis); +} +#endif + int cpu_eth_init(bd_t *bis) { int error = 0; #ifdef CONFIG_FSL_MC_ENET - error = mc_init(bis); + error = fsl_mc_ldpaa_init(bis); #endif return error; } - int arch_early_init_r(void) { int rv; @@ -393,5 +440,43 @@ int arch_early_init_r(void) if (rv) printf("Did not wake secondary cores\n"); +#ifdef CONFIG_SYS_HAS_SERDES + fsl_serdes_init(); +#endif + return 0; +} + +int timer_init(void) +{ + u32 __iomem *cntcr = (u32 *)CONFIG_SYS_FSL_TIMER_ADDR; + u32 __iomem *cltbenr = (u32 *)CONFIG_SYS_FSL_PMU_CLTBENR; +#ifdef COUNTER_FREQUENCY_REAL + unsigned long cntfrq = COUNTER_FREQUENCY_REAL; + + /* Update with accurate clock frequency */ + asm volatile("msr cntfrq_el0, %0" : : "r" (cntfrq) : "memory"); +#endif + + /* Enable timebase for all clusters. + * It is safe to do so even some clusters are not enabled. + */ + out_le32(cltbenr, 0xf); + + /* Enable clock for timer + * This is a global setting. + */ + out_le32(cntcr, 0x1); + return 0; } + +void reset_cpu(ulong addr) +{ + u32 __iomem *rstcr = (u32 *)CONFIG_SYS_FSL_RST_ADDR; + u32 val; + + /* Raise RESET_REQ_B */ + val = in_le32(rstcr); + val |= 0x02; + out_le32(rstcr, val); +} diff --git a/arch/arm/cpu/armv8/fsl-lsch3/fdt.c b/arch/arm/cpu/armv8/fsl-lsch3/fdt.c index 7eb9b6a..d370023 100644 --- a/arch/arm/cpu/armv8/fsl-lsch3/fdt.c +++ b/arch/arm/cpu/armv8/fsl-lsch3/fdt.c @@ -7,6 +7,9 @@ #include <common.h> #include <libfdt.h> #include <fdt_support.h> +#ifdef CONFIG_FSL_ESDHC +#include <fsl_esdhc.h> +#endif #include "mp.h" #ifdef CONFIG_MP @@ -62,7 +65,11 @@ void ft_cpu_setup(void *blob, bd_t *bd) #endif #ifdef CONFIG_SYS_NS16550 - do_fixup_by_compat_u32(blob, "ns16550", + do_fixup_by_compat_u32(blob, "fsl,ns16550", "clock-frequency", CONFIG_SYS_NS16550_CLK, 1); #endif + +#if defined(CONFIG_FSL_ESDHC) + fdt_fixup_esdhc(blob, bd); +#endif } diff --git a/arch/arm/cpu/armv8/fsl-lsch3/fsl_lsch3_serdes.c b/arch/arm/cpu/armv8/fsl-lsch3/fsl_lsch3_serdes.c new file mode 100644 index 0000000..02ca126 --- /dev/null +++ b/arch/arm/cpu/armv8/fsl-lsch3/fsl_lsch3_serdes.c @@ -0,0 +1,115 @@ +/* + * Copyright 2015 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/errno.h> +#include <asm/arch/fsl_serdes.h> +#include <asm/arch-fsl-lsch3/immap_lsch3.h> +#include <fsl-mc/ldpaa_wriop.h> + +#ifdef CONFIG_SYS_FSL_SRDS_1 +static u8 serdes1_prtcl_map[SERDES_PRCTL_COUNT]; +#endif +#ifdef CONFIG_SYS_FSL_SRDS_2 +static u8 serdes2_prtcl_map[SERDES_PRCTL_COUNT]; +#endif + +int is_serdes_configured(enum srds_prtcl device) +{ + int ret = 0; + +#ifdef CONFIG_SYS_FSL_SRDS_1 + ret |= serdes1_prtcl_map[device]; +#endif +#ifdef CONFIG_SYS_FSL_SRDS_2 + ret |= serdes2_prtcl_map[device]; +#endif + + return !!ret; +} + +int serdes_get_first_lane(u32 sd, enum srds_prtcl device) +{ + struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); + u32 cfg = in_le32(&gur->rcwsr[28]); + int i; + + switch (sd) { +#ifdef CONFIG_SYS_FSL_SRDS_1 + case FSL_SRDS_1: + cfg &= FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_MASK; + cfg >>= FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_SHIFT; + break; +#endif +#ifdef CONFIG_SYS_FSL_SRDS_2 + case FSL_SRDS_2: + cfg &= FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_MASK; + cfg >>= FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_SHIFT; + break; +#endif + default: + printf("invalid SerDes%d\n", sd); + break; + } + /* Is serdes enabled at all? */ + if (cfg == 0) + return -ENODEV; + + for (i = 0; i < SRDS_MAX_LANES; i++) { + if (serdes_get_prtcl(sd, cfg, i) == device) + return i; + } + + return -ENODEV; +} + +void serdes_init(u32 sd, u32 sd_addr, u32 sd_prctl_mask, u32 sd_prctl_shift, + u8 serdes_prtcl_map[SERDES_PRCTL_COUNT]) +{ + struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); + u32 cfg; + int lane; + + memset(serdes_prtcl_map, 0, sizeof(serdes_prtcl_map)); + + cfg = in_le32(&gur->rcwsr[28]) & sd_prctl_mask; + cfg >>= sd_prctl_shift; + printf("Using SERDES%d Protocol: %d (0x%x)\n", sd + 1, cfg, cfg); + + if (!is_serdes_prtcl_valid(sd, cfg)) + printf("SERDES%d[PRTCL] = 0x%x is not valid\n", sd + 1, cfg); + + for (lane = 0; lane < SRDS_MAX_LANES; lane++) { + enum srds_prtcl lane_prtcl = serdes_get_prtcl(sd, cfg, lane); + if (unlikely(lane_prtcl >= SERDES_PRCTL_COUNT)) + debug("Unknown SerDes lane protocol %d\n", lane_prtcl); + else { + serdes_prtcl_map[lane_prtcl] = 1; +#ifdef CONFIG_FSL_MC_ENET + wriop_init_dpmac(sd, lane + 1, (int)lane_prtcl); +#endif + } + } +} + +void fsl_serdes_init(void) +{ +#ifdef CONFIG_SYS_FSL_SRDS_1 + serdes_init(FSL_SRDS_1, + CONFIG_SYS_FSL_LSCH3_SERDES_ADDR, + FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_MASK, + FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_SHIFT, + serdes1_prtcl_map); +#endif +#ifdef CONFIG_SYS_FSL_SRDS_2 + serdes_init(FSL_SRDS_2, + CONFIG_SYS_FSL_LSCH3_SERDES_ADDR + FSL_SRDS_2 * 0x10000, + FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_MASK, + FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_SHIFT, + serdes2_prtcl_map); +#endif +} diff --git a/arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S b/arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S index 886576e..018c617 100644 --- a/arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S +++ b/arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S @@ -15,6 +15,15 @@ ENTRY(lowlevel_init) mov x29, lr /* Save LR */ + /* Add fully-coherent masters to DVM domain */ + ldr x1, =CCI_MN_BASE + ldr x2, [x1, #CCI_MN_RNF_NODEID_LIST] + str x2, [x1, #CCI_MN_DVM_DOMAIN_CTL_SET] +1: ldr x3, [x1, #CCI_MN_DVM_DOMAIN_CTL_SET] + mvn x0, x3 + tst x0, x3 /* Wait for domain addition to complete */ + b.ne 1b + /* Set the SMMU page size in the sACR register */ ldr x1, =SMMU_BASE ldr w0, [x1, #0x10] @@ -224,6 +233,9 @@ ENTRY(secondary_boot_func) /* physical address of this cpus spin table element */ add x11, x1, x0 + ldr x0, =__real_cntfrq + ldr x0, [x0] + msr cntfrq_el0, x0 /* set with real frequency */ str x9, [x11, #16] /* LPID */ mov x4, #1 str x4, [x11, #8] /* STATUS */ @@ -275,6 +287,9 @@ ENDPROC(secondary_switch_to_el1) /* 64 bit alignment for elements accessed as data */ .align 4 + .global __real_cntfrq +__real_cntfrq: + .quad COUNTER_FREQUENCY .globl __secondary_boot_code_size .type __secondary_boot_code_size, %object /* Secondary Boot Code ends here */ diff --git a/arch/arm/cpu/armv8/fsl-lsch3/ls2085a_serdes.c b/arch/arm/cpu/armv8/fsl-lsch3/ls2085a_serdes.c new file mode 100644 index 0000000..098745b --- /dev/null +++ b/arch/arm/cpu/armv8/fsl-lsch3/ls2085a_serdes.c @@ -0,0 +1,117 @@ +/* + * Copyright 2015 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/fsl_serdes.h> +#include <asm/arch-fsl-lsch3/immap_lsch3.h> + +struct serdes_config { + u8 protocol; + u8 lanes[SRDS_MAX_LANES]; +}; + +static struct serdes_config serdes1_cfg_tbl[] = { + /* SerDes 1 */ + {0x03, {PCIE1, PCIE1, PCIE1, PCIE1, PCIE2, PCIE2, PCIE2, PCIE2 } }, + {0x05, {PCIE2, PCIE2, PCIE2, PCIE2, SGMII4, SGMII3, SGMII2, SGMII1 } }, + {0x07, {SGMII8, SGMII7, SGMII6, SGMII5, SGMII4, SGMII3, SGMII2, + SGMII1 } }, + {0x09, {SGMII8, SGMII7, SGMII6, SGMII5, SGMII4, SGMII3, SGMII2, + SGMII1 } }, + {0x0A, {SGMII8, SGMII7, SGMII6, SGMII5, SGMII4, SGMII3, SGMII2, + SGMII1 } }, + {0x0C, {SGMII8, SGMII7, SGMII6, SGMII5, SGMII4, SGMII3, SGMII2, + SGMII1 } }, + {0x0E, {SGMII8, SGMII7, SGMII6, SGMII5, SGMII4, SGMII3, SGMII2, + SGMII1 } }, + {0x26, {SGMII8, SGMII7, SGMII6, SGMII5, SGMII4, SGMII3, XFI2, XFI1 } }, + {0x28, {SGMII8, SGMII7, SGMII6, SGMII5, XFI4, XFI3, XFI2, XFI1 } }, + {0x2A, {XFI8, XFI7, XFI6, XFI5, XFI4, XFI3, XFI2, XFI1 } }, + {0x2B, {SGMII8, SGMII7, SGMII6, SGMII5, XAUI1, XAUI1, XAUI1, XAUI1 } }, + {0x32, {XAUI2, XAUI2, XAUI2, XAUI2, XAUI1, XAUI1, XAUI1, XAUI1 } }, + {0x33, {PCIE2, PCIE2, PCIE2, PCIE2, QSGMII_D, QSGMII_C, QSGMII_B, + QSGMII_A} }, + {0x35, {QSGMII_D, QSGMII_C, QSGMII_B, PCIE2, XFI4, XFI3, XFI2, XFI1 } }, + {} +}; +static struct serdes_config serdes2_cfg_tbl[] = { + /* SerDes 2 */ + {0x07, {SGMII9, SGMII10, SGMII11, SGMII12, SGMII13, SGMII14, SGMII15, + SGMII16 } }, + {0x09, {SGMII9, SGMII10, SGMII11, SGMII12, SGMII13, SGMII14, SGMII15, + SGMII16 } }, + {0x0A, {SGMII9, SGMII10, SGMII11, SGMII12, SGMII13, SGMII14, SGMII15, + SGMII16 } }, + {0x0C, {SGMII9, SGMII10, SGMII11, SGMII12, SGMII13, SGMII14, SGMII15, + SGMII16 } }, + {0x0E, {SGMII9, SGMII10, SGMII11, SGMII12, SGMII13, SGMII14, SGMII15, + SGMII16 } }, + {0x3D, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE3, PCIE3, PCIE3, PCIE3 } }, + {0x3E, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE3, PCIE3, PCIE3, PCIE3 } }, + {0x3F, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE4, PCIE4, PCIE4, PCIE4 } }, + {0x40, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE4, PCIE4, PCIE4, PCIE4 } }, + {0x41, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE4, PCIE4, SATA1, SATA2 } }, + {0x42, {PCIE3, PCIE3, PCIE3, PCIE3, PCIE4, PCIE4, SATA1, SATA2 } }, + {0x43, {PCIE3, PCIE3, PCIE3, PCIE3, NONE, NONE, SATA1, SATA2 } }, + {0x44, {PCIE3, PCIE3, PCIE3, PCIE3, NONE, NONE, SATA1, SATA2 } }, + {0x45, {PCIE3, SGMII10, SGMII11, SGMII12, PCIE4, SGMII14, SGMII15, + SGMII16 } }, + {0x47, {SGMII9, SGMII10, SGMII11, SGMII12, PCIE4, PCIE4, PCIE4, + PCIE4 } }, + {0x49, {SGMII9, SGMII10, SGMII11, SGMII12, PCIE4, PCIE4, SATA1, + SATA2 } }, + {0x4A, {SGMII9, SGMII10, SGMII11, SGMII12, PCIE4, PCIE4, SATA1, + SATA2 } }, + {} +}; + +static struct serdes_config *serdes_cfg_tbl[] = { + serdes1_cfg_tbl, + serdes2_cfg_tbl, +}; + +enum srds_prtcl serdes_get_prtcl(int serdes, int cfg, int lane) +{ + struct serdes_config *ptr; + + if (serdes >= ARRAY_SIZE(serdes_cfg_tbl)) + return 0; + + ptr = serdes_cfg_tbl[serdes]; + while (ptr->protocol) { + if (ptr->protocol == cfg) + return ptr->lanes[lane]; + ptr++; + } + + return 0; +} + +int is_serdes_prtcl_valid(int serdes, u32 prtcl) +{ + int i; + struct serdes_config *ptr; + + if (serdes >= ARRAY_SIZE(serdes_cfg_tbl)) + return 0; + + ptr = serdes_cfg_tbl[serdes]; + while (ptr->protocol) { + if (ptr->protocol == prtcl) + break; + ptr++; + } + + if (!ptr->protocol) + return 0; + + for (i = 0; i < SRDS_MAX_LANES; i++) { + if (ptr->lanes[i] != NONE) + return 1; + } + + return 0; +} diff --git a/arch/arm/cpu/armv8/fsl-lsch3/mp.c b/arch/arm/cpu/armv8/fsl-lsch3/mp.c index ce9c0c1..da7853a 100644 --- a/arch/arm/cpu/armv8/fsl-lsch3/mp.c +++ b/arch/arm/cpu/armv8/fsl-lsch3/mp.c @@ -31,6 +31,13 @@ int fsl_lsch3_wake_seconday_cores(void) int i, timeout = 10; u64 *table = get_spin_tbl_addr(); +#ifdef COUNTER_FREQUENCY_REAL + /* update for secondary cores */ + __real_cntfrq = COUNTER_FREQUENCY_REAL; + flush_dcache_range((unsigned long)&__real_cntfrq, + (unsigned long)&__real_cntfrq + 8); +#endif + cores = cpu_mask(); /* Clear spin table so that secondary processors * observe the correct value after waking up from wfe. diff --git a/arch/arm/cpu/armv8/fsl-lsch3/mp.h b/arch/arm/cpu/armv8/fsl-lsch3/mp.h index 66144d6..c985d6a 100644 --- a/arch/arm/cpu/armv8/fsl-lsch3/mp.h +++ b/arch/arm/cpu/armv8/fsl-lsch3/mp.h @@ -26,6 +26,7 @@ #define id_to_core(x) ((x & 3) | (x >> 6)) #ifndef __ASSEMBLY__ extern u64 __spin_table[]; +extern u64 __real_cntfrq; extern u64 *secondary_boot_code; extern size_t __secondary_boot_code_size; int fsl_lsch3_wake_seconday_cores(void); diff --git a/arch/arm/cpu/armv8/fsl-lsch3/soc.c b/arch/arm/cpu/armv8/fsl-lsch3/soc.c new file mode 100644 index 0000000..2538001 --- /dev/null +++ b/arch/arm/cpu/armv8/fsl-lsch3/soc.c @@ -0,0 +1,107 @@ +/* + * Copyright 2015 Freescale Semiconductor + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <fsl_ifc.h> +#include <nand.h> +#include <spl.h> +#include <asm/arch-fsl-lsch3/soc.h> +#include <asm/io.h> +#include <asm/global_data.h> + +DECLARE_GLOBAL_DATA_PTR; + +static void erratum_a008751(void) +{ +#ifdef CONFIG_SYS_FSL_ERRATUM_A008751 + u32 __iomem *scfg = (u32 __iomem *)SCFG_BASE; + + writel(0x27672b2a, scfg + SCFG_USB3PRM1CR / 4); +#endif +} + +static void erratum_rcw_src(void) +{ +#if defined(CONFIG_SPL) + u32 __iomem *dcfg_ccsr = (u32 __iomem *)DCFG_BASE; + u32 __iomem *dcfg_dcsr = (u32 __iomem *)DCFG_DCSR_BASE; + u32 val; + + val = in_le32(dcfg_ccsr + DCFG_PORSR1 / 4); + val &= ~DCFG_PORSR1_RCW_SRC; + val |= DCFG_PORSR1_RCW_SRC_NOR; + out_le32(dcfg_dcsr + DCFG_DCSR_PORCR1 / 4, val); +#endif +} + +#define I2C_DEBUG_REG 0x6 +#define I2C_GLITCH_EN 0x8 +/* + * This erratum requires setting glitch_en bit to enable + * digital glitch filter to improve clock stability. + */ +static void erratum_a009203(void) +{ + u8 __iomem *ptr; +#ifdef CONFIG_SYS_I2C +#ifdef I2C1_BASE_ADDR + ptr = (u8 __iomem *)(I2C1_BASE_ADDR + I2C_DEBUG_REG); + + writeb(I2C_GLITCH_EN, ptr); +#endif +#ifdef I2C2_BASE_ADDR + ptr = (u8 __iomem *)(I2C2_BASE_ADDR + I2C_DEBUG_REG); + + writeb(I2C_GLITCH_EN, ptr); +#endif +#ifdef I2C3_BASE_ADDR + ptr = (u8 __iomem *)(I2C3_BASE_ADDR + I2C_DEBUG_REG); + + writeb(I2C_GLITCH_EN, ptr); +#endif +#ifdef I2C4_BASE_ADDR + ptr = (u8 __iomem *)(I2C4_BASE_ADDR + I2C_DEBUG_REG); + + writeb(I2C_GLITCH_EN, ptr); +#endif +#endif +} + +void fsl_lsch3_early_init_f(void) +{ + erratum_a008751(); + erratum_rcw_src(); + init_early_memctl_regs(); /* tighten IFC timing */ + erratum_a009203(); +} + +#ifdef CONFIG_SPL_BUILD +void board_init_f(ulong dummy) +{ + /* Clear global data */ + memset((void *)gd, 0, sizeof(gd_t)); + + arch_cpu_init(); + board_early_init_f(); + timer_init(); + env_init(); + gd->baudrate = getenv_ulong("baudrate", 10, CONFIG_BAUDRATE); + + serial_init(); + console_init_f(); + dram_init(); + + /* Clear the BSS. */ + memset(__bss_start, 0, __bss_end - __bss_start); + + board_init_r(NULL, 0); +} + +u32 spl_boot_device(void) +{ + return BOOT_DEVICE_NAND; +} +#endif diff --git a/arch/arm/cpu/armv8/fsl-lsch3/speed.c b/arch/arm/cpu/armv8/fsl-lsch3/speed.c index 72cd999..cac4f92 100644 --- a/arch/arm/cpu/armv8/fsl-lsch3/speed.c +++ b/arch/arm/cpu/armv8/fsl-lsch3/speed.c @@ -26,7 +26,7 @@ void get_sys_info(struct sys_info *sys_info) { struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); #ifdef CONFIG_FSL_IFC - struct fsl_ifc *ifc_regs = (void *)CONFIG_SYS_IFC_ADDR; + struct fsl_ifc ifc_regs = {(void *)CONFIG_SYS_IFC_ADDR, (void *)NULL}; u32 ccr; #endif struct ccsr_clk_cluster_group __iomem *clk_grp[2] = { @@ -86,6 +86,8 @@ void get_sys_info(struct sys_info *sys_info) sys_info->freq_systembus *= (in_le32(&gur->rcwsr[0]) >> FSL_CHASSIS3_RCWSR0_SYS_PLL_RAT_SHIFT) & FSL_CHASSIS3_RCWSR0_SYS_PLL_RAT_MASK; + /* Platform clock is half of platform PLL */ + sys_info->freq_systembus /= 2; sys_info->freq_ddrbus *= (in_le32(&gur->rcwsr[0]) >> FSL_CHASSIS3_RCWSR0_MEM_PLL_RAT_SHIFT) & FSL_CHASSIS3_RCWSR0_MEM_PLL_RAT_MASK; @@ -102,10 +104,7 @@ void get_sys_info(struct sys_info *sys_info) offsetof(struct ccsr_clk_cluster_group, pllngsr[i%3].gsr)); ratio[i] = (in_le32(offset) >> 1) & 0x3f; - if (ratio[i] > 4) - freq_c_pll[i] = sysclk * ratio[i]; - else - freq_c_pll[i] = sys_info->freq_systembus * ratio[i]; + freq_c_pll[i] = sysclk * ratio[i]; } for_each_cpu(i, cpu, cpu_numcores(), cpu_mask()) { @@ -119,7 +118,7 @@ void get_sys_info(struct sys_info *sys_info) } #if defined(CONFIG_FSL_IFC) - ccr = in_le32(&ifc_regs->ifc_ccr); + ccr = in_le32(&ifc_regs.gregs->ifc_ccr); ccr = ((ccr & IFC_CCR_CLK_DIV_MASK) >> IFC_CCR_CLK_DIV_SHIFT) + 1; sys_info->freq_localbus = sys_info->freq_systembus / ccr; diff --git a/arch/arm/cpu/armv8/generic_timer.c b/arch/arm/cpu/armv8/generic_timer.c index 223b95e..8e60bae 100644 --- a/arch/arm/cpu/armv8/generic_timer.c +++ b/arch/arm/cpu/armv8/generic_timer.c @@ -25,7 +25,18 @@ unsigned long get_tbclk(void) unsigned long timer_read_counter(void) { unsigned long cntpct; +#ifdef CONFIG_SYS_FSL_ERRATUM_A008585 + /* This erratum number needs to be confirmed to match ARM document */ + unsigned long temp; +#endif isb(); asm volatile("mrs %0, cntpct_el0" : "=r" (cntpct)); +#ifdef CONFIG_SYS_FSL_ERRATUM_A008585 + asm volatile("mrs %0, cntpct_el0" : "=r" (temp)); + while (temp != cntpct) { + asm volatile("mrs %0, cntpct_el0" : "=r" (cntpct)); + asm volatile("mrs %0, cntpct_el0" : "=r" (temp)); + } +#endif return cntpct; } diff --git a/arch/arm/cpu/armv8/u-boot-spl.lds b/arch/arm/cpu/armv8/u-boot-spl.lds new file mode 100644 index 0000000..4df339c --- /dev/null +++ b/arch/arm/cpu/armv8/u-boot-spl.lds @@ -0,0 +1,77 @@ +/* + * (C) Copyright 2013 + * David Feng <fenghua@phytium.com.cn> + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> + * + * (C) Copyright 2010 + * Texas Instruments, <www.ti.com> + * Aneesh V <aneesh@ti.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE, + LENGTH = CONFIG_SPL_MAX_SIZE } +MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR, + LENGTH = CONFIG_SPL_BSS_MAX_SIZE } + +OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64") +OUTPUT_ARCH(aarch64) +ENTRY(_start) +SECTIONS +{ + .text : { + . = ALIGN(8); + *(.__image_copy_start) + CPUDIR/start.o (.text*) + *(.text*) + } >.sram + + .rodata : { + . = ALIGN(8); + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) + } >.sram + + .data : { + . = ALIGN(8); + *(.data*) + } >.sram + + .u_boot_list : { + . = ALIGN(8); + KEEP(*(SORT(.u_boot_list*))); + } >.sram + + .image_copy_end : { + . = ALIGN(8); + *(.__image_copy_end) + } >.sram + + .end : { + . = ALIGN(8); + *(.__end) + } >.sram + + .bss_start : { + . = ALIGN(8); + KEEP(*(.__bss_start)); + } >.sdram + + .bss : { + *(.bss*) + . = ALIGN(8); + } >.sdram + + .bss_end : { + KEEP(*(.__bss_end)); + } >.sdram + + /DISCARD/ : { *(.dynsym) } + /DISCARD/ : { *(.dynstr*) } + /DISCARD/ : { *(.dynamic*) } + /DISCARD/ : { *(.plt*) } + /DISCARD/ : { *(.interp*) } + /DISCARD/ : { *(.gnu*) } +} |