459 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
			
		
		
	
	
			459 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
 |