Basic SDRAM runtime lib, software working without SRAM
[mw/milkymist.git] / software / libhpdmc / libhpdmc.S
1 /*
2  * libHPDMC - SDRAM initialization runtime for Milkymist bootloaders
3  * Copyright (C) 2010 Sebastien Bourdeauducq
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation;
8  * version 3 of the License.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, see <http://www.gnu.org/licenses>.
17  */
18
19 #include <hw/uart.h>
20 #include <hw/hpdmc.h>
21 #include <hw/vga.h>
22 #include <hw/interrupts.h>
23 #include <hw/sysctl.h>
24 #include <hw/gpio.h>
25 #include <version.h>
26
27 /*
28  * GLOBAL VARIABLES
29  * r25: Input delay
30  * r24: DQS phase
31  * r23: return address
32  */
33
34 .section .text, "ax", @progbits
35 .global _sdram_init
36 _sdram_init:
37         mv      r23, ra
38         mvhi    r1, hi(banner)
39         ori     r1, r1, lo(banner)
40         calli   print
41         mvhi    r1, hi(version)
42         ori     r1, r1, lo(version)
43         calli   print
44         mvhi    r1, hi(nl)
45         ori     r1, r1, lo(nl)
46         calli   print
47         mvhi    r1, hi(nl)
48         ori     r1, r1, lo(nl)
49         calli   print
50         
51         bi send_init
52 send_init_return:
53         mvhi    r1, hi(seqcomplete)
54         ori     r1, r1, lo(seqcomplete)
55         calli   print
56
57         /* set IDELAY=0 */
58         mvhi    r1, hi(CSR_HPDMC_IODELAY)
59         ori     r1, r1, lo(CSR_HPDMC_IODELAY)
60         mvu     r2, (HPDMC_IDELAY_RST)
61         sw      (r1+0), r2
62         xor     r25, r25, r25
63         xor     r24, r24, r24
64
65         mvhi    r1, hi(CSR_GPIO_IN)
66         ori     r1, r1, lo(CSR_GPIO_IN)
67         lw      r2, (r1+0)
68         andi    r2, r2, (GPIO_PBC)
69         bne     r2, r0, mancal
70
71         bi      autocalibrate
72 autocalibrate_fail_return:
73         mvhi    r1, hi(autocalfail)
74         ori     r1, r1, lo(autocalfail)
75         calli   print
76         bi      mancal /* does not return */
77 autocalibrate_success_return:
78         mvhi    r1, hi(autocalok)
79         ori     r1, r1, lo(autocalok)
80         calli   print
81         
82         /* small memory test */
83         mvi     r1, 0
84         xor     r2, r2, r2
85         calli   memtest
86         be      r1, r0, memtest_fail
87         mvhi    r1, hi(continueboot)
88         ori     r1, r1, lo(continueboot)
89         calli   print
90         
91         b       r23
92 memtest_fail:
93         mvhi    r1, hi(testfailmsg)
94         ori     r1, r1, lo(testfailmsg)
95         calli   print
96         bi      mancal /* does not return */
97
98 /* clobbers: r1, r2, r3 */
99 send_init:
100         /* Bring CKE high */
101         mvhi    r2, hi(CSR_HPDMC_SYSTEM)
102         ori     r2, r2, lo(CSR_HPDMC_SYSTEM)
103         mvu     r3, (HPDMC_SYSTEM_BYPASS|HPDMC_SYSTEM_RESET|HPDMC_SYSTEM_CKE)
104         sw      (r2+0), r3
105         
106         ori     r1, r0, 2
107         calli   delay
108         
109         mvhi    r2, hi(CSR_HPDMC_BYPASS)
110         ori     r2, r2, lo(CSR_HPDMC_BYPASS)
111         
112         /* Precharge All */
113         mvu     r3, 0x400B
114         sw      (r2+0), r3
115         mvu     r1, 2
116         calli   delay
117         
118         /* Load Extended Mode Register */
119         mvhi    r3, 0x2
120         ori     r3, r3, 0x000F
121         sw      (r2+0), r3
122         mvu     r1, 2
123         calli   delay
124         
125         /* Load Mode Register */
126         mvu     r3, 0x123F
127         sw      (r2+0), r3
128         mvu     r1, 200
129         calli   delay
130         
131         /* Precharge All */
132         mvu     r3, 0x400B
133         sw      (r2+0), r3
134         mvu     r1, 2
135         calli   delay
136         
137         /* Auto Refresh */
138         mvu     r3, 0xD
139         sw      (r2+0), r3
140         mvu     r1, 8
141         calli   delay
142         
143         /* Auto Refresh */
144         mvu     r3, 0xD
145         sw      (r2+0), r3
146         mvu     r1, 8
147         calli   delay
148         
149         /* Load Mode Register, Enable DLL */
150         mvu     r3, 0x23F
151         sw      (r2+0), r3
152         mvu     r1, 200
153         calli   delay
154
155         /* All done, get the controller into gear */
156         mvhi    r2, hi(CSR_HPDMC_SYSTEM)
157         ori     r2, r2, lo(CSR_HPDMC_SYSTEM)
158         mvu     r3, (HPDMC_SYSTEM_CKE)
159         sw      (r2+0), r3
160
161         bi      send_init_return
162
163 /*
164  * TODO: proper dynamic autocalibration:
165  * scan IDELAY/DQS and memtest,
166  * then place in the middle of the working zone.
167  */
168 /* clobbers: r1, r2, r3, r4 */
169 autocalibrate:
170         mvu     r24, 244 /* DQS phase, change this number for your board */
171         mvhi    r1, hi(CSR_HPDMC_IODELAY)
172         ori     r1, r1, lo(CSR_HPDMC_IODELAY)
173         xor     r2, r2, r2
174         mvu     r3, (HPDMC_DQSDELAY_CE|HPDMC_DQSDELAY_INC)
175         be      r2, r24, dqs_loop_end
176 dqs_loop:
177         sw      (r1+0), r3
178 dqs_loop_wait:
179         lw      r4, (r1+0)
180         andi    r4, r4, HPDMC_DQSDELAY_RDY
181         be      r4, r0, dqs_loop_wait
182         addi    r2, r2, 1
183         bne     r2, r24, dqs_loop
184 dqs_loop_end:
185         bi      autocalibrate_success_return
186
187 /* does not return */
188 mancal:
189         /* enable VGA out */
190         mvhi    r1, hi(CSR_VGA_BASEADDRESS)
191         ori     r1, r1, lo(CSR_VGA_BASEADDRESS)
192         mvhi    r2, 0x4000
193         sw      (r1+0), r2
194         mvhi    r1, hi(CSR_VGA_RESET)
195         ori     r1, r1, lo(CSR_VGA_RESET)
196         sw      (r1+0), r0
197 mancal_loop:
198         mvhi    r1, hi(manualkeys)
199         ori     r1, r1, lo(manualkeys)
200         calli   print
201         mv      r1, r25
202         calli   printint
203         mvhi    r1, hi(spacer)
204         ori     r1, r1, lo(spacer)
205         calli   print
206         mv      r1, r24
207         calli   printint
208         mvhi    r1, hi(nl)
209         ori     r1, r1, lo(nl)
210         calli   print
211         calli   getkey
212         mvu     r2, 'u'
213         be      r1, r2, inc_input_delay
214         mvu     r2, 'd'
215         be      r1, r2, dec_input_delay
216         mvu     r2, 'U'
217         be      r1, r2, inc_dqs_phase
218         mvu     r2, 'D'
219         be      r1, r2, dec_dqs_phase
220         mvu     r2, 't'
221         be      r1, r2, small_test
222         mvu     r2, 'T'
223         be      r1, r2, big_test
224         mvu     r2, 'p'
225         be      r1, r2, disp_pattern
226         mvu     r2, 'b'
227         be      r1, r2, boot
228         bi mancal_loop
229 inc_input_delay:
230         mvu     r1, 63
231         be      r25, r1, mancal_loop
232         addi    r25, r25, 1
233         mvhi    r1, hi(CSR_HPDMC_IODELAY)
234         ori     r1, r1, lo(CSR_HPDMC_IODELAY)
235         mvu     r2, (HPDMC_IDELAY_CE|HPDMC_IDELAY_INC)
236         sw      (r1+0), r2
237         bi      mancal_loop
238 dec_input_delay:
239         be      r25, r0, mancal_loop
240         addi    r25, r25, -1
241         mvhi    r1, hi(CSR_HPDMC_IODELAY)
242         ori     r1, r1, lo(CSR_HPDMC_IODELAY)
243         mvu     r2, (HPDMC_IDELAY_CE)
244         sw      (r1+0), r2
245         bi      mancal_loop
246 inc_dqs_phase:
247         mvu     r1, 255
248         be      r24, r1, mancal_loop
249         addi    r24, r24, 1
250         mvhi    r1, hi(CSR_HPDMC_IODELAY)
251         ori     r1, r1, lo(CSR_HPDMC_IODELAY)
252         mvu     r2, (HPDMC_DQSDELAY_CE|HPDMC_DQSDELAY_INC)
253         sw      (r1+0), r2
254         bi      wait_dqs
255 dec_dqs_phase:
256         be      r24, r0, mancal_loop
257         addi    r24, r24, -1
258         mvhi    r1, hi(CSR_HPDMC_IODELAY)
259         ori     r1, r1, lo(CSR_HPDMC_IODELAY)
260         mvu     r2, (HPDMC_DQSDELAY_CE)
261         sw      (r1+0), r2
262 wait_dqs:
263         lw      r2, (r1+0)
264         andi    r2, r2, HPDMC_DQSDELAY_RDY
265         be      r2, r0, wait_dqs
266         bi      mancal_loop
267 small_test:
268         xor     r1, r1, r1
269         xor     r2, r2, r2
270         calli   memtest
271         bi      after_test
272 big_test:
273         mvu     r1, 1
274         xor     r2, r2, r2
275         calli memtest
276 after_test:
277         be      r1, r0, print_test_fail
278         mvhi    r1, hi(memtestpassed)
279         ori     r1, r1, lo(memtestpassed)
280         calli   print
281         bi      mancal_loop
282 print_test_fail:
283         mvhi    r1, hi(memtestfailed)
284         ori     r1, r1, lo(memtestfailed)
285         calli   print
286         bi      mancal_loop
287 disp_pattern:
288         mvu     r1, 640
289         mvu     r2, 480
290         mvu     r7, 12
291         mvu     r8, 6
292         xor     r4, r4, r4 /* current Y pos */
293         mvhi    r5, 0x4000 /* current address */
294 yloop:
295         xor     r3, r3, r3 /* current X pos */
296 xloop:
297         add     r6, r3, r4
298         modu    r9, r6, r7
299         mvu     r6, 0xffff
300         bge     r9, r8, staywhite
301         xor     r6, r6, r6
302 staywhite:
303         sh      (r5+0), r6
304         addi    r5, r5, 2
305         addi    r3, r3, 1
306         bne     r3, r1, xloop
307         addi    r4, r4, 1
308         bne     r4, r2, yloop
309         bi      mancal_loop
310 boot:
311         mvhi    r1, hi(CSR_VGA_RESET)
312         ori     r1, r1, lo(CSR_VGA_RESET)
313         mvi     r2, VGA_RESET
314         sw      (r1+0), r2
315         b       r23
316
317 /* memtest - tests memory
318  *
319  * inputs:      r1 - big/small
320  *              r2 - PRNG seed
321  * outputs:     r1 - pass/fail
322  * clobbers:    r1, r3, r4, r5, r6, r7
323  */
324 memtest:
325         /* 1. fill with pattern */
326         mvhi    r5, 0x4000      /* r5 - current address */
327         mvhi    r3, 0x100       /* r3 - remaining words */
328         mv      r4, r3          /* r4 - number of words to test */
329         mv      r6, r2          /* r6 - current value of the PRNG */
330         mvhi    r7, hi(22695477)
331         ori     r7, r7, lo(22695477)
332         bne     r1, r0, patloop
333         mvhi    r3, 0x10
334         mv      r4, r3
335 patloop:
336         sw      (r5+0), r6
337         mul     r6, r6, r7
338         addi    r6, r6, 1
339         addi    r5, r5, 4
340         addi    r3, r3, -1
341         bne     r3, r0, patloop
342         /* 2. check pattern */
343         mvhi    r5, 0x4000      /* r5 - current address */
344         mv      r3, r4          /* r3 - remaining words */
345         mv      r6, r2          /* r6 - current value of the PRNG */
346 chkloop:
347         lw      r4, (r5+0)
348         bne     r4, r6, testfail
349         mul     r6, r6, r7
350         addi    r6, r6, 1
351         addi    r5, r5, 4
352         addi    r3, r3, -1
353         bne     r3, r0, chkloop
354         mvu     r1, 1
355         ret
356 testfail:
357         xor r1, r1, r1
358         ret
359
360 /* getkey - gets a character from the console
361  *
362  * inputs:      none
363  * outputs:     r1 - character
364  * clobbers:    r1
365  */
366 getkey:
367         rcsr    r1, IP
368         andi    r1, r1, IRQ_UARTRX
369         be      r1, r0, getkey
370         wcsr    IP, r1
371         mvhi    r1, hi(CSR_UART_RXTX)
372         ori     r1, r1, lo(CSR_UART_RXTX)
373         lw      r1, (r1+0)
374         ret
375
376 /* printint - prints an integer 0-999
377  *
378  * inputs:      r1 - input
379  * outputs:     none
380  * clobbers:    r1, r2, r3, r4
381  */
382 printint:
383         mvhi    r2, hi(CSR_UART_RXTX)
384         ori     r2, r2, lo(CSR_UART_RXTX)
385         
386         mvu     r4, 100
387         divu    r3, r1, r4
388         modu    r1, r1, r4
389         addi    r3, r3, '0'
390         sw      (r2+0), r3
391 writeintwait1:
392         rcsr    r3, IP
393         andi    r3, r3, IRQ_UARTTX
394         be      r3, r0, writeintwait1
395         wcsr    IP, r3
396         
397         mvu     r4, 10
398         divu    r3, r1, r4
399         modu    r1, r1, r4
400         addi    r3, r3, '0'
401         sw      (r2+0), r3
402 writeintwait2:
403         rcsr    r3, IP
404         andi    r3, r3, IRQ_UARTTX
405         be      r3, r0, writeintwait2
406         wcsr    IP, r3
407         
408         addi    r3, r1, '0'
409         sw      (r2+0), r3
410 writeintwait3:
411         rcsr    r3, IP
412         andi    r3, r3, IRQ_UARTTX
413         be      r3, r0, writeintwait3
414         wcsr    IP, r3
415
416         ret
417
418 /* print - prints a zero terminated string on the console
419  *
420  * inputs:      r1 - address of the string
421  * outputs:     none
422  * clobbers:    r1, r2, r3
423  */
424 print:
425         mvhi    r2, hi(CSR_UART_RXTX)
426         ori     r2, r2, lo(CSR_UART_RXTX)
427 writeloop:
428         lb      r3, (r1+0)
429         be      r3, r0, print_endloop
430         sw      (r2+0), r3
431 writewait:
432         rcsr    r3, IP
433         andi    r3, r3, IRQ_UARTTX
434         be      r3, r0, writewait
435         wcsr    IP, r3
436         addi    r1, r1, 1
437         bi      writeloop
438 print_endloop:
439         ret
440
441 /* delay - delay loop
442  *
443  * inputs:      r1 - number of iterations
444  * outputs:     none
445  * clobbers:    r1
446  */
447 delay:
448         addi    r1, r1, -1
449         bne     r1, r0, delay
450         ret
451
452 .section .rodata, "a"
453 banner: .string "libHPDMC SDRAM initialization runtime\n(c) Copyright 2010 Sebastien Bourdeauducq, released under GNU LGPL version 3.\nVersion "
454 version: .string VERSION
455 seqcomplete: .string "Initialization sequence completed.\n"
456 autocalfail: .string "Autocalibration failed, entering manual mode.\n"
457 autocalok: .string "Autocalibration OK, testing memory...\n"
458 continueboot: .string "All SDRAM initialization completed, boot continuing.\n\n"
459 testfailmsg: .string "Memory test failed, entering manual mode.\n"
460 manualkeys: .string "\nu: inc. input delay // d: dec. input delay\nU: inc. DQS phase   // D: dec. DQS phase\nt: test (small)     // T: test (large)\np: display pattern\nb: boot\n"
461 memtestfailed: .string "Memory test failed.\n"
462 memtestpassed: .string "Memory test passed.\n"
463 spacer: .string " -- "
464 nl: .string "\n"