diff options
author | Albert ARIBAUD <albert.u.boot@aribaud.net> | 2015-05-05 10:09:06 +0200 |
---|---|---|
committer | Albert ARIBAUD <albert.u.boot@aribaud.net> | 2015-05-05 10:09:06 +0200 |
commit | b939689c7b87773c44275a578ffc8674a867e39d (patch) | |
tree | 785d71eb0bbc707385e4456a14b21706223d99a3 /arch/arm/cpu | |
parent | 97840b5d1fe0960134c3553a9d9d1c1cd1be784d (diff) | |
parent | ace97d26176a3ebc9ec07738450de93eea35975c (diff) | |
download | u-boot-imx-b939689c7b87773c44275a578ffc8674a867e39d.zip u-boot-imx-b939689c7b87773c44275a578ffc8674a867e39d.tar.gz u-boot-imx-b939689c7b87773c44275a578ffc8674a867e39d.tar.bz2 |
Merge branch 'u-boot/master' into 'u-boot-arm/master'
Diffstat (limited to 'arch/arm/cpu')
63 files changed, 2000 insertions, 1664 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/arm926ejs/mxs/spl_boot.c b/arch/arm/cpu/arm926ejs/mxs/spl_boot.c index d7956e5..eb8669b 100644 --- a/arch/arm/cpu/arm926ejs/mxs/spl_boot.c +++ b/arch/arm/cpu/arm926ejs/mxs/spl_boot.c @@ -49,13 +49,6 @@ static const iomux_cfg_t iomux_boot[] = { MX23_PAD_LCD_D03__GPIO_1_3 | MUX_CONFIG_BOOTMODE_PAD, MX23_PAD_LCD_D04__GPIO_1_4 | MUX_CONFIG_BOOTMODE_PAD, MX23_PAD_LCD_D05__GPIO_1_5 | MUX_CONFIG_BOOTMODE_PAD, -#elif defined(CONFIG_MX28) - MX28_PAD_LCD_D00__GPIO_1_0 | MUX_CONFIG_BOOTMODE_PAD, - MX28_PAD_LCD_D01__GPIO_1_1 | MUX_CONFIG_BOOTMODE_PAD, - MX28_PAD_LCD_D02__GPIO_1_2 | MUX_CONFIG_BOOTMODE_PAD, - MX28_PAD_LCD_D03__GPIO_1_3 | MUX_CONFIG_BOOTMODE_PAD, - MX28_PAD_LCD_D04__GPIO_1_4 | MUX_CONFIG_BOOTMODE_PAD, - MX28_PAD_LCD_D05__GPIO_1_5 | MUX_CONFIG_BOOTMODE_PAD, #endif }; @@ -65,10 +58,10 @@ static uint8_t mxs_get_bootmode_index(void) int i; uint8_t masked; +#if defined(CONFIG_MX23) /* Setup IOMUX of bootmode pads to GPIO */ mxs_iomux_setup_multiple_pads(iomux_boot, ARRAY_SIZE(iomux_boot)); -#if defined(CONFIG_MX23) /* Setup bootmode pins as GPIO input */ gpio_direction_input(MX23_PAD_LCD_D00__GPIO_1_0); gpio_direction_input(MX23_PAD_LCD_D01__GPIO_1_1); @@ -83,21 +76,11 @@ static uint8_t mxs_get_bootmode_index(void) bootmode |= (gpio_get_value(MX23_PAD_LCD_D03__GPIO_1_3) ? 1 : 0) << 3; bootmode |= (gpio_get_value(MX23_PAD_LCD_D05__GPIO_1_5) ? 1 : 0) << 5; #elif defined(CONFIG_MX28) - /* Setup bootmode pins as GPIO input */ - gpio_direction_input(MX28_PAD_LCD_D00__GPIO_1_0); - gpio_direction_input(MX28_PAD_LCD_D01__GPIO_1_1); - gpio_direction_input(MX28_PAD_LCD_D02__GPIO_1_2); - gpio_direction_input(MX28_PAD_LCD_D03__GPIO_1_3); - gpio_direction_input(MX28_PAD_LCD_D04__GPIO_1_4); - gpio_direction_input(MX28_PAD_LCD_D05__GPIO_1_5); - - /* Read bootmode pads */ - bootmode |= (gpio_get_value(MX28_PAD_LCD_D00__GPIO_1_0) ? 1 : 0) << 0; - bootmode |= (gpio_get_value(MX28_PAD_LCD_D01__GPIO_1_1) ? 1 : 0) << 1; - bootmode |= (gpio_get_value(MX28_PAD_LCD_D02__GPIO_1_2) ? 1 : 0) << 2; - bootmode |= (gpio_get_value(MX28_PAD_LCD_D03__GPIO_1_3) ? 1 : 0) << 3; - bootmode |= (gpio_get_value(MX28_PAD_LCD_D04__GPIO_1_4) ? 1 : 0) << 4; - bootmode |= (gpio_get_value(MX28_PAD_LCD_D05__GPIO_1_5) ? 1 : 0) << 5; + /* The global boot mode will be detected by ROM code and its value + * is stored at the fixed address 0x00019BF0 in OCRAM. + */ +#define GLOBAL_BOOT_MODE_ADDR 0x00019BF0 + bootmode = __raw_readl(GLOBAL_BOOT_MODE_ADDR); #endif for (i = 0; i < ARRAY_SIZE(mxs_boot_modes); i++) { diff --git a/arch/arm/cpu/arm926ejs/spear/cpu.c b/arch/arm/cpu/arm926ejs/spear/cpu.c index 697e094..1ce9db7 100644 --- a/arch/arm/cpu/arm926ejs/spear/cpu.c +++ b/arch/arm/cpu/arm926ejs/spear/cpu.c @@ -32,7 +32,7 @@ int arch_cpu_init(void) periph_clk_cfg |= CONFIG_SPEAR_UART48M; writel(periph_clk_cfg, &misc_p->periph_clk_cfg); #endif -#if defined(CONFIG_DESIGNWARE_ETH) +#if defined(CONFIG_ETH_DESIGNWARE) periph1_clken |= MISC_ETHENB; #endif #if defined(CONFIG_DW_UDC) 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/Makefile b/arch/arm/cpu/armv7/Makefile index 21fc03b..fcccd0c 100644 --- a/arch/arm/cpu/armv7/Makefile +++ b/arch/arm/cpu/armv7/Makefile @@ -12,7 +12,7 @@ obj-y += cache_v7.o obj-y += cpu.o cp15.o obj-y += syslib.o -ifneq ($(CONFIG_AM43XX)$(CONFIG_AM33XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX)$(CONFIG_TEGRA)$(CONFIG_MX6)$(CONFIG_TI81XX)$(CONFIG_AT91FAMILY)$(CONFIG_SUNXI),) +ifneq ($(CONFIG_AM43XX)$(CONFIG_AM33XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX)$(CONFIG_TEGRA)$(CONFIG_MX6)$(CONFIG_TI81XX)$(CONFIG_AT91FAMILY)$(CONFIG_SUNXI)$(CONFIG_SOCFPGA),) ifneq ($(CONFIG_SKIP_LOWLEVEL_INIT),y) obj-y += lowlevel_init.o endif @@ -56,4 +56,3 @@ obj-$(if $(filter stv0991,$(SOC)),y) += stv0991/ obj-$(CONFIG_ARCH_SUNXI) += sunxi/ obj-$(CONFIG_U8500) += u8500/ obj-$(CONFIG_VF610) += vf610/ -obj-$(CONFIG_ZYNQ) += zynq/ diff --git a/arch/arm/cpu/armv7/exynos/Kconfig b/arch/arm/cpu/armv7/exynos/Kconfig index bd7540a..f6084ac 100644 --- a/arch/arm/cpu/armv7/exynos/Kconfig +++ b/arch/arm/cpu/armv7/exynos/Kconfig @@ -65,19 +65,7 @@ endchoice config SYS_SOC default "exynos" -config DM - default y - -config DM_SERIAL - default y - -config DM_SPI - default y - -config DM_SPI_FLASH - default y - -config DM_GPIO +config DM_USB default y source "board/samsung/smdkv310/Kconfig" 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/mx6/ddr.c b/arch/arm/cpu/armv7/mx6/ddr.c index fef2231..653d58e 100644 --- a/arch/arm/cpu/armv7/mx6/ddr.c +++ b/arch/arm/cpu/armv7/mx6/ddr.c @@ -514,17 +514,21 @@ void mx6_dram_cfg(const struct mx6_ddr_sysinfo *sysinfo, /* MR2 */ val = (sysinfo->rtt_wr & 3) << 9 | (ddr3_cfg->SRT & 1) << 7 | ((tcwl - 3) & 3) << 3; + debug("MR2 CS%d: 0x%08x\n", cs, (u32)MR(val, 2, 3, cs)); mmdc0->mdscr = MR(val, 2, 3, cs); /* MR3 */ + debug("MR3 CS%d: 0x%08x\n", cs, (u32)MR(0, 3, 3, cs)); mmdc0->mdscr = MR(0, 3, 3, cs); /* MR1 */ val = ((sysinfo->rtt_nom & 1) ? 1 : 0) << 2 | ((sysinfo->rtt_nom & 2) ? 1 : 0) << 6; + debug("MR1 CS%d: 0x%08x\n", cs, (u32)MR(val, 1, 3, cs)); mmdc0->mdscr = MR(val, 1, 3, cs); /* MR0 */ val = ((tcl - 1) << 4) | /* CAS */ (1 << 8) | /* DLL Reset */ ((twr - 3) << 9); /* Write Recovery */ + debug("MR0 CS%d: 0x%08x\n", cs, (u32)MR(val, 0, 3, cs)); mmdc0->mdscr = MR(val, 0, 3, cs); /* ZQ calibration */ val = (1 << 10); @@ -535,10 +539,11 @@ void mx6_dram_cfg(const struct mx6_ddr_sysinfo *sysinfo, mmdc0->mdpdc = (tcke & 0x7) << 16 | 5 << 12 | /* PWDT_1: 256 cycles */ 5 << 8 | /* PWDT_0: 256 cycles */ - 1 << 7 | /* SLOW_PD */ 1 << 6 | /* BOTH_CS_PD */ (tcksrx & 0x7) << 3 | (tcksre & 0x7); + if (!sysinfo->pd_fast_exit) + mmdc0->mdpdc |= (1 << 7); /* SLOW_PD */ mmdc0->mapsr = 0x00001006; /* ADOPT power down enabled */ /* Step 11: Configure ZQ calibration: one-time and periodic 1ms */ diff --git a/arch/arm/cpu/armv7/omap-common/boot-common.c b/arch/arm/cpu/armv7/omap-common/boot-common.c index 17500f2..bbc6bed 100644 --- a/arch/arm/cpu/armv7/omap-common/boot-common.c +++ b/arch/arm/cpu/armv7/omap-common/boot-common.c @@ -159,6 +159,16 @@ void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image) #ifdef CONFIG_SCSI_AHCI_PLAT void arch_preboot_os(void) { - ahci_reset(DWC_AHSATA_BASE); + 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/sata.c b/arch/arm/cpu/armv7/omap-common/sata.c index d18bc50..2c2d1bc 100644 --- a/arch/arm/cpu/armv7/omap-common/sata.c +++ b/arch/arm/cpu/armv7/omap-common/sata.c @@ -69,7 +69,7 @@ int init_sata(int dev) val = TI_SATA_IDLE_NO | TI_SATA_STANDBY_NO; writel(val, TI_SATA_WRAPPER_BASE + TI_SATA_SYSCONFIG); - ret = ahci_init(DWC_AHSATA_BASE); + ret = ahci_init((void __iomem *)DWC_AHSATA_BASE); return ret; } @@ -88,6 +88,6 @@ void scsi_init(void) void scsi_bus_reset(void) { - ahci_reset(DWC_AHSATA_BASE); - ahci_init(DWC_AHSATA_BASE); + ahci_reset((void __iomem *)DWC_AHSATA_BASE); + ahci_init((void __iomem *)DWC_AHSATA_BASE); } 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/omap3/Kconfig b/arch/arm/cpu/armv7/omap3/Kconfig index 1f96498..cc82c50 100644 --- a/arch/arm/cpu/armv7/omap3/Kconfig +++ b/arch/arm/cpu/armv7/omap3/Kconfig @@ -17,6 +17,9 @@ config TARGET_OMAP3_SDP3430 config TARGET_OMAP3_BEAGLE bool "TI OMAP3 BeagleBoard" select SUPPORT_SPL + select DM + select DM_SERIAL + select DM_GPIO config TARGET_CM_T35 bool "CompuLab CM-T3530 and CM-T3730 boards" @@ -28,6 +31,9 @@ config TARGET_CM_T3517 config TARGET_DEVKIT8000 bool "TimLL OMAP3 Devkit8000" select SUPPORT_SPL + select DM + select DM_SERIAL + select DM_GPIO config TARGET_OMAP3_EVM bool "TI OMAP3 EVM" @@ -44,13 +50,22 @@ config TARGET_OMAP3_EVM_QUICK_NAND config TARGET_OMAP3_IGEP00X0 bool "IGEP" select SUPPORT_SPL + select DM + select DM_SERIAL + select DM_GPIO config TARGET_OMAP3_OVERO bool "OMAP35xx Gumstix Overo" select SUPPORT_SPL + select DM + select DM_SERIAL + select DM_GPIO config TARGET_OMAP3_ZOOM1 bool "TI Zoom1" + select DM + select DM_SERIAL + select DM_GPIO config TARGET_AM3517_CRANE bool "am3517_crane" @@ -94,18 +109,12 @@ config TARGET_TWISTER config TARGET_OMAP3_CAIRO bool "QUIPOS CAIRO" select SUPPORT_SPL + select DM + select DM_SERIAL + select DM_GPIO endchoice -config DM - default y - -config DM_GPIO - default y if DM - -config DM_SERIAL - default y if DM - config SYS_SOC default "omap3" diff --git a/arch/arm/cpu/armv7/omap5/hw_data.c b/arch/arm/cpu/armv7/omap5/hw_data.c index e4abb25..868415d 100644 --- a/arch/arm/cpu/armv7/omap5/hw_data.c +++ b/arch/arm/cpu/armv7/omap5/hw_data.c @@ -460,7 +460,7 @@ void enable_basic_clocks(void) (*prcm)->cm_l4per_gpio6_clkctrl, (*prcm)->cm_l4per_gpio7_clkctrl, (*prcm)->cm_l4per_gpio8_clkctrl, -#ifdef CONFIG_USB_DWC3 +#if defined(CONFIG_USB_DWC3) || defined(CONFIG_USB_XHCI_OMAP) (*prcm)->cm_l3init_ocp2scp1_clkctrl, (*prcm)->cm_l3init_usb_otg_ss1_clkctrl, #endif @@ -495,7 +495,7 @@ void enable_basic_clocks(void) setbits_le32((*prcm)->cm_l3init_hsmmc2_clkctrl, HSMMC_CLKCTRL_CLKSEL_MASK); -#ifdef CONFIG_USB_DWC3 +#if defined(CONFIG_USB_DWC3) || defined(CONFIG_USB_XHCI_OMAP) /* Enable 960 MHz clock for dwc3 */ setbits_le32((*prcm)->cm_l3init_usb_otg_ss1_clkctrl, OPTFCLKEN_REFCLK960M); 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/rmobile/Kconfig b/arch/arm/cpu/armv7/rmobile/Kconfig index 2b333a3..57dccec 100644 --- a/arch/arm/cpu/armv7/rmobile/Kconfig +++ b/arch/arm/cpu/armv7/rmobile/Kconfig @@ -8,24 +8,36 @@ config TARGET_ARMADILLO_800EVA config TARGET_GOSE bool "Gose board" + select DM + select DM_SERIAL config TARGET_KOELSCH bool "Koelsch board" + select DM + select DM_SERIAL config TARGET_LAGER bool "Lager board" + select DM + select DM_SERIAL config TARGET_KZM9G bool "KZM9D board" config TARGET_ALT bool "Alt board" + select DM + select DM_SERIAL config TARGET_SILK bool "Silk board" + select DM + select DM_SERIAL config TARGET_PORTER bool "Porter board" + select DM + select DM_SERIAL endchoice diff --git a/arch/arm/cpu/armv7/socfpga/Makefile b/arch/arm/cpu/armv7/socfpga/Makefile index 8b6e108..7524ef9 100644 --- a/arch/arm/cpu/armv7/socfpga/Makefile +++ b/arch/arm/cpu/armv7/socfpga/Makefile @@ -7,7 +7,6 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-y := lowlevel_init.o obj-y += misc.o timer.o reset_manager.o system_manager.o clock_manager.o \ fpga_manager.o obj-$(CONFIG_SPL_BUILD) += spl.o freeze_controller.o scan_manager.o diff --git a/arch/arm/cpu/armv7/socfpga/lowlevel_init.S b/arch/arm/cpu/armv7/socfpga/lowlevel_init.S deleted file mode 100644 index b4d0627..0000000 --- a/arch/arm/cpu/armv7/socfpga/lowlevel_init.S +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2012 Altera Corporation <www.altera.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <config.h> - -/* Set up the platform, once the cpu has been initialized */ -.globl lowlevel_init -lowlevel_init: - - /* Remap */ -#ifdef CONFIG_SPL_BUILD - /* - * SPL : configure the remap (L3 NIC-301 GPV) - * so the on-chip RAM at lower memory instead ROM. - */ - ldr r0, =SOCFPGA_L3REGS_ADDRESS - mov r1, #0x19 - str r1, [r0] -#else - /* - * U-Boot : configure the remap (L3 NIC-301 GPV) - * so the SDRAM at lower memory instead on-chip RAM. - */ - ldr r0, =SOCFPGA_L3REGS_ADDRESS - mov r1, #0x2 - str r1, [r0] - - /* Private components security */ - - /* - * U-Boot : configure private timer, global timer and cpu - * component access as non secure for kernel stage (as required - * by kernel) - */ - mrc p15,4,r0,c15,c0,0 - add r1, r0, #0x54 - ldr r2, [r1] - orr r2, r2, #0xff - orr r2, r2, #0xf00 - str r2, [r1] -#endif /* #ifdef CONFIG_SPL_BUILD */ - mov pc, lr diff --git a/arch/arm/cpu/armv7/socfpga/misc.c b/arch/arm/cpu/armv7/socfpga/misc.c index 7873c38..0f8b4d0 100644 --- a/arch/arm/cpu/armv7/socfpga/misc.c +++ b/arch/arm/cpu/armv7/socfpga/misc.c @@ -49,7 +49,7 @@ void enable_caches(void) /* * DesignWare Ethernet initialization */ -#ifdef CONFIG_DESIGNWARE_ETH +#ifdef CONFIG_ETH_DESIGNWARE int cpu_eth_init(bd_t *bis) { #if CONFIG_EMAC_BASE == SOCFPGA_EMAC0_ADDRESS diff --git a/arch/arm/cpu/armv7/socfpga/reset_manager.c b/arch/arm/cpu/armv7/socfpga/reset_manager.c index 25921e7..45b352b 100644 --- a/arch/arm/cpu/armv7/socfpga/reset_manager.c +++ b/arch/arm/cpu/armv7/socfpga/reset_manager.c @@ -113,3 +113,27 @@ void socfpga_spim_enable(void) clrbits_le32(reset, (1 << RSTMGR_PERMODRST_SPIM0_LSB) | (1 << RSTMGR_PERMODRST_SPIM1_LSB)); } + +/* Bring UART0 out of reset. */ +void socfpga_uart0_enable(void) +{ + const void *reset = &reset_manager_base->per_mod_reset; + + clrbits_le32(reset, 1 << RSTMGR_PERMODRST_UART0_LSB); +} + +/* Bring SDRAM controller out of reset. */ +void socfpga_sdram_enable(void) +{ + const void *reset = &reset_manager_base->per_mod_reset; + + clrbits_le32(reset, 1 << RSTMGR_PERMODRST_SDR_LSB); +} + +/* Bring OSC1 timer out of reset. */ +void socfpga_osc1timer_enable(void) +{ + const void *reset = &reset_manager_base->per_mod_reset; + + clrbits_le32(reset, 1 << RSTMGR_PERMODRST_OSC1TIMER0_LSB); +} diff --git a/arch/arm/cpu/armv7/socfpga/spl.c b/arch/arm/cpu/armv7/socfpga/spl.c index 6a8c15d..f994658 100644 --- a/arch/arm/cpu/armv7/socfpga/spl.c +++ b/arch/arm/cpu/armv7/socfpga/spl.c @@ -6,6 +6,7 @@ #include <common.h> #include <asm/io.h> +#include <asm/pl310.h> #include <asm/u-boot.h> #include <asm/utils.h> #include <image.h> @@ -15,9 +16,13 @@ #include <asm/arch/freeze_controller.h> #include <asm/arch/clock_manager.h> #include <asm/arch/scan_manager.h> +#include <asm/arch/sdram.h> DECLARE_GLOBAL_DATA_PTR; +static struct pl310_regs *const pl310 = + (struct pl310_regs *)CONFIG_SYS_PL310_BASE; + #define MAIN_VCO_BASE ( \ (CONFIG_HPS_MAINPLLGRP_VCO_DENOM << \ CLKMGR_MAINPLLGRP_VCO_DENOM_OFFSET) | \ @@ -43,6 +48,31 @@ DECLARE_GLOBAL_DATA_PTR; CLKMGR_SDRPLLGRP_VCO_NUMER_OFFSET) \ ) +void board_init_f(ulong dummy) +{ + struct socfpga_system_manager *sysmgr_regs = + (struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS; + unsigned long reg; + /* + * First C code to run. Clear fake OCRAM ECC first as SBE + * and DBE might triggered during power on + */ + reg = readl(&sysmgr_regs->eccgrp_ocram); + if (reg & SYSMGR_ECC_OCRAM_SERR) + writel(SYSMGR_ECC_OCRAM_SERR | SYSMGR_ECC_OCRAM_EN, + &sysmgr_regs->eccgrp_ocram); + if (reg & SYSMGR_ECC_OCRAM_DERR) + writel(SYSMGR_ECC_OCRAM_DERR | SYSMGR_ECC_OCRAM_EN, + &sysmgr_regs->eccgrp_ocram); + + memset(__bss_start, 0, __bss_end - __bss_start); + + /* Remap SDRAM to 0x0 */ + writel(0x1, &pl310->pl310_addr_filter_start); + + board_init_r(NULL, 0); +} + u32 spl_boot_device(void) { return BOOT_DEVICE_RAM; @@ -53,6 +83,7 @@ u32 spl_boot_device(void) */ void spl_board_init(void) { + unsigned long sdram_size; #ifndef CONFIG_SOCFPGA_VIRTUAL_TARGET cm_config_t cm_default_cfg = { /* main group */ @@ -144,10 +175,19 @@ void spl_board_init(void) /* freeze all IO banks */ sys_mgr_frzctrl_freeze_req(); + socfpga_sdram_enable(); + socfpga_uart0_enable(); + socfpga_osc1timer_enable(); + + timer_init(); + debug("Reconfigure Clock Manager\n"); /* reconfigure the PLLs */ cm_basic_init(&cm_default_cfg); + /* Enable bootrom to configure IOs. */ + sysmgr_enable_warmrstcfgio(); + /* configure the IOCSR / IO buffer settings */ if (scan_mgr_configure_iocsr()) hang(); @@ -165,4 +205,25 @@ void spl_board_init(void) /* enable console uart printing */ preloader_console_init(); + + if (sdram_mmr_init_full(0xffffffff) != 0) { + puts("SDRAM init failed.\n"); + hang(); + } + + debug("SDRAM: Calibrating PHY\n"); + /* SDRAM calibration */ + if (sdram_calibration_full() == 0) { + puts("SDRAM calibration failed.\n"); + hang(); + } + + sdram_size = sdram_calculate_size(); + debug("SDRAM: %ld MiB\n", sdram_size >> 20); + + /* Sanity check ensure correct SDRAM size specified */ + if (get_ram_size(0, sdram_size) != sdram_size) { + puts("SDRAM size check failed!\n"); + hang(); + } } diff --git a/arch/arm/cpu/armv7/socfpga/system_manager.c b/arch/arm/cpu/armv7/socfpga/system_manager.c index 11f7bad..8126e0d 100644 --- a/arch/arm/cpu/armv7/socfpga/system_manager.c +++ b/arch/arm/cpu/armv7/socfpga/system_manager.c @@ -66,3 +66,12 @@ void sysmgr_pinmux_init(void) populate_sysmgr_fpgaintf_module(); } + +/* + * This bit allows the bootrom to configure the IOs after a warm reset. + */ +void sysmgr_enable_warmrstcfgio(void) +{ + setbits_le32(&sysmgr_regs->romcodegrp_ctrl, + SYSMGR_ROMCODEGRP_CTRL_WARMRSTCFGIO); +} diff --git a/arch/arm/cpu/armv7/sunxi/board.c b/arch/arm/cpu/armv7/sunxi/board.c index c02c015..c1b4cf5 100644 --- a/arch/arm/cpu/armv7/sunxi/board.c +++ b/arch/arm/cpu/armv7/sunxi/board.c @@ -46,28 +46,33 @@ static int gpio_init(void) sunxi_gpio_set_cfgpin(SUNXI_GPB(22), SUNXI_GPIO_INPUT); sunxi_gpio_set_cfgpin(SUNXI_GPB(23), SUNXI_GPIO_INPUT); #endif - sunxi_gpio_set_cfgpin(SUNXI_GPF(2), SUNXI_GPF2_UART0_TX); - sunxi_gpio_set_cfgpin(SUNXI_GPF(4), SUNXI_GPF4_UART0_RX); +#if defined(CONFIG_MACH_SUN8I) + sunxi_gpio_set_cfgpin(SUNXI_GPF(2), SUN8I_GPF_UART0_TX); + sunxi_gpio_set_cfgpin(SUNXI_GPF(4), SUN8I_GPF_UART0_RX); +#else + sunxi_gpio_set_cfgpin(SUNXI_GPF(2), SUNXI_GPF_UART0_TX); + sunxi_gpio_set_cfgpin(SUNXI_GPF(4), SUNXI_GPF_UART0_RX); +#endif sunxi_gpio_set_pull(SUNXI_GPF(4), 1); #elif CONFIG_CONS_INDEX == 1 && (defined(CONFIG_MACH_SUN4I) || defined(CONFIG_MACH_SUN7I)) - sunxi_gpio_set_cfgpin(SUNXI_GPB(22), SUN4I_GPB22_UART0_TX); - sunxi_gpio_set_cfgpin(SUNXI_GPB(23), SUN4I_GPB23_UART0_RX); + sunxi_gpio_set_cfgpin(SUNXI_GPB(22), SUN4I_GPB_UART0); + sunxi_gpio_set_cfgpin(SUNXI_GPB(23), SUN4I_GPB_UART0); sunxi_gpio_set_pull(SUNXI_GPB(23), SUNXI_GPIO_PULL_UP); #elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN5I) - sunxi_gpio_set_cfgpin(SUNXI_GPB(19), SUN5I_GPB19_UART0_TX); - sunxi_gpio_set_cfgpin(SUNXI_GPB(20), SUN5I_GPB20_UART0_RX); + sunxi_gpio_set_cfgpin(SUNXI_GPB(19), SUN5I_GPB_UART0); + sunxi_gpio_set_cfgpin(SUNXI_GPB(20), SUN5I_GPB_UART0); sunxi_gpio_set_pull(SUNXI_GPB(20), SUNXI_GPIO_PULL_UP); #elif CONFIG_CONS_INDEX == 1 && defined(CONFIG_MACH_SUN6I) - sunxi_gpio_set_cfgpin(SUNXI_GPH(20), SUN6I_GPH20_UART0_TX); - sunxi_gpio_set_cfgpin(SUNXI_GPH(21), SUN6I_GPH21_UART0_RX); + sunxi_gpio_set_cfgpin(SUNXI_GPH(20), SUN6I_GPH_UART0); + sunxi_gpio_set_cfgpin(SUNXI_GPH(21), SUN6I_GPH_UART0); sunxi_gpio_set_pull(SUNXI_GPH(21), SUNXI_GPIO_PULL_UP); #elif CONFIG_CONS_INDEX == 2 && defined(CONFIG_MACH_SUN5I) - sunxi_gpio_set_cfgpin(SUNXI_GPG(3), SUN5I_GPG3_UART1_TX); - sunxi_gpio_set_cfgpin(SUNXI_GPG(4), SUN5I_GPG4_UART1_RX); + sunxi_gpio_set_cfgpin(SUNXI_GPG(3), SUN5I_GPG_UART1); + sunxi_gpio_set_cfgpin(SUNXI_GPG(4), SUN5I_GPG_UART1); sunxi_gpio_set_pull(SUNXI_GPG(4), SUNXI_GPIO_PULL_UP); #elif CONFIG_CONS_INDEX == 5 && defined(CONFIG_MACH_SUN8I) - sunxi_gpio_set_cfgpin(SUNXI_GPL(2), SUN8I_GPL2_R_UART_TX); - sunxi_gpio_set_cfgpin(SUNXI_GPL(3), SUN8I_GPL3_R_UART_RX); + sunxi_gpio_set_cfgpin(SUNXI_GPL(2), SUN8I_GPL_R_UART); + sunxi_gpio_set_cfgpin(SUNXI_GPL(3), SUN8I_GPL_R_UART); sunxi_gpio_set_pull(SUNXI_GPL(3), SUNXI_GPIO_PULL_UP); #else #error Unsupported console port number. Please fix pin mux settings in board.c diff --git a/arch/arm/cpu/armv7/sunxi/rsb.c b/arch/arm/cpu/armv7/sunxi/rsb.c index b00befb..f115a9c 100644 --- a/arch/arm/cpu/armv7/sunxi/rsb.c +++ b/arch/arm/cpu/armv7/sunxi/rsb.c @@ -21,15 +21,15 @@ static int rsb_set_device_mode(void); static void rsb_cfg_io(void) { #ifdef CONFIG_MACH_SUN8I - sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN8I_GPL0_R_RSB_SCK); - sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUN8I_GPL1_R_RSB_SDA); + sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN8I_GPL_R_RSB); + sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUN8I_GPL_R_RSB); sunxi_gpio_set_pull(SUNXI_GPL(0), 1); sunxi_gpio_set_pull(SUNXI_GPL(1), 1); sunxi_gpio_set_drv(SUNXI_GPL(0), 2); sunxi_gpio_set_drv(SUNXI_GPL(1), 2); #elif defined CONFIG_MACH_SUN9I - sunxi_gpio_set_cfgpin(SUNXI_GPN(0), SUN9I_GPN0_R_RSB_SCK); - sunxi_gpio_set_cfgpin(SUNXI_GPN(1), SUN9I_GPN1_R_RSB_SDA); + sunxi_gpio_set_cfgpin(SUNXI_GPN(0), SUN9I_GPN_R_RSB); + sunxi_gpio_set_cfgpin(SUNXI_GPN(1), SUN9I_GPN_R_RSB); sunxi_gpio_set_pull(SUNXI_GPN(0), 1); sunxi_gpio_set_pull(SUNXI_GPN(1), 1); sunxi_gpio_set_drv(SUNXI_GPN(0), 2); diff --git a/arch/arm/cpu/armv7/sunxi/usbc.c b/arch/arm/cpu/armv7/sunxi/usbc.c index 524f25c..a0e9604 100644 --- a/arch/arm/cpu/armv7/sunxi/usbc.c +++ b/arch/arm/cpu/armv7/sunxi/usbc.c @@ -41,6 +41,7 @@ static struct sunxi_usbc_hcd { int usb_rst_mask; int ahb_clk_mask; int gpio_vbus; + int gpio_vbus_det; int irq; int id; } sunxi_usbc_hcd[] = { @@ -80,12 +81,6 @@ static struct sunxi_usbc_hcd { static int enabled_hcd_count; -static bool use_axp_drivebus(int index) -{ - return index == 0 && - strcmp(CONFIG_USB0_VBUS_PIN, "axp_drivebus") == 0; -} - void *sunxi_usbc_get_io_base(int index) { switch (index) { @@ -102,9 +97,6 @@ void *sunxi_usbc_get_io_base(int index) static int get_vbus_gpio(int index) { - if (use_axp_drivebus(index)) - return -1; - switch (index) { case 0: return sunxi_name_to_gpio(CONFIG_USB0_VBUS_PIN); case 1: return sunxi_name_to_gpio(CONFIG_USB1_VBUS_PIN); @@ -113,6 +105,14 @@ static int get_vbus_gpio(int index) return -1; } +static int get_vbus_detect_gpio(int index) +{ + switch (index) { + case 0: return sunxi_name_to_gpio(CONFIG_USB0_VBUS_DET); + } + return -1; +} + static void usb_phy_write(struct sunxi_usbc_hcd *sunxi_usbc, int addr, int data, int len) { @@ -192,22 +192,35 @@ void sunxi_usbc_enable_squelch_detect(int index, int enable) int sunxi_usbc_request_resources(int index) { struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index]; + int ret = 0; sunxi_usbc->gpio_vbus = get_vbus_gpio(index); - if (sunxi_usbc->gpio_vbus != -1) - return gpio_request(sunxi_usbc->gpio_vbus, "usbc_vbus"); + if (sunxi_usbc->gpio_vbus != -1) { + ret |= gpio_request(sunxi_usbc->gpio_vbus, "usbc_vbus"); + ret |= gpio_direction_output(sunxi_usbc->gpio_vbus, 0); + } + + sunxi_usbc->gpio_vbus_det = get_vbus_detect_gpio(index); + if (sunxi_usbc->gpio_vbus_det != -1) { + ret |= gpio_request(sunxi_usbc->gpio_vbus_det, "usbc_vbus_det"); + ret |= gpio_direction_input(sunxi_usbc->gpio_vbus_det); + } - return 0; + return ret; } int sunxi_usbc_free_resources(int index) { struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index]; + int ret = 0; if (sunxi_usbc->gpio_vbus != -1) - return gpio_free(sunxi_usbc->gpio_vbus); + ret |= gpio_free(sunxi_usbc->gpio_vbus); - return 0; + if (sunxi_usbc->gpio_vbus_det != -1) + ret |= gpio_free(sunxi_usbc->gpio_vbus_det); + + return ret; } void sunxi_usbc_enable(int index) @@ -258,22 +271,38 @@ void sunxi_usbc_vbus_enable(int index) { struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index]; -#ifdef AXP_DRIVEBUS - if (use_axp_drivebus(index)) - axp_drivebus_enable(); -#endif if (sunxi_usbc->gpio_vbus != -1) - gpio_direction_output(sunxi_usbc->gpio_vbus, 1); + gpio_set_value(sunxi_usbc->gpio_vbus, 1); } void sunxi_usbc_vbus_disable(int index) { struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index]; -#ifdef AXP_DRIVEBUS - if (use_axp_drivebus(index)) - axp_drivebus_disable(); -#endif if (sunxi_usbc->gpio_vbus != -1) - gpio_direction_output(sunxi_usbc->gpio_vbus, 0); + gpio_set_value(sunxi_usbc->gpio_vbus, 0); +} + +int sunxi_usbc_vbus_detect(int index) +{ + struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index]; + int err, retries = 3; + + if (sunxi_usbc->gpio_vbus_det == -1) { + eprintf("Error: invalid vbus detection pin\n"); + return -1; + } + + err = gpio_get_value(sunxi_usbc->gpio_vbus_det); + /* + * Vbus may have been provided by the board and just been turned of + * some milliseconds ago on reset, what we're measuring then is a + * residual charge on Vbus, sleep a bit and try again. + */ + while (err > 0 && retries--) { + mdelay(100); + err = gpio_get_value(sunxi_usbc->gpio_vbus_det); + } + + return err; } 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/armv7/zynq/Kconfig b/arch/arm/cpu/armv7/zynq/Kconfig deleted file mode 100644 index 3a52535..0000000 --- a/arch/arm/cpu/armv7/zynq/Kconfig +++ /dev/null @@ -1,39 +0,0 @@ -if ZYNQ - -choice - prompt "Xilinx Zynq board select" - -config TARGET_ZYNQ_ZED - bool "Zynq ZedBoard" - -config TARGET_ZYNQ_MICROZED - bool "Zynq MicroZed" - -config TARGET_ZYNQ_ZC70X - bool "Zynq ZC702/ZC706 Board" - -config TARGET_ZYNQ_ZC770 - bool "Zynq ZC770 Board" - -config TARGET_ZYNQ_ZYBO - bool "Zynq Zybo Board" - -endchoice - -config SYS_BOARD - default "zynq" - -config SYS_VENDOR - default "xilinx" - -config SYS_SOC - default "zynq" - -config SYS_CONFIG_NAME - default "zynq_zed" if TARGET_ZYNQ_ZED - default "zynq_microzed" if TARGET_ZYNQ_MICROZED - default "zynq_zc70x" if TARGET_ZYNQ_ZC70X - default "zynq_zc770" if TARGET_ZYNQ_ZC770 - default "zynq_zybo" if TARGET_ZYNQ_ZYBO - -endif diff --git a/arch/arm/cpu/armv7/zynq/Makefile b/arch/arm/cpu/armv7/zynq/Makefile deleted file mode 100644 index 901f2ce..0000000 --- a/arch/arm/cpu/armv7/zynq/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# -# (C) Copyright 2000-2003 -# Wolfgang Denk, DENX Software Engineering, wd@denx.de. -# -# (C) Copyright 2008 -# Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de> -# -# SPDX-License-Identifier: GPL-2.0+ -# - -obj-y := timer.o -obj-y += cpu.o -obj-y += ddrc.o -obj-y += slcr.o -obj-y += clk.o -obj-y += lowlevel_init.o -obj-$(CONFIG_SPL_BUILD) += spl.o diff --git a/arch/arm/cpu/armv7/zynq/clk.c b/arch/arm/cpu/armv7/zynq/clk.c deleted file mode 100644 index d2885dc..0000000 --- a/arch/arm/cpu/armv7/zynq/clk.c +++ /dev/null @@ -1,664 +0,0 @@ -/* - * Copyright (C) 2013 Soren Brinkmann <soren.brinkmann@xilinx.com> - * Copyright (C) 2013 Xilinx, Inc. All rights reserved. - * - * SPDX-License-Identifier: GPL-2.0+ - */ -#include <common.h> -#include <errno.h> -#include <clk.h> -#include <asm/io.h> -#include <asm/arch/hardware.h> -#include <asm/arch/clk.h> - -/* Board oscillator frequency */ -#ifndef CONFIG_ZYNQ_PS_CLK_FREQ -# define CONFIG_ZYNQ_PS_CLK_FREQ 33333333UL -#endif - -/* Register bitfield defines */ -#define PLLCTRL_FBDIV_MASK 0x7f000 -#define PLLCTRL_FBDIV_SHIFT 12 -#define PLLCTRL_BPFORCE_MASK (1 << 4) -#define PLLCTRL_PWRDWN_MASK 2 -#define PLLCTRL_PWRDWN_SHIFT 1 -#define PLLCTRL_RESET_MASK 1 -#define PLLCTRL_RESET_SHIFT 0 - -#define ZYNQ_CLK_MAXDIV 0x3f -#define CLK_CTRL_DIV1_SHIFT 20 -#define CLK_CTRL_DIV1_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV1_SHIFT) -#define CLK_CTRL_DIV0_SHIFT 8 -#define CLK_CTRL_DIV0_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV0_SHIFT) -#define CLK_CTRL_SRCSEL_SHIFT 4 -#define CLK_CTRL_SRCSEL_MASK (0x3 << CLK_CTRL_SRCSEL_SHIFT) - -#define CLK_CTRL_DIV2X_SHIFT 26 -#define CLK_CTRL_DIV2X_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV2X_SHIFT) -#define CLK_CTRL_DIV3X_SHIFT 20 -#define CLK_CTRL_DIV3X_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV3X_SHIFT) - -#define ZYNQ_CLKMUX_SEL_0 0 -#define ZYNQ_CLKMUX_SEL_1 1 -#define ZYNQ_CLKMUX_SEL_2 2 -#define ZYNQ_CLKMUX_SEL_3 3 - -DECLARE_GLOBAL_DATA_PTR; - -struct clk; - -/** - * struct clk_ops: - * @set_rate: Function pointer to set_rate() implementation - * @get_rate: Function pointer to get_rate() implementation - */ -struct clk_ops { - int (*set_rate)(struct clk *clk, unsigned long rate); - unsigned long (*get_rate)(struct clk *clk); -}; - -/** - * struct clk: - * @name: Clock name - * @frequency: Currenct frequency - * @parent: Parent clock - * @flags: Clock flags - * @reg: Clock control register - * @ops: Clock operations - */ -struct clk { - char *name; - unsigned long frequency; - enum zynq_clk parent; - unsigned int flags; - u32 *reg; - struct clk_ops ops; -}; -#define ZYNQ_CLK_FLAGS_HAS_2_DIVS 1 - -static struct clk clks[clk_max]; - -/** - * __zynq_clk_cpu_get_parent() - Decode clock multiplexer - * @srcsel: Mux select value - * Returns the clock identifier associated with the selected mux input. - */ -static int __zynq_clk_cpu_get_parent(unsigned int srcsel) -{ - unsigned int ret; - - switch (srcsel) { - case ZYNQ_CLKMUX_SEL_0: - case ZYNQ_CLKMUX_SEL_1: - ret = armpll_clk; - break; - case ZYNQ_CLKMUX_SEL_2: - ret = ddrpll_clk; - break; - case ZYNQ_CLKMUX_SEL_3: - ret = iopll_clk; - break; - default: - ret = armpll_clk; - break; - } - - return ret; -} - -/** - * ddr2x_get_rate() - Get clock rate of DDR2x clock - * @clk: Clock handle - * Returns the current clock rate of @clk. - */ -static unsigned long ddr2x_get_rate(struct clk *clk) -{ - u32 clk_ctrl = readl(clk->reg); - u32 div = (clk_ctrl & CLK_CTRL_DIV2X_MASK) >> CLK_CTRL_DIV2X_SHIFT; - - return DIV_ROUND_CLOSEST(zynq_clk_get_rate(clk->parent), div); -} - -/** - * ddr3x_get_rate() - Get clock rate of DDR3x clock - * @clk: Clock handle - * Returns the current clock rate of @clk. - */ -static unsigned long ddr3x_get_rate(struct clk *clk) -{ - u32 clk_ctrl = readl(clk->reg); - u32 div = (clk_ctrl & CLK_CTRL_DIV3X_MASK) >> CLK_CTRL_DIV3X_SHIFT; - - return DIV_ROUND_CLOSEST(zynq_clk_get_rate(clk->parent), div); -} - -static void init_ddr_clocks(void) -{ - u32 div0, div1; - unsigned long prate = zynq_clk_get_rate(ddrpll_clk); - u32 clk_ctrl = readl(&slcr_base->ddr_clk_ctrl); - - /* DDR2x */ - clks[ddr2x_clk].reg = &slcr_base->ddr_clk_ctrl; - clks[ddr2x_clk].parent = ddrpll_clk; - clks[ddr2x_clk].name = "ddr_2x"; - clks[ddr2x_clk].frequency = ddr2x_get_rate(&clks[ddr2x_clk]); - clks[ddr2x_clk].ops.get_rate = ddr2x_get_rate; - - /* DDR3x */ - clks[ddr3x_clk].reg = &slcr_base->ddr_clk_ctrl; - clks[ddr3x_clk].parent = ddrpll_clk; - clks[ddr3x_clk].name = "ddr_3x"; - clks[ddr3x_clk].frequency = ddr3x_get_rate(&clks[ddr3x_clk]); - clks[ddr3x_clk].ops.get_rate = ddr3x_get_rate; - - /* DCI */ - clk_ctrl = readl(&slcr_base->dci_clk_ctrl); - div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; - div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT; - clks[dci_clk].reg = &slcr_base->dci_clk_ctrl; - clks[dci_clk].parent = ddrpll_clk; - clks[dci_clk].frequency = DIV_ROUND_CLOSEST( - DIV_ROUND_CLOSEST(prate, div0), div1); - clks[dci_clk].name = "dci"; - - gd->bd->bi_ddr_freq = clks[ddr3x_clk].frequency / 1000000; -} - -static void init_cpu_clocks(void) -{ - int clk_621; - u32 reg, div, srcsel; - enum zynq_clk parent; - - reg = readl(&slcr_base->arm_clk_ctrl); - clk_621 = readl(&slcr_base->clk_621_true) & 1; - div = (reg & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; - srcsel = (reg & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT; - parent = __zynq_clk_cpu_get_parent(srcsel); - - /* cpu clocks */ - clks[cpu_6or4x_clk].reg = &slcr_base->arm_clk_ctrl; - clks[cpu_6or4x_clk].parent = parent; - clks[cpu_6or4x_clk].frequency = DIV_ROUND_CLOSEST( - zynq_clk_get_rate(parent), div); - clks[cpu_6or4x_clk].name = "cpu_6or4x"; - - clks[cpu_3or2x_clk].reg = &slcr_base->arm_clk_ctrl; - clks[cpu_3or2x_clk].parent = cpu_6or4x_clk; - clks[cpu_3or2x_clk].frequency = zynq_clk_get_rate(cpu_6or4x_clk) / 2; - clks[cpu_3or2x_clk].name = "cpu_3or2x"; - - clks[cpu_2x_clk].reg = &slcr_base->arm_clk_ctrl; - clks[cpu_2x_clk].parent = cpu_6or4x_clk; - clks[cpu_2x_clk].frequency = zynq_clk_get_rate(cpu_6or4x_clk) / - (2 + clk_621); - clks[cpu_2x_clk].name = "cpu_2x"; - - clks[cpu_1x_clk].reg = &slcr_base->arm_clk_ctrl; - clks[cpu_1x_clk].parent = cpu_6or4x_clk; - clks[cpu_1x_clk].frequency = zynq_clk_get_rate(cpu_6or4x_clk) / - (4 + 2 * clk_621); - clks[cpu_1x_clk].name = "cpu_1x"; -} - -/** - * periph_calc_two_divs() - Calculate clock dividers - * @cur_rate: Current clock rate - * @tgt_rate: Target clock rate - * @prate: Parent clock rate - * @div0: First divider (output) - * @div1: Second divider (output) - * Returns the actual clock rate possible. - * - * Calculates clock dividers for clocks with two 6-bit dividers. - */ -static unsigned long periph_calc_two_divs(unsigned long cur_rate, - unsigned long tgt_rate, unsigned long prate, u32 *div0, - u32 *div1) -{ - long err, best_err = (long)(~0UL >> 1); - unsigned long rate, best_rate = 0; - u32 d0, d1; - - for (d0 = 1; d0 <= ZYNQ_CLK_MAXDIV; d0++) { - for (d1 = 1; d1 <= ZYNQ_CLK_MAXDIV >> 1; d1++) { - rate = DIV_ROUND_CLOSEST(DIV_ROUND_CLOSEST(prate, d0), - d1); - err = abs(rate - tgt_rate); - - if (err < best_err) { - *div0 = d0; - *div1 = d1; - best_err = err; - best_rate = rate; - } - } - } - - return best_rate; -} - -/** - * zynq_clk_periph_set_rate() - Set clock rate - * @clk: Handle of the peripheral clock - * @rate: New clock rate - * Sets the clock frequency of @clk to @rate. Returns zero on success. - */ -static int zynq_clk_periph_set_rate(struct clk *clk, - unsigned long rate) -{ - u32 ctrl, div0 = 0, div1 = 0; - unsigned long prate, new_rate, cur_rate = clk->frequency; - - ctrl = readl(clk->reg); - prate = zynq_clk_get_rate(clk->parent); - ctrl &= ~CLK_CTRL_DIV0_MASK; - - if (clk->flags & ZYNQ_CLK_FLAGS_HAS_2_DIVS) { - ctrl &= ~CLK_CTRL_DIV1_MASK; - new_rate = periph_calc_two_divs(cur_rate, rate, prate, &div0, - &div1); - ctrl |= div1 << CLK_CTRL_DIV1_SHIFT; - } else { - div0 = DIV_ROUND_CLOSEST(prate, rate); - div0 &= ZYNQ_CLK_MAXDIV; - new_rate = DIV_ROUND_CLOSEST(rate, div0); - } - - /* write new divs to hardware */ - ctrl |= div0 << CLK_CTRL_DIV0_SHIFT; - writel(ctrl, clk->reg); - - /* update frequency in clk framework */ - clk->frequency = new_rate; - - return 0; -} - -/** - * zynq_clk_periph_get_rate() - Get clock rate - * @clk: Handle of the peripheral clock - * Returns the current clock rate of @clk. - */ -static unsigned long zynq_clk_periph_get_rate(struct clk *clk) -{ - u32 clk_ctrl = readl(clk->reg); - u32 div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; - u32 div1 = 1; - - if (clk->flags & ZYNQ_CLK_FLAGS_HAS_2_DIVS) - div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT; - - /* a register value of zero == division by 1 */ - if (!div0) - div0 = 1; - if (!div1) - div1 = 1; - - return - DIV_ROUND_CLOSEST( - DIV_ROUND_CLOSEST(zynq_clk_get_rate(clk->parent), div0), - div1); -} - -/** - * __zynq_clk_periph_get_parent() - Decode clock multiplexer - * @srcsel: Mux select value - * Returns the clock identifier associated with the selected mux input. - */ -static enum zynq_clk __zynq_clk_periph_get_parent(u32 srcsel) -{ - switch (srcsel) { - case ZYNQ_CLKMUX_SEL_0: - case ZYNQ_CLKMUX_SEL_1: - return iopll_clk; - case ZYNQ_CLKMUX_SEL_2: - return armpll_clk; - case ZYNQ_CLKMUX_SEL_3: - return ddrpll_clk; - default: - return 0; - } -} - -/** - * zynq_clk_periph_get_parent() - Decode clock multiplexer - * @clk: Clock handle - * Returns the clock identifier associated with the selected mux input. - */ -static enum zynq_clk zynq_clk_periph_get_parent(struct clk *clk) -{ - u32 clk_ctrl = readl(clk->reg); - u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT; - - return __zynq_clk_periph_get_parent(srcsel); -} - -/** - * zynq_clk_register_periph_clk() - Set up a peripheral clock with the framework - * @clk: Pointer to struct clk for the clock - * @ctrl: Clock control register - * @name: PLL name - * @two_divs: Indicates whether the clock features one or two dividers - */ -static int zynq_clk_register_periph_clk(struct clk *clk, u32 *ctrl, char *name, - bool two_divs) -{ - clk->name = name; - clk->reg = ctrl; - if (two_divs) - clk->flags = ZYNQ_CLK_FLAGS_HAS_2_DIVS; - clk->parent = zynq_clk_periph_get_parent(clk); - clk->frequency = zynq_clk_periph_get_rate(clk); - clk->ops.get_rate = zynq_clk_periph_get_rate; - clk->ops.set_rate = zynq_clk_periph_set_rate; - - return 0; -} - -static void init_periph_clocks(void) -{ - zynq_clk_register_periph_clk(&clks[gem0_clk], &slcr_base->gem0_clk_ctrl, - "gem0", 1); - zynq_clk_register_periph_clk(&clks[gem1_clk], &slcr_base->gem1_clk_ctrl, - "gem1", 1); - - zynq_clk_register_periph_clk(&clks[smc_clk], &slcr_base->smc_clk_ctrl, - "smc", 0); - - zynq_clk_register_periph_clk(&clks[lqspi_clk], - &slcr_base->lqspi_clk_ctrl, "lqspi", 0); - - zynq_clk_register_periph_clk(&clks[sdio0_clk], - &slcr_base->sdio_clk_ctrl, "sdio0", 0); - zynq_clk_register_periph_clk(&clks[sdio1_clk], - &slcr_base->sdio_clk_ctrl, "sdio1", 0); - - zynq_clk_register_periph_clk(&clks[spi0_clk], &slcr_base->spi_clk_ctrl, - "spi0", 0); - zynq_clk_register_periph_clk(&clks[spi1_clk], &slcr_base->spi_clk_ctrl, - "spi1", 0); - - zynq_clk_register_periph_clk(&clks[uart0_clk], - &slcr_base->uart_clk_ctrl, "uart0", 0); - zynq_clk_register_periph_clk(&clks[uart1_clk], - &slcr_base->uart_clk_ctrl, "uart1", 0); - - zynq_clk_register_periph_clk(&clks[dbg_trc_clk], - &slcr_base->dbg_clk_ctrl, "dbg_trc", 0); - zynq_clk_register_periph_clk(&clks[dbg_apb_clk], - &slcr_base->dbg_clk_ctrl, "dbg_apb", 0); - - zynq_clk_register_periph_clk(&clks[pcap_clk], - &slcr_base->pcap_clk_ctrl, "pcap", 0); - - zynq_clk_register_periph_clk(&clks[fclk0_clk], - &slcr_base->fpga0_clk_ctrl, "fclk0", 1); - zynq_clk_register_periph_clk(&clks[fclk1_clk], - &slcr_base->fpga1_clk_ctrl, "fclk1", 1); - zynq_clk_register_periph_clk(&clks[fclk2_clk], - &slcr_base->fpga2_clk_ctrl, "fclk2", 1); - zynq_clk_register_periph_clk(&clks[fclk3_clk], - &slcr_base->fpga3_clk_ctrl, "fclk3", 1); -} - -/** - * zynq_clk_register_aper_clk() - Set up a APER clock with the framework - * @clk: Pointer to struct clk for the clock - * @ctrl: Clock control register - * @name: PLL name - */ -static void zynq_clk_register_aper_clk(struct clk *clk, u32 *ctrl, char *name) -{ - clk->name = name; - clk->reg = ctrl; - clk->parent = cpu_1x_clk; - clk->frequency = zynq_clk_get_rate(clk->parent); -} - -static void init_aper_clocks(void) -{ - zynq_clk_register_aper_clk(&clks[usb0_aper_clk], - &slcr_base->aper_clk_ctrl, "usb0_aper"); - zynq_clk_register_aper_clk(&clks[usb1_aper_clk], - &slcr_base->aper_clk_ctrl, "usb1_aper"); - - zynq_clk_register_aper_clk(&clks[gem0_aper_clk], - &slcr_base->aper_clk_ctrl, "gem0_aper"); - zynq_clk_register_aper_clk(&clks[gem1_aper_clk], - &slcr_base->aper_clk_ctrl, "gem1_aper"); - - zynq_clk_register_aper_clk(&clks[sdio0_aper_clk], - &slcr_base->aper_clk_ctrl, "sdio0_aper"); - zynq_clk_register_aper_clk(&clks[sdio1_aper_clk], - &slcr_base->aper_clk_ctrl, "sdio1_aper"); - - zynq_clk_register_aper_clk(&clks[spi0_aper_clk], - &slcr_base->aper_clk_ctrl, "spi0_aper"); - zynq_clk_register_aper_clk(&clks[spi1_aper_clk], - &slcr_base->aper_clk_ctrl, "spi1_aper"); - - zynq_clk_register_aper_clk(&clks[can0_aper_clk], - &slcr_base->aper_clk_ctrl, "can0_aper"); - zynq_clk_register_aper_clk(&clks[can1_aper_clk], - &slcr_base->aper_clk_ctrl, "can1_aper"); - - zynq_clk_register_aper_clk(&clks[i2c0_aper_clk], - &slcr_base->aper_clk_ctrl, "i2c0_aper"); - zynq_clk_register_aper_clk(&clks[i2c1_aper_clk], - &slcr_base->aper_clk_ctrl, "i2c1_aper"); - - zynq_clk_register_aper_clk(&clks[uart0_aper_clk], - &slcr_base->aper_clk_ctrl, "uart0_aper"); - zynq_clk_register_aper_clk(&clks[uart1_aper_clk], - &slcr_base->aper_clk_ctrl, "uart1_aper"); - - zynq_clk_register_aper_clk(&clks[gpio_aper_clk], - &slcr_base->aper_clk_ctrl, "gpio_aper"); - - zynq_clk_register_aper_clk(&clks[lqspi_aper_clk], - &slcr_base->aper_clk_ctrl, "lqspi_aper"); - - zynq_clk_register_aper_clk(&clks[smc_aper_clk], - &slcr_base->aper_clk_ctrl, "smc_aper"); -} - -/** - * __zynq_clk_pll_get_rate() - Get PLL rate - * @addr: Address of the PLL's control register - * Returns the current PLL output rate. - */ -static unsigned long __zynq_clk_pll_get_rate(u32 *addr) -{ - u32 reg, mul, bypass; - - reg = readl(addr); - bypass = reg & PLLCTRL_BPFORCE_MASK; - if (bypass) - mul = 1; - else - mul = (reg & PLLCTRL_FBDIV_MASK) >> PLLCTRL_FBDIV_SHIFT; - - return CONFIG_ZYNQ_PS_CLK_FREQ * mul; -} - -/** - * zynq_clk_pll_get_rate() - Get PLL rate - * @pll: Handle of the PLL - * Returns the current clock rate of @pll. - */ -static unsigned long zynq_clk_pll_get_rate(struct clk *pll) -{ - return __zynq_clk_pll_get_rate(pll->reg); -} - -/** - * zynq_clk_register_pll() - Set up a PLL with the framework - * @clk: Pointer to struct clk for the PLL - * @ctrl: PLL control register - * @name: PLL name - * @prate: PLL input clock rate - */ -static void zynq_clk_register_pll(struct clk *clk, u32 *ctrl, char *name, - unsigned long prate) -{ - clk->name = name; - clk->reg = ctrl; - clk->frequency = zynq_clk_pll_get_rate(clk); - clk->ops.get_rate = zynq_clk_pll_get_rate; -} - -/** - * clkid_2_register() - Get clock control register - * @id: Clock identifier of one of the PLLs - * Returns the address of the requested PLL's control register. - */ -static u32 *clkid_2_register(enum zynq_clk id) -{ - switch (id) { - case armpll_clk: - return &slcr_base->arm_pll_ctrl; - case ddrpll_clk: - return &slcr_base->ddr_pll_ctrl; - case iopll_clk: - return &slcr_base->io_pll_ctrl; - default: - return &slcr_base->io_pll_ctrl; - } -} - -/* API */ -/** - * zynq_clk_early_init() - Early init for the clock framework - * - * This function is called from before relocation and sets up the CPU clock - * frequency in the global data struct. - */ -void zynq_clk_early_init(void) -{ - u32 reg = readl(&slcr_base->arm_clk_ctrl); - u32 div = (reg & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; - u32 srcsel = (reg & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT; - enum zynq_clk parent = __zynq_clk_cpu_get_parent(srcsel); - u32 *pllreg = clkid_2_register(parent); - unsigned long prate = __zynq_clk_pll_get_rate(pllreg); - - if (!div) - div = 1; - - gd->cpu_clk = DIV_ROUND_CLOSEST(prate, div); -} - -/** - * get_uart_clk() - Get UART input frequency - * @dev_index: UART ID - * Returns UART input clock frequency in Hz. - * - * Compared to zynq_clk_get_rate() this function is designed to work before - * relocation and can be called when the serial UART is set up. - */ -unsigned long get_uart_clk(int dev_index) -{ - u32 reg = readl(&slcr_base->uart_clk_ctrl); - u32 div = (reg & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; - u32 srcsel = (reg & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT; - enum zynq_clk parent = __zynq_clk_periph_get_parent(srcsel); - u32 *pllreg = clkid_2_register(parent); - unsigned long prate = __zynq_clk_pll_get_rate(pllreg); - - if (!div) - div = 1; - - return DIV_ROUND_CLOSEST(prate, div); -} - -/** - * set_cpu_clk_info() - Initialize clock framework - * Always returns zero. - * - * This function is called from common code after relocation and sets up the - * clock framework. The framework must not be used before this function had been - * called. - */ -int set_cpu_clk_info(void) -{ - zynq_clk_register_pll(&clks[armpll_clk], &slcr_base->arm_pll_ctrl, - "armpll", CONFIG_ZYNQ_PS_CLK_FREQ); - zynq_clk_register_pll(&clks[ddrpll_clk], &slcr_base->ddr_pll_ctrl, - "ddrpll", CONFIG_ZYNQ_PS_CLK_FREQ); - zynq_clk_register_pll(&clks[iopll_clk], &slcr_base->io_pll_ctrl, - "iopll", CONFIG_ZYNQ_PS_CLK_FREQ); - - init_ddr_clocks(); - init_cpu_clocks(); - init_periph_clocks(); - init_aper_clocks(); - - gd->bd->bi_arm_freq = gd->cpu_clk / 1000000; - gd->bd->bi_dsp_freq = 0; - - return 0; -} - -/** - * zynq_clk_get_rate() - Get clock rate - * @clk: Clock identifier - * Returns the current clock rate of @clk on success or zero for an invalid - * clock id. - */ -unsigned long zynq_clk_get_rate(enum zynq_clk clk) -{ - if (clk < 0 || clk >= clk_max) - return 0; - - return clks[clk].frequency; -} - -/** - * zynq_clk_set_rate() - Set clock rate - * @clk: Clock identifier - * @rate: Requested clock rate - * Passes on the return value from the clock's set_rate() function or negative - * errno. - */ -int zynq_clk_set_rate(enum zynq_clk clk, unsigned long rate) -{ - if (clk < 0 || clk >= clk_max) - return -ENODEV; - - if (clks[clk].ops.set_rate) - return clks[clk].ops.set_rate(&clks[clk], rate); - - return -ENXIO; -} - -/** - * zynq_clk_get_name() - Get clock name - * @clk: Clock identifier - * Returns the name of @clk. - */ -const char *zynq_clk_get_name(enum zynq_clk clk) -{ - return clks[clk].name; -} - -/** - * soc_clk_dump() - Print clock frequencies - * Returns zero on success - * - * Implementation for the clk dump command. - */ -int soc_clk_dump(void) -{ - int i; - - printf("clk\t\tfrequency\n"); - for (i = 0; i < clk_max; i++) { - const char *name = zynq_clk_get_name(i); - if (name) - printf("%10s%20lu\n", name, zynq_clk_get_rate(i)); - } - - return 0; -} diff --git a/arch/arm/cpu/armv7/zynq/config.mk b/arch/arm/cpu/armv7/zynq/config.mk deleted file mode 100644 index 778a377..0000000 --- a/arch/arm/cpu/armv7/zynq/config.mk +++ /dev/null @@ -1,7 +0,0 @@ -# -# Copyright (C) 2013 - 2015 Xilinx, Inc. All rights reserved. -# -# SPDX-License-Identifier: GPL-2.0 -# -# Allow NEON instructions (needed for lowlevel_init.S with GNU toolchain) -PLATFORM_RELFLAGS += -mfpu=neon diff --git a/arch/arm/cpu/armv7/zynq/cpu.c b/arch/arm/cpu/armv7/zynq/cpu.c deleted file mode 100644 index 914b1fe..0000000 --- a/arch/arm/cpu/armv7/zynq/cpu.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2012 Michal Simek <monstr@monstr.eu> - * Copyright (C) 2012 Xilinx, Inc. All rights reserved. - * - * SPDX-License-Identifier: GPL-2.0+ - */ -#include <common.h> -#include <asm/io.h> -#include <asm/arch/clk.h> -#include <asm/arch/sys_proto.h> -#include <asm/arch/hardware.h> - -#define ZYNQ_SILICON_VER_MASK 0xF0000000 -#define ZYNQ_SILICON_VER_SHIFT 28 - -int arch_cpu_init(void) -{ - zynq_slcr_unlock(); -#ifndef CONFIG_SPL_BUILD - /* Device config APB, unlock the PCAP */ - writel(0x757BDF0D, &devcfg_base->unlock); - writel(0xFFFFFFFF, &devcfg_base->rom_shadow); - -#if (CONFIG_SYS_SDRAM_BASE == 0) - /* remap DDR to zero, FILTERSTART */ - writel(0, &scu_base->filter_start); - - /* OCM_CFG, Mask out the ROM, map ram into upper addresses */ - writel(0x1F, &slcr_base->ocm_cfg); - /* FPGA_RST_CTRL, clear resets on AXI fabric ports */ - writel(0x0, &slcr_base->fpga_rst_ctrl); - /* Set urgent bits with register */ - writel(0x0, &slcr_base->ddr_urgent_sel); - /* Urgent write, ports S2/S3 */ - writel(0xC, &slcr_base->ddr_urgent); -#endif -#endif - zynq_clk_early_init(); - zynq_slcr_lock(); - - return 0; -} - -unsigned int zynq_get_silicon_version(void) -{ - unsigned int ver; - - ver = (readl(&devcfg_base->mctrl) & - ZYNQ_SILICON_VER_MASK) >> ZYNQ_SILICON_VER_SHIFT; - - return ver; -} - -void reset_cpu(ulong addr) -{ - zynq_slcr_cpu_reset(); - while (1) - ; -} - -#ifndef CONFIG_SYS_DCACHE_OFF -void enable_caches(void) -{ - /* Enable D-cache. I-cache is already enabled in start.S */ - dcache_enable(); -} -#endif diff --git a/arch/arm/cpu/armv7/zynq/ddrc.c b/arch/arm/cpu/armv7/zynq/ddrc.c deleted file mode 100644 index 5b20acc..0000000 --- a/arch/arm/cpu/armv7/zynq/ddrc.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2012 - 2013 Michal Simek <monstr@monstr.eu> - * Copyright (C) 2012 - 2013 Xilinx, Inc. All rights reserved. - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <asm/io.h> -#include <asm/arch/sys_proto.h> -#include <asm/arch/hardware.h> - -DECLARE_GLOBAL_DATA_PTR; - -/* Control regsiter bitfield definitions */ -#define ZYNQ_DDRC_CTRLREG_BUSWIDTH_MASK 0xC -#define ZYNQ_DDRC_CTRLREG_BUSWIDTH_SHIFT 2 -#define ZYNQ_DDRC_CTRLREG_BUSWIDTH_16BIT 1 - -/* ECC scrub regsiter definitions */ -#define ZYNQ_DDRC_ECC_SCRUBREG_ECC_MODE_MASK 0x7 -#define ZYNQ_DDRC_ECC_SCRUBREG_ECCMODE_SECDED 0x4 - -void zynq_ddrc_init(void) -{ - u32 width, ecctype; - - width = readl(&ddrc_base->ddrc_ctrl); - width = (width & ZYNQ_DDRC_CTRLREG_BUSWIDTH_MASK) >> - ZYNQ_DDRC_CTRLREG_BUSWIDTH_SHIFT; - ecctype = (readl(&ddrc_base->ecc_scrub) & - ZYNQ_DDRC_ECC_SCRUBREG_ECC_MODE_MASK); - - /* ECC is enabled when memory is in 16bit mode and it is enabled */ - if ((ecctype == ZYNQ_DDRC_ECC_SCRUBREG_ECCMODE_SECDED) && - (width == ZYNQ_DDRC_CTRLREG_BUSWIDTH_16BIT)) { - puts("ECC enabled "); - /* - * Clear the first 1MB because it is not initialized from - * first stage bootloader. To get ECC to work all memory has - * been initialized by writing any value. - */ - /* cppcheck-suppress nullPointer */ - memset((void *)0, 0, 1 * 1024 * 1024); - - gd->ram_size /= 2; - } else { - puts("ECC disabled "); - } -} diff --git a/arch/arm/cpu/armv7/zynq/lowlevel_init.S b/arch/arm/cpu/armv7/zynq/lowlevel_init.S deleted file mode 100644 index 6d714b7..0000000 --- a/arch/arm/cpu/armv7/zynq/lowlevel_init.S +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2013 Xilinx, Inc. All rights reserved. - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <asm-offsets.h> -#include <config.h> -#include <linux/linkage.h> - -ENTRY(lowlevel_init) - - /* Enable the the VFP */ - mrc p15, 0, r1, c1, c0, 2 - orr r1, r1, #(0x3 << 20) - orr r1, r1, #(0x3 << 20) - mcr p15, 0, r1, c1, c0, 2 - isb - fmrx r1, FPEXC - orr r1,r1, #(1<<30) - fmxr FPEXC, r1 - - /* Move back to caller */ - mov pc, lr - -ENDPROC(lowlevel_init) diff --git a/arch/arm/cpu/armv7/zynq/slcr.c b/arch/arm/cpu/armv7/zynq/slcr.c deleted file mode 100644 index 2521589..0000000 --- a/arch/arm/cpu/armv7/zynq/slcr.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (c) 2013 Xilinx Inc. - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <asm/io.h> -#include <malloc.h> -#include <asm/arch/hardware.h> -#include <asm/arch/sys_proto.h> -#include <asm/arch/clk.h> - -#define SLCR_LOCK_MAGIC 0x767B -#define SLCR_UNLOCK_MAGIC 0xDF0D - -#define SLCR_USB_L1_SEL 0x04 - -#define SLCR_IDCODE_MASK 0x1F000 -#define SLCR_IDCODE_SHIFT 12 - -/* - * zynq_slcr_mio_get_status - Get the status of MIO peripheral. - * - * @peri_name: Name of the peripheral for checking MIO status - * @get_pins: Pointer to array of get pin for this peripheral - * @num_pins: Number of pins for this peripheral - * @mask: Mask value - * @check_val: Required check value to get the status of periph - */ -struct zynq_slcr_mio_get_status { - const char *peri_name; - const int *get_pins; - int num_pins; - u32 mask; - u32 check_val; -}; - -static const int usb0_pins[] = { - 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39 -}; - -static const int usb1_pins[] = { - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 -}; - -static const struct zynq_slcr_mio_get_status mio_periphs[] = { - { - "usb0", - usb0_pins, - ARRAY_SIZE(usb0_pins), - SLCR_USB_L1_SEL, - SLCR_USB_L1_SEL, - }, - { - "usb1", - usb1_pins, - ARRAY_SIZE(usb1_pins), - SLCR_USB_L1_SEL, - SLCR_USB_L1_SEL, - }, -}; - -static int slcr_lock = 1; /* 1 means locked, 0 means unlocked */ - -void zynq_slcr_lock(void) -{ - if (!slcr_lock) { - writel(SLCR_LOCK_MAGIC, &slcr_base->slcr_lock); - slcr_lock = 1; - } -} - -void zynq_slcr_unlock(void) -{ - if (slcr_lock) { - writel(SLCR_UNLOCK_MAGIC, &slcr_base->slcr_unlock); - slcr_lock = 0; - } -} - -/* Reset the entire system */ -void zynq_slcr_cpu_reset(void) -{ - /* - * Unlock the SLCR then reset the system. - * Note that this seems to require raw i/o - * functions or there's a lockup? - */ - zynq_slcr_unlock(); - - /* - * Clear 0x0F000000 bits of reboot status register to workaround - * the FSBL not loading the bitstream after soft-reboot - * This is a temporary solution until we know more. - */ - clrbits_le32(&slcr_base->reboot_status, 0xF000000); - - writel(1, &slcr_base->pss_rst_ctrl); -} - -/* Setup clk for network */ -void zynq_slcr_gem_clk_setup(u32 gem_id, unsigned long clk_rate) -{ - int ret; - - zynq_slcr_unlock(); - - if (gem_id > 1) { - printf("Non existing GEM id %d\n", gem_id); - goto out; - } - - ret = zynq_clk_set_rate(gem0_clk + gem_id, clk_rate); - if (ret) - goto out; - - if (gem_id) { - /* Configure GEM_RCLK_CTRL */ - writel(1, &slcr_base->gem1_rclk_ctrl); - } else { - /* Configure GEM_RCLK_CTRL */ - writel(1, &slcr_base->gem0_rclk_ctrl); - } - udelay(100000); -out: - zynq_slcr_lock(); -} - -void zynq_slcr_devcfg_disable(void) -{ - zynq_slcr_unlock(); - - /* Disable AXI interface by asserting FPGA resets */ - writel(0xF, &slcr_base->fpga_rst_ctrl); - - /* Set Level Shifters DT618760 */ - writel(0xA, &slcr_base->lvl_shftr_en); - - zynq_slcr_lock(); -} - -void zynq_slcr_devcfg_enable(void) -{ - zynq_slcr_unlock(); - - /* Set Level Shifters DT618760 */ - writel(0xF, &slcr_base->lvl_shftr_en); - - /* Enable AXI interface by de-asserting FPGA resets */ - writel(0x0, &slcr_base->fpga_rst_ctrl); - - zynq_slcr_lock(); -} - -u32 zynq_slcr_get_boot_mode(void) -{ - /* Get the bootmode register value */ - return readl(&slcr_base->boot_mode); -} - -u32 zynq_slcr_get_idcode(void) -{ - return (readl(&slcr_base->pss_idcode) & SLCR_IDCODE_MASK) >> - SLCR_IDCODE_SHIFT; -} - -/* - * zynq_slcr_get_mio_pin_status - Get the MIO pin status of peripheral. - * - * @periph: Name of the peripheral - * - * Returns count to indicate the number of pins configured for the - * given @periph. - */ -int zynq_slcr_get_mio_pin_status(const char *periph) -{ - const struct zynq_slcr_mio_get_status *mio_ptr; - int val, i, j; - int mio = 0; - - for (i = 0; i < ARRAY_SIZE(mio_periphs); i++) { - if (strcmp(periph, mio_periphs[i].peri_name) == 0) { - mio_ptr = &mio_periphs[i]; - for (j = 0; j < mio_ptr->num_pins; j++) { - val = readl(&slcr_base->mio_pin - [mio_ptr->get_pins[j]]); - if ((val & mio_ptr->mask) == mio_ptr->check_val) - mio++; - } - break; - } - } - - return mio; -} diff --git a/arch/arm/cpu/armv7/zynq/spl.c b/arch/arm/cpu/armv7/zynq/spl.c deleted file mode 100644 index b80c357..0000000 --- a/arch/arm/cpu/armv7/zynq/spl.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * (C) Copyright 2014 Xilinx, Inc. Michal Simek - * - * SPDX-License-Identifier: GPL-2.0+ - */ -#include <common.h> -#include <spl.h> - -#include <asm/io.h> -#include <asm/arch/hardware.h> -#include <asm/spl.h> -#include <asm/arch/sys_proto.h> - -DECLARE_GLOBAL_DATA_PTR; - -void board_init_f(ulong dummy) -{ - ps7_init(); - - /* Clear the BSS. */ - memset(__bss_start, 0, __bss_end - __bss_start); - - preloader_console_init(); - arch_cpu_init(); - board_init_r(NULL, 0); -} - -#ifdef CONFIG_SPL_BOARD_INIT -void spl_board_init(void) -{ - board_init(); -} -#endif - -u32 spl_boot_device(void) -{ - u32 mode; - - switch ((zynq_slcr_get_boot_mode()) & ZYNQ_BM_MASK) { -#ifdef CONFIG_SPL_SPI_SUPPORT - case ZYNQ_BM_QSPI: - puts("qspi boot\n"); - mode = BOOT_DEVICE_SPI; - break; -#endif - case ZYNQ_BM_NAND: - mode = BOOT_DEVICE_NAND; - break; - case ZYNQ_BM_NOR: - mode = BOOT_DEVICE_NOR; - break; -#ifdef CONFIG_SPL_MMC_SUPPORT - case ZYNQ_BM_SD: - puts("mmc boot\n"); - mode = BOOT_DEVICE_MMC1; - break; -#endif - case ZYNQ_BM_JTAG: - mode = BOOT_DEVICE_RAM; - break; - default: - puts("Unsupported boot mode selected\n"); - hang(); - } - - return mode; -} - -#ifdef CONFIG_SPL_MMC_SUPPORT -u32 spl_boot_mode(void) -{ - return MMCSD_MODE_FS; -} -#endif - -#ifdef CONFIG_SPL_OS_BOOT -int spl_start_uboot(void) -{ - /* boot linux */ - return 0; -} -#endif - -__weak void ps7_init(void) -{ - /* - * This function is overridden by the one in - * board/xilinx/zynq/ps7_init.c, if it exists. - */ -} diff --git a/arch/arm/cpu/armv7/zynq/timer.c b/arch/arm/cpu/armv7/zynq/timer.c deleted file mode 100644 index 303dbcf..0000000 --- a/arch/arm/cpu/armv7/zynq/timer.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 2012 Michal Simek <monstr@monstr.eu> - * Copyright (C) 2011-2012 Xilinx, Inc. All rights reserved. - * - * (C) Copyright 2008 - * Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de> - * - * (C) Copyright 2004 - * Philippe Robin, ARM Ltd. <philippe.robin@arm.com> - * - * (C) Copyright 2002-2004 - * Gary Jennejohn, DENX Software Engineering, <gj@denx.de> - * - * (C) Copyright 2003 - * Texas Instruments <www.ti.com> - * - * (C) Copyright 2002 - * Sysgo Real-Time Solutions, GmbH <www.elinos.com> - * Marius Groeger <mgroeger@sysgo.de> - * - * (C) Copyright 2002 - * Sysgo Real-Time Solutions, GmbH <www.elinos.com> - * Alex Zuepke <azu@sysgo.de> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <div64.h> -#include <asm/io.h> -#include <asm/arch/hardware.h> -#include <asm/arch/clk.h> - -DECLARE_GLOBAL_DATA_PTR; - -struct scu_timer { - u32 load; /* Timer Load Register */ - u32 counter; /* Timer Counter Register */ - u32 control; /* Timer Control Register */ -}; - -static struct scu_timer *timer_base = - (struct scu_timer *)ZYNQ_SCUTIMER_BASEADDR; - -#define SCUTIMER_CONTROL_PRESCALER_MASK 0x0000FF00 /* Prescaler */ -#define SCUTIMER_CONTROL_PRESCALER_SHIFT 8 -#define SCUTIMER_CONTROL_AUTO_RELOAD_MASK 0x00000002 /* Auto-reload */ -#define SCUTIMER_CONTROL_ENABLE_MASK 0x00000001 /* Timer enable */ - -#define TIMER_LOAD_VAL 0xFFFFFFFF -#define TIMER_PRESCALE 255 - -int timer_init(void) -{ - const u32 emask = SCUTIMER_CONTROL_AUTO_RELOAD_MASK | - (TIMER_PRESCALE << SCUTIMER_CONTROL_PRESCALER_SHIFT) | - SCUTIMER_CONTROL_ENABLE_MASK; - - gd->arch.timer_rate_hz = (gd->cpu_clk / 2) / (TIMER_PRESCALE + 1); - - /* Load the timer counter register */ - writel(0xFFFFFFFF, &timer_base->load); - - /* - * Start the A9Timer device - * Enable Auto reload mode, Clear prescaler control bits - * Set prescaler value, Enable the decrementer - */ - clrsetbits_le32(&timer_base->control, SCUTIMER_CONTROL_PRESCALER_MASK, - emask); - - /* Reset time */ - gd->arch.lastinc = readl(&timer_base->counter) / - (gd->arch.timer_rate_hz / CONFIG_SYS_HZ); - gd->arch.tbl = 0; - - return 0; -} - -/* - * This function is derived from PowerPC code (read timebase as long long). - * On ARM it just returns the timer value. - */ -ulong get_timer_masked(void) -{ - ulong now; - - now = readl(&timer_base->counter) / - (gd->arch.timer_rate_hz / CONFIG_SYS_HZ); - - if (gd->arch.lastinc >= now) { - /* Normal mode */ - gd->arch.tbl += gd->arch.lastinc - now; - } else { - /* We have an overflow ... */ - gd->arch.tbl += gd->arch.lastinc + TIMER_LOAD_VAL - now + 1; - } - gd->arch.lastinc = now; - - return gd->arch.tbl; -} - -void __udelay(unsigned long usec) -{ - u32 countticks; - u32 timeend; - u32 timediff; - u32 timenow; - - if (usec == 0) - return; - - countticks = lldiv(((unsigned long long)gd->arch.timer_rate_hz * usec), - 1000000); - - /* decrementing timer */ - timeend = readl(&timer_base->counter) - countticks; - -#if TIMER_LOAD_VAL != 0xFFFFFFFF - /* do not manage multiple overflow */ - if (countticks >= TIMER_LOAD_VAL) - countticks = TIMER_LOAD_VAL - 1; -#endif - - do { - timenow = readl(&timer_base->counter); - - if (timenow >= timeend) { - /* normal case */ - timediff = timenow - timeend; - } else { - if ((TIMER_LOAD_VAL - timeend + timenow) <= - countticks) { - /* overflow */ - timediff = TIMER_LOAD_VAL - timeend + timenow; - } else { - /* missed the exact match */ - break; - } - } - } while (timediff > 0); -} - -/* Timer without interrupts */ -ulong get_timer(ulong base) -{ - return get_timer_masked() - base; -} - -/* - * This function is derived from PowerPC code (read timebase as long long). - * On ARM it just returns the timer value. - */ -unsigned long long get_ticks(void) -{ - return get_timer(0); -} - -/* - * 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; -} diff --git a/arch/arm/cpu/armv7/zynq/u-boot-spl.lds b/arch/arm/cpu/armv7/zynq/u-boot-spl.lds deleted file mode 100644 index 0f2f756..0000000 --- a/arch/arm/cpu/armv7/zynq/u-boot-spl.lds +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2014 Xilinx, Inc. Michal Simek - * Copyright (c) 2004-2008 Texas Instruments - * - * (C) Copyright 2002 - * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> - * - * 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("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") -OUTPUT_ARCH(arm) -ENTRY(_start) -SECTIONS -{ - . = ALIGN(4); - .text : - { - __image_copy_start = .; - *(.vectors) - CPUDIR/start.o (.text*) - *(.text*) - } > .sram - - . = ALIGN(4); - .rodata : { - *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) - } > .sram - - . = ALIGN(4); - .data : { - *(.data*) - } > .sram - - . = ALIGN(4); - - . = .; - - __image_copy_end = .; - - _end = .; - - /* Move BSS section to RAM because of FAT */ - .bss (NOLOAD) : { - __bss_start = .; - *(.bss*) - . = ALIGN(4); - __bss_end = .; - } > .sdram - - /DISCARD/ : { *(.dynsym) } - /DISCARD/ : { *(.dynstr*) } - /DISCARD/ : { *(.dynamic*) } - /DISCARD/ : { *(.plt*) } - /DISCARD/ : { *(.interp*) } - /DISCARD/ : { *(.gnu*) } -} diff --git a/arch/arm/cpu/armv7/zynq/u-boot.lds b/arch/arm/cpu/armv7/zynq/u-boot.lds deleted file mode 100644 index 4dc9bb0..0000000 --- a/arch/arm/cpu/armv7/zynq/u-boot.lds +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2004-2008 Texas Instruments - * - * (C) Copyright 2002 - * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") -OUTPUT_ARCH(arm) -ENTRY(_start) -SECTIONS -{ - . = 0x00000000; - - . = ALIGN(4); - .text : - { - *(.__image_copy_start) - *(.vectors) - CPUDIR/start.o (.text*) - *(.text*) - } - - . = ALIGN(4); - .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } - - . = ALIGN(4); - .data : { - *(.data*) - } - - . = ALIGN(4); - - . = .; - - . = ALIGN(4); - .u_boot_list : { - KEEP(*(SORT(.u_boot_list*))); - } - - . = ALIGN(4); - - .image_copy_end : - { - *(.__image_copy_end) - } - - .rel_dyn_start : - { - *(.__rel_dyn_start) - } - - .rel.dyn : { - *(.rel*) - } - - .rel_dyn_end : - { - *(.__rel_dyn_end) - } - - .end : - { - *(.__end) - } - - _image_binary_end = .; - -/* - * Compiler-generated __bss_start and __bss_end, see arch/arm/lib/bss.c - * __bss_base and __bss_limit are for linker only (overlay ordering) - */ - - .bss_start __rel_dyn_start (OVERLAY) : { - KEEP(*(.__bss_start)); - __bss_base = .; - } - - .bss __bss_base (OVERLAY) : { - *(.bss*) - . = ALIGN(4); - __bss_limit = .; - } - - .bss_end __bss_limit (OVERLAY) : { - KEEP(*(.__bss_end)); - } - - /* - * Zynq needs to discard these sections because the user - * is expected to pass this image on to tools for boot.bin - * generation that require them to be dropped. - */ - /DISCARD/ : { *(.dynsym) } - /DISCARD/ : { *(.dynbss*) } - /DISCARD/ : { *(.dynstr*) } - /DISCARD/ : { *(.dynamic*) } - /DISCARD/ : { *(.plt*) } - /DISCARD/ : { *(.interp*) } - /DISCARD/ : { *(.gnu*) } - /DISCARD/ : { *(.ARM.exidx*) } - /DISCARD/ : { *(.gnu.linkonce.armexidx.*) } -} 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*) } +} diff --git a/arch/arm/cpu/armv8/zynqmp/Makefile b/arch/arm/cpu/armv8/zynqmp/Makefile index a997e04..efab5ea 100644 --- a/arch/arm/cpu/armv8/zynqmp/Makefile +++ b/arch/arm/cpu/armv8/zynqmp/Makefile @@ -7,3 +7,4 @@ obj-y += clk.o obj-y += cpu.o +obj-$(CONFIG_MP) += mp.o diff --git a/arch/arm/cpu/armv8/zynqmp/clk.c b/arch/arm/cpu/armv8/zynqmp/clk.c index 0af619d..9218586 100644 --- a/arch/arm/cpu/armv8/zynqmp/clk.c +++ b/arch/arm/cpu/armv8/zynqmp/clk.c @@ -6,6 +6,7 @@ */ #include <common.h> +#include <asm/arch/clk.h> #include <asm/arch/hardware.h> #include <asm/arch/sys_proto.h> @@ -16,6 +17,8 @@ unsigned long get_uart_clk(int dev_id) u32 ver = zynqmp_get_silicon_version(); switch (ver) { + case ZYNQMP_CSU_VERSION_VELOCE: + return 48000; case ZYNQMP_CSU_VERSION_EP108: return 25000000; } diff --git a/arch/arm/cpu/armv8/zynqmp/cpu.c b/arch/arm/cpu/armv8/zynqmp/cpu.c index 6fae03c..60d7d20 100644 --- a/arch/arm/cpu/armv8/zynqmp/cpu.c +++ b/arch/arm/cpu/armv8/zynqmp/cpu.c @@ -20,9 +20,175 @@ unsigned int zynqmp_get_silicon_version(void) gd->cpu_clk = get_tbclk(); switch (gd->cpu_clk) { + case 0 ... 1000000: + return ZYNQMP_CSU_VERSION_VELOCE; case 50000000: return ZYNQMP_CSU_VERSION_QEMU; } return ZYNQMP_CSU_VERSION_EP108; } + +#ifndef CONFIG_SYS_DCACHE_OFF +#include <asm/armv8/mmu.h> + +#define SECTION_SHIFT_L1 30UL +#define SECTION_SHIFT_L2 21UL +#define BLOCK_SIZE_L0 0x8000000000UL +#define BLOCK_SIZE_L1 (1 << SECTION_SHIFT_L1) +#define BLOCK_SIZE_L2 (1 << SECTION_SHIFT_L2) + +#define TCR_TG1_4K (1 << 31) +#define TCR_EPD1_DISABLE (1 << 23) +#define ZYNQMO_VA_BITS 40 +#define ZYNQMP_TCR TCR_TG1_4K | \ + TCR_EPD1_DISABLE | \ + TCR_SHARED_OUTER | \ + TCR_SHARED_INNER | \ + TCR_IRGN_WBWA | \ + TCR_ORGN_WBWA | \ + TCR_T0SZ(ZYNQMO_VA_BITS) + +#define MEMORY_ATTR PMD_SECT_AF | PMD_SECT_INNER_SHARE | \ + PMD_ATTRINDX(MT_NORMAL) | \ + PMD_TYPE_SECT +#define DEVICE_ATTR PMD_SECT_AF | PMD_SECT_PXN | \ + PMD_SECT_UXN | PMD_ATTRINDX(MT_DEVICE_NGNRNE) | \ + PMD_TYPE_SECT + +/* 4K size is required to place 512 entries in each level */ +#define TLB_TABLE_SIZE 0x1000 + +struct attr_tbl { + u32 num; + u64 attr; +}; + +static struct attr_tbl attr_tbll1t0[4] = { {16, 0x0}, + {8, DEVICE_ATTR}, + {32, MEMORY_ATTR}, + {456, DEVICE_ATTR} + }; +static struct attr_tbl attr_tbll2t3[4] = { {0x180, DEVICE_ATTR}, + {0x40, 0x0}, + {0x3F, DEVICE_ATTR}, + {0x1, MEMORY_ATTR} + }; + +/* + * This mmu table looks as below + * Level 0 table contains two entries to 512GB sizes. One is Level1 Table 0 + * and other Level1 Table1. + * Level1 Table0 contains entries for each 1GB from 0 to 511GB. + * Level1 Table1 contains entries for each 1GB from 512GB to 1TB. + * Level2 Table0, Level2 Table1, Level2 Table2 and Level2 Table3 contains + * entries for each 2MB starting from 0GB, 1GB, 2GB and 3GB respectively. + */ +static void zynqmp_mmu_setup(void) +{ + int el; + u32 index_attr; + u64 i, section_l1t0, section_l1t1; + u64 section_l2t0, section_l2t1, section_l2t2, section_l2t3; + u64 *level0_table = (u64 *)gd->arch.tlb_addr; + u64 *level1_table_0 = (u64 *)(gd->arch.tlb_addr + TLB_TABLE_SIZE); + u64 *level1_table_1 = (u64 *)(gd->arch.tlb_addr + (2 * TLB_TABLE_SIZE)); + u64 *level2_table_0 = (u64 *)(gd->arch.tlb_addr + (3 * TLB_TABLE_SIZE)); + u64 *level2_table_1 = (u64 *)(gd->arch.tlb_addr + (4 * TLB_TABLE_SIZE)); + u64 *level2_table_2 = (u64 *)(gd->arch.tlb_addr + (5 * TLB_TABLE_SIZE)); + u64 *level2_table_3 = (u64 *)(gd->arch.tlb_addr + (6 * TLB_TABLE_SIZE)); + + level0_table[0] = + (u64)level1_table_0 | PMD_TYPE_TABLE; + level0_table[1] = + (u64)level1_table_1 | PMD_TYPE_TABLE; + + /* + * set level 1 table 0, covering 0 to 512GB + * set level 1 table 1, covering 512GB to 1TB + */ + section_l1t0 = 0; + section_l1t1 = BLOCK_SIZE_L0; + + index_attr = 0; + for (i = 0; i < 512; i++) { + level1_table_0[i] = section_l1t0; + level1_table_0[i] |= attr_tbll1t0[index_attr].attr; + attr_tbll1t0[index_attr].num--; + if (attr_tbll1t0[index_attr].num == 0) + index_attr++; + level1_table_1[i] = section_l1t1; + level1_table_1[i] |= DEVICE_ATTR; + section_l1t0 += BLOCK_SIZE_L1; + section_l1t1 += BLOCK_SIZE_L1; + } + + level1_table_0[0] = + (u64)level2_table_0 | PMD_TYPE_TABLE; + level1_table_0[1] = + (u64)level2_table_1 | PMD_TYPE_TABLE; + level1_table_0[2] = + (u64)level2_table_2 | PMD_TYPE_TABLE; + level1_table_0[3] = + (u64)level2_table_3 | PMD_TYPE_TABLE; + + section_l2t0 = 0; + section_l2t1 = section_l2t0 + BLOCK_SIZE_L1; /* 1GB */ + section_l2t2 = section_l2t1 + BLOCK_SIZE_L1; /* 2GB */ + section_l2t3 = section_l2t2 + BLOCK_SIZE_L1; /* 3GB */ + + index_attr = 0; + + for (i = 0; i < 512; i++) { + level2_table_0[i] = section_l2t0 | MEMORY_ATTR; + level2_table_1[i] = section_l2t1 | MEMORY_ATTR; + level2_table_2[i] = section_l2t2 | DEVICE_ATTR; + level2_table_3[i] = section_l2t3 | + attr_tbll2t3[index_attr].attr; + attr_tbll2t3[index_attr].num--; + if (attr_tbll2t3[index_attr].num == 0) + index_attr++; + section_l2t0 += BLOCK_SIZE_L2; + section_l2t1 += BLOCK_SIZE_L2; + section_l2t2 += BLOCK_SIZE_L2; + section_l2t3 += BLOCK_SIZE_L2; + } + + /* flush new MMU table */ + flush_dcache_range(gd->arch.tlb_addr, + gd->arch.tlb_addr + gd->arch.tlb_size); + + /* point TTBR to the new table */ + el = current_el(); + set_ttbr_tcr_mair(el, gd->arch.tlb_addr, + ZYNQMP_TCR, MEMORY_ATTRIBUTES); + + set_sctlr(get_sctlr() | CR_M); +} + +int arch_cpu_init(void) +{ + icache_enable(); + __asm_invalidate_dcache_all(); + __asm_invalidate_tlb_all(); + return 0; +} + +/* + * This function is called from lib/board.c. + * It recreates MMU table in main memory. MMU and d-cache are enabled earlier. + * There is no need to disable d-cache for this operation. + */ +void enable_caches(void) +{ + /* The data cache is not active unless the mmu is enabled */ + if (!(get_sctlr() & CR_M)) { + invalidate_dcache_all(); + __asm_invalidate_tlb_all(); + zynqmp_mmu_setup(); + } + puts("Enabling Caches...\n"); + + set_sctlr(get_sctlr() | CR_C); +} +#endif diff --git a/arch/arm/cpu/armv8/zynqmp/mp.c b/arch/arm/cpu/armv8/zynqmp/mp.c new file mode 100644 index 0000000..17e32a7 --- /dev/null +++ b/arch/arm/cpu/armv8/zynqmp/mp.c @@ -0,0 +1,242 @@ +/* + * (C) Copyright 2014 - 2015 Xilinx, Inc. + * Michal Simek <michal.simek@xilinx.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/hardware.h> +#include <asm/arch/sys_proto.h> +#include <asm/io.h> + +#define LOCK 0 +#define SPLIT 1 + +#define HALT 0 +#define RELEASE 1 + +#define ZYNQMP_BOOTADDR_HIGH_MASK 0xFFFFFFFF +#define ZYNQMP_R5_HIVEC_ADDR 0xFFFF0000 +#define ZYNQMP_R5_LOVEC_ADDR 0x0 +#define ZYNQMP_RPU_CFG_CPU_HALT_MASK 0x01 +#define ZYNQMP_RPU_CFG_HIVEC_MASK 0x04 +#define ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK 0x08 +#define ZYNQMP_RPU_GLBL_CTRL_TCM_COMB_MASK 0x40 +#define ZYNQMP_RPU_GLBL_CTRL_SLCLAMP_MASK 0x10 + +#define ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK 0x04 +#define ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK 0x01 +#define ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK 0x02 +#define ZYNQMP_CRLAPB_CPU_R5_CTRL_CLKACT_MASK 0x1000000 + +#define ZYNQMP_TCM_START_ADDRESS 0xFFE00000 +#define ZYNQMP_TCM_BOTH_SIZE 0x40000 + +#define ZYNQMP_CORE_APU0 0 +#define ZYNQMP_CORE_APU3 3 + +#define ZYNQMP_MAX_CORES 6 + +int is_core_valid(unsigned int core) +{ + if (core < ZYNQMP_MAX_CORES) + return 1; + + return 0; +} + +int cpu_reset(int nr) +{ + puts("Feature is not implemented.\n"); + return 0; +} + +static void set_r5_halt_mode(u8 halt, u8 mode) +{ + u32 tmp; + + tmp = readl(&rpu_base->rpu0_cfg); + if (halt == HALT) + tmp &= ~ZYNQMP_RPU_CFG_CPU_HALT_MASK; + else + tmp |= ZYNQMP_RPU_CFG_CPU_HALT_MASK; + writel(tmp, &rpu_base->rpu0_cfg); + + if (mode == LOCK) { + tmp = readl(&rpu_base->rpu1_cfg); + if (halt == HALT) + tmp &= ~ZYNQMP_RPU_CFG_CPU_HALT_MASK; + else + tmp |= ZYNQMP_RPU_CFG_CPU_HALT_MASK; + writel(tmp, &rpu_base->rpu1_cfg); + } +} + +static void set_r5_tcm_mode(u8 mode) +{ + u32 tmp; + + tmp = readl(&rpu_base->rpu_glbl_ctrl); + if (mode == LOCK) { + tmp &= ~ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK; + tmp |= ZYNQMP_RPU_GLBL_CTRL_TCM_COMB_MASK | + ZYNQMP_RPU_GLBL_CTRL_SLCLAMP_MASK; + } else { + tmp |= ZYNQMP_RPU_GLBL_CTRL_SPLIT_LOCK_MASK; + tmp &= ~(ZYNQMP_RPU_GLBL_CTRL_TCM_COMB_MASK | + ZYNQMP_RPU_GLBL_CTRL_SLCLAMP_MASK); + } + + writel(tmp, &rpu_base->rpu_glbl_ctrl); +} + +static void set_r5_reset(u8 mode) +{ + u32 tmp; + + tmp = readl(&crlapb_base->rst_lpd_top); + tmp |= (ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK | + ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK); + + if (mode == LOCK) + tmp |= ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK; + + writel(tmp, &crlapb_base->rst_lpd_top); +} + +static void release_r5_reset(u8 mode) +{ + u32 tmp; + + tmp = readl(&crlapb_base->rst_lpd_top); + tmp &= ~(ZYNQMP_CRLAPB_RST_LPD_AMBA_RST_MASK | + ZYNQMP_CRLAPB_RST_LPD_R50_RST_MASK); + + if (mode == LOCK) + tmp &= ~ZYNQMP_CRLAPB_RST_LPD_R51_RST_MASK; + + writel(tmp, &crlapb_base->rst_lpd_top); +} + +static void enable_clock_r5(void) +{ + u32 tmp; + + tmp = readl(&crlapb_base->cpu_r5_ctrl); + tmp |= ZYNQMP_CRLAPB_CPU_R5_CTRL_CLKACT_MASK; + writel(tmp, &crlapb_base->cpu_r5_ctrl); + + /* Give some delay for clock + * to propogate */ + udelay(0x500); +} + +int cpu_disable(int nr) +{ + if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) { + u32 val = readl(&crfapb_base->rst_fpd_apu); + val |= 1 << nr; + writel(val, &crfapb_base->rst_fpd_apu); + } else { + set_r5_reset(LOCK); + } + + return 0; +} + +int cpu_status(int nr) +{ + if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) { + u32 addr_low = readl(((u8 *)&apu_base->rvbar_addr0_l) + nr * 8); + u32 addr_high = readl(((u8 *)&apu_base->rvbar_addr0_h) + + nr * 8); + u32 val = readl(&crfapb_base->rst_fpd_apu); + val &= 1 << nr; + printf("APU CPU%d %s - starting address HI: %x, LOW: %x\n", + nr, val ? "OFF" : "ON" , addr_high, addr_low); + } else { + u32 val = readl(&crlapb_base->rst_lpd_top); + val &= 1 << (nr - 4); + printf("RPU CPU%d %s\n", nr - 4, val ? "OFF" : "ON"); + } + + return 0; +} + +static void set_r5_start(u8 high) +{ + u32 tmp; + + tmp = readl(&rpu_base->rpu0_cfg); + if (high) + tmp |= ZYNQMP_RPU_CFG_HIVEC_MASK; + else + tmp &= ~ZYNQMP_RPU_CFG_HIVEC_MASK; + writel(tmp, &rpu_base->rpu0_cfg); + + tmp = readl(&rpu_base->rpu1_cfg); + if (high) + tmp |= ZYNQMP_RPU_CFG_HIVEC_MASK; + else + tmp &= ~ZYNQMP_RPU_CFG_HIVEC_MASK; + writel(tmp, &rpu_base->rpu1_cfg); +} + +int cpu_release(int nr, int argc, char * const argv[]) +{ + if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) { + u64 boot_addr = simple_strtoull(argv[0], NULL, 16); + /* HIGH */ + writel((u32)(boot_addr >> 32), + ((u8 *)&apu_base->rvbar_addr0_h) + nr * 8); + /* LOW */ + writel((u32)(boot_addr & ZYNQMP_BOOTADDR_HIGH_MASK), + ((u8 *)&apu_base->rvbar_addr0_l) + nr * 8); + + u32 val = readl(&crfapb_base->rst_fpd_apu); + val &= ~(1 << nr); + writel(val, &crfapb_base->rst_fpd_apu); + } else { + if (argc != 2) { + printf("Invalid number of arguments to release.\n"); + printf("<addr> <mode>-Start addr lockstep or split\n"); + return 1; + } + + u32 boot_addr = simple_strtoul(argv[0], NULL, 16); + if (!(boot_addr == ZYNQMP_R5_LOVEC_ADDR || + boot_addr == ZYNQMP_R5_HIVEC_ADDR)) { + printf("Invalid starting address 0x%x\n", boot_addr); + printf("0 or 0xffff0000 are permitted\n"); + return 1; + } + + if (!strncmp(argv[1], "lockstep", 8)) { + printf("R5 lockstep mode\n"); + set_r5_tcm_mode(LOCK); + set_r5_halt_mode(HALT, LOCK); + + if (boot_addr == 0) + set_r5_start(0); + else + set_r5_start(1); + + enable_clock_r5(); + release_r5_reset(LOCK); + set_r5_halt_mode(RELEASE, LOCK); + } else if (!strncmp(argv[1], "split", 5)) { + printf("R5 split mode\n"); + set_r5_tcm_mode(SPLIT); + set_r5_halt_mode(HALT, SPLIT); + enable_clock_r5(); + release_r5_reset(SPLIT); + set_r5_halt_mode(RELEASE, SPLIT); + } else { + printf("Unsupported mode\n"); + return 1; + } + } + + return 0; +} |