e6cf7cacfe95093374ae73d411f21fdd99763614
[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
24 /*
25  * GLOBAL VARIABLES
26  * r25: Input delay
27  * r24: DQS phase
28  * r23: return address
29  */
30
31 .section .text, "ax", @progbits 
32 .global _sdram_init
33 _sdram_init:
34         mv      r23, ra
35         mvhi    r1, hi(banner)
36         ori     r1, r1, lo(banner)
37         calli   print
38         
39         bi send_init
40 send_init_return:
41         mvhi    r1, hi(seqcomplete)
42         ori     r1, r1, lo(seqcomplete)
43         calli   print
44         
45         xor     r25, r25, r25
46         xor     r24, r24, r24
47         bi      autocalibrate
48 autocalibrate_fail_return:
49         mvhi    r1, hi(autocalfail)
50         ori     r1, r1, lo(autocalfail)
51         calli   print
52         bi      mancal /* does not return */
53 autocalibrate_success_return:
54         mvhi    r1, hi(autocalok)
55         ori     r1, r1, lo(autocalok)
56         calli   print
57         
58         /* big memory test */
59         mvi     r1, 1
60         xor     r2, r2, r2
61         calli   memtest
62         be      r1, r0, memtest_fail
63         mvhi    r1, hi(continueboot)
64         ori     r1, r1, lo(continueboot)
65         calli   print
66         
67         b       r23
68 memtest_fail:
69         mvhi    r1, hi(testfailmsg)
70         ori     r1, r1, lo(testfailmsg)
71         calli   print
72         bi      mancal /* does not return */
73
74 /* clobbers: r1, r2, r3 */
75 send_init:
76         /* Bring CKE high */
77         mvhi    r2, hi(CSR_HPDMC_SYSTEM)
78         ori     r2, r2, lo(CSR_HPDMC_SYSTEM)
79         mvu     r3, (HPDMC_SYSTEM_BYPASS|HPDMC_SYSTEM_RESET|HPDMC_SYSTEM_CKE)
80         sw      (r2+0), r3
81         
82         ori     r1, r0, 2
83         calli   delay
84         
85         mvhi    r2, hi(CSR_HPDMC_BYPASS)
86         ori     r2, r2, lo(CSR_HPDMC_BYPASS)
87         
88         /* Precharge All */
89         mvu     r3, 0x400B
90         sw      (r2+0), r3
91         mvu     r1, 2
92         calli   delay
93         
94         /* Load Extended Mode Register */
95         mvhi    r3, 0x2
96         ori     r3, r3, 0x000F
97         sw      (r2+0), r3
98         mvu     r1, 2
99         calli   delay
100         
101         /* Load Mode Register */
102         mvu     r3, 0x123F
103         sw      (r2+0), r3
104         mvu     r1, 200
105         calli   delay
106         
107         /* Precharge All */
108         mvu     r3, 0x400B
109         sw      (r2+0), r3
110         mvu     r1, 2
111         calli   delay
112         
113         /* Auto Refresh */
114         mvu     r3, 0xD
115         sw      (r2+0), r3
116         mvu     r1, 8
117         calli   delay
118         
119         /* Auto Refresh */
120         mvu     r3, 0xD
121         sw      (r2+0), r3
122         mvu     r1, 8
123         calli   delay
124         
125         /* Load Mode Register, Enable DLL */
126         mvu     r3, 0x23F
127         sw      (r2+0), r3
128         mvu     r1, 200
129         calli   delay
130
131         /* All done, get the controller into gear */
132         mvhi    r2, hi(CSR_HPDMC_SYSTEM)
133         ori     r2, r2, lo(CSR_HPDMC_SYSTEM)
134         mvu     r3, (HPDMC_SYSTEM_CKE)
135         sw      (r2+0), r3
136
137         bi      send_init_return
138
139 /* clobbers: */
140 autocalibrate:
141         bi      autocalibrate_fail_return
142
143 /* does not return */
144 mancal:
145         /* enable VGA out */
146         mvhi    r1, hi(CSR_VGA_BASEADDRESS)
147         ori     r1, r1, lo(CSR_VGA_BASEADDRESS)
148         mvhi    r2, 0x4000
149         sw      (r1+0), r2
150         mvhi    r1, hi(CSR_VGA_RESET)
151         ori     r1, r1, lo(CSR_VGA_RESET)
152         sw      (r1+0), r0
153 mancal_loop:
154         mvhi    r1, hi(manualkeys)
155         ori     r1, r1, lo(manualkeys)
156         calli   print
157         mv      r1, r25
158         calli   printint
159         mvhi    r1, hi(spacer)
160         ori     r1, r1, lo(spacer)
161         calli   print
162         mv      r1, r24
163         calli   printint
164         mvhi    r1, hi(nl)
165         ori     r1, r1, lo(nl)
166         calli   print
167         calli   getkey
168         mvu     r2, 'u'
169         be      r1, r2, inc_input_delay
170         mvu     r2, 'd'
171         be      r1, r2, dec_input_delay
172         mvu     r2, 'U'
173         be      r1, r2, inc_dqs_phase
174         mvu     r2, 'D'
175         be      r1, r2, dec_dqs_phase
176         mvu     r2, 't'
177         be      r1, r2, small_test
178         mvu     r2, 'T'
179         be      r1, r2, big_test
180         mvu     r2, 'p'
181         be      r1, r2, disp_pattern
182         mvu     r2, 'b'
183         be      r1, r2, boot
184         bi mancal_loop
185 inc_input_delay:
186         mvu     r1, 63
187         be      r25, r1, mancal_loop
188         addi    r25, r25, 1
189         mvhi    r1, hi(CSR_HPDMC_IODELAY)
190         ori     r1, r1, lo(CSR_HPDMC_IODELAY)
191         mvu     r2, (HPDMC_IDELAY_CE|HPDMC_IDELAY_INC)
192         sw      (r1+0), r2
193         bi      mancal_loop
194 dec_input_delay:
195         be      r25, r0, mancal_loop
196         addi    r25, r25, -1
197         mvhi    r1, hi(CSR_HPDMC_IODELAY)
198         ori     r1, r1, lo(CSR_HPDMC_IODELAY)
199         mvu     r2, (HPDMC_IDELAY_CE)
200         sw      (r1+0), r2
201         bi      mancal_loop
202 inc_dqs_phase:
203         mvu     r1, 255
204         be      r24, r1, mancal_loop
205         addi    r24, r24, 1
206         mvhi    r1, hi(CSR_HPDMC_IODELAY)
207         ori     r1, r1, lo(CSR_HPDMC_IODELAY)
208         mvu     r2, (HPDMC_DQSDELAY_CE|HPDMC_DQSDELAY_INC)
209         sw      (r1+0), r2
210         bi      wait_dqs
211 dec_dqs_phase:
212         be      r24, r0, mancal_loop
213         addi    r24, r24, -1
214         mvhi    r1, hi(CSR_HPDMC_IODELAY)
215         ori     r1, r1, lo(CSR_HPDMC_IODELAY)
216         mvu     r2, (HPDMC_DQSDELAY_CE)
217         sw      (r1+0), r2
218 wait_dqs:
219         lw      r2, (r1+0)
220         andi    r2, r2, HPDMC_DQSDELAY_RDY
221         be      r2, r0, wait_dqs
222         bi      mancal_loop
223 small_test:
224         xor     r1, r1, r1
225         xor     r2, r2, r2
226         calli   memtest
227         bi      after_test
228 big_test:
229         mvu     r1, 1
230         xor     r2, r2, r2
231         calli memtest
232 after_test:
233         be      r1, r0, print_test_fail
234         mvhi    r1, hi(memtestpassed)
235         ori     r1, r1, lo(memtestpassed)
236         calli   print
237         bi      mancal_loop
238 print_test_fail:
239         mvhi    r1, hi(memtestfailed)
240         ori     r1, r1, lo(memtestfailed)
241         calli   print
242         bi      mancal_loop
243 disp_pattern:
244         mvu     r1, 640
245         mvu     r2, 480
246         mvu     r7, 12
247         mvu     r8, 6
248         xor     r4, r4, r4 /* current Y pos */
249         mvhi    r5, 0x4000 /* current address */
250 yloop:
251         xor     r3, r3, r3 /* current X pos */
252 xloop:
253         add     r6, r3, r4
254         modu    r9, r6, r7
255         mvu     r6, 0xffff
256         bge     r9, r8, staywhite
257         xor     r6, r6, r6
258 staywhite:
259         sh      (r5+0), r6
260         addi    r5, r5, 2
261         addi    r3, r3, 1
262         bne     r3, r1, xloop
263         addi    r4, r4, 1
264         bne     r4, r2, yloop
265         bi      mancal_loop
266 boot:
267         mvhi    r1, hi(CSR_VGA_RESET)
268         ori     r1, r1, lo(CSR_VGA_RESET)
269         mvi     r2, VGA_RESET
270         sw      (r1+0), r2
271         b       r23
272
273 /* memtest - tests memory
274  *
275  * inputs:      r1 - 64MB/1MB
276  *              r2 - PRNG seed
277  * outputs:     r1 - pass/fail
278  * clobbers:    r1, r3, r4, r5, r6, r7
279  */
280 memtest:
281         /* 1. fill with pattern */
282         mvhi    r5, 0x4000      /* r5 - current address */
283         mvhi    r3, 0x100       /* r3 - remaining words */
284         mv      r4, r3          /* r4 - number of words to test */
285         mv      r6, r2          /* r6 - current value of the PRNG */
286         mvhi    r7, hi(22695477)
287         ori     r7, r7, lo(22695477)
288         bne     r1, r0, patloop
289         mvhi    r3, 0x4
290         mv      r4, r3
291 patloop:
292         sw      (r5+0), r6
293         mul     r6, r6, r7
294         addi    r6, r6, 1
295         addi    r5, r5, 4
296         addi    r3, r3, -1
297         bne     r3, r0, patloop
298         /* 2. check pattern */
299         mvhi    r5, 0x4000      /* r5 - current address */
300         mv      r3, r4          /* r3 - remaining words */
301         mv      r6, r2          /* r6 - current value of the PRNG */
302 chkloop:
303         lw      r4, (r5+0)
304         bne     r4, r6, testfail
305         mul     r6, r6, r7
306         addi    r6, r6, 1
307         addi    r5, r5, 4
308         addi    r3, r3, -1
309         bne     r3, r0, chkloop
310         mvu     r1, 1
311         ret
312 testfail:
313         xor r1, r1, r1
314         ret
315
316 /* getkey - gets a character from the console
317  *
318  * inputs:      none
319  * outputs:     r1 - character
320  * clobbers:    r1
321  */
322 getkey:
323         rcsr    r1, IP
324         andi    r1, r1, IRQ_UARTRX
325         be      r1, r0, getkey
326         wcsr    IP, r1
327         mvhi    r1, hi(CSR_UART_RXTX)
328         ori     r1, r1, lo(CSR_UART_RXTX)
329         lw      r1, (r1+0)
330         ret
331
332 /* printint - prints an integer 0-999
333  *
334  * inputs:      r1 - input
335  * outputs:     none
336  * clobbers:    r1, r2, r3, r4
337  */
338 printint:
339         mvhi    r2, hi(CSR_UART_RXTX)
340         ori     r2, r2, lo(CSR_UART_RXTX)
341         
342         mvu     r4, 100
343         divu    r3, r1, r4
344         modu    r1, r1, r4
345         addi    r3, r3, '0'
346         sw      (r2+0), r3
347 writeintwait1:
348         rcsr    r3, IP
349         andi    r3, r3, IRQ_UARTTX
350         be      r3, r0, writeintwait1
351         wcsr    IP, r3
352         
353         mvu     r4, 10
354         divu    r3, r1, r4
355         modu    r1, r1, r4
356         addi    r3, r3, '0'
357         sw      (r2+0), r3
358 writeintwait2:
359         rcsr    r3, IP
360         andi    r3, r3, IRQ_UARTTX
361         be      r3, r0, writeintwait2
362         wcsr    IP, r3
363         
364         addi    r3, r1, '0'
365         sw      (r2+0), r3
366 writeintwait3:
367         rcsr    r3, IP
368         andi    r3, r3, IRQ_UARTTX
369         be      r3, r0, writeintwait3
370         wcsr    IP, r3
371
372         ret
373
374 /* print - prints a zero terminated string on the console
375  *
376  * inputs:      r1 - address of the string
377  * outputs:     none
378  * clobbers:    r1, r2, r3
379  */
380 print:
381         mvhi    r2, hi(CSR_UART_RXTX)
382         ori     r2, r2, lo(CSR_UART_RXTX)
383 writeloop:
384         lb      r3, (r1+0)
385         be      r3, r0, print_endloop
386         sw      (r2+0), r3
387 writewait:
388         rcsr    r3, IP
389         andi    r3, r3, IRQ_UARTTX
390         be      r3, r0, writewait
391         wcsr    IP, r3
392         addi    r1, r1, 1
393         bi      writeloop
394 print_endloop:
395         ret
396
397 /* delay - delay loop
398  *
399  * inputs:      r1 - number of iterations
400  * outputs:     none
401  * clobbers:    r1
402  */
403 delay:
404         addi    r1, r1, -1
405         bne     r1, r0, delay
406         ret
407
408 .section .rodata, "a"
409 banner: .string "libHPDMC SDRAM initialization runtime\n(c) Copyright 2010 Sebastien Bourdeauducq, released under GNU LGPL version 3.\n\n\0"
410 seqcomplete: .string "Initialization sequence completed.\n\0"
411 autocalfail: .string "Autocalibration failed, entering manual mode.\n\0"
412 autocalok: .string "Autocalibration OK, testing memory...\n\0"
413 continueboot: .string "All SDRAM initialization completed, boot continuing.\n\0"
414 testfailmsg: .string "Memory test failed, entering manual mode.\n\0"
415 manualkeys: .string "\nu: inc. input delay // d: dec. input delay\nU: inc. DQS phase   // D: dec. DQS phase\nt: test 1MB         // T: test 64MB\np: display pattern\nb: boot\n\0"
416 memtestfailed: .string "Memory test failed.\n\0"
417 memtestpassed: .string "Memory test passed.\n\0"
418 spacer: .string " -- \0"
419 nl: .string "\n\0"