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