1 // #========================================================================
5 // # StrongARM EBSA-285 memory setup
7 // #========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 // #========================================================================
41 // ######DESCRIPTIONBEGIN####
43 // # Author(s): Red Hat, hmt
44 // # Contributors: Red Hat, hmt
46 // # Purpose: StrongARM EBSA-285 SDRAM initialization
47 // # Description: SDRAM Initialization for Intel(R) SA-110 21285 Companion
49 // # Intel is a Registered Trademark of Intel Corporation.
50 // # Other Brands and Trademarks are the property of their
51 // # respective owners.
53 // #####DESCRIPTIONEND####
55 // #========================================================================
58 .title "SDRAM Init for Intel(R) SA-110 21285 Companion Chip"
60 #include <cyg/hal/hal_ebsa285.h>
62 #include <pkgconf/system.h>
67 #define ARRAY_0_MODE_REGISTER (SA110_SDRAM_ARRAY_0_MODE_REGISTER_BASE)
68 #define ARRAY_1_MODE_REGISTER (SA110_SDRAM_ARRAY_1_MODE_REGISTER_BASE)
70 #define MODE_REGISTER_STEP (ARRAY_1_MODE_REGISTER - ARRAY_0_MODE_REGISTER)
72 // [6:4] /CAS Latency is 2 (2)
73 // [ 3 ] Burst Type is 0, Sequential
74 // [2:0] Burst Length is 2, meaning 4
75 #define SDRAM_MODE_REGISTER_SETUP 0x22
76 // Shifted left 2 because this is a word-address-offset!
77 #define SDRAM_MODE_REGISTER_SETUP_OFFSET ((SDRAM_MODE_REGISTER_SETUP) << 2)
80 #define SDRAM_TIMING_VALUE (SA110_SDRAM_ROW_PRECHARGE_2_CYCLES | \
81 SA110_SDRAM_LAST_DATA_IN_3_CYCLES | \
82 SA110_SDRAM_RAS_TO_CAS_DELAY_2_CYCLES | \
83 SA110_SDRAM_CAS_LATENCY_2_CYCLES | \
84 SA110_SDRAM_ROW_CYCLE_TIME_4_CYCLES | \
85 SA110_SDRAM_COMMAND_DRIVE_SAME_CYCLE)
87 #define SDRAM_TIMING_VALUE_MIN (SDRAM_TIMING_VALUE | \
88 SA110_SDRAM_REFRESH_INTERVAL_MIN)
90 #define SDRAM_TIMING_VALUE_NORMAL (SDRAM_TIMING_VALUE | \
91 SA110_SDRAM_REFRESH_INTERVAL_NORMAL)
96 * This subroutine sizes and configures up to four banks of SDRAM DIMMs.
97 * It runs early without a stack.
99 * R0 - R9 are destroyed. All others preserved.
100 * Except r11 which is also destroyed.
103 .global __mem285_init
107 * First we find out whether the SDRAMs are already initialized,
108 * and if so, leave them alone. RAM start implies just do the
109 * sizing sums to return top of memory.
111 ldr r0, =SA110_CONTROL_STATUS_BASE
113 #ifndef CYG_HAL_STARTUP_RAM
114 // This is conditional even in ROM start for
115 // a) testing ROM images eg. stubs in RAM really
116 // b) cooperation with eg. POST code, so we are not really at reset
117 ldr r0, =SA110_CONTROL_STATUS_BASE
118 ldr r1, [r0, #SA110_SDRAM_TIMING_o]
119 ldr r2, =SDRAM_TIMING_VALUE_NORMAL
123 #endif // ! defined CYG_HAL_STARTUP_RAM
125 // Add up the sizes and return in r0:
126 mov r1, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_0_o
131 ands r4, r4, #7 // if zero, no mem here
132 addne r2, r2, r3, asl r4 // tot up array sizes (in 1/2 Megs)
134 cmps r1, #(SA110_SDRAM_ADDRESS_SIZE_ARRAY_3_o + 4)
137 mov r0, r2, asl #19 // get size into Mb
140 #ifndef CYG_HAL_STARTUP_RAM
144 * Write to the SDRAM Timing Register in the 21285. Disable
148 str r1, [r0, #SA110_SDRAM_TIMING_o]
150 // Disable each array
152 str r1, [r0, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_0_o]
153 str r1, [r0, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_1_o]
154 str r1, [r0, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_2_o]
155 str r1, [r0, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_3_o]
157 // Wait for 8 refresh cycles to complete
163 * Force an all-banks recharge on all four SDRAM arrays
165 * This code came from the SA-IOP ver 1.0 (3-16-98) spec pg 22
167 * You must access all four arrays regardless of whether there is
168 * memory there because the 21285 counts the precharge accesses and
169 * inhibits access to the SDRAM until all four have been done.
171 * An all banks rechargs is initiated by a read from any address
172 * in the mode register space.
176 mov r0, #ARRAY_0_MODE_REGISTER
179 add r0, r0, #MODE_REGISTER_STEP
184 * Now we need to write to the SDRAM Mode Register.
185 * The address is important, not the data. The mode register
186 * should be configured for a burst size of 4 with linear addressing
189 mov r0, #ARRAY_0_MODE_REGISTER
191 str r0, [r0, #SDRAM_MODE_REGISTER_SETUP_OFFSET]
192 add r0, r0, #MODE_REGISTER_STEP
197 * Write to the SDRAM Timing Register in the 21285. Set the
198 * refresh interval to the minimum because we have to wait for
199 * 8 refresh cycles to complete before we can rely on the SDRAMs
200 * to be operating normally
202 ldr r0, =SA110_CONTROL_STATUS_BASE
203 ldr r1, =SDRAM_TIMING_VALUE_MIN
204 str r1, [r0, #SA110_SDRAM_TIMING_o]
206 // Disable each array
208 str r1, [r0, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_0_o]
209 str r1, [r0, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_1_o]
210 str r1, [r0, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_2_o]
211 str r1, [r0, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_3_o]
213 // Wait for 8 refresh cycles to complete
218 // Now reset the Refresh interval to a sensible value
219 ldr r1, =SDRAM_TIMING_VALUE_NORMAL
220 str r1, [r0, #SA110_SDRAM_TIMING_o]
222 /* start out assuming 64M part with MUX mode 2 */
223 mov r1, #(SA110_SDRAM_SIZE_64MB | SA110_SDRAM_MUX_MODE2)
224 str r1, [r0, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_0_o]
225 add r1, r1, #(64 << 20) // Add 64Mb
226 str r1, [r0, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_1_o]
227 add r1, r1, #(64 << 20) // Add 64Mb again
228 str r1, [r0, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_2_o]
229 add r1, r1, #(64 << 20) // Add 64Mb and again
230 str r1, [r0, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_3_o]
233 * First, try to figure out which banks are populated and
234 * the real mux mode for those banks.
237 * r0 - Base of control/status registers
240 * r8 - offset to SDRAM addr/size register
242 * r4 - inverse pattern
243 * r3 - scratch/mux mode output
244 * r2 - scratch offset
245 * r1 - base address of 64M block in consideration
246 * r0 - base address of control register sets
248 mov r8, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_0_o
255 str r5, [r1] // Offset 0 should work regardless
256 str r4, [r1, #4] // put something else on the data bus
257 ldr r3, [r1] // read back original
260 // If we didn't read pattern, then no memory present
262 strne r3, [r0, r8] // write to addr/size register
263 bne 49f // straight to next loop
266 * This bank is populated, so try to determine mux mode.
267 * All banks are currently set for mux mode 2.
270 // A21 having no effect distinguishes the need for mux mode 0.
273 str r4, [r1, r2] // Store bad value at A21 mirror address
274 // expect to trash value at r1 if mode 0
277 // If we don't read back pattern, then its mux mode 0
279 // Force to 32M size to include A18 when sizing:
280 movne r3, #(SA110_SDRAM_SIZE_32MB | SA110_SDRAM_MUX_MODE0)
283 // A23 having effect distinguishes the need for mux mode 2.
286 str r4, [r1, r2] // Store bad value at A23 mirror address
287 // expect to preserve value at r1 if mode 2
290 // if pattern still there, then mode 2
291 moveq r3, #(SA110_SDRAM_SIZE_64MB | SA110_SDRAM_MUX_MODE2)
294 // A22 having effect distinguishes the need for mux mode 4.
297 str r4, [r1, r2] // Store bad value at A22 mirror address
298 // expect to preserve value at r1 if mode 4
301 // if pattern A still there, then mode 4
302 moveq r3, #(SA110_SDRAM_SIZE_64MB | SA110_SDRAM_MUX_MODE4)
306 * At this point it is either mode 1 or 3. There is no clear cut
307 * test to differentiate the two, so make a best guess now, then
308 * correct later (if necessary) while sizing the bank.
311 // NB the bank is still in mux mode 2, so A24 is fed to the wire for
312 // A22 (mode 1) or no-connection (mode 3); so:
313 // A24 having effect distinguishes the need for mux mode 1
314 // A24 having no effect distinguishes the need for mux mode 3
320 // If pattern, try mode 1
321 moveq r3, #(SA110_SDRAM_SIZE_64MB | SA110_SDRAM_MUX_MODE1)
322 // otherwise, try mode 3
323 movne r3, #(SA110_SDRAM_SIZE_64MB | SA110_SDRAM_MUX_MODE3)
328 orr r3, r3, r1 // add in base address
329 str r3, [r0, r8] // write to addr/size register
332 * Now that mux mode for this array is (hopefully) setup, we can try
333 * to size this SDRAM array.
336 * r8 - offset to current size/mode register
337 * r1 - offset to current base (in 64M blocks)
338 * r0 - base address of control register sets
341 mov r4, #(63 << 20) // 63Mb to start with
343 subs r4, r4, #(1 << 20) // go down in increments of 1Mb
346 str r4, [r1, #4] // change pattern on data bus
348 // search for first unexpected data in ascending order
353 bne 23f // different so end of array
354 add r4, r4, #(1 << 20) // go up in increments of 1Mb
357 // fall-through assumes it is a 64Mb device
359 movs r4, r4, lsr #20 // get a plain number of Mb
360 // if this gave a zero, maybe we were mistaken about the RAM
361 // working earlier: disable this bank.
362 streq r4, [r0, r8] // write to addr/size register
363 beq 49f // straight to next loop
365 // apparently, mode 3 devices *must* be 8Mb; if we got a different
366 // answer, set it to mode 1 and go back to try again:
370 // skip if 8Mb; we are happy
371 ldr r3, [r0, r8] // read in the mode we set
372 and r3, r3, #SA110_SDRAM_MUX_MODE_MASK
373 cmp r3, #SA110_SDRAM_MUX_MODE3
374 // Must be misconfigured mux mode. Set to mode 1 and retry
375 moveq r3, #(SA110_SDRAM_SIZE_64MB | SA110_SDRAM_MUX_MODE1)
377 // not mux mode 3; drop though OK
380 // convert MB size to register size val
383 5: movs r3, r3, lsr #1
387 // Double check that the size was a power of 2
389 mov r6, r6, lsl r5 // should get Mb count back doubled
390 cmps r6, r4, lsl #1 // compare with doubled
391 movne r5, #0 // disable this bank
392 ldr r3, [r0, r8] // Load current setting
394 orr r3, r3, r5 // insert the correct size code
395 str r3, [r0, r8] // into the control register
398 add r8, r8, #4 // next addr/size register
399 add r1, r1, #(64<<20) // next array
400 cmps r1, #(256<<20) // top address + 1 bank
402 // END of main loop to size all 4 DRAM banks
405 * At this point, the size values are all in the control registers.
407 * We want to set memory up to be contiguous. Since the
408 * banks' base address needs to be naturally aligned, we
409 * need to sort the bank sizes from large to small.
412 * r0 - base address of control register sets
413 * r1 - bitmap of which slots we have covered in toto
414 * r2 - cumulative base address of mapped SDRAM
415 * r3 - biggest size code this pass
416 * r4 - bit index of current slot
417 * r5 - bit index of biggest slot found this pass
418 * r6 - scratch control reg contents
419 * r7 - scratch size code
420 * r8 - address of current slot's control register
421 * r9 - address of biggest slot found's control register
423 mov r1, #0 // bitmap of which we have covered
424 mov r2, #0 // cumulative base address
425 // do... until there are no more slots to deal with
427 mov r3, #0 // biggest this pass
428 mov r4, #1 // bit index of current slot
429 mov r5, #0 // bit index of biggest slot found
430 mov r8, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_0_o
431 mov r9, #0 // address of biggest slot found
432 // Foreach slot we have not yet dealt with
439 movgt r3, r7 // save biggest's size
440 movgt r5, r4 // save biggest's index
441 movgt r9, r8 // save biggest's reg address
447 // Did we find a largest slot?
449 beq 95f // No! Finished
451 orr r1, r1, r5 // can forget r4 and r5 now
452 ldr r6, [r0, r9] // get the control register
453 bic r6, r6, #0x0ff00000 // clear base address bits
454 orr r6, r6, r2 // insert base address to use
455 str r6, [r0, r9] // store the new control register
458 mov r6, r6, asl #19 // 1 << (size-code + 19) is size
459 add r2, r2, r6 // increment the cumulating address
461 b 70b // go look for the next one
464 // at this point, r2 contains the top of memory.
465 // (r11 is the value from last time or zero if first time)
467 cmps r11, r2 // Same answer as last time?
468 movne r11, r2 // if not, save memsize
469 bne 12b // ...and try again.
473 #endif // ! defined CYG_HAL_STARTUP_RAM
474 //FUNC_END __mem285_init