summaryrefslogtreecommitdiff
path: root/arch/arm/cpu
diff options
context:
space:
mode:
authorStefano Babic <sbabic@denx.de>2014-07-16 08:51:30 +0200
committerStefano Babic <sbabic@denx.de>2014-07-16 08:51:30 +0200
commitdab5e3469d294a4e1ffed8407d296a78e02cc01f (patch)
treec6378034591210b3142ca3add806d52c6ea22b3b /arch/arm/cpu
parent14a1613140519a8d0a88e6054c302a8cb3e067a5 (diff)
parent524123a70761110c5cf3ccc5f52f6d4da071b959 (diff)
downloadu-boot-imx-dab5e3469d294a4e1ffed8407d296a78e02cc01f.zip
u-boot-imx-dab5e3469d294a4e1ffed8407d296a78e02cc01f.tar.gz
u-boot-imx-dab5e3469d294a4e1ffed8407d296a78e02cc01f.tar.bz2
Merge branch 'master' of git://git.denx.de/u-boot
Signed-off-by: Stefano Babic <sbabic@denx.de> Conflicts: boards.cfg
Diffstat (limited to 'arch/arm/cpu')
-rw-r--r--arch/arm/cpu/arm920t/ep93xx/lowlevel_init.S463
-rw-r--r--arch/arm/cpu/arm926ejs/at91/at91sam9m10g45_devices.c17
-rw-r--r--arch/arm/cpu/arm926ejs/davinci/da850_lowlevel.c2
-rw-r--r--arch/arm/cpu/arm926ejs/davinci/dm365_lowlevel.c1
-rw-r--r--arch/arm/cpu/arm926ejs/kirkwood/cpu.c3
-rw-r--r--arch/arm/cpu/arm926ejs/orion5x/cpu.c1
-rw-r--r--arch/arm/cpu/armv7/am33xx/board.c28
-rw-r--r--arch/arm/cpu/armv7/am33xx/clock.c11
-rw-r--r--arch/arm/cpu/armv7/am33xx/clock_am43xx.c9
-rw-r--r--arch/arm/cpu/armv7/am33xx/ddr.c13
-rw-r--r--arch/arm/cpu/armv7/am33xx/emif4.c6
-rw-r--r--arch/arm/cpu/armv7/at91/config.mk10
-rw-r--r--arch/arm/cpu/armv7/at91/cpu.c2
-rw-r--r--arch/arm/cpu/armv7/cache_v7.c45
-rw-r--r--arch/arm/cpu/armv7/exynos/clock.c45
-rw-r--r--arch/arm/cpu/armv7/exynos/dmc_common.c2
-rw-r--r--arch/arm/cpu/armv7/exynos/dmc_init_ddr3.c369
-rw-r--r--arch/arm/cpu/armv7/exynos/exynos5_setup.h21
-rw-r--r--arch/arm/cpu/armv7/exynos/lowlevel_init.c6
-rw-r--r--arch/arm/cpu/armv7/exynos/pinmux.c35
-rw-r--r--arch/arm/cpu/armv7/exynos/power.c6
-rw-r--r--arch/arm/cpu/armv7/exynos/spl_boot.c4
-rw-r--r--arch/arm/cpu/armv7/keystone/Makefile1
-rw-r--r--arch/arm/cpu/armv7/keystone/aemif.c71
-rw-r--r--arch/arm/cpu/armv7/keystone/init.c9
-rw-r--r--arch/arm/cpu/armv7/omap-common/Makefile4
-rw-r--r--arch/arm/cpu/armv7/omap-common/hwinit-common.c42
-rw-r--r--arch/arm/cpu/armv7/omap-common/mem-common.c6
-rw-r--r--arch/arm/cpu/armv7/omap-common/omap-cache.c56
-rw-r--r--arch/arm/cpu/armv7/omap3/board.c12
-rw-r--r--arch/arm/cpu/armv7/omap3/mem.c12
-rw-r--r--arch/arm/cpu/armv7/socfpga/Makefile2
-rw-r--r--arch/arm/cpu/armv7/socfpga/misc.c24
-rw-r--r--arch/arm/cpu/armv7/socfpga/scan_manager.c209
-rw-r--r--arch/arm/cpu/armv7/socfpga/spl.c4
-rw-r--r--arch/arm/cpu/armv7/tegra20/display.c2
-rw-r--r--arch/arm/cpu/armv7/zynq/u-boot.lds1
-rw-r--r--arch/arm/cpu/armv8/cache_v8.c57
-rw-r--r--arch/arm/cpu/armv8/fsl-lsch3/Makefile9
-rw-r--r--arch/arm/cpu/armv8/fsl-lsch3/README10
-rw-r--r--arch/arm/cpu/armv8/fsl-lsch3/cpu.c436
-rw-r--r--arch/arm/cpu/armv8/fsl-lsch3/cpu.h7
-rw-r--r--arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S65
-rw-r--r--arch/arm/cpu/armv8/fsl-lsch3/speed.c176
-rw-r--r--arch/arm/cpu/armv8/fsl-lsch3/speed.h7
-rw-r--r--arch/arm/cpu/armv8/transition.S2
-rw-r--r--arch/arm/cpu/at91-common/spl.c39
47 files changed, 1971 insertions, 391 deletions
diff --git a/arch/arm/cpu/arm920t/ep93xx/lowlevel_init.S b/arch/arm/cpu/arm920t/ep93xx/lowlevel_init.S
index bf2fa2a..cfad206 100644
--- a/arch/arm/cpu/arm920t/ep93xx/lowlevel_init.S
+++ b/arch/arm/cpu/arm920t/ep93xx/lowlevel_init.S
@@ -2,48 +2,457 @@
* Low-level initialization for EP93xx
*
* Copyright (C) 2009 Matthias Kaehlcke <matthias@kaehlcke.net>
+ * Copyright (C) 2013
+ * Sergey Kostanabev <sergey.kostanbaev <at> fairwaves.ru>
*
* Copyright (C) 2006 Dominic Rath <Dominic.Rath@gmx.de>
+ * Copyright (C) 2006 Cirrus Logic Inc.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
*
* SPDX-License-Identifier: GPL-2.0+
*/
-#include <version.h>
-#include <asm/arch/ep93xx.h>
+#include <config.h>
+#include <asm/arch-ep93xx/ep93xx.h>
+
+/*
+/* Configure the SDRAM based on the supplied settings.
+ *
+ * Input: r0 - SDRAM DEVCFG register
+ * r2 - configuration for SDRAM chips
+ * Output: none
+ * Modifies: r3, r4
+ */
+ep93xx_sdram_config:
+ /* Program the SDRAM device configuration register. */
+ ldr r3, =SDRAM_BASE
+#ifdef CONFIG_EDB93XX_SDCS0
+ str r0, [r3, #SDRAM_OFF_DEVCFG0]
+#endif
+#ifdef CONFIG_EDB93XX_SDCS1
+ str r0, [r3, #SDRAM_OFF_DEVCFG1]
+#endif
+#ifdef CONFIG_EDB93XX_SDCS2
+ str r0, [r3, #SDRAM_OFF_DEVCFG2]
+#endif
+#ifdef CONFIG_EDB93XX_SDCS3
+ str r0, [r3, #SDRAM_OFF_DEVCFG3]
+#endif
+
+ /* Set the Initialize and MRS bits (issue continuous NOP commands
+ * (INIT & MRS set))
+ */
+ ldr r4, =(EP93XX_SDRAMCTRL_GLOBALCFG_INIT | \
+ EP93XX_SDRAMCTRL_GLOBALCFG_MRS | \
+ EP93XX_SDRAMCTRL_GLOBALCFG_CKE)
+ str r4, [r3, #SDRAM_OFF_GLCONFIG]
+
+ /* Delay for 200us. */
+ mov r4, #0x3000
+delay1:
+ subs r4, r4, #1
+ bne delay1
+
+ /* Clear the MRS bit to issue a precharge all. */
+ ldr r4, =(EP93XX_SDRAMCTRL_GLOBALCFG_INIT | \
+ EP93XX_SDRAMCTRL_GLOBALCFG_CKE)
+ str r4, [r3, #SDRAM_OFF_GLCONFIG]
+
+ /* Temporarily set the refresh timer to 0x10. Make it really low so
+ * that refresh cycles are generated.
+ */
+ ldr r4, =0x10
+ str r4, [r3, #SDRAM_OFF_REFRSHTIMR]
+
+ /* Delay for at least 80 SDRAM clock cycles. */
+ mov r4, #80
+delay2:
+ subs r4, r4, #1
+ bne delay2
+
+ /* Set the refresh timer to the fastest required for any device
+ * that might be used. Set 9.6 ms refresh time.
+ */
+ ldr r4, =0x01e0
+ str r4, [r3, #SDRAM_OFF_REFRSHTIMR]
+
+ /* Select mode register update mode. */
+ ldr r4, =(EP93XX_SDRAMCTRL_GLOBALCFG_CKE | \
+ EP93XX_SDRAMCTRL_GLOBALCFG_MRS)
+ str r4, [r3, #SDRAM_OFF_GLCONFIG]
+
+ /* Program the mode register on the SDRAM by performing fake read */
+ ldr r4, [r2]
+
+ /* Select normal operating mode. */
+ ldr r4, =EP93XX_SDRAMCTRL_GLOBALCFG_CKE
+ str r4, [r3, #SDRAM_OFF_GLCONFIG]
+
+ /* Return to the caller. */
+ mov pc, lr
+
+/*
+ * Test to see if the SDRAM has been configured in a usable mode.
+ *
+ * Input: r0 - Test address of SDRAM
+ * Output: r0 - 0 -- Test OK, -1 -- Failed
+ * Modifies: r0-r5
+ */
+ep93xx_sdram_test:
+ /* Load the test patterns to be written to SDRAM. */
+ ldr r1, =0xf00dface
+ ldr r2, =0xdeadbeef
+ ldr r3, =0x08675309
+ ldr r4, =0xdeafc0ed
+
+ /* Store the test patterns to SDRAM. */
+ stmia r0, {r1-r4}
+
+ /* Load the test patterns from SDRAM one at a time and compare them
+ * to the actual pattern.
+ */
+ ldr r5, [r0]
+ cmp r5, r1
+ ldreq r5, [r0, #0x0004]
+ cmpeq r5, r2
+ ldreq r5, [r0, #0x0008]
+ cmpeq r5, r3
+ ldreq r5, [r0, #0x000c]
+ cmpeq r5, r4
+
+ /* Return -1 if a mismatch was encountered, 0 otherwise. */
+ mvnne r0, #0xffffffff
+ moveq r0, #0x00000000
+
+ /* Return to the caller. */
+ mov pc, lr
+
+/*
+ * Determine the size of the SDRAM. Use data=address for the scan.
+ *
+ * Input: r0 - Start SDRAM address
+ * Return: r0 - Single block size
+ * r1 - Valid block mask
+ * r2 - Total block count
+ * Modifies: r0-r5
+ */
+ep93xx_sdram_size:
+ /* Store zero at offset zero. */
+ str r0, [r0]
+
+ /* Start checking for an alias at 1MB into SDRAM. */
+ ldr r1, =0x00100000
+
+ /* Store the offset at the current offset. */
+check_block_size:
+ str r1, [r0, r1]
+
+ /* Read back from zero. */
+ ldr r2, [r0]
+
+ /* Stop searching of an alias was found. */
+ cmp r1, r2
+ beq found_block_size
+
+ /* Advance to the next power of two boundary. */
+ mov r1, r1, lsl #1
+
+ /* Loop back if the size has not reached 256MB. */
+ cmp r1, #0x10000000
+ bne check_block_size
+
+ /* A full 256MB of memory was found, so return it now. */
+ ldr r0, =0x10000000
+ ldr r1, =0x00000000
+ ldr r2, =0x00000001
+ mov pc, lr
+
+ /* An alias was found. See if the first block is 128MB in size. */
+found_block_size:
+ cmp r1, #0x08000000
+
+ /* The first block is 128MB, so there is no further memory. Return it
+ * now.
+ */
+ ldreq r0, =0x08000000
+ ldreq r1, =0x00000000
+ ldreq r2, =0x00000001
+ moveq pc, lr
+
+ /* Save the block size, set the block address bits to zero, and
+ * initialize the block count to one.
+ */
+ mov r3, r1
+ ldr r4, =0x00000000
+ ldr r5, =0x00000001
+
+ /* Look for additional blocks of memory by searching for non-aliases. */
+find_blocks:
+ /* Store zero back to address zero. It may be overwritten. */
+ str r0, [r0]
+
+ /* Advance to the next power of two boundary. */
+ mov r1, r1, lsl #1
+
+ /* Store the offset at the current offset. */
+ str r1, [r0, r1]
+
+ /* Read back from zero. */
+ ldr r2, [r0]
+
+ /* See if a non-alias was found. */
+ cmp r1, r2
+
+ /* If a non-alias was found, then or in the block address bit and
+ * multiply the block count by two (since there are two unique
+ * blocks, one with this bit zero and one with it one).
+ */
+ orrne r4, r4, r1
+ movne r5, r5, lsl #1
+
+ /* Continue searching if there are more address bits to check. */
+ cmp r1, #0x08000000
+ bne find_blocks
+
+ /* Return the block size, address mask, and count. */
+ mov r0, r3
+ mov r1, r4
+ mov r2, r5
+
+ /* Return to the caller. */
+ mov pc, lr
+
.globl lowlevel_init
lowlevel_init:
- /* backup return address */
- ldr r1, =SYSCON_SCRATCH0
- str lr, [r1]
- /* Turn on both LEDs */
- bl red_led_on
- bl green_led_on
+ mov r6, lr
+
+ /* Make sure caches are off and invalidated. */
+ ldr r0, =0x00000000
+ mcr p15, 0, r0, c1, c0, 0
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ /* Turn off the green LED and turn on the red LED. If the red LED
+ * is left on for too long, the external reset circuit described
+ * by application note AN258 will cause the system to reset.
+ */
+ ldr r1, =EP93XX_LED_DATA
+ ldr r0, [r1]
+ bic r0, r0, #EP93XX_LED_GREEN_ON
+ orr r0, r0, #EP93XX_LED_RED_ON
+ str r0, [r1]
+
+ /* Undo the silly static memory controller programming performed
+ * by the boot rom.
+ */
+ ldr r0, =SMC_BASE
+
+ /* Set WST1 and WST2 to 31 HCLK cycles (slowest access) */
+ ldr r1, =0x0000fbe0
+
+ /* Reset EP93XX_OFF_SMCBCR0 */
+ ldr r2, [r0]
+ orr r2, r2, r1
+ str r2, [r0]
+
+ ldr r2, [r0, #EP93XX_OFF_SMCBCR1]
+ orr r2, r2, r1
+ str r2, [r0, #EP93XX_OFF_SMCBCR1]
+
+ ldr r2, [r0, #EP93XX_OFF_SMCBCR2]
+ orr r2, r2, r1
+ str r2, [r0, #EP93XX_OFF_SMCBCR2]
+
+ ldr r2, [r0, #EP93XX_OFF_SMCBCR3]
+ orr r2, r2, r1
+ str r2, [r0, #EP93XX_OFF_SMCBCR3]
+
+ ldr r2, [r0, #EP93XX_OFF_SMCBCR6]
+ orr r2, r2, r1
+ str r2, [r0, #EP93XX_OFF_SMCBCR6]
+
+ ldr r2, [r0, #EP93XX_OFF_SMCBCR7]
+ orr r2, r2, r1
+ str r2, [r0, #EP93XX_OFF_SMCBCR7]
+
+ /* Set the PLL1 and processor clock. */
+ ldr r0, =SYSCON_BASE
+#ifdef CONFIG_EDB9301
+ /* 332MHz, giving a 166MHz processor clock. */
+ ldr r1, = 0x02b49907
+#else
+
+#ifdef CONFIG_EDB93XX_INDUSTRIAL
+ /* 384MHz, giving a 196MHz processor clock. */
+ ldr r1, =0x02a4bb38
+#else
+ /* 400MHz, giving a 200MHz processor clock. */
+ ldr r1, =0x02a4e39e
+#endif
+#endif
+ str r1, [r0, #SYSCON_OFF_CLKSET1]
+
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ /* Need to make sure that SDRAM is configured correctly before
+ * coping the code into it.
+ */
+
+#ifdef CONFIG_EDB93XX_SDCS0
+ mov r11, #SDRAM_DEVCFG0_BASE
+#endif
+#ifdef CONFIG_EDB93XX_SDCS1
+ mov r11, #SDRAM_DEVCFG1_BASE
+#endif
+#ifdef CONFIG_EDB93XX_SDCS2
+ mov r11, #SDRAM_DEVCFG2_BASE
+#endif
+#ifdef CONFIG_EDB93XX_SDCS3
+ ldr r0, =SYSCON_BASE
+ ldr r0, [r0, #SYSCON_OFF_SYSCFG]
+ ands r0, r0, #SYSCON_SYSCFG_LASDO
+ moveq r11, #SDRAM_DEVCFG3_ASD0_BASE
+ movne r11, #SDRAM_DEVCFG3_ASD1_BASE
+#endif
+ /* See Table 13-5 in EP93xx datasheet for more info about DRAM
+ * register mapping */
+
+ /* Try a 32-bit wide configuration of SDRAM. */
+ ldr r0, =(EP93XX_SDRAMCTRL_DEVCFG_BANKCOUNT | \
+ EP93XX_SDRAMCTRL_DEVCFG_SROMLL | \
+ EP93XX_SDRAMCTRL_DEVCFG_CASLAT_2 | \
+ EP93XX_SDRAMCTRL_DEVCFG_RASTOCAS_2)
+
+ /* Set burst count: 4 and CAS: 2
+ * Burst mode [A11:A10]; CAS [A16:A14]
+ */
+ orr r2, r11, #0x00008800
+ bl ep93xx_sdram_config
+
+ /* Test the SDRAM. */
+ mov r0, r11
+ bl ep93xx_sdram_test
+ cmp r0, #0x00000000
+ beq ep93xx_sdram_done
+
+ /* Try a 16-bit wide configuration of SDRAM. */
+ ldr r0, =(EP93XX_SDRAMCTRL_DEVCFG_BANKCOUNT | \
+ EP93XX_SDRAMCTRL_DEVCFG_SROMLL | \
+ EP93XX_SDRAMCTRL_DEVCFG_CASLAT_2 | \
+ EP93XX_SDRAMCTRL_DEVCFG_RASTOCAS_2 | \
+ EP93XX_SDRAMCTRL_DEVCFG_EXTBUSWIDTH)
+
+ /* Set burst count: 8, CAS: 2, sequential burst
+ * Accoring to Table 13-3 for 16bit operations mapping must be shifted.
+ * Burst mode [A10:A9]; CAS [A15:A13]
+ */
+ orr r2, r11, #0x00004600
+ bl ep93xx_sdram_config
+
+ /* Test the SDRAM. */
+ mov r0, r11
+ bl ep93xx_sdram_test
+ cmp r0, #0x00000000
+ beq ep93xx_sdram_done
+
+ /* Turn off the red LED. */
+ ldr r0, =EP93XX_LED_DATA
+ ldr r1, [r0]
+ bic r1, r1, #EP93XX_LED_RED_ON
+ str r1, [r0]
+
+ /* There is no SDRAM so flash the green LED. */
+flash_green:
+ orr r1, r1, #EP93XX_LED_GREEN_ON
+ str r1, [r0]
+ ldr r2, =0x00010000
+flash_green_delay_1:
+ subs r2, r2, #1
+ bne flash_green_delay_1
+ bic r1, r1, #EP93XX_LED_GREEN_ON
+ str r1, [r0]
+ ldr r2, =0x00010000
+flash_green_delay_2:
+ subs r2, r2, #1
+ bne flash_green_delay_2
+ orr r1, r1, #EP93XX_LED_GREEN_ON
+ str r1, [r0]
+ ldr r2, =0x00010000
+flash_green_delay_3:
+ subs r2, r2, #1
+ bne flash_green_delay_3
+ bic r1, r1, #EP93XX_LED_GREEN_ON
+ str r1, [r0]
+ ldr r2, =0x00050000
+flash_green_delay_4:
+ subs r2, r2, #1
+ bne flash_green_delay_4
+ b flash_green
+
- /* Configure flash wait states before we switch to the PLL */
- bl flash_cfg
+ep93xx_sdram_done:
+ ldr r1, =EP93XX_LED_DATA
+ ldr r0, [r1]
+ bic r0, r0, #EP93XX_LED_RED_ON
+ str r0, [r1]
- /* Set up PLL */
- bl pll_cfg
+ /* Determine the size of the SDRAM. */
+ mov r0, r11
+ bl ep93xx_sdram_size
- /* Turn off the Green LED and leave the Red LED on */
- bl green_led_off
+ /* Save the SDRAM characteristics. */
+ mov r8, r0
+ mov r9, r1
+ mov r10, r2
- /* Setup SDRAM */
- bl sdram_cfg
+ /* Compute total memory size into r1 */
+ mul r1, r8, r10
+#ifdef CONFIG_EDB93XX_SDCS0
+ ldr r2, [r0, #SDRAM_OFF_DEVCFG0]
+#endif
+#ifdef CONFIG_EDB93XX_SDCS1
+ ldr r2, [r0, #SDRAM_OFF_DEVCFG1]
+#endif
+#ifdef CONFIG_EDB93XX_SDCS2
+ ldr r2, [r0, #SDRAM_OFF_DEVCFG2]
+#endif
+#ifdef CONFIG_EDB93XX_SDCS3
+ ldr r2, [r0, #SDRAM_OFF_DEVCFG3]
+#endif
- /* Turn on Green LED, Turn off the Red LED */
- bl green_led_on
- bl red_led_off
+ /* Consider small DRAM size as:
+ * < 32Mb for 32bit bus
+ * < 64Mb for 16bit bus
+ */
+ tst r2, #EP93XX_SDRAMCTRL_DEVCFG_EXTBUSWIDTH
+ moveq r1, r1, lsr #1
+ cmp r1, #0x02000000
- /* FIXME: we use async mode for now */
- mrc p15, 0, r0, c1, c0, 0
- orr r0, r0, #0xc0000000
- mcr p15, 0, r0, c1, c0, 0
+#if defined(CONFIG_EDB9301)
+ /* Set refresh counter to 20ms for small DRAM size, otherwise 9.6ms */
+ movlt r1, #0x03f0
+ movge r1, #0x01e0
+#else
+ /* Set refresh counter to 30.7ms for small DRAM size, otherwise 15ms */
+ movlt r1, #0x0600
+ movge r1, #0x2f0
+#endif
+ str r1, [r0, #SDRAM_OFF_REFRSHTIMR]
- /* restore return address */
- ldr r1, =SYSCON_SCRATCH0
- ldr lr, [r1]
+ /* Save the memory configuration information. */
+ orr r0, r11, #UBOOT_MEMORYCNF_BANK_SIZE
+ stmia r0, {r8-r11}
- mov pc, lr
+ mov lr, r6
+ mov pc, lr
diff --git a/arch/arm/cpu/arm926ejs/at91/at91sam9m10g45_devices.c b/arch/arm/cpu/arm926ejs/at91/at91sam9m10g45_devices.c
index 7d7725c..0e6c0da 100644
--- a/arch/arm/cpu/arm926ejs/at91/at91sam9m10g45_devices.c
+++ b/arch/arm/cpu/arm926ejs/at91/at91sam9m10g45_devices.c
@@ -165,3 +165,20 @@ void at91_macb_hw_init(void)
#endif
}
#endif
+
+#ifdef CONFIG_GENERIC_ATMEL_MCI
+void at91_mci_hw_init(void)
+{
+ struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
+
+ at91_set_a_periph(AT91_PIO_PORTA, 0, 0); /* MCI0 CLK */
+ at91_set_a_periph(AT91_PIO_PORTA, 1, 0); /* MCI0 CDA */
+ at91_set_a_periph(AT91_PIO_PORTA, 2, 0); /* MCI0 DA0 */
+ at91_set_a_periph(AT91_PIO_PORTA, 3, 0); /* MCI0 DA1 */
+ at91_set_a_periph(AT91_PIO_PORTA, 4, 0); /* MCI0 DA2 */
+ at91_set_a_periph(AT91_PIO_PORTA, 5, 0); /* MCI0 DA3 */
+
+ /* Enable clock */
+ writel(1 << ATMEL_ID_MCI0, &pmc->pcer);
+}
+#endif
diff --git a/arch/arm/cpu/arm926ejs/davinci/da850_lowlevel.c b/arch/arm/cpu/arm926ejs/davinci/da850_lowlevel.c
index b91e948..19730ce 100644
--- a/arch/arm/cpu/arm926ejs/davinci/da850_lowlevel.c
+++ b/arch/arm/cpu/arm926ejs/davinci/da850_lowlevel.c
@@ -14,7 +14,7 @@
#include <asm/arch/hardware.h>
#include <asm/arch/davinci_misc.h>
#include <asm/arch/ddr2_defs.h>
-#include <asm/arch/emif_defs.h>
+#include <asm/ti-common/davinci_nand.h>
#include <asm/arch/pll_defs.h>
void davinci_enable_uart0(void)
diff --git a/arch/arm/cpu/arm926ejs/davinci/dm365_lowlevel.c b/arch/arm/cpu/arm926ejs/davinci/dm365_lowlevel.c
index ee096fe..c8b4498 100644
--- a/arch/arm/cpu/arm926ejs/davinci/dm365_lowlevel.c
+++ b/arch/arm/cpu/arm926ejs/davinci/dm365_lowlevel.c
@@ -11,6 +11,7 @@
#include <nand.h>
#include <ns16550.h>
#include <post.h>
+#include <asm/ti-common/davinci_nand.h>
#include <asm/arch/dm365_lowlevel.h>
#include <asm/arch/hardware.h>
diff --git a/arch/arm/cpu/arm926ejs/kirkwood/cpu.c b/arch/arm/cpu/arm926ejs/kirkwood/cpu.c
index d4711c0..da80240 100644
--- a/arch/arm/cpu/arm926ejs/kirkwood/cpu.c
+++ b/arch/arm/cpu/arm926ejs/kirkwood/cpu.c
@@ -13,7 +13,6 @@
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/kirkwood.h>
-#include <hush.h>
#define BUFLEN 16
@@ -211,7 +210,7 @@ static void kw_sysrst_action(void)
debug("Starting %s process...\n", __FUNCTION__);
ret = run_command(s, 0);
- if (ret < 0)
+ if (ret != 0)
debug("Error.. %s failed\n", __FUNCTION__);
else
debug("%s process finished\n", __FUNCTION__);
diff --git a/arch/arm/cpu/arm926ejs/orion5x/cpu.c b/arch/arm/cpu/arm926ejs/orion5x/cpu.c
index b55c5f0..f88db3b 100644
--- a/arch/arm/cpu/arm926ejs/orion5x/cpu.c
+++ b/arch/arm/cpu/arm926ejs/orion5x/cpu.c
@@ -15,7 +15,6 @@
#include <asm/io.h>
#include <u-boot/md5.h>
#include <asm/arch/cpu.h>
-#include <hush.h>
#define BUFLEN 16
diff --git a/arch/arm/cpu/armv7/am33xx/board.c b/arch/arm/cpu/armv7/am33xx/board.c
index 28c16f8..828d10b 100644
--- a/arch/arm/cpu/armv7/am33xx/board.c
+++ b/arch/arm/cpu/armv7/am33xx/board.c
@@ -144,6 +144,19 @@ int arch_misc_init(void)
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
/*
+ * In the case of non-SPL based booting we'll want to call these
+ * functions a tiny bit later as it will require gd to be set and cleared
+ * and that's not true in s_init in this case so we cannot do it there.
+ */
+int board_early_init_f(void)
+{
+ prcm_init();
+ set_mux_conf_regs();
+
+ return 0;
+}
+
+/*
* This function is the place to do per-board things such as ramp up the
* MPU clock frequency.
*/
@@ -224,7 +237,7 @@ void s_init(void)
set_uart_mux_conf();
setup_clocks_for_console();
uart_soft_reset();
-#ifdef CONFIG_NOR_BOOT
+#if defined(CONFIG_NOR_BOOT) || defined(CONFIG_QSPI_BOOT)
gd->baudrate = CONFIG_BAUDRATE;
serial_init();
gd->have_console = 1;
@@ -232,20 +245,13 @@ void s_init(void)
gd = &gdata;
preloader_console_init();
#endif
- prcm_init();
- set_mux_conf_regs();
#if defined(CONFIG_SPL_AM33XX_ENABLE_RTC32K_OSC)
/* Enable RTC32K clock */
rtc32k_enable();
#endif
+#ifdef CONFIG_SPL_BUILD
+ board_early_init_f();
sdram_init();
-}
#endif
-
-#ifndef CONFIG_SYS_DCACHE_OFF
-void enable_caches(void)
-{
- /* Enable D-cache. I-cache is already enabled in start.S */
- dcache_enable();
}
-#endif /* !CONFIG_SYS_DCACHE_OFF */
+#endif
diff --git a/arch/arm/cpu/armv7/am33xx/clock.c b/arch/arm/cpu/armv7/am33xx/clock.c
index 0672798..ec7d468 100644
--- a/arch/arm/cpu/armv7/am33xx/clock.c
+++ b/arch/arm/cpu/armv7/am33xx/clock.c
@@ -170,8 +170,19 @@ void do_enable_clocks(u32 *const *clk_domains,
};
}
+/*
+ * Before scaling up the clocks we need to have the PMIC scale up the
+ * voltages first. This will be dependent on which PMIC is in use
+ * and in some cases we may not be scaling things up at all and thus not
+ * need to do anything here.
+ */
+__weak void scale_vcores(void)
+{
+}
+
void prcm_init()
{
enable_basic_clocks();
+ scale_vcores();
setup_dplls();
}
diff --git a/arch/arm/cpu/armv7/am33xx/clock_am43xx.c b/arch/arm/cpu/armv7/am33xx/clock_am43xx.c
index d0bc234..31188c8 100644
--- a/arch/arm/cpu/armv7/am33xx/clock_am43xx.c
+++ b/arch/arm/cpu/armv7/am33xx/clock_am43xx.c
@@ -53,6 +53,8 @@ const struct dpll_regs dpll_ddr_regs = {
void setup_clocks_for_console(void)
{
+ u32 clkctrl, idlest = MODULE_CLKCTRL_IDLEST_DISABLED;
+
/* Do not add any spl_debug prints in this function */
clrsetbits_le32(&cmwkup->wkclkstctrl, CD_CLKCTRL_CLKTRCTRL_MASK,
CD_CLKCTRL_CLKTRCTRL_SW_WKUP <<
@@ -63,6 +65,13 @@ void setup_clocks_for_console(void)
MODULE_CLKCTRL_MODULEMODE_MASK,
MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN <<
MODULE_CLKCTRL_MODULEMODE_SHIFT);
+
+ while ((idlest == MODULE_CLKCTRL_IDLEST_DISABLED) ||
+ (idlest == MODULE_CLKCTRL_IDLEST_TRANSITIONING)) {
+ clkctrl = readl(&cmwkup->wkup_uart0ctrl);
+ idlest = (clkctrl & MODULE_CLKCTRL_IDLEST_MASK) >>
+ MODULE_CLKCTRL_IDLEST_SHIFT;
+ }
}
void enable_basic_clocks(void)
diff --git a/arch/arm/cpu/armv7/am33xx/ddr.c b/arch/arm/cpu/armv7/am33xx/ddr.c
index 9a625c4..fc66872 100644
--- a/arch/arm/cpu/armv7/am33xx/ddr.c
+++ b/arch/arm/cpu/armv7/am33xx/ddr.c
@@ -94,7 +94,20 @@ void config_sdram_emif4d5(const struct emif_regs *regs, int nr)
writel(regs->emif_rd_wr_exec_thresh,
&emif_reg[nr]->emif_rd_wr_exec_thresh);
+ /*
+ * for most SOCs these registers won't need to be changed so only
+ * write to these registers if someone explicitly has set the
+ * register's value.
+ */
+ if(regs->emif_cos_config) {
+ writel(regs->emif_prio_class_serv_map, &emif_reg[nr]->emif_prio_class_serv_map);
+ writel(regs->emif_connect_id_serv_1_map, &emif_reg[nr]->emif_connect_id_serv_1_map);
+ writel(regs->emif_connect_id_serv_2_map, &emif_reg[nr]->emif_connect_id_serv_2_map);
+ writel(regs->emif_cos_config, &emif_reg[nr]->emif_cos_config);
+ }
+
writel(regs->ref_ctrl, &emif_reg[nr]->emif_sdram_ref_ctrl);
+ writel(regs->ref_ctrl, &emif_reg[nr]->emif_sdram_ref_ctrl_shdw);
writel(regs->sdram_config, &emif_reg[nr]->emif_sdram_config);
writel(regs->sdram_config, &cstat->secure_emif_sdram_config);
diff --git a/arch/arm/cpu/armv7/am33xx/emif4.c b/arch/arm/cpu/armv7/am33xx/emif4.c
index 2c67c32..8b7527c 100644
--- a/arch/arm/cpu/armv7/am33xx/emif4.c
+++ b/arch/arm/cpu/armv7/am33xx/emif4.c
@@ -21,6 +21,10 @@ DECLARE_GLOBAL_DATA_PTR;
int dram_init(void)
{
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+ sdram_init();
+#endif
+
/* dram_init must store complete ramsize in gd->ram_size */
gd->ram_size = get_ram_size(
(void *)CONFIG_SYS_SDRAM_BASE,
@@ -111,7 +115,7 @@ void config_ddr(unsigned int pll, const struct ctrl_ioregs *ioregs,
#endif
#ifdef CONFIG_AM43XX
writel(readl(&cm_device->cm_dll_ctrl) & ~0x1, &cm_device->cm_dll_ctrl);
- while ((readl(&cm_device->cm_dll_ctrl) && CM_DLL_READYST) == 0)
+ while ((readl(&cm_device->cm_dll_ctrl) & CM_DLL_READYST) == 0)
;
writel(0x80000000, &ddrctrl->ddrioctrl);
diff --git a/arch/arm/cpu/armv7/at91/config.mk b/arch/arm/cpu/armv7/at91/config.mk
new file mode 100644
index 0000000..09eab70
--- /dev/null
+++ b/arch/arm/cpu/armv7/at91/config.mk
@@ -0,0 +1,10 @@
+#
+# Copyright (C) 2014, Andreas Bießmann <andreas.devel@googlemail.com>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+ifdef CONFIG_SPL_BUILD
+ALL-y += boot.bin
+else
+ALL-y += u-boot.img
+endif
diff --git a/arch/arm/cpu/armv7/at91/cpu.c b/arch/arm/cpu/armv7/at91/cpu.c
index 2fbf60d..8d86f97 100644
--- a/arch/arm/cpu/armv7/at91/cpu.c
+++ b/arch/arm/cpu/armv7/at91/cpu.c
@@ -61,6 +61,8 @@ int print_cpuinfo(void)
void enable_caches(void)
{
+ icache_enable();
+ dcache_enable();
}
unsigned int get_chip_id(void)
diff --git a/arch/arm/cpu/armv7/cache_v7.c b/arch/arm/cpu/armv7/cache_v7.c
index bc5fc42..a2c4032 100644
--- a/arch/arm/cpu/armv7/cache_v7.c
+++ b/arch/arm/cpu/armv7/cache_v7.c
@@ -354,41 +354,10 @@ void invalidate_icache_all(void)
}
#endif
-/*
- * Stub implementations for outer cache operations
- */
-void __v7_outer_cache_enable(void)
-{
-}
-void v7_outer_cache_enable(void)
- __attribute__((weak, alias("__v7_outer_cache_enable")));
-
-void __v7_outer_cache_disable(void)
-{
-}
-void v7_outer_cache_disable(void)
- __attribute__((weak, alias("__v7_outer_cache_disable")));
-
-void __v7_outer_cache_flush_all(void)
-{
-}
-void v7_outer_cache_flush_all(void)
- __attribute__((weak, alias("__v7_outer_cache_flush_all")));
-
-void __v7_outer_cache_inval_all(void)
-{
-}
-void v7_outer_cache_inval_all(void)
- __attribute__((weak, alias("__v7_outer_cache_inval_all")));
-
-void __v7_outer_cache_flush_range(u32 start, u32 end)
-{
-}
-void v7_outer_cache_flush_range(u32 start, u32 end)
- __attribute__((weak, alias("__v7_outer_cache_flush_range")));
-
-void __v7_outer_cache_inval_range(u32 start, u32 end)
-{
-}
-void v7_outer_cache_inval_range(u32 start, u32 end)
- __attribute__((weak, alias("__v7_outer_cache_inval_range")));
+/* Stub implementations for outer cache operations */
+__weak void v7_outer_cache_enable(void) {}
+__weak void v7_outer_cache_disable(void) {}
+__weak void v7_outer_cache_flush_all(void) {}
+__weak void v7_outer_cache_inval_all(void) {}
+__weak void v7_outer_cache_flush_range(u32 start, u32 end) {}
+__weak void v7_outer_cache_inval_range(u32 start, u32 end) {}
diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c
index 1fea4d6..400d134 100644
--- a/arch/arm/cpu/armv7/exynos/clock.c
+++ b/arch/arm/cpu/armv7/exynos/clock.c
@@ -869,7 +869,7 @@ static void exynos4_set_mmc_clk(int dev_index, unsigned int div)
{
struct exynos4_clock *clk =
(struct exynos4_clock *)samsung_get_base_clock();
- unsigned int addr;
+ unsigned int addr, clear_bit, set_bit;
/*
* CLK_DIV_FSYS1
@@ -877,44 +877,26 @@ static void exynos4_set_mmc_clk(int dev_index, unsigned int div)
* CLK_DIV_FSYS2
* MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
* CLK_DIV_FSYS3
- * MMC4_PRE_RATIO [15:8]
+ * MMC4_RATIO [3:0]
*/
if (dev_index < 2) {
addr = (unsigned int)&clk->div_fsys1;
- } else if (dev_index == 4) {
+ clear_bit = MASK_PRE_RATIO(dev_index);
+ set_bit = SET_PRE_RATIO(dev_index, div);
+ } else if (dev_index == 4) {
addr = (unsigned int)&clk->div_fsys3;
dev_index -= 4;
+ /* MMC4 is controlled with the MMC4_RATIO value */
+ clear_bit = MASK_RATIO(dev_index);
+ set_bit = SET_RATIO(dev_index, div);
} else {
addr = (unsigned int)&clk->div_fsys2;
dev_index -= 2;
+ clear_bit = MASK_PRE_RATIO(dev_index);
+ set_bit = SET_PRE_RATIO(dev_index, div);
}
- clrsetbits_le32(addr, 0xff << ((dev_index << 4) + 8),
- (div & 0xff) << ((dev_index << 4) + 8));
-}
-
-/* exynos4x12: set the mmc clock */
-static void exynos4x12_set_mmc_clk(int dev_index, unsigned int div)
-{
- struct exynos4x12_clock *clk =
- (struct exynos4x12_clock *)samsung_get_base_clock();
- unsigned int addr;
-
- /*
- * CLK_DIV_FSYS1
- * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
- * CLK_DIV_FSYS2
- * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
- */
- if (dev_index < 2) {
- addr = (unsigned int)&clk->div_fsys1;
- } else {
- addr = (unsigned int)&clk->div_fsys2;
- dev_index -= 2;
- }
-
- clrsetbits_le32(addr, 0xff << ((dev_index << 4) + 8),
- (div & 0xff) << ((dev_index << 4) + 8));
+ clrsetbits_le32(addr, clear_bit, set_bit);
}
/* exynos5: set the mmc clock */
@@ -1612,10 +1594,7 @@ void set_mmc_clk(int dev_index, unsigned int div)
else
exynos5_set_mmc_clk(dev_index, div);
} else {
- if (proid_is_exynos4412())
- exynos4x12_set_mmc_clk(dev_index, div);
- else
- exynos4_set_mmc_clk(dev_index, div);
+ exynos4_set_mmc_clk(dev_index, div);
}
}
diff --git a/arch/arm/cpu/armv7/exynos/dmc_common.c b/arch/arm/cpu/armv7/exynos/dmc_common.c
index cca925e..9b6ee69 100644
--- a/arch/arm/cpu/armv7/exynos/dmc_common.c
+++ b/arch/arm/cpu/armv7/exynos/dmc_common.c
@@ -162,7 +162,7 @@ void mem_ctrl_init(int reset)
/* If there are any other memory variant, add their init call below */
if (param->mem_type == DDR_MODE_DDR3) {
- ret = ddr3_mem_ctrl_init(mem, param->mem_iv_size, reset);
+ ret = ddr3_mem_ctrl_init(mem, reset);
if (ret) {
/* will hang if failed to init memory control */
while (1)
diff --git a/arch/arm/cpu/armv7/exynos/dmc_init_ddr3.c b/arch/arm/cpu/armv7/exynos/dmc_init_ddr3.c
index 487e6f4..b86dd2d 100644
--- a/arch/arm/cpu/armv7/exynos/dmc_init_ddr3.c
+++ b/arch/arm/cpu/armv7/exynos/dmc_init_ddr3.c
@@ -6,6 +6,7 @@
* SPDX-License-Identifier: GPL-2.0+
*/
+#include <common.h>
#include <config.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
@@ -16,7 +17,11 @@
#include "exynos5_setup.h"
#include "clock_init.h"
-#define TIMEOUT 10000
+#define TIMEOUT_US 10000
+#define NUM_BYTE_LANES 4
+#define DEFAULT_DQS 8
+#define DEFAULT_DQS_X4 (DEFAULT_DQS << 24) || (DEFAULT_DQS << 16) \
+ || (DEFAULT_DQS << 8) || (DEFAULT_DQS << 0)
#ifdef CONFIG_EXYNOS5250
static void reset_phy_ctrl(void)
@@ -28,8 +33,7 @@ static void reset_phy_ctrl(void)
writel(DDR3PHY_CTRL_PHY_RESET, &clk->lpddr3phy_ctrl);
}
-int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,
- int reset)
+int ddr3_mem_ctrl_init(struct mem_timings *mem, int reset)
{
unsigned int val;
struct exynos5_phy_control *phy0_ctrl, *phy1_ctrl;
@@ -177,7 +181,7 @@ int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,
writel(val, &phy1_ctrl->phy_con1);
writel(CTRL_RDLVL_GATE_ENABLE, &dmc->rdlvl_config);
- i = TIMEOUT;
+ i = TIMEOUT_US;
while ((readl(&dmc->phystatus) &
(RDLVL_COMPLETE_CHO | RDLVL_COMPLETE_CH1)) !=
(RDLVL_COMPLETE_CHO | RDLVL_COMPLETE_CH1) && i > 0) {
@@ -221,8 +225,220 @@ int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,
#endif
#ifdef CONFIG_EXYNOS5420
-int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,
- int reset)
+/**
+ * RAM address to use in the test.
+ *
+ * We'll use 4 words at this address and 4 at this address + 0x80 (Ares
+ * interleaves channels every 128 bytes). This will allow us to evaluate all of
+ * the chips in a 1 chip per channel (2GB) system and half the chips in a 2
+ * chip per channel (4GB) system. We can't test the 2nd chip since we need to
+ * do tests before the 2nd chip is enabled. Looking at the 2nd chip isn't
+ * critical because the 1st and 2nd chip have very similar timings (they'd
+ * better have similar timings, since there's only a single adjustment that is
+ * shared by both chips).
+ */
+const unsigned int test_addr = CONFIG_SYS_SDRAM_BASE;
+
+/* Test pattern with which RAM will be tested */
+static const unsigned int test_pattern[] = {
+ 0x5a5a5a5a,
+ 0xa5a5a5a5,
+ 0xf0f0f0f0,
+ 0x0f0f0f0f,
+};
+
+/**
+ * This function is a test vector for sw read leveling,
+ * it compares the read data with the written data.
+ *
+ * @param ch DMC channel number
+ * @param byte_lane which DQS byte offset,
+ * possible values are 0,1,2,3
+ * @return TRUE if memory was good, FALSE if not.
+ */
+static bool dmc_valid_window_test_vector(int ch, int byte_lane)
+{
+ unsigned int read_data;
+ unsigned int mask;
+ int i;
+
+ mask = 0xFF << (8 * byte_lane);
+
+ for (i = 0; i < ARRAY_SIZE(test_pattern); i++) {
+ read_data = readl(test_addr + i * 4 + ch * 0x80);
+ if ((read_data & mask) != (test_pattern[i] & mask))
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * This function returns current read offset value.
+ *
+ * @param phy_ctrl pointer to the current phy controller
+ */
+static unsigned int dmc_get_read_offset_value(struct exynos5420_phy_control
+ *phy_ctrl)
+{
+ return readl(&phy_ctrl->phy_con4);
+}
+
+/**
+ * This function performs resync, so that slave DLL is updated.
+ *
+ * @param phy_ctrl pointer to the current phy controller
+ */
+static void ddr_phy_set_do_resync(struct exynos5420_phy_control *phy_ctrl)
+{
+ setbits_le32(&phy_ctrl->phy_con10, PHY_CON10_CTRL_OFFSETR3);
+ clrbits_le32(&phy_ctrl->phy_con10, PHY_CON10_CTRL_OFFSETR3);
+}
+
+/**
+ * This function sets read offset value register with 'offset'.
+ *
+ * ...we also call call ddr_phy_set_do_resync().
+ *
+ * @param phy_ctrl pointer to the current phy controller
+ * @param offset offset to read DQS
+ */
+static void dmc_set_read_offset_value(struct exynos5420_phy_control *phy_ctrl,
+ unsigned int offset)
+{
+ writel(offset, &phy_ctrl->phy_con4);
+ ddr_phy_set_do_resync(phy_ctrl);
+}
+
+/**
+ * Convert a 2s complement byte to a byte with a sign bit.
+ *
+ * NOTE: you shouldn't use normal math on the number returned by this function.
+ * As an example, -10 = 0xf6. After this function -10 = 0x8a. If you wanted
+ * to do math and get the average of 10 and -10 (should be 0):
+ * 0x8a + 0xa = 0x94 (-108)
+ * 0x94 / 2 = 0xca (-54)
+ * ...and 0xca = sign bit plus 0x4a, or -74
+ *
+ * Also note that you lose the ability to represent -128 since there are two
+ * representations of 0.
+ *
+ * @param b The byte to convert in two's complement.
+ * @return The 7-bit value + sign bit.
+ */
+
+unsigned char make_signed_byte(signed char b)
+{
+ if (b < 0)
+ return 0x80 | -b;
+ else
+ return b;
+}
+
+/**
+ * Test various shifts starting at 'start' and going to 'end'.
+ *
+ * For each byte lane, we'll walk through shift starting at 'start' and going
+ * to 'end' (inclusive). When we are finally able to read the test pattern
+ * we'll store the value in the results array.
+ *
+ * @param phy_ctrl pointer to the current phy controller
+ * @param ch channel number
+ * @param start the start shift. -127 to 127
+ * @param end the end shift. -127 to 127
+ * @param results we'll store results for each byte lane.
+ */
+
+void test_shifts(struct exynos5420_phy_control *phy_ctrl, int ch,
+ int start, int end, int results[NUM_BYTE_LANES])
+{
+ int incr = (start < end) ? 1 : -1;
+ int byte_lane;
+
+ for (byte_lane = 0; byte_lane < NUM_BYTE_LANES; byte_lane++) {
+ int shift;
+
+ dmc_set_read_offset_value(phy_ctrl, DEFAULT_DQS_X4);
+ results[byte_lane] = DEFAULT_DQS;
+
+ for (shift = start; shift != (end + incr); shift += incr) {
+ unsigned int byte_offsetr;
+ unsigned int offsetr;
+
+ byte_offsetr = make_signed_byte(shift);
+
+ offsetr = dmc_get_read_offset_value(phy_ctrl);
+ offsetr &= ~(0xFF << (8 * byte_lane));
+ offsetr |= (byte_offsetr << (8 * byte_lane));
+ dmc_set_read_offset_value(phy_ctrl, offsetr);
+
+ if (dmc_valid_window_test_vector(ch, byte_lane)) {
+ results[byte_lane] = shift;
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * This function performs SW read leveling to compensate DQ-DQS skew at
+ * receiver it first finds the optimal read offset value on each DQS
+ * then applies the value to PHY.
+ *
+ * Read offset value has its min margin and max margin. If read offset
+ * value exceeds its min or max margin, read data will have corruption.
+ * To avoid this we are doing sw read leveling.
+ *
+ * SW read leveling is:
+ * 1> Finding offset value's left_limit and right_limit
+ * 2> and calculate its center value
+ * 3> finally programs that center value to PHY
+ * 4> then PHY gets its optimal offset value.
+ *
+ * @param phy_ctrl pointer to the current phy controller
+ * @param ch channel number
+ * @param coarse_lock_val The coarse lock value read from PHY_CON13.
+ * (0 - 0x7f)
+ */
+static void software_find_read_offset(struct exynos5420_phy_control *phy_ctrl,
+ int ch, unsigned int coarse_lock_val)
+{
+ unsigned int offsetr_cent;
+ int byte_lane;
+ int left_limit;
+ int right_limit;
+ int left[NUM_BYTE_LANES];
+ int right[NUM_BYTE_LANES];
+ int i;
+
+ /* Fill the memory with test patterns */
+ for (i = 0; i < ARRAY_SIZE(test_pattern); i++)
+ writel(test_pattern[i], test_addr + i * 4 + ch * 0x80);
+
+ /* Figure out the limits we'll test with; keep -127 < limit < 127 */
+ left_limit = DEFAULT_DQS - coarse_lock_val;
+ right_limit = DEFAULT_DQS + coarse_lock_val;
+ if (right_limit > 127)
+ right_limit = 127;
+
+ /* Fill in the location where reads were OK from left and right */
+ test_shifts(phy_ctrl, ch, left_limit, right_limit, left);
+ test_shifts(phy_ctrl, ch, right_limit, left_limit, right);
+
+ /* Make a final value by taking the center between the left and right */
+ offsetr_cent = 0;
+ for (byte_lane = 0; byte_lane < NUM_BYTE_LANES; byte_lane++) {
+ int temp_center;
+ unsigned int vmwc;
+
+ temp_center = (left[byte_lane] + right[byte_lane]) / 2;
+ vmwc = make_signed_byte(temp_center);
+ offsetr_cent |= vmwc << (8 * byte_lane);
+ }
+ dmc_set_read_offset_value(phy_ctrl, offsetr_cent);
+}
+
+int ddr3_mem_ctrl_init(struct mem_timings *mem, int reset)
{
struct exynos5420_clock *clk =
(struct exynos5420_clock *)samsung_get_base_clock();
@@ -231,7 +447,9 @@ int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,
struct exynos5420_phy_control *phy0_ctrl, *phy1_ctrl;
struct exynos5420_dmc *drex0, *drex1;
struct exynos5420_tzasc *tzasc0, *tzasc1;
+ struct exynos5_power *pmu;
uint32_t val, n_lock_r, n_lock_w_phy0, n_lock_w_phy1;
+ uint32_t lock0_info, lock1_info;
int chip;
int i;
@@ -244,6 +462,7 @@ int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,
tzasc0 = (struct exynos5420_tzasc *)samsung_get_base_dmc_tzasc();
tzasc1 = (struct exynos5420_tzasc *)(samsung_get_base_dmc_tzasc()
+ DMC_OFFSET);
+ pmu = (struct exynos5_power *)EXYNOS5420_POWER_BASE;
/* Enable PAUSE for DREX */
setbits_le32(&clk->pause, ENABLE_BIT);
@@ -394,7 +613,41 @@ int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,
*/
dmc_config_mrs(mem, &drex0->directcmd);
dmc_config_mrs(mem, &drex1->directcmd);
- } else {
+ }
+
+ /*
+ * Get PHY_CON13 from both phys. Gate CLKM around reading since
+ * PHY_CON13 is glitchy when CLKM is running. We're paranoid and
+ * wait until we get a "fine lock", though a coarse lock is probably
+ * OK (we only use the coarse numbers below). We try to gate the
+ * clock for as short a time as possible in case SDRAM is somehow
+ * sensitive. sdelay(10) in the loop is arbitrary to make sure
+ * there is some time for PHY_CON13 to get updated. In practice
+ * no delay appears to be needed.
+ */
+ val = readl(&clk->gate_bus_cdrex);
+ while (true) {
+ writel(val & ~0x1, &clk->gate_bus_cdrex);
+ lock0_info = readl(&phy0_ctrl->phy_con13);
+ writel(val, &clk->gate_bus_cdrex);
+
+ if ((lock0_info & CTRL_FINE_LOCKED) == CTRL_FINE_LOCKED)
+ break;
+
+ sdelay(10);
+ }
+ while (true) {
+ writel(val & ~0x2, &clk->gate_bus_cdrex);
+ lock1_info = readl(&phy1_ctrl->phy_con13);
+ writel(val, &clk->gate_bus_cdrex);
+
+ if ((lock1_info & CTRL_FINE_LOCKED) == CTRL_FINE_LOCKED)
+ break;
+
+ sdelay(10);
+ }
+
+ if (!reset) {
/*
* During Suspend-Resume & S/W-Reset, as soon as PMU releases
* pad retention, CKE goes high. This causes memory contents
@@ -445,15 +698,13 @@ int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,
val |= (RDLVL_PASS_ADJ_VAL << RDLVL_PASS_ADJ_OFFSET);
writel(val, &phy1_ctrl->phy_con1);
- n_lock_r = readl(&phy0_ctrl->phy_con13);
- n_lock_w_phy0 = (n_lock_r & CTRL_LOCK_COARSE_MASK) >> 2;
+ n_lock_w_phy0 = (lock0_info & CTRL_LOCK_COARSE_MASK) >> 2;
n_lock_r = readl(&phy0_ctrl->phy_con12);
n_lock_r &= ~CTRL_DLL_ON;
n_lock_r |= n_lock_w_phy0;
writel(n_lock_r, &phy0_ctrl->phy_con12);
- n_lock_r = readl(&phy1_ctrl->phy_con13);
- n_lock_w_phy1 = (n_lock_r & CTRL_LOCK_COARSE_MASK) >> 2;
+ n_lock_w_phy1 = (lock1_info & CTRL_LOCK_COARSE_MASK) >> 2;
n_lock_r = readl(&phy1_ctrl->phy_con12);
n_lock_r &= ~CTRL_DLL_ON;
n_lock_r |= n_lock_w_phy1;
@@ -482,7 +733,7 @@ int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,
writel(val, &phy1_ctrl->phy_con1);
writel(CTRL_RDLVL_GATE_ENABLE, &drex0->rdlvl_config);
- i = TIMEOUT;
+ i = TIMEOUT_US;
while (((readl(&drex0->phystatus) & RDLVL_COMPLETE_CHO) !=
RDLVL_COMPLETE_CHO) && (i > 0)) {
/*
@@ -497,7 +748,7 @@ int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,
writel(CTRL_RDLVL_GATE_DISABLE, &drex0->rdlvl_config);
writel(CTRL_RDLVL_GATE_ENABLE, &drex1->rdlvl_config);
- i = TIMEOUT;
+ i = TIMEOUT_US;
while (((readl(&drex1->phystatus) & RDLVL_COMPLETE_CHO) !=
RDLVL_COMPLETE_CHO) && (i > 0)) {
/*
@@ -522,77 +773,6 @@ int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,
&drex1->directcmd);
}
- if (mem->read_leveling_enable) {
- /* Set Read DQ Calibration */
- val = (0x3 << DIRECT_CMD_BANK_SHIFT) | 0x4;
- for (chip = 0; chip < mem->chips_to_configure; chip++) {
- writel(val | (chip << DIRECT_CMD_CHIP_SHIFT),
- &drex0->directcmd);
- writel(val | (chip << DIRECT_CMD_CHIP_SHIFT),
- &drex1->directcmd);
- }
-
- val = readl(&phy0_ctrl->phy_con1);
- val |= READ_LEVELLING_DDR3;
- writel(val, &phy0_ctrl->phy_con1);
- val = readl(&phy1_ctrl->phy_con1);
- val |= READ_LEVELLING_DDR3;
- writel(val, &phy1_ctrl->phy_con1);
-
- val = readl(&phy0_ctrl->phy_con2);
- val |= (RDLVL_EN | RDLVL_INCR_ADJ);
- writel(val, &phy0_ctrl->phy_con2);
- val = readl(&phy1_ctrl->phy_con2);
- val |= (RDLVL_EN | RDLVL_INCR_ADJ);
- writel(val, &phy1_ctrl->phy_con2);
-
- setbits_le32(&drex0->rdlvl_config,
- CTRL_RDLVL_DATA_ENABLE);
- i = TIMEOUT;
- while (((readl(&drex0->phystatus) & RDLVL_COMPLETE_CHO)
- != RDLVL_COMPLETE_CHO) && (i > 0)) {
- /*
- * TODO(waihong): Comment on how long this take
- * to timeout
- */
- sdelay(100);
- i--;
- }
- if (!i)
- return SETUP_ERR_RDLV_COMPLETE_TIMEOUT;
-
- clrbits_le32(&drex0->rdlvl_config,
- CTRL_RDLVL_DATA_ENABLE);
- setbits_le32(&drex1->rdlvl_config,
- CTRL_RDLVL_DATA_ENABLE);
- i = TIMEOUT;
- while (((readl(&drex1->phystatus) & RDLVL_COMPLETE_CHO)
- != RDLVL_COMPLETE_CHO) && (i > 0)) {
- /*
- * TODO(waihong): Comment on how long this take
- * to timeout
- */
- sdelay(100);
- i--;
- }
- if (!i)
- return SETUP_ERR_RDLV_COMPLETE_TIMEOUT;
-
- clrbits_le32(&drex1->rdlvl_config,
- CTRL_RDLVL_DATA_ENABLE);
-
- val = (0x3 << DIRECT_CMD_BANK_SHIFT);
- for (chip = 0; chip < mem->chips_to_configure; chip++) {
- writel(val | (chip << DIRECT_CMD_CHIP_SHIFT),
- &drex0->directcmd);
- writel(val | (chip << DIRECT_CMD_CHIP_SHIFT),
- &drex1->directcmd);
- }
-
- update_reset_dll(&drex0->phycontrol0, DDR_MODE_DDR3);
- update_reset_dll(&drex1->phycontrol0, DDR_MODE_DDR3);
- }
-
/* Common Settings for Leveling */
val = PHY_CON12_RESET_VAL;
writel((val + n_lock_w_phy0), &phy0_ctrl->phy_con12);
@@ -602,6 +782,27 @@ int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,
setbits_le32(&phy1_ctrl->phy_con2, DLL_DESKEW_EN);
}
+ /*
+ * Do software read leveling
+ *
+ * Do this before we turn on auto refresh since the auto refresh can
+ * be in conflict with the resync operation that's part of setting
+ * read leveling.
+ */
+ if (!reset) {
+ /* restore calibrated value after resume */
+ dmc_set_read_offset_value(phy0_ctrl, readl(&pmu->pmu_spare1));
+ dmc_set_read_offset_value(phy1_ctrl, readl(&pmu->pmu_spare2));
+ } else {
+ software_find_read_offset(phy0_ctrl, 0,
+ CTRL_LOCK_COARSE(lock0_info));
+ software_find_read_offset(phy1_ctrl, 1,
+ CTRL_LOCK_COARSE(lock1_info));
+ /* save calibrated value to restore after resume */
+ writel(dmc_get_read_offset_value(phy0_ctrl), &pmu->pmu_spare1);
+ writel(dmc_get_read_offset_value(phy1_ctrl), &pmu->pmu_spare2);
+ }
+
/* Send PALL command */
dmc_config_prech(mem, &drex0->directcmd);
dmc_config_prech(mem, &drex1->directcmd);
diff --git a/arch/arm/cpu/armv7/exynos/exynos5_setup.h b/arch/arm/cpu/armv7/exynos/exynos5_setup.h
index 53b0ace..3242093 100644
--- a/arch/arm/cpu/armv7/exynos/exynos5_setup.h
+++ b/arch/arm/cpu/armv7/exynos/exynos5_setup.h
@@ -282,8 +282,12 @@
#define PHY_CON12_VAL 0x10107F50
#define CTRL_START (1 << 6)
#define CTRL_DLL_ON (1 << 5)
+#define CTRL_LOCK_COARSE_OFFSET 10
+#define CTRL_LOCK_COARSE_MASK (0x7F << CTRL_LOCK_COARSE_OFFSET)
+#define CTRL_LOCK_COARSE(x) (((x) & CTRL_LOCK_COARSE_MASK) >> \
+ CTRL_LOCK_COARSE_OFFSET)
#define CTRL_FORCE_MASK (0x7F << 8)
-#define CTRL_LOCK_COARSE_MASK (0x7F << 10)
+#define CTRL_FINE_LOCKED 0x7
#define CTRL_OFFSETD_RESET_VAL 0x8
#define CTRL_OFFSETD_VAL 0x7F
@@ -431,10 +435,10 @@
/*
* Definitions that differ with SoC's.
- * Below is the part defining macros for smdk5250.
- * Else part introduces macros for smdk5420.
+ * Below is the part defining macros for Exynos5250.
+ * Else part introduces macros for Exynos5420.
*/
-#ifndef CONFIG_SMDK5420
+#ifndef CONFIG_EXYNOS5420
/* APLL_CON1 */
#define APLL_CON1_VAL (0x00203800)
@@ -890,16 +894,11 @@ enum {
/*
* Memory variant specific initialization code for DDR3
*
- * @param mem Memory timings for this memory type.
- * @param mem_iv_size Memory interleaving size is a configurable parameter
- * which the DMC uses to decide how to split a memory
- * chunk into smaller chunks to support concurrent
- * accesses; may vary across boards.
+ * @param mem Memory timings for this memory type.
* @param reset Reset DDR PHY during initialization.
* @return 0 if ok, SETUP_ERR_... if there is a problem
*/
-int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,
- int reset);
+int ddr3_mem_ctrl_init(struct mem_timings *mem, int reset);
/* Memory variant specific initialization code for LPDDR3 */
void lpddr3_mem_ctrl_init(void);
diff --git a/arch/arm/cpu/armv7/exynos/lowlevel_init.c b/arch/arm/cpu/armv7/exynos/lowlevel_init.c
index 11fe5b8..83e1dcf 100644
--- a/arch/arm/cpu/armv7/exynos/lowlevel_init.c
+++ b/arch/arm/cpu/armv7/exynos/lowlevel_init.c
@@ -39,6 +39,7 @@ enum {
DO_CLOCKS = 1 << 1,
DO_MEM_RESET = 1 << 2,
DO_UART = 1 << 3,
+ DO_POWER = 1 << 4,
};
int do_lowlevel_init(void)
@@ -60,9 +61,12 @@ int do_lowlevel_init(void)
break;
default:
/* This is a normal boot (not a wake from sleep) */
- actions = DO_CLOCKS | DO_MEM_RESET;
+ actions = DO_CLOCKS | DO_MEM_RESET | DO_POWER;
}
+ if (actions & DO_POWER)
+ set_ps_hold_ctrl();
+
if (actions & DO_CLOCKS) {
system_clock_init();
mem_ctrl_init(actions & DO_MEM_RESET);
diff --git a/arch/arm/cpu/armv7/exynos/pinmux.c b/arch/arm/cpu/armv7/exynos/pinmux.c
index ee7c2e5..86a0c75 100644
--- a/arch/arm/cpu/armv7/exynos/pinmux.c
+++ b/arch/arm/cpu/armv7/exynos/pinmux.c
@@ -573,15 +573,26 @@ static void exynos4_i2c_config(int peripheral, int flags)
static int exynos4_mmc_config(int peripheral, int flags)
{
int i, start = 0, start_ext = 0;
+ unsigned int func, ext_func;
switch (peripheral) {
case PERIPH_ID_SDMMC0:
start = EXYNOS4_GPIO_K00;
start_ext = EXYNOS4_GPIO_K13;
+ func = S5P_GPIO_FUNC(0x2);
+ ext_func = S5P_GPIO_FUNC(0x3);
break;
case PERIPH_ID_SDMMC2:
start = EXYNOS4_GPIO_K20;
start_ext = EXYNOS4_GPIO_K33;
+ func = S5P_GPIO_FUNC(0x2);
+ ext_func = S5P_GPIO_FUNC(0x3);
+ break;
+ case PERIPH_ID_SDMMC4:
+ start = EXYNOS4_GPIO_K00;
+ start_ext = EXYNOS4_GPIO_K13;
+ func = S5P_GPIO_FUNC(0x3);
+ ext_func = S5P_GPIO_FUNC(0x4);
break;
default:
return -1;
@@ -589,13 +600,14 @@ static int exynos4_mmc_config(int peripheral, int flags)
for (i = start; i < (start + 7); i++) {
if (i == (start + 2))
continue;
- gpio_cfg_pin(i, S5P_GPIO_FUNC(0x2));
+ gpio_cfg_pin(i, func);
gpio_set_pull(i, S5P_GPIO_PULL_NONE);
gpio_set_drv(i, S5P_GPIO_DRV_4X);
}
+ /* SDMMC2 do not use 8bit mode at exynos4 */
if (flags & PINMUX_FLAG_8BIT_MODE) {
for (i = start_ext; i < (start_ext + 4); i++) {
- gpio_cfg_pin(i, S5P_GPIO_FUNC(0x3));
+ gpio_cfg_pin(i, ext_func);
gpio_set_pull(i, S5P_GPIO_PULL_NONE);
gpio_set_drv(i, S5P_GPIO_DRV_4X);
}
@@ -676,15 +688,26 @@ static void exynos4x12_i2c_config(int peripheral, int flags)
static int exynos4x12_mmc_config(int peripheral, int flags)
{
int i, start = 0, start_ext = 0;
+ unsigned int func, ext_func;
switch (peripheral) {
case PERIPH_ID_SDMMC0:
start = EXYNOS4X12_GPIO_K00;
start_ext = EXYNOS4X12_GPIO_K13;
+ func = S5P_GPIO_FUNC(0x2);
+ ext_func = S5P_GPIO_FUNC(0x3);
break;
case PERIPH_ID_SDMMC2:
start = EXYNOS4X12_GPIO_K20;
start_ext = EXYNOS4X12_GPIO_K33;
+ func = S5P_GPIO_FUNC(0x2);
+ ext_func = S5P_GPIO_FUNC(0x3);
+ break;
+ case PERIPH_ID_SDMMC4:
+ start = EXYNOS4_GPIO_K00;
+ start_ext = EXYNOS4_GPIO_K13;
+ func = S5P_GPIO_FUNC(0x3);
+ ext_func = S5P_GPIO_FUNC(0x4);
break;
default:
return -1;
@@ -692,13 +715,13 @@ static int exynos4x12_mmc_config(int peripheral, int flags)
for (i = start; i < (start + 7); i++) {
if (i == (start + 2))
continue;
- gpio_cfg_pin(i, S5P_GPIO_FUNC(0x2));
+ gpio_cfg_pin(i, func);
gpio_set_pull(i, S5P_GPIO_PULL_NONE);
gpio_set_drv(i, S5P_GPIO_DRV_4X);
}
if (flags & PINMUX_FLAG_8BIT_MODE) {
for (i = start_ext; i < (start_ext + 4); i++) {
- gpio_cfg_pin(i, S5P_GPIO_FUNC(0x3));
+ gpio_cfg_pin(i, ext_func);
gpio_set_pull(i, S5P_GPIO_PULL_NONE);
gpio_set_drv(i, S5P_GPIO_DRV_4X);
}
@@ -759,10 +782,10 @@ static int exynos4_pinmux_config(int peripheral, int flags)
break;
case PERIPH_ID_SDMMC0:
case PERIPH_ID_SDMMC2:
+ case PERIPH_ID_SDMMC4:
return exynos4_mmc_config(peripheral, flags);
case PERIPH_ID_SDMMC1:
case PERIPH_ID_SDMMC3:
- case PERIPH_ID_SDMMC4:
debug("SDMMC device %d not implemented\n", peripheral);
return -1;
default:
@@ -794,10 +817,10 @@ static int exynos4x12_pinmux_config(int peripheral, int flags)
break;
case PERIPH_ID_SDMMC0:
case PERIPH_ID_SDMMC2:
+ case PERIPH_ID_SDMMC4:
return exynos4x12_mmc_config(peripheral, flags);
case PERIPH_ID_SDMMC1:
case PERIPH_ID_SDMMC3:
- case PERIPH_ID_SDMMC4:
debug("SDMMC device %d not implemented\n", peripheral);
return -1;
default:
diff --git a/arch/arm/cpu/armv7/exynos/power.c b/arch/arm/cpu/armv7/exynos/power.c
index 563abd7..638ee0b 100644
--- a/arch/arm/cpu/armv7/exynos/power.c
+++ b/arch/arm/cpu/armv7/exynos/power.c
@@ -112,6 +112,12 @@ static void exynos5_set_ps_hold_ctrl(void)
EXYNOS_PS_HOLD_CONTROL_DATA_HIGH);
}
+/*
+ * Set ps_hold data driving value high
+ * This enables the machine to stay powered on
+ * after the initial power-on condition goes away
+ * (e.g. power button).
+ */
void set_ps_hold_ctrl(void)
{
if (cpu_is_exynos5())
diff --git a/arch/arm/cpu/armv7/exynos/spl_boot.c b/arch/arm/cpu/armv7/exynos/spl_boot.c
index ade45fd..7916630 100644
--- a/arch/arm/cpu/armv7/exynos/spl_boot.c
+++ b/arch/arm/cpu/armv7/exynos/spl_boot.c
@@ -4,8 +4,8 @@
* SPDX-License-Identifier: GPL-2.0+
*/
-#include<common.h>
-#include<config.h>
+#include <common.h>
+#include <config.h>
#include <asm/arch/clock.h>
#include <asm/arch/clk.h>
diff --git a/arch/arm/cpu/armv7/keystone/Makefile b/arch/arm/cpu/armv7/keystone/Makefile
index b1bd022..c4af252 100644
--- a/arch/arm/cpu/armv7/keystone/Makefile
+++ b/arch/arm/cpu/armv7/keystone/Makefile
@@ -5,7 +5,6 @@
# SPDX-License-Identifier: GPL-2.0+
#
-obj-y += aemif.o
obj-y += init.o
obj-y += psc.o
obj-y += clock.o
diff --git a/arch/arm/cpu/armv7/keystone/aemif.c b/arch/arm/cpu/armv7/keystone/aemif.c
deleted file mode 100644
index 9b26886..0000000
--- a/arch/arm/cpu/armv7/keystone/aemif.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Keystone2: Asynchronous EMIF Configuration
- *
- * (C) Copyright 2012-2014
- * Texas Instruments Incorporated, <www.ti.com>
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#include <common.h>
-#include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/emif_defs.h>
-
-#define AEMIF_CFG_SELECT_STROBE(v) ((v) ? 1 << 31 : 0)
-#define AEMIF_CFG_EXTEND_WAIT(v) ((v) ? 1 << 30 : 0)
-#define AEMIF_CFG_WR_SETUP(v) (((v) & 0x0f) << 26)
-#define AEMIF_CFG_WR_STROBE(v) (((v) & 0x3f) << 20)
-#define AEMIF_CFG_WR_HOLD(v) (((v) & 0x07) << 17)
-#define AEMIF_CFG_RD_SETUP(v) (((v) & 0x0f) << 13)
-#define AEMIF_CFG_RD_STROBE(v) (((v) & 0x3f) << 7)
-#define AEMIF_CFG_RD_HOLD(v) (((v) & 0x07) << 4)
-#define AEMIF_CFG_TURN_AROUND(v) (((v) & 0x03) << 2)
-#define AEMIF_CFG_WIDTH(v) (((v) & 0x03) << 0)
-
-#define set_config_field(reg, field, val) \
- do { \
- if (val != -1) { \
- reg &= ~AEMIF_CFG_##field(0xffffffff); \
- reg |= AEMIF_CFG_##field(val); \
- } \
- } while (0)
-
-void configure_async_emif(int cs, struct async_emif_config *cfg)
-{
- unsigned long tmp;
-
- if (cfg->mode == ASYNC_EMIF_MODE_NAND) {
- tmp = __raw_readl(&davinci_emif_regs->nandfcr);
- tmp |= (1 << cs);
- __raw_writel(tmp, &davinci_emif_regs->nandfcr);
-
- } else if (cfg->mode == ASYNC_EMIF_MODE_ONENAND) {
- tmp = __raw_readl(&davinci_emif_regs->one_nand_cr);
- tmp |= (1 << cs);
- __raw_writel(tmp, &davinci_emif_regs->one_nand_cr);
- }
-
- tmp = __raw_readl(&davinci_emif_regs->abncr[cs]);
-
- set_config_field(tmp, SELECT_STROBE, cfg->select_strobe);
- set_config_field(tmp, EXTEND_WAIT, cfg->extend_wait);
- set_config_field(tmp, WR_SETUP, cfg->wr_setup);
- set_config_field(tmp, WR_STROBE, cfg->wr_strobe);
- set_config_field(tmp, WR_HOLD, cfg->wr_hold);
- set_config_field(tmp, RD_SETUP, cfg->rd_setup);
- set_config_field(tmp, RD_STROBE, cfg->rd_strobe);
- set_config_field(tmp, RD_HOLD, cfg->rd_hold);
- set_config_field(tmp, TURN_AROUND, cfg->turn_around);
- set_config_field(tmp, WIDTH, cfg->width);
-
- __raw_writel(tmp, &davinci_emif_regs->abncr[cs]);
-}
-
-void init_async_emif(int num_cs, struct async_emif_config *config)
-{
- int cs;
-
- for (cs = 0; cs < num_cs; cs++)
- configure_async_emif(cs, config + cs);
-}
diff --git a/arch/arm/cpu/armv7/keystone/init.c b/arch/arm/cpu/armv7/keystone/init.c
index 044015a..4df5ae1 100644
--- a/arch/arm/cpu/armv7/keystone/init.c
+++ b/arch/arm/cpu/armv7/keystone/init.c
@@ -8,6 +8,7 @@
*/
#include <common.h>
+#include <ns16550.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/hardware.h>
@@ -30,6 +31,14 @@ int arch_cpu_init(void)
share_all_segments(11); /* PCIE */
#endif
+ /*
+ * just initialise the COM2 port so that TI specific
+ * UART register PWREMU_MGMT is initialized. Linux UART
+ * driver doesn't handle this.
+ */
+ NS16550_init((NS16550_t)(CONFIG_SYS_NS16550_COM2),
+ CONFIG_SYS_NS16550_CLK / 16 / CONFIG_BAUDRATE);
+
return 0;
}
diff --git a/arch/arm/cpu/armv7/omap-common/Makefile b/arch/arm/cpu/armv7/omap-common/Makefile
index 5f5132f..7695e16 100644
--- a/arch/arm/cpu/armv7/omap-common/Makefile
+++ b/arch/arm/cpu/armv7/omap-common/Makefile
@@ -22,6 +22,10 @@ obj-y += pipe3-phy.o
obj-$(CONFIG_SCSI_AHCI_PLAT) += sata.o
endif
+ifeq ($(CONFIG_SYS_DCACHE_OFF),)
+obj-y += omap-cache.o
+endif
+
ifeq ($(CONFIG_OMAP34XX),)
obj-y += boot-common.o
obj-y += lowlevel_init.o
diff --git a/arch/arm/cpu/armv7/omap-common/hwinit-common.c b/arch/arm/cpu/armv7/omap-common/hwinit-common.c
index ba97d9e..5f50a19 100644
--- a/arch/arm/cpu/armv7/omap-common/hwinit-common.c
+++ b/arch/arm/cpu/armv7/omap-common/hwinit-common.c
@@ -18,13 +18,8 @@
#include <asm/emif.h>
#include <asm/omap_common.h>
#include <linux/compiler.h>
-#include <asm/cache.h>
#include <asm/system.h>
-#define ARMV7_DCACHE_WRITEBACK 0xe
-#define ARMV7_DOMAIN_CLIENT 1
-#define ARMV7_DOMAIN_MASK (0x3 << 0)
-
DECLARE_GLOBAL_DATA_PTR;
void do_set_mux(u32 base, struct pad_conf_entry const *array, int size)
@@ -263,40 +258,3 @@ int print_cpuinfo(void)
return 0;
}
#endif
-
-#ifndef CONFIG_SYS_DCACHE_OFF
-void enable_caches(void)
-{
- /* Enable D-cache. I-cache is already enabled in start.S */
- dcache_enable();
-}
-
-void dram_bank_mmu_setup(int bank)
-{
- bd_t *bd = gd->bd;
- int i;
-
- u32 start = bd->bi_dram[bank].start >> 20;
- u32 size = bd->bi_dram[bank].size >> 20;
- u32 end = start + size;
-
- debug("%s: bank: %d\n", __func__, bank);
- for (i = start; i < end; i++)
- set_section_dcache(i, ARMV7_DCACHE_WRITEBACK);
-
-}
-
-void arm_init_domains(void)
-{
- u32 reg;
-
- reg = get_dacr();
- /*
- * Set DOMAIN to client access so that all permissions
- * set in pagetables are validated by the mmu.
- */
- reg &= ~ARMV7_DOMAIN_MASK;
- reg |= ARMV7_DOMAIN_CLIENT;
- set_dacr(reg);
-}
-#endif
diff --git a/arch/arm/cpu/armv7/omap-common/mem-common.c b/arch/arm/cpu/armv7/omap-common/mem-common.c
index 944ef84..5bc7e1f 100644
--- a/arch/arm/cpu/armv7/omap-common/mem-common.c
+++ b/arch/arm/cpu/armv7/omap-common/mem-common.c
@@ -121,7 +121,8 @@ void gpmc_init(void)
writel(0x00000008, &gpmc_cfg->sysconfig);
writel(0x00000000, &gpmc_cfg->irqstatus);
writel(0x00000000, &gpmc_cfg->irqenable);
- writel(0x00000000, &gpmc_cfg->timeout_control);
+ /* disable timeout, set a safe reset value */
+ writel(0x00001ff0, &gpmc_cfg->timeout_control);
#ifdef CONFIG_NOR
writel(0x00000200, &gpmc_cfg->config);
#else
@@ -133,5 +134,6 @@ void gpmc_init(void)
writel(0, &gpmc_cfg->cs[0].config7);
sdelay(1000);
/* enable chip-select specific configurations */
- enable_gpmc_cs_config(gpmc_regs, &gpmc_cfg->cs[0], base, size);
+ if (base != 0)
+ enable_gpmc_cs_config(gpmc_regs, &gpmc_cfg->cs[0], base, size);
}
diff --git a/arch/arm/cpu/armv7/omap-common/omap-cache.c b/arch/arm/cpu/armv7/omap-common/omap-cache.c
new file mode 100644
index 0000000..579bebf
--- /dev/null
+++ b/arch/arm/cpu/armv7/omap-common/omap-cache.c
@@ -0,0 +1,56 @@
+/*
+ *
+ * Common functions for OMAP4/5 based boards
+ *
+ * (C) Copyright 2010
+ * Texas Instruments, <www.ti.com>
+ *
+ * Author :
+ * Aneesh V <aneesh@ti.com>
+ * Steve Sakoman <steve@sakoman.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/cache.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define ARMV7_DCACHE_WRITEBACK 0xe
+#define ARMV7_DOMAIN_CLIENT 1
+#define ARMV7_DOMAIN_MASK (0x3 << 0)
+
+void enable_caches(void)
+{
+ /* Enable D-cache. I-cache is already enabled in start.S */
+ dcache_enable();
+}
+
+void dram_bank_mmu_setup(int bank)
+{
+ bd_t *bd = gd->bd;
+ int i;
+
+ u32 start = bd->bi_dram[bank].start >> 20;
+ u32 size = bd->bi_dram[bank].size >> 20;
+ u32 end = start + size;
+
+ debug("%s: bank: %d\n", __func__, bank);
+ for (i = start; i < end; i++)
+ set_section_dcache(i, ARMV7_DCACHE_WRITEBACK);
+}
+
+void arm_init_domains(void)
+{
+ u32 reg;
+
+ reg = get_dacr();
+ /*
+ * Set DOMAIN to client access so that all permissions
+ * set in pagetables are validated by the mmu.
+ */
+ reg &= ~ARMV7_DOMAIN_MASK;
+ reg |= ARMV7_DOMAIN_CLIENT;
+ set_dacr(reg);
+}
diff --git a/arch/arm/cpu/armv7/omap3/board.c b/arch/arm/cpu/armv7/omap3/board.c
index 9bb1a1c..667e77f 100644
--- a/arch/arm/cpu/armv7/omap3/board.c
+++ b/arch/arm/cpu/armv7/omap3/board.c
@@ -147,7 +147,7 @@ void secure_unlock_mem(void)
* configure secure registers and exit secure world
* general use.
*****************************************************************************/
-void secureworld_exit()
+void secureworld_exit(void)
{
unsigned long i;
@@ -178,7 +178,7 @@ void secureworld_exit()
* Description: If chip is GP/EMU(special) type, unlock the SRAM for
* general use.
*****************************************************************************/
-void try_unlock_memory()
+void try_unlock_memory(void)
{
int mode;
int in_sdram = is_running_in_sdram();
@@ -478,11 +478,3 @@ void omap3_outer_cache_disable(void)
omap3_update_aux_cr(0, 0x2);
}
#endif /* !CONFIG_SYS_L2CACHE_OFF */
-
-#ifndef CONFIG_SYS_DCACHE_OFF
-void enable_caches(void)
-{
- /* Enable D-cache. I-cache is already enabled in start.S */
- dcache_enable();
-}
-#endif /* !CONFIG_SYS_DCACHE_OFF */
diff --git a/arch/arm/cpu/armv7/omap3/mem.c b/arch/arm/cpu/armv7/omap3/mem.c
index e649409..1832aff 100644
--- a/arch/arm/cpu/armv7/omap3/mem.c
+++ b/arch/arm/cpu/armv7/omap3/mem.c
@@ -21,17 +21,6 @@
struct gpmc *gpmc_cfg;
#if defined(CONFIG_CMD_NAND)
-#if defined(GPMC_NAND_ECC_SP_x8_LAYOUT) || defined(GPMC_NAND_ECC_LP_x8_LAYOUT)
-static const u32 gpmc_m_nand[GPMC_MAX_REG] = {
- SMNAND_GPMC_CONFIG1,
- SMNAND_GPMC_CONFIG2,
- SMNAND_GPMC_CONFIG3,
- SMNAND_GPMC_CONFIG4,
- SMNAND_GPMC_CONFIG5,
- SMNAND_GPMC_CONFIG6,
- 0,
-};
-#else
static const u32 gpmc_m_nand[GPMC_MAX_REG] = {
M_NAND_GPMC_CONFIG1,
M_NAND_GPMC_CONFIG2,
@@ -40,7 +29,6 @@ static const u32 gpmc_m_nand[GPMC_MAX_REG] = {
M_NAND_GPMC_CONFIG5,
M_NAND_GPMC_CONFIG6, 0
};
-#endif
#endif /* CONFIG_CMD_NAND */
#if defined(CONFIG_CMD_ONENAND)
diff --git a/arch/arm/cpu/armv7/socfpga/Makefile b/arch/arm/cpu/armv7/socfpga/Makefile
index cbe1d40..eb33f2c 100644
--- a/arch/arm/cpu/armv7/socfpga/Makefile
+++ b/arch/arm/cpu/armv7/socfpga/Makefile
@@ -9,4 +9,4 @@
obj-y := lowlevel_init.o
obj-y += misc.o timer.o reset_manager.o system_manager.o clock_manager.o
-obj-$(CONFIG_SPL_BUILD) += spl.o freeze_controller.o
+obj-$(CONFIG_SPL_BUILD) += spl.o freeze_controller.o scan_manager.o
diff --git a/arch/arm/cpu/armv7/socfpga/misc.c b/arch/arm/cpu/armv7/socfpga/misc.c
index 2f1c716..5268f2c 100644
--- a/arch/arm/cpu/armv7/socfpga/misc.c
+++ b/arch/arm/cpu/armv7/socfpga/misc.c
@@ -14,3 +14,27 @@ int dram_init(void)
gd->ram_size = get_ram_size((long *)PHYS_SDRAM_1, PHYS_SDRAM_1_SIZE);
return 0;
}
+
+#if defined(CONFIG_DISPLAY_CPUINFO)
+/*
+ * Print CPU information
+ */
+int print_cpuinfo(void)
+{
+ puts("CPU : Altera SOCFPGA Platform\n");
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_SYS_CONSOLE_IS_IN_ENV) && \
+defined(CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE)
+int overwrite_console(void)
+{
+ return 0;
+}
+#endif
+
+int misc_init_r(void)
+{
+ return 0;
+}
diff --git a/arch/arm/cpu/armv7/socfpga/scan_manager.c b/arch/arm/cpu/armv7/socfpga/scan_manager.c
new file mode 100644
index 0000000..a820b1b
--- /dev/null
+++ b/arch/arm/cpu/armv7/socfpga/scan_manager.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2013 Altera Corporation <www.altera.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/freeze_controller.h>
+#include <asm/arch/scan_manager.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const struct socfpga_scan_manager *scan_manager_base =
+ (void *)(SOCFPGA_SCANMGR_ADDRESS);
+static const struct socfpga_freeze_controller *freeze_controller_base =
+ (void *)(SOCFPGA_SYSMGR_ADDRESS + SYSMGR_FRZCTRL_ADDRESS);
+
+/*
+ * Function to check IO scan chain engine status and wait if the engine is
+ * is active. Poll the IO scan chain engine till maximum iteration reached.
+ */
+static inline uint32_t scan_chain_engine_is_idle(uint32_t max_iter)
+{
+ uint32_t scanmgr_status;
+
+ scanmgr_status = readl(&scan_manager_base->stat);
+
+ /* Poll the engine until the scan engine is inactive */
+ while (SCANMGR_STAT_ACTIVE_GET(scanmgr_status) ||
+ (SCANMGR_STAT_WFIFOCNT_GET(scanmgr_status) > 0)) {
+ max_iter--;
+ if (max_iter > 0)
+ scanmgr_status = readl(&scan_manager_base->stat);
+ else
+ return 0;
+ }
+ return 1;
+}
+
+/* Program HPS IO Scan Chain */
+uint32_t scan_mgr_io_scan_chain_prg(
+ uint32_t io_scan_chain_id,
+ uint32_t io_scan_chain_len_in_bits,
+ const uint32_t *iocsr_scan_chain)
+{
+ uint16_t tdi_tdo_header;
+ uint32_t io_program_iter;
+ uint32_t io_scan_chain_data_residual;
+ uint32_t residual;
+ uint32_t i;
+ uint32_t index = 0;
+
+ /*
+ * De-assert reinit if the IO scan chain is intended for HIO. In
+ * this, its the chain 3.
+ */
+ if (io_scan_chain_id == 3)
+ clrbits_le32(&freeze_controller_base->hioctrl,
+ SYSMGR_FRZCTRL_HIOCTRL_DLLRST_MASK);
+
+ /*
+ * Check if the scan chain engine is inactive and the
+ * WFIFO is empty before enabling the IO scan chain
+ */
+ if (!scan_chain_engine_is_idle(SCAN_MAX_DELAY))
+ return 1;
+
+ /*
+ * Enable IO Scan chain based on scan chain id
+ * Note: only one chain can be enabled at a time
+ */
+ setbits_le32(&scan_manager_base->en, 1 << io_scan_chain_id);
+
+ /*
+ * Calculate number of iteration needed for full 128-bit (4 x32-bits)
+ * bits shifting. Each TDI_TDO packet can shift in maximum 128-bits
+ */
+ io_program_iter = io_scan_chain_len_in_bits >>
+ IO_SCAN_CHAIN_128BIT_SHIFT;
+ io_scan_chain_data_residual = io_scan_chain_len_in_bits &
+ IO_SCAN_CHAIN_128BIT_MASK;
+
+ /* Construct TDI_TDO packet for 128-bit IO scan chain (2 bytes) */
+ tdi_tdo_header = TDI_TDO_HEADER_FIRST_BYTE |
+ (TDI_TDO_MAX_PAYLOAD << TDI_TDO_HEADER_SECOND_BYTE_SHIFT);
+
+ /* Program IO scan chain in 128-bit iteration */
+ for (i = 0; i < io_program_iter; i++) {
+ /* write TDI_TDO packet header to scan manager */
+ writel(tdi_tdo_header, &scan_manager_base->fifo_double_byte);
+
+ /* calculate array index. Multiply by 4 as write 4 x 32bits */
+ index = i * 4;
+
+ /* write 4 successive 32-bit IO scan chain data into WFIFO */
+ writel(iocsr_scan_chain[index],
+ &scan_manager_base->fifo_quad_byte);
+ writel(iocsr_scan_chain[index + 1],
+ &scan_manager_base->fifo_quad_byte);
+ writel(iocsr_scan_chain[index + 2],
+ &scan_manager_base->fifo_quad_byte);
+ writel(iocsr_scan_chain[index + 3],
+ &scan_manager_base->fifo_quad_byte);
+
+ /*
+ * Check if the scan chain engine has completed the
+ * IO scan chain data shifting
+ */
+ if (!scan_chain_engine_is_idle(SCAN_MAX_DELAY))
+ goto error;
+ }
+
+ /* Calculate array index for final TDI_TDO packet */
+ index = io_program_iter * 4;
+
+ /* Final TDI_TDO packet if any */
+ if (io_scan_chain_data_residual) {
+ /*
+ * Calculate number of quad bytes FIFO write
+ * needed for the final TDI_TDO packet
+ */
+ io_program_iter = io_scan_chain_data_residual >>
+ IO_SCAN_CHAIN_32BIT_SHIFT;
+
+ /*
+ * Construct TDI_TDO packet for remaining IO
+ * scan chain (2 bytes)
+ */
+ tdi_tdo_header = TDI_TDO_HEADER_FIRST_BYTE |
+ ((io_scan_chain_data_residual - 1) <<
+ TDI_TDO_HEADER_SECOND_BYTE_SHIFT);
+
+ /*
+ * Program the last part of IO scan chain write TDI_TDO packet
+ * header (2 bytes) to scan manager
+ */
+ writel(tdi_tdo_header, &scan_manager_base->fifo_double_byte);
+
+ for (i = 0; i < io_program_iter; i++) {
+ /*
+ * write remaining scan chain data into scan
+ * manager WFIFO with 4 bytes write
+ */
+ writel(iocsr_scan_chain[index + i],
+ &scan_manager_base->fifo_quad_byte);
+ }
+
+ index += io_program_iter;
+ residual = io_scan_chain_data_residual &
+ IO_SCAN_CHAIN_32BIT_MASK;
+
+ if (IO_SCAN_CHAIN_PAYLOAD_24BIT < residual) {
+ /*
+ * write the last 4B scan chain data
+ * into scan manager WFIFO
+ */
+ writel(iocsr_scan_chain[index],
+ &scan_manager_base->fifo_quad_byte);
+ } else {
+ /*
+ * write the remaining 1 - 3 bytes scan chain
+ * data into scan manager WFIFO byte by byte
+ * to prevent JTAG engine shifting unused data
+ * from the FIFO and mistaken the data as a
+ * valid command (even though unused bits are
+ * set to 0, but just to prevent hardware
+ * glitch)
+ */
+ for (i = 0; i < residual; i += 8) {
+ writel(((iocsr_scan_chain[index] >> i)
+ & IO_SCAN_CHAIN_BYTE_MASK),
+ &scan_manager_base->fifo_single_byte);
+ }
+ }
+
+ /*
+ * Check if the scan chain engine has completed the
+ * IO scan chain data shifting
+ */
+ if (!scan_chain_engine_is_idle(SCAN_MAX_DELAY))
+ goto error;
+ }
+
+ /* Disable IO Scan chain when configuration done*/
+ clrbits_le32(&scan_manager_base->en, 1 << io_scan_chain_id);
+ return 0;
+
+error:
+ /* Disable IO Scan chain when error detected */
+ clrbits_le32(&scan_manager_base->en, 1 << io_scan_chain_id);
+ return 1;
+}
+
+int scan_mgr_configure_iocsr(void)
+{
+ int status = 0;
+
+ /* configure the IOCSR through scan chain */
+ status |= scan_mgr_io_scan_chain_prg(0,
+ CONFIG_HPS_IOCSR_SCANCHAIN0_LENGTH, iocsr_scan_chain0_table);
+ status |= scan_mgr_io_scan_chain_prg(1,
+ CONFIG_HPS_IOCSR_SCANCHAIN1_LENGTH, iocsr_scan_chain1_table);
+ status |= scan_mgr_io_scan_chain_prg(2,
+ CONFIG_HPS_IOCSR_SCANCHAIN2_LENGTH, iocsr_scan_chain2_table);
+ status |= scan_mgr_io_scan_chain_prg(3,
+ CONFIG_HPS_IOCSR_SCANCHAIN3_LENGTH, iocsr_scan_chain3_table);
+ return status;
+}
diff --git a/arch/arm/cpu/armv7/socfpga/spl.c b/arch/arm/cpu/armv7/socfpga/spl.c
index 2ae88bb..4bed19d 100644
--- a/arch/arm/cpu/armv7/socfpga/spl.c
+++ b/arch/arm/cpu/armv7/socfpga/spl.c
@@ -121,6 +121,10 @@ void spl_board_init(void)
/* reconfigure the PLLs */
cm_basic_init(&cm_default_cfg);
+ /* configure the IOCSR / IO buffer settings */
+ if (scan_mgr_configure_iocsr())
+ hang();
+
/* configure the pin muxing through system manager */
sysmgr_pinmux_init();
#endif /* CONFIG_SOCFPGA_VIRTUAL_TARGET */
diff --git a/arch/arm/cpu/armv7/tegra20/display.c b/arch/arm/cpu/armv7/tegra20/display.c
index 488f0c6..fd77f3f 100644
--- a/arch/arm/cpu/armv7/tegra20/display.c
+++ b/arch/arm/cpu/armv7/tegra20/display.c
@@ -328,7 +328,7 @@ static int tegra_display_decode_config(const void *blob,
rgb = fdt_subnode_offset(blob, node, "rgb");
config->panel_node = fdtdec_lookup_phandle(blob, rgb, "nvidia,panel");
- if (!config->panel_node < 0) {
+ if (config->panel_node < 0) {
debug("%s: Cannot find panel information\n", __func__);
return -1;
}
diff --git a/arch/arm/cpu/armv7/zynq/u-boot.lds b/arch/arm/cpu/armv7/zynq/u-boot.lds
index 69500a6..4dc9bb0 100644
--- a/arch/arm/cpu/armv7/zynq/u-boot.lds
+++ b/arch/arm/cpu/armv7/zynq/u-boot.lds
@@ -18,6 +18,7 @@ SECTIONS
.text :
{
*(.__image_copy_start)
+ *(.vectors)
CPUDIR/start.o (.text*)
*(.text*)
}
diff --git a/arch/arm/cpu/armv8/cache_v8.c b/arch/arm/cpu/armv8/cache_v8.c
index a96ecda..9dbcdf2 100644
--- a/arch/arm/cpu/armv8/cache_v8.c
+++ b/arch/arm/cpu/armv8/cache_v8.c
@@ -12,15 +12,14 @@
DECLARE_GLOBAL_DATA_PTR;
#ifndef CONFIG_SYS_DCACHE_OFF
-
-static void set_pgtable_section(u64 section, u64 memory_type)
+void set_pgtable_section(u64 *page_table, u64 index, u64 section,
+ u64 memory_type)
{
- u64 *page_table = (u64 *)gd->arch.tlb_addr;
u64 value;
- value = (section << SECTION_SHIFT) | PMD_TYPE_SECT | PMD_SECT_AF;
+ value = section | PMD_TYPE_SECT | PMD_SECT_AF;
value |= PMD_ATTRINDX(memory_type);
- page_table[section] = value;
+ page_table[index] = value;
}
/* to activate the MMU we need to set up virtual memory */
@@ -28,10 +27,13 @@ static void mmu_setup(void)
{
int i, j, el;
bd_t *bd = gd->bd;
+ u64 *page_table = (u64 *)gd->arch.tlb_addr;
/* Setup an identity-mapping for all spaces */
- for (i = 0; i < (PGTABLE_SIZE >> 3); i++)
- set_pgtable_section(i, MT_DEVICE_NGNRNE);
+ for (i = 0; i < (PGTABLE_SIZE >> 3); i++) {
+ set_pgtable_section(page_table, i, i << SECTION_SHIFT,
+ MT_DEVICE_NGNRNE);
+ }
/* Setup an identity-mapping for all RAM space */
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
@@ -39,38 +41,26 @@ static void mmu_setup(void)
ulong end = bd->bi_dram[i].start + bd->bi_dram[i].size;
for (j = start >> SECTION_SHIFT;
j < end >> SECTION_SHIFT; j++) {
- set_pgtable_section(j, MT_NORMAL);
+ set_pgtable_section(page_table, j, j << SECTION_SHIFT,
+ MT_NORMAL);
}
}
/* load TTBR0 */
el = current_el();
if (el == 1) {
- asm volatile("msr ttbr0_el1, %0"
- : : "r" (gd->arch.tlb_addr) : "memory");
- asm volatile("msr tcr_el1, %0"
- : : "r" (TCR_FLAGS | TCR_EL1_IPS_BITS)
- : "memory");
- asm volatile("msr mair_el1, %0"
- : : "r" (MEMORY_ATTRIBUTES) : "memory");
+ set_ttbr_tcr_mair(el, gd->arch.tlb_addr,
+ TCR_FLAGS | TCR_EL1_IPS_BITS,
+ MEMORY_ATTRIBUTES);
} else if (el == 2) {
- asm volatile("msr ttbr0_el2, %0"
- : : "r" (gd->arch.tlb_addr) : "memory");
- asm volatile("msr tcr_el2, %0"
- : : "r" (TCR_FLAGS | TCR_EL2_IPS_BITS)
- : "memory");
- asm volatile("msr mair_el2, %0"
- : : "r" (MEMORY_ATTRIBUTES) : "memory");
+ set_ttbr_tcr_mair(el, gd->arch.tlb_addr,
+ TCR_FLAGS | TCR_EL2_IPS_BITS,
+ MEMORY_ATTRIBUTES);
} else {
- asm volatile("msr ttbr0_el3, %0"
- : : "r" (gd->arch.tlb_addr) : "memory");
- asm volatile("msr tcr_el3, %0"
- : : "r" (TCR_FLAGS | TCR_EL2_IPS_BITS)
- : "memory");
- asm volatile("msr mair_el3, %0"
- : : "r" (MEMORY_ATTRIBUTES) : "memory");
+ set_ttbr_tcr_mair(el, gd->arch.tlb_addr,
+ TCR_FLAGS | TCR_EL3_IPS_BITS,
+ MEMORY_ATTRIBUTES);
}
-
/* enable the mmu */
set_sctlr(get_sctlr() | CR_M);
}
@@ -83,12 +73,17 @@ void invalidate_dcache_all(void)
__asm_invalidate_dcache_all();
}
+void __weak flush_l3_cache(void)
+{
+}
+
/*
* Performs a clean & invalidation of the entire data cache at all levels
*/
void flush_dcache_all(void)
{
__asm_flush_dcache_all();
+ flush_l3_cache();
}
/*
@@ -221,7 +216,7 @@ void invalidate_icache_all(void)
* Enable dCache & iCache, whether cache is actually enabled
* depend on CONFIG_SYS_DCACHE_OFF and CONFIG_SYS_ICACHE_OFF
*/
-void enable_caches(void)
+void __weak enable_caches(void)
{
icache_enable();
dcache_enable();
diff --git a/arch/arm/cpu/armv8/fsl-lsch3/Makefile b/arch/arm/cpu/armv8/fsl-lsch3/Makefile
new file mode 100644
index 0000000..9249537
--- /dev/null
+++ b/arch/arm/cpu/armv8/fsl-lsch3/Makefile
@@ -0,0 +1,9 @@
+#
+# Copyright 2014, Freescale Semiconductor
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-y += cpu.o
+obj-y += lowlevel.o
+obj-y += speed.o
diff --git a/arch/arm/cpu/armv8/fsl-lsch3/README b/arch/arm/cpu/armv8/fsl-lsch3/README
new file mode 100644
index 0000000..cc47466
--- /dev/null
+++ b/arch/arm/cpu/armv8/fsl-lsch3/README
@@ -0,0 +1,10 @@
+#
+# Copyright 2014 Freescale Semiconductor
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+Freescale LayerScape with Chassis Generation 3
+
+This architecture supports Freescale ARMv8 SoCs with Chassis generation 3,
+for example LS2085A.
diff --git a/arch/arm/cpu/armv8/fsl-lsch3/cpu.c b/arch/arm/cpu/armv8/fsl-lsch3/cpu.c
new file mode 100644
index 0000000..c129d03
--- /dev/null
+++ b/arch/arm/cpu/armv8/fsl-lsch3/cpu.c
@@ -0,0 +1,436 @@
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/armv8/mmu.h>
+#include <asm/io.h>
+#include <asm/arch-fsl-lsch3/immap_lsch3.h>
+#include "cpu.h"
+#include "speed.h"
+#include <fsl_mc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifndef CONFIG_SYS_DCACHE_OFF
+/*
+ * To start MMU before DDR is available, we create MMU table in SRAM.
+ * The base address of SRAM is CONFIG_SYS_FSL_OCRAM_BASE. We use three
+ * 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
+ */
+
+#define SECTION_SHIFT_L0 39UL
+#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 CONFIG_SYS_IFC_BASE 0x30000000
+#define CONFIG_SYS_IFC_SIZE 0x10000000
+#define CONFIG_SYS_IFC_BASE2 0x500000000
+#define CONFIG_SYS_IFC_SIZE2 0x100000000
+#define TCR_EL2_PS_40BIT (2 << 16)
+#define LSCH3_VA_BITS (40)
+#define LSCH3_TCR (TCR_TG0_4K | \
+ TCR_EL2_PS_40BIT | \
+ TCR_SHARED_NON | \
+ TCR_ORGN_NC | \
+ TCR_IRGN_NC | \
+ TCR_T0SZ(LSCH3_VA_BITS))
+
+/*
+ * Final MMU
+ * Let's start from the same layout as early MMU and modify as needed.
+ * IFC regions will be cache-inhibit.
+ */
+#define FINAL_QBMAN_CACHED_MEM 0x818000000UL
+#define FINAL_QBMAN_CACHED_SIZE 0x4000000
+
+
+static inline void early_mmu_setup(void)
+{
+ int el;
+ u64 i;
+ u64 section_l1t0, section_l1t1, section_l2;
+ 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);
+
+
+ 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 to cache_inhibit, covering 0 to 512GB
+ * set level 1 table 1 to cache enabled, covering 512GB to 1TB
+ * set level 2 table to cache-inhibit, covering 0 to 1GB
+ */
+ section_l1t0 = 0;
+ section_l1t1 = BLOCK_SIZE_L0;
+ section_l2 = 0;
+ 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,
+ MT_DEVICE_NGNRNE);
+ section_l1t0 += BLOCK_SIZE_L1;
+ section_l1t1 += BLOCK_SIZE_L1;
+ section_l2 += BLOCK_SIZE_L2;
+ }
+
+ level1_table_0[0] =
+ (u64)level2_table | PMD_TYPE_TABLE;
+ level1_table_0[1] =
+ 0x40000000 | PMD_SECT_AF | PMD_TYPE_SECT |
+ PMD_ATTRINDX(MT_DEVICE_NGNRNE);
+ level1_table_0[2] =
+ 0x80000000 | PMD_SECT_AF | PMD_TYPE_SECT |
+ PMD_ATTRINDX(MT_NORMAL);
+ level1_table_0[3] =
+ 0xc0000000 | PMD_SECT_AF | PMD_TYPE_SECT |
+ PMD_ATTRINDX(MT_NORMAL);
+
+ /* Rewrite table to enable cache */
+ set_pgtable_section(level2_table,
+ 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);
+ }
+
+ el = current_el();
+ set_ttbr_tcr_mair(el, (u64)level0_table, LSCH3_TCR, MEMORY_ATTRIBUTES);
+ set_sctlr(get_sctlr() | CR_M);
+}
+
+/*
+ * This final tale looks similar to early table, but different in detail.
+ * These tables are in regular memory. Cache on IFC is disabled. One sub table
+ * is added to enable cache for QBMan.
+ */
+static inline void final_mmu_setup(void)
+{
+ int el;
+ u64 i, tbl_base, tbl_limit, section_base;
+ u64 section_l1t0, section_l1t1, section_l2;
+ u64 *level0_table = (u64 *)gd->arch.tlb_addr;
+ u64 *level1_table_0 = (u64 *)(gd->arch.tlb_addr + 0x1000);
+ u64 *level1_table_1 = (u64 *)(gd->arch.tlb_addr + 0x2000);
+ u64 *level2_table_0 = (u64 *)(gd->arch.tlb_addr + 0x3000);
+ u64 *level2_table_1 = (u64 *)(gd->arch.tlb_addr + 0x4000);
+
+
+ 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 to cache_inhibit, covering 0 to 512GB
+ * set level 1 table 1 to cache enabled, covering 512GB to 1TB
+ * set level 2 table 0 to cache-inhibit, covering 0 to 1GB
+ */
+ section_l1t0 = 0;
+ section_l1t1 = BLOCK_SIZE_L0;
+ section_l2 = 0;
+ 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_0, i, section_l2,
+ MT_DEVICE_NGNRNE);
+ section_l1t0 += BLOCK_SIZE_L1;
+ section_l1t1 += BLOCK_SIZE_L1;
+ section_l2 += BLOCK_SIZE_L2;
+ }
+
+ level1_table_0[0] =
+ (u64)level2_table_0 | PMD_TYPE_TABLE;
+ level1_table_0[2] =
+ 0x80000000 | PMD_SECT_AF | PMD_TYPE_SECT |
+ PMD_ATTRINDX(MT_NORMAL);
+ level1_table_0[3] =
+ 0xc0000000 | PMD_SECT_AF | PMD_TYPE_SECT |
+ PMD_ATTRINDX(MT_NORMAL);
+
+ /* Rewrite table to enable cache */
+ set_pgtable_section(level2_table_0,
+ CONFIG_SYS_FSL_OCRAM_BASE >> SECTION_SHIFT_L2,
+ CONFIG_SYS_FSL_OCRAM_BASE,
+ MT_NORMAL);
+
+ /*
+ * Fill in other part of tables if cache is needed
+ * If finer granularity than 1GB is needed, sub table
+ * should be created.
+ */
+ section_base = FINAL_QBMAN_CACHED_MEM & ~(BLOCK_SIZE_L1 - 1);
+ i = section_base >> SECTION_SHIFT_L1;
+ level1_table_0[i] = (u64)level2_table_1 | PMD_TYPE_TABLE;
+ section_l2 = section_base;
+ for (i = 0; i < 512; i++) {
+ set_pgtable_section(level2_table_1, i, section_l2,
+ MT_DEVICE_NGNRNE);
+ section_l2 += BLOCK_SIZE_L2;
+ }
+ tbl_base = FINAL_QBMAN_CACHED_MEM & (BLOCK_SIZE_L1 - 1);
+ tbl_limit = (FINAL_QBMAN_CACHED_MEM + FINAL_QBMAN_CACHED_SIZE) &
+ (BLOCK_SIZE_L1 - 1);
+ for (i = tbl_base >> SECTION_SHIFT_L2;
+ i < tbl_limit >> SECTION_SHIFT_L2; i++) {
+ section_l2 = section_base + (i << SECTION_SHIFT_L2);
+ set_pgtable_section(level2_table_1, i,
+ section_l2, MT_NORMAL);
+ }
+
+ /* 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();
+ asm volatile("dsb sy");
+ if (el == 1) {
+ asm volatile("msr ttbr0_el1, %0"
+ : : "r" ((u64)level0_table) : "memory");
+ } else if (el == 2) {
+ asm volatile("msr ttbr0_el2, %0"
+ : : "r" ((u64)level0_table) : "memory");
+ } else if (el == 3) {
+ asm volatile("msr ttbr0_el3, %0"
+ : : "r" ((u64)level0_table) : "memory");
+ } else {
+ hang();
+ }
+ asm volatile("isb");
+
+ /*
+ * MMU is already enabled, just need to invalidate TLB to load the
+ * new table. The new table is compatible with the current table, if
+ * MMU somehow walks through the new table before invalidation TLB,
+ * it still works. So we don't need to turn off MMU here.
+ */
+}
+
+int arch_cpu_init(void)
+{
+ icache_enable();
+ __asm_invalidate_dcache_all();
+ __asm_invalidate_tlb_all();
+ early_mmu_setup();
+ set_sctlr(get_sctlr() | CR_C);
+ return 0;
+}
+
+/*
+ * flush_l3_cache
+ * Dickens L3 cache can be flushed by transitioning from FAM to SFONLY power
+ * state, by writing to HP-F P-state request register.
+ * Fixme: This function should moved to a common file if other SoCs also use
+ * the same Dickens.
+ */
+#define HNF0_PSTATE_REQ 0x04200010
+#define HNF1_PSTATE_REQ 0x04210010
+#define HNF2_PSTATE_REQ 0x04220010
+#define HNF3_PSTATE_REQ 0x04230010
+#define HNF4_PSTATE_REQ 0x04240010
+#define HNF5_PSTATE_REQ 0x04250010
+#define HNF6_PSTATE_REQ 0x04260010
+#define HNF7_PSTATE_REQ 0x04270010
+#define HNFPSTAT_MASK (0xFFFFFFFFFFFFFFFC)
+#define HNFPSTAT_FAM 0x3
+#define HNFPSTAT_SFONLY 0x01
+
+static void hnf_pstate_req(u64 *ptr, u64 state)
+{
+ int timeout = 1000;
+ out_le64(ptr, (in_le64(ptr) & HNFPSTAT_MASK) | (state & 0x3));
+ ptr++;
+ /* checking if the transition is completed */
+ while (timeout > 0) {
+ if (((in_le64(ptr) & 0x0c) >> 2) == (state & 0x3))
+ break;
+ udelay(100);
+ timeout--;
+ }
+}
+
+void flush_l3_cache(void)
+{
+ hnf_pstate_req((u64 *)HNF0_PSTATE_REQ, HNFPSTAT_SFONLY);
+ hnf_pstate_req((u64 *)HNF1_PSTATE_REQ, HNFPSTAT_SFONLY);
+ hnf_pstate_req((u64 *)HNF2_PSTATE_REQ, HNFPSTAT_SFONLY);
+ hnf_pstate_req((u64 *)HNF3_PSTATE_REQ, HNFPSTAT_SFONLY);
+ hnf_pstate_req((u64 *)HNF4_PSTATE_REQ, HNFPSTAT_SFONLY);
+ hnf_pstate_req((u64 *)HNF5_PSTATE_REQ, HNFPSTAT_SFONLY);
+ hnf_pstate_req((u64 *)HNF6_PSTATE_REQ, HNFPSTAT_SFONLY);
+ hnf_pstate_req((u64 *)HNF7_PSTATE_REQ, HNFPSTAT_SFONLY);
+ hnf_pstate_req((u64 *)HNF0_PSTATE_REQ, HNFPSTAT_FAM);
+ hnf_pstate_req((u64 *)HNF1_PSTATE_REQ, HNFPSTAT_FAM);
+ hnf_pstate_req((u64 *)HNF2_PSTATE_REQ, HNFPSTAT_FAM);
+ hnf_pstate_req((u64 *)HNF3_PSTATE_REQ, HNFPSTAT_FAM);
+ hnf_pstate_req((u64 *)HNF4_PSTATE_REQ, HNFPSTAT_FAM);
+ hnf_pstate_req((u64 *)HNF5_PSTATE_REQ, HNFPSTAT_FAM);
+ hnf_pstate_req((u64 *)HNF6_PSTATE_REQ, HNFPSTAT_FAM);
+ hnf_pstate_req((u64 *)HNF7_PSTATE_REQ, HNFPSTAT_FAM);
+}
+
+/*
+ * 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)
+{
+ final_mmu_setup();
+ __asm_invalidate_tlb_all();
+}
+#endif
+
+static inline u32 initiator_type(u32 cluster, int init_id)
+{
+ struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
+ u32 idx = (cluster >> (init_id * 8)) & TP_CLUSTER_INIT_MASK;
+ u32 type = in_le32(&gur->tp_ityp[idx]);
+
+ if (type & TP_ITYP_AV)
+ return type;
+
+ return 0;
+}
+
+u32 cpu_mask(void)
+{
+ struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
+ int i = 0, count = 0;
+ u32 cluster, type, mask = 0;
+
+ do {
+ int j;
+ cluster = in_le32(&gur->tp_cluster[i].lower);
+ for (j = 0; j < TP_INIT_PER_CLUSTER; j++) {
+ type = initiator_type(cluster, j);
+ if (type) {
+ if (TP_ITYP_TYPE(type) == TP_ITYP_TYPE_ARM)
+ mask |= 1 << count;
+ count++;
+ }
+ }
+ i++;
+ } while ((cluster & TP_CLUSTER_EOC) != TP_CLUSTER_EOC);
+
+ return mask;
+}
+
+/*
+ * Return the number of cores on this SOC.
+ */
+int cpu_numcores(void)
+{
+ return hweight32(cpu_mask());
+}
+
+int fsl_qoriq_core_to_cluster(unsigned int core)
+{
+ struct ccsr_gur __iomem *gur =
+ (void __iomem *)(CONFIG_SYS_FSL_GUTS_ADDR);
+ int i = 0, count = 0;
+ u32 cluster;
+
+ do {
+ int j;
+ cluster = in_le32(&gur->tp_cluster[i].lower);
+ for (j = 0; j < TP_INIT_PER_CLUSTER; j++) {
+ if (initiator_type(cluster, j)) {
+ if (count == core)
+ return i;
+ count++;
+ }
+ }
+ i++;
+ } while ((cluster & TP_CLUSTER_EOC) != TP_CLUSTER_EOC);
+
+ return -1; /* cannot identify the cluster */
+}
+
+u32 fsl_qoriq_core_to_type(unsigned int core)
+{
+ struct ccsr_gur __iomem *gur =
+ (void __iomem *)(CONFIG_SYS_FSL_GUTS_ADDR);
+ int i = 0, count = 0;
+ u32 cluster, type;
+
+ do {
+ int j;
+ cluster = in_le32(&gur->tp_cluster[i].lower);
+ for (j = 0; j < TP_INIT_PER_CLUSTER; j++) {
+ type = initiator_type(cluster, j);
+ if (type) {
+ if (count == core)
+ return type;
+ count++;
+ }
+ }
+ i++;
+ } while ((cluster & TP_CLUSTER_EOC) != TP_CLUSTER_EOC);
+
+ return -1; /* cannot identify the cluster */
+}
+
+#ifdef CONFIG_DISPLAY_CPUINFO
+int print_cpuinfo(void)
+{
+ struct sys_info sysinfo;
+ char buf[32];
+ unsigned int i, core;
+ u32 type;
+
+ get_sys_info(&sysinfo);
+ puts("Clock Configuration:");
+ for_each_cpu(i, core, cpu_numcores(), cpu_mask()) {
+ if (!(i % 3))
+ puts("\n ");
+ type = TP_ITYP_VER(fsl_qoriq_core_to_type(core));
+ printf("CPU%d(%s):%-4s MHz ", core,
+ type == TY_ITYP_VER_A7 ? "A7 " :
+ (type == TY_ITYP_VER_A53 ? "A53" :
+ (type == TY_ITYP_VER_A57 ? "A57" : " ")),
+ strmhz(buf, sysinfo.freq_processor[core]));
+ }
+ printf("\n Bus: %-4s MHz ",
+ strmhz(buf, sysinfo.freq_systembus));
+ printf("DDR: %-4s MHz", strmhz(buf, sysinfo.freq_ddrbus));
+ puts("\n");
+
+ return 0;
+}
+#endif
+
+int cpu_eth_init(bd_t *bis)
+{
+ int error = 0;
+
+#ifdef CONFIG_FSL_MC_ENET
+ error = mc_init(bis);
+#endif
+ return error;
+}
diff --git a/arch/arm/cpu/armv8/fsl-lsch3/cpu.h b/arch/arm/cpu/armv8/fsl-lsch3/cpu.h
new file mode 100644
index 0000000..28544d7
--- /dev/null
+++ b/arch/arm/cpu/armv8/fsl-lsch3/cpu.h
@@ -0,0 +1,7 @@
+/*
+ * Copyright 2014, Freescale Semiconductor
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+int fsl_qoriq_core_to_cluster(unsigned int core);
diff --git a/arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S b/arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S
new file mode 100644
index 0000000..ad32b6c
--- /dev/null
+++ b/arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S
@@ -0,0 +1,65 @@
+/*
+ * (C) Copyright 2014 Freescale Semiconductor
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Extracted from armv8/start.S
+ */
+
+#include <config.h>
+#include <linux/linkage.h>
+#include <asm/macro.h>
+
+ENTRY(lowlevel_init)
+ mov x29, lr /* Save LR */
+
+ /* Set the SMMU page size in the sACR register */
+ ldr x1, =SMMU_BASE
+ ldr w0, [x1, #0x10]
+ orr w0, w0, #1 << 16 /* set sACR.pagesize to indicate 64K page */
+ str w0, [x1, #0x10]
+
+ /* Initialize GIC Secure Bank Status */
+#if defined(CONFIG_GICV2) || defined(CONFIG_GICV3)
+ branch_if_slave x0, 1f
+ ldr x0, =GICD_BASE
+ bl gic_init_secure
+1:
+#ifdef CONFIG_GICV3
+ ldr x0, =GICR_BASE
+ bl gic_init_secure_percpu
+#elif defined(CONFIG_GICV2)
+ ldr x0, =GICD_BASE
+ ldr x1, =GICC_BASE
+ bl gic_init_secure_percpu
+#endif
+#endif
+
+ branch_if_master x0, x1, 1f
+
+ /*
+ * Slave should wait for master clearing spin table.
+ * This sync prevent salves observing incorrect
+ * value of spin table and jumping to wrong place.
+ */
+#if defined(CONFIG_GICV2) || defined(CONFIG_GICV3)
+#ifdef CONFIG_GICV2
+ ldr x0, =GICC_BASE
+#endif
+ bl gic_wait_for_interrupt
+#endif
+
+ /*
+ * All processors will enter EL2 and optionally EL1.
+ */
+ bl armv8_switch_to_el2
+#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
+ bl armv8_switch_to_el1
+#endif
+ b 2f
+
+1:
+2:
+ mov lr, x29 /* Restore LR */
+ ret
+ENDPROC(lowlevel_init)
diff --git a/arch/arm/cpu/armv8/fsl-lsch3/speed.c b/arch/arm/cpu/armv8/fsl-lsch3/speed.c
new file mode 100644
index 0000000..dc4a34b
--- /dev/null
+++ b/arch/arm/cpu/armv8/fsl-lsch3/speed.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2014, Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Derived from arch/power/cpu/mpc85xx/speed.c
+ */
+
+#include <common.h>
+#include <linux/compiler.h>
+#include <fsl_ifc.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/arch-fsl-lsch3/immap_lsch3.h>
+#include <asm/arch/clock.h>
+#include "cpu.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifndef CONFIG_SYS_FSL_NUM_CC_PLLS
+#define CONFIG_SYS_FSL_NUM_CC_PLLS 6
+#endif
+
+
+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;
+ u32 ccr;
+#endif
+ struct ccsr_clk_cluster_group __iomem *clk_grp[2] = {
+ (void *)(CONFIG_SYS_FSL_CH3_CLK_GRPA_ADDR),
+ (void *)(CONFIG_SYS_FSL_CH3_CLK_GRPB_ADDR)
+ };
+ struct ccsr_clk_ctrl __iomem *clk_ctrl =
+ (void *)(CONFIG_SYS_FSL_CH3_CLK_CTRL_ADDR);
+ unsigned int cpu;
+ const u8 core_cplx_pll[16] = {
+ [0] = 0, /* CC1 PPL / 1 */
+ [1] = 0, /* CC1 PPL / 2 */
+ [2] = 0, /* CC1 PPL / 4 */
+ [4] = 1, /* CC2 PPL / 1 */
+ [5] = 1, /* CC2 PPL / 2 */
+ [6] = 1, /* CC2 PPL / 4 */
+ [8] = 2, /* CC3 PPL / 1 */
+ [9] = 2, /* CC3 PPL / 2 */
+ [10] = 2, /* CC3 PPL / 4 */
+ [12] = 3, /* CC4 PPL / 1 */
+ [13] = 3, /* CC4 PPL / 2 */
+ [14] = 3, /* CC4 PPL / 4 */
+ };
+
+ const u8 core_cplx_pll_div[16] = {
+ [0] = 1, /* CC1 PPL / 1 */
+ [1] = 2, /* CC1 PPL / 2 */
+ [2] = 4, /* CC1 PPL / 4 */
+ [4] = 1, /* CC2 PPL / 1 */
+ [5] = 2, /* CC2 PPL / 2 */
+ [6] = 4, /* CC2 PPL / 4 */
+ [8] = 1, /* CC3 PPL / 1 */
+ [9] = 2, /* CC3 PPL / 2 */
+ [10] = 4, /* CC3 PPL / 4 */
+ [12] = 1, /* CC4 PPL / 1 */
+ [13] = 2, /* CC4 PPL / 2 */
+ [14] = 4, /* CC4 PPL / 4 */
+ };
+
+ uint i, cluster;
+ uint freq_c_pll[CONFIG_SYS_FSL_NUM_CC_PLLS];
+ uint ratio[CONFIG_SYS_FSL_NUM_CC_PLLS];
+ unsigned long sysclk = CONFIG_SYS_CLK_FREQ;
+ int cc_group[12] = CONFIG_SYS_FSL_CLUSTER_CLOCKS;
+ u32 c_pll_sel, cplx_pll;
+ void *offset;
+
+ sys_info->freq_systembus = sysclk;
+#ifdef CONFIG_DDR_CLK_FREQ
+ sys_info->freq_ddrbus = CONFIG_DDR_CLK_FREQ;
+#else
+ sys_info->freq_ddrbus = sysclk;
+#endif
+
+ sys_info->freq_systembus *= (in_le32(&gur->rcwsr[0]) >>
+ FSL_CHASSIS3_RCWSR0_SYS_PLL_RAT_SHIFT) &
+ FSL_CHASSIS3_RCWSR0_SYS_PLL_RAT_MASK;
+ sys_info->freq_ddrbus *= (in_le32(&gur->rcwsr[0]) >>
+ FSL_CHASSIS3_RCWSR0_MEM_PLL_RAT_SHIFT) &
+ FSL_CHASSIS3_RCWSR0_MEM_PLL_RAT_MASK;
+
+ for (i = 0; i < CONFIG_SYS_FSL_NUM_CC_PLLS; i++) {
+ /*
+ * fixme: prefer to combine the following into one line, but
+ * cannot pass compiling without warning about in_le32.
+ */
+ offset = (void *)((size_t)clk_grp[i/3] +
+ 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];
+ }
+
+ for_each_cpu(i, cpu, cpu_numcores(), cpu_mask()) {
+ cluster = fsl_qoriq_core_to_cluster(cpu);
+ c_pll_sel = (in_le32(&clk_ctrl->clkcncsr[cluster].csr) >> 27)
+ & 0xf;
+ cplx_pll = core_cplx_pll[c_pll_sel];
+ cplx_pll += cc_group[cluster] - 1;
+ sys_info->freq_processor[cpu] =
+ freq_c_pll[cplx_pll] / core_cplx_pll_div[c_pll_sel];
+ }
+
+#if defined(CONFIG_FSL_IFC)
+ ccr = in_le32(&ifc_regs->ifc_ccr);
+ ccr = ((ccr & IFC_CCR_CLK_DIV_MASK) >> IFC_CCR_CLK_DIV_SHIFT) + 1;
+
+ sys_info->freq_localbus = sys_info->freq_systembus / ccr;
+#endif
+}
+
+
+int get_clocks(void)
+{
+ struct sys_info sys_info;
+ get_sys_info(&sys_info);
+ gd->cpu_clk = sys_info.freq_processor[0];
+ gd->bus_clk = sys_info.freq_systembus;
+ gd->mem_clk = sys_info.freq_ddrbus;
+
+#if defined(CONFIG_FSL_ESDHC)
+ gd->arch.sdhc_clk = gd->bus_clk / 2;
+#endif /* defined(CONFIG_FSL_ESDHC) */
+
+ if (gd->cpu_clk != 0)
+ return 0;
+ else
+ return 1;
+}
+
+/********************************************
+ * get_bus_freq
+ * return system bus freq in Hz
+ *********************************************/
+ulong get_bus_freq(ulong dummy)
+{
+ if (!gd->bus_clk)
+ get_clocks();
+
+ return gd->bus_clk;
+}
+
+/********************************************
+ * get_ddr_freq
+ * return ddr bus freq in Hz
+ *********************************************/
+ulong get_ddr_freq(ulong dummy)
+{
+ if (!gd->mem_clk)
+ get_clocks();
+
+ return gd->mem_clk;
+}
+
+unsigned int mxc_get_clock(enum mxc_clock clk)
+{
+ switch (clk) {
+ case MXC_I2C_CLK:
+ return get_bus_freq(0) / 2;
+ default:
+ printf("Unsupported clock\n");
+ }
+ return 0;
+}
diff --git a/arch/arm/cpu/armv8/fsl-lsch3/speed.h b/arch/arm/cpu/armv8/fsl-lsch3/speed.h
new file mode 100644
index 0000000..15af5b9
--- /dev/null
+++ b/arch/arm/cpu/armv8/fsl-lsch3/speed.h
@@ -0,0 +1,7 @@
+/*
+ * Copyright 2014, Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+void get_sys_info(struct sys_info *sys_info);
diff --git a/arch/arm/cpu/armv8/transition.S b/arch/arm/cpu/armv8/transition.S
index e0a5946..38dea5c 100644
--- a/arch/arm/cpu/armv8/transition.S
+++ b/arch/arm/cpu/armv8/transition.S
@@ -43,7 +43,7 @@ ENTRY(armv8_switch_to_el1)
mrs x0, cnthctl_el2
orr x0, x0, #0x3 /* Enable EL1 access to timers */
msr cnthctl_el2, x0
- msr cntvoff_el2, x0
+ msr cntvoff_el2, xzr
mrs x0, cntkctl_el1
orr x0, x0, #0x3 /* Enable EL0 access to timers */
msr cntkctl_el1, x0
diff --git a/arch/arm/cpu/at91-common/spl.c b/arch/arm/cpu/at91-common/spl.c
index 7f4debb..cbb5a52 100644
--- a/arch/arm/cpu/at91-common/spl.c
+++ b/arch/arm/cpu/at91-common/spl.c
@@ -20,6 +20,43 @@ static void at91_disable_wdt(void)
writel(AT91_WDT_MR_WDDIS, &wdt->mr);
}
+static void switch_to_main_crystal_osc(void)
+{
+ struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
+ u32 tmp;
+
+ tmp = readl(&pmc->mor);
+ tmp &= ~AT91_PMC_MOR_OSCOUNT(0xff);
+ tmp &= ~AT91_PMC_MOR_KEY(0xff);
+ tmp |= AT91_PMC_MOR_MOSCEN;
+ tmp |= AT91_PMC_MOR_OSCOUNT(8);
+ tmp |= AT91_PMC_MOR_KEY(0x37);
+ writel(tmp, &pmc->mor);
+ while (!(readl(&pmc->sr) & AT91_PMC_IXR_MOSCS))
+ ;
+
+ tmp = readl(&pmc->mor);
+ tmp &= ~AT91_PMC_MOR_OSCBYPASS;
+ tmp &= ~AT91_PMC_MOR_KEY(0xff);
+ tmp |= AT91_PMC_MOR_KEY(0x37);
+ writel(tmp, &pmc->mor);
+
+ tmp = readl(&pmc->mor);
+ tmp |= AT91_PMC_MOR_MOSCSEL;
+ tmp &= ~AT91_PMC_MOR_KEY(0xff);
+ tmp |= AT91_PMC_MOR_KEY(0x37);
+ writel(tmp, &pmc->mor);
+
+ while (!(readl(&pmc->sr) & AT91_PMC_IXR_MOSCSELS))
+ ;
+
+ tmp = readl(&pmc->mor);
+ tmp &= ~AT91_PMC_MOR_MOSCRCEN;
+ tmp &= ~AT91_PMC_MOR_KEY(0xff);
+ tmp |= AT91_PMC_MOR_KEY(0x37);
+ writel(tmp, &pmc->mor);
+}
+
void at91_plla_init(u32 pllar)
{
struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
@@ -76,6 +113,8 @@ u32 spl_boot_mode(void)
void s_init(void)
{
+ switch_to_main_crystal_osc();
+
/* disable watchdog */
at91_disable_wdt();