diff packages/hal/arm/ebsa285/current/src/mem285.S @ 76:435cced73e2f ecos-v1_3_1-release

eCos v1.3.1 merged from eCos master repository on 2000-03-27-23:22:51-BST
author jlarmour
date Tue, 28 Mar 2000 14:10:45 +0000
parents
children e0c0827131d1
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/packages/hal/arm/ebsa285/current/src/mem285.S
@@ -0,0 +1,467 @@
+// #========================================================================
+// #
+// #    mem285.S
+// #
+// #    StrongARM EBSA-285 memory setup
+// #
+// #========================================================================
+// ####COPYRIGHTBEGIN####
+//                                                                          
+// -------------------------------------------                              
+// The contents of this file are subject to the Red Hat eCos Public License 
+// Version 1.1 (the "License"); you may not use this file except in         
+// compliance with the License.  You may obtain a copy of the License at    
+// http://www.redhat.com/                                                   
+//                                                                          
+// Software distributed under the License is distributed on an "AS IS"      
+// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the 
+// License for the specific language governing rights and limitations under 
+// the License.                                                             
+//                                                                          
+// The Original Code is eCos - Embedded Configurable Operating System,      
+// released September 30, 1998.                                             
+//                                                                          
+// The Initial Developer of the Original Code is Red Hat.                   
+// Portions created by Red Hat are                                          
+// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.                             
+// All Rights Reserved.                                                     
+// -------------------------------------------                              
+//                                                                          
+// ####COPYRIGHTEND####
+// #========================================================================
+// ######DESCRIPTIONBEGIN####
+// #
+// # Author(s):     Red Hat, hmt
+// # Contributors:  Red Hat, hmt
+// # Date:          1999-07-05
+// # Purpose:       StrongARM EBSA-285 SDRAM initialization
+// # Description:   SDRAM Initialization for Intel(R) SA-110 21285 Companion
+// #                Chip
+// #                Intel is a Registered Trademark of Intel Corporation.
+// #                Other Brands and Trademarks are the property of their
+// #                respective owners.        
+// #
+// #####DESCRIPTIONEND####
+// #
+// #========================================================================
+
+	.file "mem285.S"
+        .title "SDRAM Init for Intel(R) SA-110 21285 Companion Chip"
+
+#include <cyg/hal/hal_ebsa285.h>
+
+#include <pkgconf/system.h>
+
+	.text
+        .align     4
+
+#define ARRAY_0_MODE_REGISTER     (SA110_SDRAM_ARRAY_0_MODE_REGISTER_BASE)
+#define ARRAY_1_MODE_REGISTER     (SA110_SDRAM_ARRAY_1_MODE_REGISTER_BASE)
+
+#define MODE_REGISTER_STEP (ARRAY_1_MODE_REGISTER - ARRAY_0_MODE_REGISTER)
+
+        // [6:4] /CAS Latency is 2 (2)
+        // [ 3 ] Burst Type is 0, Sequential
+        // [2:0] Burst Length is 2, meaning 4
+#define SDRAM_MODE_REGISTER_SETUP 0x22
+        // Shifted left 2 because this is a word-address-offset!
+#define SDRAM_MODE_REGISTER_SETUP_OFFSET ((SDRAM_MODE_REGISTER_SETUP) << 2)
+
+	
+#define SDRAM_TIMING_VALUE        (SA110_SDRAM_ROW_PRECHARGE_2_CYCLES    | \
+                                   SA110_SDRAM_LAST_DATA_IN_3_CYCLES     | \
+                                   SA110_SDRAM_RAS_TO_CAS_DELAY_2_CYCLES | \
+                                   SA110_SDRAM_CAS_LATENCY_2_CYCLES      | \
+                                   SA110_SDRAM_ROW_CYCLE_TIME_4_CYCLES   | \
+                                   SA110_SDRAM_COMMAND_DRIVE_SAME_CYCLE)
+
+#define SDRAM_TIMING_VALUE_MIN    (SDRAM_TIMING_VALUE                    | \
+                                   SA110_SDRAM_REFRESH_INTERVAL_MIN)
+
+#define SDRAM_TIMING_VALUE_NORMAL (SDRAM_TIMING_VALUE                    | \
+                                   SA110_SDRAM_REFRESH_INTERVAL_NORMAL)
+
+
+
+	/*
+	 * This subroutine sizes and configures up to four banks of SDRAM DIMMs.
+	 * It runs early without a stack.
+	 *
+	 * R0 - R9 are destroyed. All others preserved.
+	 * Except r11 which is also destroyed.
+	 *
+	 */
+	.global __mem285_init
+__mem285_init:
+
+	/*
+	 * First we find out whether the SDRAMs are already initialized,
+	 * and if so, leave them alone.  RAM start implies just do the
+	 * sizing sums to return top of memory.
+	 */
+	ldr	r0, =SA110_CONTROL_STATUS_BASE
+
+#ifndef CYG_HAL_STARTUP_RAM
+	// This is conditional even in ROM start for
+	// a) testing ROM images eg. stubs in RAM really
+	// b) cooperation with eg. POST code, so we are not really at reset
+	ldr	r0, =SA110_CONTROL_STATUS_BASE
+        ldr     r1, [r0, #SA110_SDRAM_TIMING_o]
+	ldr	r2, =SDRAM_TIMING_VALUE_NORMAL
+	cmps	r1, r2
+	movne	r11, #0
+	bne	12f
+#endif	// ! defined CYG_HAL_STARTUP_RAM
+
+	// Add up the sizes and return in r0:
+	mov	r1, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_0_o
+	mov	r2, #0
+	mov	r3, #1
+    1:
+	ldr	r4, [r0, r1]
+	ands	r4, r4, #7		// if zero, no mem here
+	addne	r2, r2, r3, asl r4	// tot up array sizes (in 1/2 Megs)
+	add	r1, r1, #4
+	cmps	r1, #(SA110_SDRAM_ADDRESS_SIZE_ARRAY_3_o + 4)
+	blt	1b
+
+	mov	r0, r2, asl #19		// get size into Mb
+	mov	pc, lr
+
+#ifndef CYG_HAL_STARTUP_RAM
+
+    12:
+	/*
+         * Write to the SDRAM Timing Register in the 21285.  Disable
+         * refresh totally.
+         */
+        mov     r1, #0
+        str     r1, [r0, #SA110_SDRAM_TIMING_o]
+
+	// Disable each array
+	mov	r1, #0
+        str     r1, [r0, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_0_o]
+        str     r1, [r0, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_1_o]
+        str     r1, [r0, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_2_o]
+        str     r1, [r0, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_3_o]
+	
+        // Wait for 8 refresh cycles to complete
+        mov     r1, #(9 * 32)
+    1:  subs    r1, r1, #1
+        bpl     1b
+
+        /*
+         * Force an all-banks recharge on all four SDRAM arrays
+         *
+         * This code came from the SA-IOP ver 1.0 (3-16-98) spec pg 22
+         *
+         * You must access all four arrays regardless of whether there is
+         * memory there because the 21285 counts the precharge accesses and
+         * inhibits access to the SDRAM until all four have been done.
+         *
+         * An all banks rechargs is initiated by a read from any address
+         * in the mode register space.
+         */
+
+        mov     r1, #3 
+        mov     r0, #ARRAY_0_MODE_REGISTER
+   1:
+        ldr     r2, [r0]
+        add     r0, r0, #MODE_REGISTER_STEP
+        subs    r1, r1, #1
+        bpl     1b
+
+        /*
+         * Now we need to write to the SDRAM Mode Register.
+         * The address is important, not the data.  The mode register
+         * should be configured for a burst size of 4 with linear addressing
+         */
+        mov     r1, #3
+        mov     r0, #ARRAY_0_MODE_REGISTER
+   1:
+        str     r0, [r0, #SDRAM_MODE_REGISTER_SETUP_OFFSET]
+        add     r0, r0, #MODE_REGISTER_STEP
+        subs    r1, r1, #1
+        bpl     1b
+        
+        /*
+         * Write to the SDRAM Timing Register in the 21285.  Set the
+         * refresh interval to the minimum because we have to wait for
+         * 8 refresh cycles to complete before we can rely on the SDRAMs
+         * to be operating normally
+         */
+	ldr	r0, =SA110_CONTROL_STATUS_BASE
+        ldr     r1, =SDRAM_TIMING_VALUE_MIN
+        str     r1, [r0, #SA110_SDRAM_TIMING_o]
+
+	// Disable each array
+	mov	r1, #0
+        str     r1, [r0, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_0_o]
+        str     r1, [r0, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_1_o]
+        str     r1, [r0, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_2_o]
+        str     r1, [r0, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_3_o]
+	
+        // Wait for 8 refresh cycles to complete
+        mov     r1, #(9 * 32)
+    1:  subs    r1, r1, #1
+        bpl     1b
+
+        // Now reset the Refresh interval to a sensible value
+        ldr     r1, =SDRAM_TIMING_VALUE_NORMAL
+        str     r1, [r0, #SA110_SDRAM_TIMING_o]
+	
+	/* start out assuming 64M part with MUX mode 2 */
+	mov	r1, #(SA110_SDRAM_SIZE_64MB | SA110_SDRAM_MUX_MODE2)
+        str     r1, [r0, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_0_o]
+	add	r1, r1, #(64 << 20) // Add 64Mb
+        str     r1, [r0, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_1_o]
+	add	r1, r1, #(64 << 20) // Add 64Mb again
+        str     r1, [r0, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_2_o]
+	add	r1, r1, #(64 << 20) // Add 64Mb and again
+        str     r1, [r0, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_3_o]
+	
+	/*
+	 * First, try to figure out which banks are populated and
+	 * the real mux mode for those banks.
+	 *
+	 * At this point:
+	 *   r0 - Base of control/status registers
+	 *
+	 * Register usage:
+	 *   r8 - offset to SDRAM addr/size register
+	 *   r5 - pattern
+	 *   r4 - inverse pattern
+	 *   r3 - scratch/mux mode output
+         *   r2 - scratch offset
+         *   r1 - base address of 64M block in consideration
+         *   r0 - base address of control register sets
+	 */	
+	mov	r8, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_0_o
+	mov     r1, #0
+
+	ldr	r5, =0x12345678
+	mvn	r4, r5
+
+    20:
+	str	r5, [r1]      // Offset 0 should work regardless
+	str	r4, [r1, #4]  // put something else on the data bus
+	ldr	r3, [r1]      // read back original
+	cmps    r3, r5
+
+	// If we didn't read pattern, then no memory present
+	movne	r3, #0
+	strne	r3, [r0, r8]            // write to addr/size register
+	bne	49f                     // straight to next loop
+
+	/*
+	 * This bank is populated, so try to determine mux mode.
+	 * All banks are currently set for mux mode 2.
+	 */
+
+	// A21 having no effect distinguishes the need for mux mode 0.
+	str	r5, [r1]
+	mov	r2, #(1 << 21)
+	str	r4, [r1, r2]   // Store bad value at A21 mirror address
+				 // expect to trash value at r1 if mode 0
+	ldr	r3, [r1]
+	cmps	r3, r5
+	// If we don't read back pattern, then its mux mode 0
+	
+	// Force to 32M size to include A18 when sizing:
+	movne	r3, #(SA110_SDRAM_SIZE_32MB | SA110_SDRAM_MUX_MODE0)
+	bne	2f
+
+	// A23 having effect distinguishes the need for mux mode 2.
+	str	r5, [r1]
+	mov	r2, #(1 << 23)
+        str	r4, [r1, r2]   // Store bad value at A23 mirror address
+                               // expect to preserve value at r1 if mode 2
+	ldr	r3, [r1]
+	cmps	r3, r5
+	// if pattern still there, then mode 2
+	moveq	r3, #(SA110_SDRAM_SIZE_64MB | SA110_SDRAM_MUX_MODE2)
+	beq	2f
+
+	// A22 having effect distinguishes the need for mux mode 4.
+	str	r5, [r1]
+	mov	r2, #(1 << 22)
+	str	r4, [r1, r2]   // Store bad value at A22 mirror address
+                               // expect to preserve value at r1 if mode 4
+	ldr	r3, [r1]
+	cmps	r3, r5
+	// if pattern A still there, then mode 4
+	moveq	r3, #(SA110_SDRAM_SIZE_64MB | SA110_SDRAM_MUX_MODE4)
+	beq	2f
+
+	/*
+	 * At this point it is either mode 1 or 3. There is no clear cut
+	 * test to differentiate the two, so make a best guess now, then
+	 * correct later (if necessary) while sizing the bank.
+	 */
+
+        // NB the bank is still in mux mode 2, so A24 is fed to the wire for
+        // A22 (mode 1) or no-connection (mode 3); so:
+        // A24 having effect distinguishes the need for mux mode 1
+        // A24 having no effect distinguishes the need for mux mode 3
+	str	r5, [r1]
+	mov	r2, #(1 << 24)
+	str	r4, [r1, r2]
+	ldr	r3, [r1]
+	cmps	r3, r5
+	// If pattern, try mode 1
+	moveq	r3, #(SA110_SDRAM_SIZE_64MB | SA110_SDRAM_MUX_MODE1)
+        // otherwise, try mode 3
+	movne	r3, #(SA110_SDRAM_SIZE_64MB | SA110_SDRAM_MUX_MODE3)
+
+	bne 2f
+
+    2:
+	orr	r3, r3, r1			// add in base address
+	str	r3, [r0, r8]			// write to addr/size register
+        
+	/*
+	 * Now that mux mode for this array is (hopefully) setup, we can try
+	 * to size this SDRAM array.
+         * 
+         * Register usage:
+         *    r8 - offset to current size/mode register
+         *    r1 - offset to current base (in 64M blocks)
+         *    r0 - base address of control register sets
+	 */
+
+        mov     r4, #(63 << 20)         // 63Mb to start with
+    1:  str     r4, [r1, r4]
+        subs    r4, r4, #(1 << 20)      // go down in increments of 1Mb
+        bpl     1b
+
+	str	r4, [r1, #4]            // change pattern on data bus
+
+	// search for first unexpected data in ascending order
+        mov     r4, #0
+    1:
+	ldr	r5, [r1, r4]
+        cmps    r5, r4
+	bne	23f                     // different so end of array
+        add     r4, r4, #(1 << 20)      // go up in increments of 1Mb
+        cmps    r4, #(64 << 20)
+	blt	1b
+        // fall-through assumes it is a 64Mb device
+   23:	
+	movs	r4, r4, lsr #20		// get a plain number of Mb
+	// if this gave a zero, maybe we were mistaken about the RAM
+        // working earlier: disable this bank.
+	streq	r4, [r0, r8]            // write to addr/size register
+	beq	49f                     // straight to next loop
+
+        // apparently, mode 3 devices *must* be 8Mb; if we got a different
+        // answer, set it to mode 1 and go back to try again:
+	cmps    r4, #8
+        beq     4f
+
+	// skip if 8Mb; we are happy
+	ldr     r3, [r0, r8]  	        // read in the mode we set
+	and	r3, r3, #SA110_SDRAM_MUX_MODE_MASK
+	cmp	r3, #SA110_SDRAM_MUX_MODE3
+	// Must be misconfigured mux mode. Set to mode 1 and retry
+	moveq	r3, #(SA110_SDRAM_SIZE_64MB | SA110_SDRAM_MUX_MODE1)
+	beq     2b
+	// not mux mode 3; drop though OK
+
+    4:
+	// convert MB size to register size val
+	mov	r5, #0
+	mov     r3, r4
+    5:  movs    r3, r3, lsr #1
+        add	r5, r5, #1
+        bcc     5b
+
+	// Double check that the size was a power of 2
+	mov     r6, #1
+        mov     r6, r6, lsl r5		// should get Mb count back doubled
+	cmps	r6, r4, lsl #1          // compare with doubled
+	movne	r5, #0			// disable this bank
+        ldr	r3, [r0, r8]            // Load current setting
+	bic     r3, r3, #7
+	orr	r3, r3, r5		// insert the correct size code
+	str	r3, [r0, r8]		// into the control register
+
+   49:
+	add	r8, r8, #4			// next addr/size register
+	add	r1, r1, #(64<<20)		// next array
+        cmps    r1, #(256<<20)                  // top address + 1 bank
+	blt	20b
+        // END of main loop to size all 4 DRAM banks
+
+	/*
+	 * At this point, the size values are all in the control registers.
+	 *
+	 * We want to set memory up to be contiguous. Since the
+	 * banks' base address needs to be naturally aligned, we
+	 * need to sort the bank sizes from large to small.
+	 *
+	 * Register usage:
+         *   r0 - base address of control register sets
+	 *   r1	- bitmap of which slots we have covered in toto
+	 *   r2	- cumulative base address of mapped SDRAM
+	 *   r3	- biggest size code this pass
+	 *   r4	- bit index of current slot
+	 *   r5	- bit index of biggest slot found this pass
+	 *   r6	- scratch control reg contents
+	 *   r7 - scratch size code
+	 *   r8 - address of current slot's control register
+	 *   r9	- address of biggest slot found's control register
+	 */
+	mov	r1, #0			// bitmap of which we have covered
+	mov	r2, #0			// cumulative base address
+	// do... until there are no more slots to deal with
+    70:
+	mov	r3, #0			// biggest this pass
+	mov     r4, #1			// bit index of current slot
+	mov	r5, #0			// bit index of biggest slot found
+	mov	r8, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_0_o
+	mov	r9, #0			// address of biggest slot found
+	// Foreach slot we have not yet dealt with
+    75:
+	tst	r4, r1
+	bne	88f
+	ldr	r6, [r0, r8]
+	and	r7, r6, #7
+	cmps	r7, r3
+	movgt	r3, r7			// save biggest's size
+	movgt	r5, r4			// save biggest's index
+	movgt	r9, r8			// save biggest's reg address
+    88:
+	mov	r4, r4, asl #1
+	add	r8, r8, #4
+	cmps	r4, #0x10
+	blt	75b			// next slot
+	// Did we find a largest slot?
+	cmps	r5, #0
+	beq	95f	// No!  Finished
+
+	orr	r1, r1, r5		// can forget r4 and r5 now
+	ldr	r6, [r0, r9]		// get the control register
+	bic	r6, r6, #0x0ff00000	// clear base address bits
+	orr	r6, r6, r2		// insert base address to use
+	str	r6, [r0, r9]		// store the new control register
+	mov	r6, #1
+	mov	r6, r6, asl r3
+	mov	r6, r6, asl #19		// 1 << (size-code + 19) is size
+	add	r2, r2, r6		// increment the cumulating address
+
+	b	70b			// go look for the next one
+
+    95:	// all done!
+	// at this point, r2 contains the top of memory.
+	// (r11 is the value from last time or zero if first time)
+
+	cmps	r11, r2			// Same answer as last time?
+	movne	r11, r2			// if not, save memsize
+	bne	12b			// ...and try again.
+	
+	mov	r0, r2
+	mov	pc, lr	
+#endif // ! defined CYG_HAL_STARTUP_RAM
+//FUNC_END __mem285_init
+
+/* EOF mem285.S */