mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-04 02:20:25 +00:00
7237d22baa
This patch returns back support for old ep93xx processors family Signed-off-by: Sergey Kostanbaev <sergey.kostanbaev@gmail.com> Cc: albert.u.boot@aribaud.net
458 lines
10 KiB
ArmAsm
458 lines
10 KiB
ArmAsm
/*
|
|
* 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 <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:
|
|
|
|
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
|
|
|
|
|
|
ep93xx_sdram_done:
|
|
ldr r1, =EP93XX_LED_DATA
|
|
ldr r0, [r1]
|
|
bic r0, r0, #EP93XX_LED_RED_ON
|
|
str r0, [r1]
|
|
|
|
/* Determine the size of the SDRAM. */
|
|
mov r0, r11
|
|
bl ep93xx_sdram_size
|
|
|
|
/* Save the SDRAM characteristics. */
|
|
mov r8, r0
|
|
mov r9, r1
|
|
mov r10, r2
|
|
|
|
/* 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
|
|
|
|
/* 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
|
|
|
|
#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]
|
|
|
|
/* Save the memory configuration information. */
|
|
orr r0, r11, #UBOOT_MEMORYCNF_BANK_SIZE
|
|
stmia r0, {r8-r11}
|
|
|
|
mov lr, r6
|
|
mov pc, lr
|