bios: print number of memory errors
[litex.git] / software / bios / sdram.c
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 #include <hw/dfii.h>
5 #include <hw/mem.h>
6 #include <csrbase.h>
7
8 #include "sdram.h"
9
10 static void cdelay(int i)
11 {
12 while(i > 0) {
13 __asm__ volatile("nop");
14 i--;
15 }
16 }
17
18 static void setaddr(int a)
19 {
20 CSR_DFII_AH_P0 = (a & 0xff00) >> 8;
21 CSR_DFII_AL_P0 = a & 0x00ff;
22 CSR_DFII_AH_P1 = (a & 0xff00) >> 8;
23 CSR_DFII_AL_P1 = a & 0x00ff;
24 }
25
26 static void command_p0(int cmd)
27 {
28 CSR_DFII_COMMAND_P0 = cmd;
29 CSR_DFII_COMMAND_ISSUE_P0 = 1;
30 }
31
32 static void command_p1(int cmd)
33 {
34 CSR_DFII_COMMAND_P1 = cmd;
35 CSR_DFII_COMMAND_ISSUE_P1 = 1;
36 }
37
38 static void init_sequence(void)
39 {
40 int i;
41
42 /* Bring CKE high */
43 setaddr(0x0000);
44 CSR_DFII_BA_P0 = 0;
45 CSR_DFII_CONTROL = DFII_CONTROL_CKE;
46
47 /* Precharge All */
48 setaddr(0x0400);
49 command_p0(DFII_COMMAND_RAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
50
51 /* Load Extended Mode Register */
52 CSR_DFII_BA_P0 = 1;
53 setaddr(0x0000);
54 command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
55 CSR_DFII_BA_P0 = 0;
56
57 /* Load Mode Register */
58 setaddr(0x0132); /* Reset DLL, CL=3, BL=4 */
59 command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
60 cdelay(200);
61
62 /* Precharge All */
63 setaddr(0x0400);
64 command_p0(DFII_COMMAND_RAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
65
66 /* 2x Auto Refresh */
67 for(i=0;i<2;i++) {
68 setaddr(0);
69 command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_CS);
70 cdelay(4);
71 }
72
73 /* Load Mode Register */
74 setaddr(0x0032); /* CL=3, BL=4 */
75 command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
76 cdelay(200);
77 }
78
79 void ddrsw(void)
80 {
81 CSR_DFII_CONTROL = DFII_CONTROL_CKE;
82 printf("DDR now under software control\n");
83 }
84
85 void ddrhw(void)
86 {
87 CSR_DFII_CONTROL = DFII_CONTROL_SEL|DFII_CONTROL_CKE;
88 printf("DDR now under hardware control\n");
89 }
90
91 void ddrrow(char *_row)
92 {
93 char *c;
94 unsigned int row;
95
96 if(*_row == 0) {
97 setaddr(0x0000);
98 CSR_DFII_BA_P0 = 0;
99 command_p0(DFII_COMMAND_RAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
100 cdelay(15);
101 printf("Precharged\n");
102 } else {
103 row = strtoul(_row, &c, 0);
104 if(*c != 0) {
105 printf("incorrect row\n");
106 return;
107 }
108 setaddr(row);
109 CSR_DFII_BA_P0 = 0;
110 command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CS);
111 cdelay(15);
112 printf("Activated row %d\n", row);
113 }
114 }
115
116 void ddrrd(char *startaddr)
117 {
118 char *c;
119 unsigned int addr;
120 int i;
121
122 if(*startaddr == 0) {
123 printf("ddrrd <address>\n");
124 return;
125 }
126 addr = strtoul(startaddr, &c, 0);
127 if(*c != 0) {
128 printf("incorrect address\n");
129 return;
130 }
131
132 setaddr(addr);
133 CSR_DFII_BA_P0 = 0;
134 command_p0(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA);
135 cdelay(15);
136
137 for(i=0;i<8;i++)
138 printf("%02x", MMPTR(0xe0000834+4*i));
139 for(i=0;i<8;i++)
140 printf("%02x", MMPTR(0xe0000884+4*i));
141 printf("\n");
142 }
143
144 void ddrwr(char *startaddr)
145 {
146 char *c;
147 unsigned int addr;
148 int i;
149
150 if(*startaddr == 0) {
151 printf("ddrrd <address>\n");
152 return;
153 }
154 addr = strtoul(startaddr, &c, 0);
155 if(*c != 0) {
156 printf("incorrect address\n");
157 return;
158 }
159
160 for(i=0;i<8;i++) {
161 MMPTR(0xe0000814+4*i) = i;
162 MMPTR(0xe0000864+4*i) = 0xf0 + i;
163 }
164
165 setaddr(addr);
166 CSR_DFII_BA_P1 = 0;
167 command_p1(DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS|DFII_COMMAND_WRDATA);
168 }
169
170 #define TEST_SIZE (4*1024*1024)
171
172 int memtest_silent(void)
173 {
174 volatile unsigned int *array = (unsigned int *)SDRAM_BASE;
175 int i;
176 unsigned int prv;
177 unsigned int error_cnt;
178
179 prv = 0;
180 for(i=0;i<TEST_SIZE/4;i++) {
181 prv = 1664525*prv + 1013904223;
182 array[i] = prv;
183 }
184
185 prv = 0;
186 error_cnt = 0;
187 for(i=0;i<TEST_SIZE/4;i++) {
188 prv = 1664525*prv + 1013904223;
189 if(array[i] != prv)
190 error_cnt++;
191 }
192 return error_cnt;
193 }
194
195 int memtest(void)
196 {
197 unsigned int e;
198
199 e = memtest_silent();
200 if(e != 0) {
201 printf("Memtest failed: %d/%d words incorrect\n", e, TEST_SIZE/4);
202 return 0;
203 } else {
204 printf("Memtest OK\n");
205 return 1;
206 }
207 }
208
209 int ddrinit(void)
210 {
211 printf("Initializing DDR SDRAM...\n");
212
213 init_sequence();
214 CSR_DFII_CONTROL = DFII_CONTROL_SEL|DFII_CONTROL_CKE;
215 if(!memtest())
216 return 0;
217
218 return 1;
219 }
220
221 static const char *format_slot_state(int state)
222 {
223 switch(state) {
224 case 0: return "Empty";
225 case 1: return "Pending";
226 case 2: return "Processing";
227 default: return "UNEXPECTED VALUE";
228 }
229 }
230
231 void asmiprobe(void)
232 {
233 volatile unsigned int *regs = (unsigned int *)ASMIPROBE_BASE;
234 int slot_count;
235 int trace_depth;
236 int i;
237 int offset;
238
239 offset = 0;
240 slot_count = regs[offset++];
241 trace_depth = regs[offset++];
242 for(i=0;i<slot_count;i++)
243 printf("Slot #%d: %s\n", i, format_slot_state(regs[offset++]));
244 printf("Latest tags:\n");
245 for(i=0;i<trace_depth;i++)
246 printf("%d ", regs[offset++]);
247 printf("\n");
248 }