]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/hal/arm/ebsa285/v2_0/src/mem285.S
Initial revision
[karo-tx-redboot.git] / packages / hal / arm / ebsa285 / v2_0 / src / mem285.S
1 // #========================================================================
2 // #
3 // #    mem285.S
4 // #
5 // #    StrongARM EBSA-285 memory setup
6 // #
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.
12 //
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.
16 //
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
20 // for more details.
21 //
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.
25 //
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.
32 //
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.
35 //
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####
42 // #
43 // # Author(s):     Red Hat, hmt
44 // # Contributors:  Red Hat, hmt
45 // # Date:          1999-07-05
46 // # Purpose:       StrongARM EBSA-285 SDRAM initialization
47 // # Description:   SDRAM Initialization for Intel(R) SA-110 21285 Companion
48 // #                Chip
49 // #                Intel is a Registered Trademark of Intel Corporation.
50 // #                Other Brands and Trademarks are the property of their
51 // #                respective owners.        
52 // #
53 // #####DESCRIPTIONEND####
54 // #
55 // #========================================================================
56
57 //      .file "mem285.S"
58         .title "SDRAM Init for Intel(R) SA-110 21285 Companion Chip"
59
60 #include <cyg/hal/hal_ebsa285.h>
61
62 #include <pkgconf/system.h>
63
64         .text
65         .align     4
66
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)
69
70 #define MODE_REGISTER_STEP (ARRAY_1_MODE_REGISTER - ARRAY_0_MODE_REGISTER)
71
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)
78
79         
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)
86
87 #define SDRAM_TIMING_VALUE_MIN    (SDRAM_TIMING_VALUE                    | \
88                                    SA110_SDRAM_REFRESH_INTERVAL_MIN)
89
90 #define SDRAM_TIMING_VALUE_NORMAL (SDRAM_TIMING_VALUE                    | \
91                                    SA110_SDRAM_REFRESH_INTERVAL_NORMAL)
92
93
94
95         /*
96          * This subroutine sizes and configures up to four banks of SDRAM DIMMs.
97          * It runs early without a stack.
98          *
99          * R0 - R9 are destroyed. All others preserved.
100          * Except r11 which is also destroyed.
101          *
102          */
103         .global __mem285_init
104 __mem285_init:
105
106         /*
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.
110          */
111         ldr     r0, =SA110_CONTROL_STATUS_BASE
112
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
120         cmps    r1, r2
121         movne   r11, #0
122         bne     12f
123 #endif  // ! defined CYG_HAL_STARTUP_RAM
124
125         // Add up the sizes and return in r0:
126         mov     r1, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_0_o
127         mov     r2, #0
128         mov     r3, #1
129     1:
130         ldr     r4, [r0, r1]
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)
133         add     r1, r1, #4
134         cmps    r1, #(SA110_SDRAM_ADDRESS_SIZE_ARRAY_3_o + 4)
135         blt     1b
136
137         mov     r0, r2, asl #19         // get size into Mb
138         mov     pc, lr
139
140 #ifndef CYG_HAL_STARTUP_RAM
141
142     12:
143         /*
144          * Write to the SDRAM Timing Register in the 21285.  Disable
145          * refresh totally.
146          */
147         mov     r1, #0
148         str     r1, [r0, #SA110_SDRAM_TIMING_o]
149
150         // Disable each array
151         mov     r1, #0
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]
156         
157         // Wait for 8 refresh cycles to complete
158         mov     r1, #(9 * 32)
159     1:  subs    r1, r1, #1
160         bpl     1b
161
162         /*
163          * Force an all-banks recharge on all four SDRAM arrays
164          *
165          * This code came from the SA-IOP ver 1.0 (3-16-98) spec pg 22
166          *
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.
170          *
171          * An all banks rechargs is initiated by a read from any address
172          * in the mode register space.
173          */
174
175         mov     r1, #3 
176         mov     r0, #ARRAY_0_MODE_REGISTER
177    1:
178         ldr     r2, [r0]
179         add     r0, r0, #MODE_REGISTER_STEP
180         subs    r1, r1, #1
181         bpl     1b
182
183         /*
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
187          */
188         mov     r1, #3
189         mov     r0, #ARRAY_0_MODE_REGISTER
190    1:
191         str     r0, [r0, #SDRAM_MODE_REGISTER_SETUP_OFFSET]
192         add     r0, r0, #MODE_REGISTER_STEP
193         subs    r1, r1, #1
194         bpl     1b
195         
196         /*
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
201          */
202         ldr     r0, =SA110_CONTROL_STATUS_BASE
203         ldr     r1, =SDRAM_TIMING_VALUE_MIN
204         str     r1, [r0, #SA110_SDRAM_TIMING_o]
205
206         // Disable each array
207         mov     r1, #0
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]
212         
213         // Wait for 8 refresh cycles to complete
214         mov     r1, #(9 * 32)
215     1:  subs    r1, r1, #1
216         bpl     1b
217
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]
221         
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]
231         
232         /*
233          * First, try to figure out which banks are populated and
234          * the real mux mode for those banks.
235          *
236          * At this point:
237          *   r0 - Base of control/status registers
238          *
239          * Register usage:
240          *   r8 - offset to SDRAM addr/size register
241          *   r5 - pattern
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
247          */     
248         mov     r8, #SA110_SDRAM_ADDRESS_SIZE_ARRAY_0_o
249         mov     r1, #0
250
251         ldr     r5, =0x12345678
252         mvn     r4, r5
253
254     20:
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
258         cmps    r3, r5
259
260         // If we didn't read pattern, then no memory present
261         movne   r3, #0
262         strne   r3, [r0, r8]            // write to addr/size register
263         bne     49f                     // straight to next loop
264
265         /*
266          * This bank is populated, so try to determine mux mode.
267          * All banks are currently set for mux mode 2.
268          */
269
270         // A21 having no effect distinguishes the need for mux mode 0.
271         str     r5, [r1]
272         mov     r2, #(1 << 21)
273         str     r4, [r1, r2]   // Store bad value at A21 mirror address
274                                  // expect to trash value at r1 if mode 0
275         ldr     r3, [r1]
276         cmps    r3, r5
277         // If we don't read back pattern, then its mux mode 0
278         
279         // Force to 32M size to include A18 when sizing:
280         movne   r3, #(SA110_SDRAM_SIZE_32MB | SA110_SDRAM_MUX_MODE0)
281         bne     2f
282
283         // A23 having effect distinguishes the need for mux mode 2.
284         str     r5, [r1]
285         mov     r2, #(1 << 23)
286         str     r4, [r1, r2]   // Store bad value at A23 mirror address
287                                // expect to preserve value at r1 if mode 2
288         ldr     r3, [r1]
289         cmps    r3, r5
290         // if pattern still there, then mode 2
291         moveq   r3, #(SA110_SDRAM_SIZE_64MB | SA110_SDRAM_MUX_MODE2)
292         beq     2f
293
294         // A22 having effect distinguishes the need for mux mode 4.
295         str     r5, [r1]
296         mov     r2, #(1 << 22)
297         str     r4, [r1, r2]   // Store bad value at A22 mirror address
298                                // expect to preserve value at r1 if mode 4
299         ldr     r3, [r1]
300         cmps    r3, r5
301         // if pattern A still there, then mode 4
302         moveq   r3, #(SA110_SDRAM_SIZE_64MB | SA110_SDRAM_MUX_MODE4)
303         beq     2f
304
305         /*
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.
309          */
310
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
315         str     r5, [r1]
316         mov     r2, #(1 << 24)
317         str     r4, [r1, r2]
318         ldr     r3, [r1]
319         cmps    r3, r5
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)
324
325         bne 2f
326
327     2:
328         orr     r3, r3, r1                      // add in base address
329         str     r3, [r0, r8]                    // write to addr/size register
330         
331         /*
332          * Now that mux mode for this array is (hopefully) setup, we can try
333          * to size this SDRAM array.
334          * 
335          * Register usage:
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
339          */
340
341         mov     r4, #(63 << 20)         // 63Mb to start with
342     1:  str     r4, [r1, r4]
343         subs    r4, r4, #(1 << 20)      // go down in increments of 1Mb
344         bpl     1b
345
346         str     r4, [r1, #4]            // change pattern on data bus
347
348         // search for first unexpected data in ascending order
349         mov     r4, #0
350     1:
351         ldr     r5, [r1, r4]
352         cmps    r5, r4
353         bne     23f                     // different so end of array
354         add     r4, r4, #(1 << 20)      // go up in increments of 1Mb
355         cmps    r4, #(64 << 20)
356         blt     1b
357         // fall-through assumes it is a 64Mb device
358    23:  
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
364
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:
367         cmps    r4, #8
368         beq     4f
369
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)
376         beq     2b
377         // not mux mode 3; drop though OK
378
379     4:
380         // convert MB size to register size val
381         mov     r5, #0
382         mov     r3, r4
383     5:  movs    r3, r3, lsr #1
384         add     r5, r5, #1
385         bcc     5b
386
387         // Double check that the size was a power of 2
388         mov     r6, #1
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
393         bic     r3, r3, #7
394         orr     r3, r3, r5              // insert the correct size code
395         str     r3, [r0, r8]            // into the control register
396
397    49:
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
401         blt     20b
402         // END of main loop to size all 4 DRAM banks
403
404         /*
405          * At this point, the size values are all in the control registers.
406          *
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.
410          *
411          * Register usage:
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
422          */
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
426     70:
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
433     75:
434         tst     r4, r1
435         bne     88f
436         ldr     r6, [r0, r8]
437         and     r7, r6, #7
438         cmps    r7, r3
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
442     88:
443         mov     r4, r4, asl #1
444         add     r8, r8, #4
445         cmps    r4, #0x10
446         blt     75b                     // next slot
447         // Did we find a largest slot?
448         cmps    r5, #0
449         beq     95f     // No!  Finished
450
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
456         mov     r6, #1
457         mov     r6, r6, asl r3
458         mov     r6, r6, asl #19         // 1 << (size-code + 19) is size
459         add     r2, r2, r6              // increment the cumulating address
460
461         b       70b                     // go look for the next one
462
463     95: // all done!
464         // at this point, r2 contains the top of memory.
465         // (r11 is the value from last time or zero if first time)
466
467         cmps    r11, r2                 // Same answer as last time?
468         movne   r11, r2                 // if not, save memsize
469         bne     12b                     // ...and try again.
470         
471         mov     r0, r2
472         mov     pc, lr  
473 #endif // ! defined CYG_HAL_STARTUP_RAM
474 //FUNC_END __mem285_init
475
476 /* EOF mem285.S */