]>
Commit | Line | Data |
---|---|---|
c609719b | 1 | /* |
5fb692ca | 2 | * (C) Copyright 2005-2007 |
5568e613 SR |
3 | * Stefan Roese, DENX Software Engineering, sr@denx.de. |
4 | * | |
62534beb SR |
5 | * (C) Copyright 2006 |
6 | * DAVE Srl <www.dave-tech.it> | |
7 | * | |
de8d5a36 | 8 | * (C) Copyright 2002-2004 |
c609719b WD |
9 | * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com |
10 | * | |
1a459660 | 11 | * SPDX-License-Identifier: GPL-2.0+ |
c609719b WD |
12 | */ |
13 | ||
14 | #include <common.h> | |
b36df561 | 15 | #include <asm/ppc4xx.h> |
c609719b | 16 | #include <asm/processor.h> |
62534beb | 17 | #include "sdram.h" |
c821b5f1 | 18 | #include "ecc.h" |
c609719b | 19 | |
c609719b WD |
20 | #ifdef CONFIG_SDRAM_BANK0 |
21 | ||
5fb692ca | 22 | #ifndef CONFIG_440 |
c609719b | 23 | |
6d0f6bcf | 24 | #ifndef CONFIG_SYS_SDRAM_TABLE |
de8d5a36 | 25 | sdram_conf_t mb0cf[] = { |
cf48eb9a WD |
26 | {(128 << 20), 13, 0x000A4001}, /* (0-128MB) Address Mode 3, 13x10(4) */ |
27 | {(64 << 20), 13, 0x00084001}, /* (0-64MB) Address Mode 3, 13x9(4) */ | |
28 | {(32 << 20), 12, 0x00062001}, /* (0-32MB) Address Mode 2, 12x9(4) */ | |
29 | {(16 << 20), 12, 0x00046001}, /* (0-16MB) Address Mode 4, 12x8(4) */ | |
30 | {(4 << 20), 11, 0x00008001}, /* (0-4MB) Address Mode 5, 11x8(2) */ | |
de8d5a36 | 31 | }; |
5568e613 | 32 | #else |
6d0f6bcf | 33 | sdram_conf_t mb0cf[] = CONFIG_SYS_SDRAM_TABLE; |
5568e613 SR |
34 | #endif |
35 | ||
cf48eb9a | 36 | #define N_MB0CF (sizeof(mb0cf) / sizeof(mb0cf[0])) |
c609719b | 37 | |
6d0f6bcf | 38 | #ifdef CONFIG_SYS_SDRAM_CASL |
62534beb SR |
39 | static ulong ns2clks(ulong ns) |
40 | { | |
41 | ulong bus_period_x_10 = ONE_BILLION / (get_bus_freq(0) / 10); | |
42 | ||
43 | return ((ns * 10) + bus_period_x_10) / bus_period_x_10; | |
44 | } | |
6d0f6bcf | 45 | #endif /* CONFIG_SYS_SDRAM_CASL */ |
62534beb SR |
46 | |
47 | static ulong compute_sdtr1(ulong speed) | |
48 | { | |
6d0f6bcf | 49 | #ifdef CONFIG_SYS_SDRAM_CASL |
cf48eb9a WD |
50 | ulong tmp; |
51 | ulong sdtr1 = 0; | |
52 | ||
53 | /* CASL */ | |
6d0f6bcf | 54 | if (CONFIG_SYS_SDRAM_CASL < 2) |
cf48eb9a WD |
55 | sdtr1 |= (1 << SDRAM0_TR_CASL); |
56 | else | |
6d0f6bcf | 57 | if (CONFIG_SYS_SDRAM_CASL > 4) |
cf48eb9a WD |
58 | sdtr1 |= (3 << SDRAM0_TR_CASL); |
59 | else | |
6d0f6bcf | 60 | sdtr1 |= ((CONFIG_SYS_SDRAM_CASL-1) << SDRAM0_TR_CASL); |
cf48eb9a WD |
61 | |
62 | /* PTA */ | |
6d0f6bcf | 63 | tmp = ns2clks(CONFIG_SYS_SDRAM_PTA); |
cf48eb9a WD |
64 | if ((tmp >= 2) && (tmp <= 4)) |
65 | sdtr1 |= ((tmp-1) << SDRAM0_TR_PTA); | |
66 | else | |
67 | sdtr1 |= ((4-1) << SDRAM0_TR_PTA); | |
68 | ||
69 | /* CTP */ | |
6d0f6bcf | 70 | tmp = ns2clks(CONFIG_SYS_SDRAM_CTP); |
cf48eb9a WD |
71 | if ((tmp >= 2) && (tmp <= 4)) |
72 | sdtr1 |= ((tmp-1) << SDRAM0_TR_CTP); | |
73 | else | |
74 | sdtr1 |= ((4-1) << SDRAM0_TR_CTP); | |
75 | ||
76 | /* LDF */ | |
6d0f6bcf | 77 | tmp = ns2clks(CONFIG_SYS_SDRAM_LDF); |
cf48eb9a WD |
78 | if ((tmp >= 2) && (tmp <= 4)) |
79 | sdtr1 |= ((tmp-1) << SDRAM0_TR_LDF); | |
80 | else | |
81 | sdtr1 |= ((2-1) << SDRAM0_TR_LDF); | |
82 | ||
83 | /* RFTA */ | |
6d0f6bcf | 84 | tmp = ns2clks(CONFIG_SYS_SDRAM_RFTA); |
cf48eb9a WD |
85 | if ((tmp >= 4) && (tmp <= 10)) |
86 | sdtr1 |= ((tmp-4) << SDRAM0_TR_RFTA); | |
87 | else | |
88 | sdtr1 |= ((10-4) << SDRAM0_TR_RFTA); | |
89 | ||
90 | /* RCD */ | |
6d0f6bcf | 91 | tmp = ns2clks(CONFIG_SYS_SDRAM_RCD); |
cf48eb9a WD |
92 | if ((tmp >= 2) && (tmp <= 4)) |
93 | sdtr1 |= ((tmp-1) << SDRAM0_TR_RCD); | |
94 | else | |
95 | sdtr1 |= ((4-1) << SDRAM0_TR_RCD); | |
96 | ||
97 | return sdtr1; | |
6d0f6bcf | 98 | #else /* CONFIG_SYS_SDRAM_CASL */ |
cf48eb9a WD |
99 | /* |
100 | * If no values are configured in the board config file | |
101 | * use the default values, which seem to be ok for most | |
102 | * boards. | |
103 | * | |
104 | * REMARK: | |
105 | * For new board ports we strongly recommend to define the | |
106 | * correct values for the used SDRAM chips in your board | |
107 | * config file (see PPChameleonEVB.h) | |
108 | */ | |
109 | if (speed > 100000000) { | |
110 | /* | |
111 | * 133 MHz SDRAM | |
112 | */ | |
113 | return 0x01074015; | |
114 | } else { | |
115 | /* | |
116 | * default: 100 MHz SDRAM | |
117 | */ | |
118 | return 0x0086400d; | |
119 | } | |
6d0f6bcf | 120 | #endif /* CONFIG_SYS_SDRAM_CASL */ |
62534beb SR |
121 | } |
122 | ||
123 | /* refresh is expressed in ms */ | |
124 | static ulong compute_rtr(ulong speed, ulong rows, ulong refresh) | |
125 | { | |
6d0f6bcf | 126 | #ifdef CONFIG_SYS_SDRAM_CASL |
cf48eb9a | 127 | ulong tmp; |
62534beb | 128 | |
cf48eb9a WD |
129 | tmp = ((refresh*1000*1000) / (1 << rows)) * (speed / 1000); |
130 | tmp /= 1000000; | |
62534beb | 131 | |
cf48eb9a | 132 | return ((tmp & 0x00003FF8) << 16); |
6d0f6bcf | 133 | #else /* CONFIG_SYS_SDRAM_CASL */ |
cf48eb9a WD |
134 | if (speed > 100000000) { |
135 | /* | |
136 | * 133 MHz SDRAM | |
137 | */ | |
62534beb | 138 | return 0x07f00000; |
cf48eb9a WD |
139 | } else { |
140 | /* | |
141 | * default: 100 MHz SDRAM | |
142 | */ | |
62534beb | 143 | return 0x05f00000; |
cf48eb9a | 144 | } |
6d0f6bcf | 145 | #endif /* CONFIG_SYS_SDRAM_CASL */ |
62534beb SR |
146 | } |
147 | ||
5568e613 SR |
148 | /* |
149 | * Autodetect onboard SDRAM on 405 platforms | |
150 | */ | |
9973e3c6 | 151 | phys_size_t initdram(int board_type) |
c609719b | 152 | { |
62534beb | 153 | ulong speed; |
c609719b | 154 | ulong sdtr1; |
de8d5a36 | 155 | int i; |
c609719b | 156 | |
cf48eb9a WD |
157 | /* |
158 | * Determine SDRAM speed | |
159 | */ | |
160 | speed = get_bus_freq(0); /* parameter not used on ppc4xx */ | |
62534beb | 161 | |
cf48eb9a WD |
162 | /* |
163 | * sdtr1 (register SDRAM0_TR) must take into account timings listed | |
164 | * in SDRAM chip datasheet. rtr (register SDRAM0_RTR) must take into | |
165 | * account actual SDRAM size. So we can set up sdtr1 according to what | |
166 | * is specified in board configuration file while rtr dependds on SDRAM | |
167 | * size we are assuming before detection. | |
168 | */ | |
169 | sdtr1 = compute_sdtr1(speed); | |
c609719b | 170 | |
de8d5a36 | 171 | for (i=0; i<N_MB0CF; i++) { |
6177445d | 172 | /* |
de8d5a36 | 173 | * Disable memory controller. |
6177445d | 174 | */ |
95b602ba | 175 | mtsdram(SDRAM0_CFG, 0x00000000); |
e5ad56b1 | 176 | |
c609719b | 177 | /* |
de8d5a36 | 178 | * Set MB0CF for bank 0. |
c609719b | 179 | */ |
95b602ba SR |
180 | mtsdram(SDRAM0_B0CR, mb0cf[i].reg); |
181 | mtsdram(SDRAM0_TR, sdtr1); | |
182 | mtsdram(SDRAM0_RTR, compute_rtr(speed, mb0cf[i].rows, 64)); | |
e5ad56b1 | 183 | |
de8d5a36 | 184 | udelay(200); |
c609719b | 185 | |
c609719b | 186 | /* |
de8d5a36 SR |
187 | * Set memory controller options reg, MCOPT1. |
188 | * Set DC_EN to '1' and BRD_PRF to '01' for 16 byte PLB Burst | |
189 | * read/prefetch. | |
c609719b | 190 | */ |
95b602ba | 191 | mtsdram(SDRAM0_CFG, 0x80800000); |
c609719b | 192 | |
de8d5a36 | 193 | udelay(10000); |
c609719b | 194 | |
de8d5a36 | 195 | if (get_ram_size(0, mb0cf[i].size) == mb0cf[i].size) { |
7bf5ecfa SR |
196 | phys_size_t size = mb0cf[i].size; |
197 | ||
de8d5a36 | 198 | /* |
d4024bb7 JO |
199 | * OK, size detected. Enable second bank if |
200 | * defined (assumes same type as bank 0) | |
de8d5a36 | 201 | */ |
d4024bb7 | 202 | #ifdef CONFIG_SDRAM_BANK1 |
95b602ba SR |
203 | mtsdram(SDRAM0_CFG, 0x00000000); |
204 | mtsdram(SDRAM0_B1CR, mb0cf[i].size | mb0cf[i].reg); | |
205 | mtsdram(SDRAM0_CFG, 0x80800000); | |
d4024bb7 | 206 | udelay(10000); |
779e9751 SR |
207 | |
208 | /* | |
209 | * Check if 2nd bank is really available. | |
210 | * If the size not equal to the size of the first | |
211 | * bank, then disable the 2nd bank completely. | |
212 | */ | |
213 | if (get_ram_size((long *)mb0cf[i].size, mb0cf[i].size) != | |
214 | mb0cf[i].size) { | |
95b602ba SR |
215 | mtsdram(SDRAM0_B1CR, 0); |
216 | mtsdram(SDRAM0_CFG, 0); | |
7bf5ecfa SR |
217 | } else { |
218 | /* | |
219 | * We have two identical banks, so the size | |
220 | * is twice the bank size | |
221 | */ | |
222 | size = 2 * size; | |
779e9751 | 223 | } |
d4024bb7 | 224 | #endif |
bbeff30c SR |
225 | |
226 | /* | |
227 | * OK, size detected -> all done | |
228 | */ | |
7bf5ecfa | 229 | return size; |
de8d5a36 | 230 | } |
6177445d | 231 | } |
bbeff30c SR |
232 | |
233 | return 0; | |
c609719b WD |
234 | } |
235 | ||
5568e613 SR |
236 | #else /* CONFIG_440 */ |
237 | ||
5fb692ca SR |
238 | /* |
239 | * Define some default values. Those can be overwritten in the | |
240 | * board config file. | |
241 | */ | |
242 | ||
6d0f6bcf | 243 | #ifndef CONFIG_SYS_SDRAM_TABLE |
5fb692ca SR |
244 | sdram_conf_t mb0cf[] = { |
245 | {(256 << 20), 13, 0x000C4001}, /* 256MB mode 3, 13x10(4) */ | |
3943d2ff | 246 | {(128 << 20), 13, 0x000A4001}, /* 128MB mode 3, 13x10(4) */ |
5fb692ca SR |
247 | {(64 << 20), 12, 0x00082001} /* 64MB mode 2, 12x9(4) */ |
248 | }; | |
249 | #else | |
6d0f6bcf | 250 | sdram_conf_t mb0cf[] = CONFIG_SYS_SDRAM_TABLE; |
5fb692ca SR |
251 | #endif |
252 | ||
6d0f6bcf JCPV |
253 | #ifndef CONFIG_SYS_SDRAM0_TR0 |
254 | #define CONFIG_SYS_SDRAM0_TR0 0x41094012 | |
5fb692ca SR |
255 | #endif |
256 | ||
3943d2ff DE |
257 | #ifndef CONFIG_SYS_SDRAM0_WDDCTR |
258 | #define CONFIG_SYS_SDRAM0_WDDCTR 0x00000000 /* wrcp=0 dcd=0 */ | |
259 | #endif | |
260 | ||
261 | #ifndef CONFIG_SYS_SDRAM0_RTR | |
262 | #define CONFIG_SYS_SDRAM0_RTR 0x04100000 /* 7.8us @ 133MHz PLB */ | |
263 | #endif | |
264 | ||
265 | #ifndef CONFIG_SYS_SDRAM0_CFG0 | |
266 | #define CONFIG_SYS_SDRAM0_CFG0 0x82000000 /* DCEN=1, PMUD=0, 64-bit */ | |
267 | #endif | |
268 | ||
5fb692ca SR |
269 | #define N_MB0CF (sizeof(mb0cf) / sizeof(mb0cf[0])) |
270 | ||
62534beb SR |
271 | #define NUM_TRIES 64 |
272 | #define NUM_READS 10 | |
273 | ||
274 | static void sdram_tr1_set(int ram_address, int* tr1_value) | |
275 | { | |
276 | int i; | |
277 | int j, k; | |
278 | volatile unsigned int* ram_pointer = (unsigned int *)ram_address; | |
279 | int first_good = -1, last_bad = 0x1ff; | |
280 | ||
281 | unsigned long test[NUM_TRIES] = { | |
282 | 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, | |
283 | 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, | |
284 | 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, | |
285 | 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, | |
286 | 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555, | |
287 | 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555, | |
288 | 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, | |
289 | 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, | |
290 | 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A, | |
291 | 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A, | |
292 | 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5, | |
293 | 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5, | |
294 | 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA, | |
295 | 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA, | |
296 | 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55, | |
297 | 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55 }; | |
298 | ||
299 | /* go through all possible SDRAM0_TR1[RDCT] values */ | |
300 | for (i=0; i<=0x1ff; i++) { | |
301 | /* set the current value for TR1 */ | |
95b602ba | 302 | mtsdram(SDRAM0_TR1, (0x80800800 | i)); |
62534beb SR |
303 | |
304 | /* write values */ | |
305 | for (j=0; j<NUM_TRIES; j++) { | |
306 | ram_pointer[j] = test[j]; | |
307 | ||
308 | /* clear any cache at ram location */ | |
309 | __asm__("dcbf 0,%0": :"r" (&ram_pointer[j])); | |
310 | } | |
311 | ||
312 | /* read values back */ | |
313 | for (j=0; j<NUM_TRIES; j++) { | |
314 | for (k=0; k<NUM_READS; k++) { | |
315 | /* clear any cache at ram location */ | |
316 | __asm__("dcbf 0,%0": :"r" (&ram_pointer[j])); | |
317 | ||
318 | if (ram_pointer[j] != test[j]) | |
319 | break; | |
320 | } | |
321 | ||
322 | /* read error */ | |
323 | if (k != NUM_READS) | |
324 | break; | |
325 | } | |
326 | ||
327 | /* we have a SDRAM0_TR1[RDCT] that is part of the window */ | |
328 | if (j == NUM_TRIES) { | |
329 | if (first_good == -1) | |
330 | first_good = i; /* found beginning of window */ | |
331 | } else { /* bad read */ | |
332 | /* if we have not had a good read then don't care */ | |
333 | if (first_good != -1) { | |
334 | /* first failure after a good read */ | |
335 | last_bad = i-1; | |
336 | break; | |
337 | } | |
338 | } | |
339 | } | |
340 | ||
341 | /* return the current value for TR1 */ | |
342 | *tr1_value = (first_good + last_bad) / 2; | |
343 | } | |
344 | ||
5568e613 SR |
345 | /* |
346 | * Autodetect onboard DDR SDRAM on 440 platforms | |
347 | * | |
348 | * NOTE: Some of the hardcoded values are hardware dependant, | |
cf48eb9a WD |
349 | * so this should be extended for other future boards |
350 | * using this routine! | |
5568e613 | 351 | */ |
9973e3c6 | 352 | phys_size_t initdram(int board_type) |
5568e613 SR |
353 | { |
354 | int i; | |
62534beb | 355 | int tr1_bank1; |
5568e613 | 356 | |
5fb692ca SR |
357 | #if defined(CONFIG_440GX) || defined(CONFIG_440EP) || \ |
358 | defined(CONFIG_440GR) || defined(CONFIG_440SP) | |
899620c2 SR |
359 | /* |
360 | * Soft-reset SDRAM controller. | |
361 | */ | |
d1c3b275 SR |
362 | mtsdr(SDR0_SRST, SDR0_SRST_DMC); |
363 | mtsdr(SDR0_SRST, 0x00000000); | |
899620c2 SR |
364 | #endif |
365 | ||
5568e613 SR |
366 | for (i=0; i<N_MB0CF; i++) { |
367 | /* | |
368 | * Disable memory controller. | |
369 | */ | |
95b602ba | 370 | mtsdram(SDRAM0_CFG0, 0x00000000); |
5568e613 SR |
371 | |
372 | /* | |
373 | * Setup some default | |
374 | */ | |
95b602ba SR |
375 | mtsdram(SDRAM0_UABBA, 0x00000000); /* ubba=0 (default) */ |
376 | mtsdram(SDRAM0_SLIO, 0x00000000); /* rdre=0 wrre=0 rarw=0 */ | |
377 | mtsdram(SDRAM0_DEVOPT, 0x00000000); /* dll=0 ds=0 (normal) */ | |
378 | mtsdram(SDRAM0_WDDCTR, CONFIG_SYS_SDRAM0_WDDCTR); | |
379 | mtsdram(SDRAM0_CLKTR, 0x40000000); /* clkp=1 (90 deg wr) dcdt=0 */ | |
5568e613 SR |
380 | |
381 | /* | |
382 | * Following for CAS Latency = 2.5 @ 133 MHz PLB | |
383 | */ | |
95b602ba SR |
384 | mtsdram(SDRAM0_B0CR, mb0cf[i].reg); |
385 | mtsdram(SDRAM0_TR0, CONFIG_SYS_SDRAM0_TR0); | |
386 | mtsdram(SDRAM0_TR1, 0x80800800); /* SS=T2 SL=STAGE 3 CD=1 CT=0x00*/ | |
387 | mtsdram(SDRAM0_RTR, CONFIG_SYS_SDRAM0_RTR); | |
388 | mtsdram(SDRAM0_CFG1, 0x00000000); /* Self-refresh exit, disable PM*/ | |
5568e613 SR |
389 | udelay(400); /* Delay 200 usecs (min) */ |
390 | ||
391 | /* | |
392 | * Enable the controller, then wait for DCEN to complete | |
393 | */ | |
95b602ba | 394 | mtsdram(SDRAM0_CFG0, CONFIG_SYS_SDRAM0_CFG0); |
5568e613 SR |
395 | udelay(10000); |
396 | ||
397 | if (get_ram_size(0, mb0cf[i].size) == mb0cf[i].size) { | |
3943d2ff | 398 | phys_size_t size = mb0cf[i].size; |
62534beb SR |
399 | /* |
400 | * Optimize TR1 to current hardware environment | |
401 | */ | |
402 | sdram_tr1_set(0x00000000, &tr1_bank1); | |
95b602ba | 403 | mtsdram(SDRAM0_TR1, (tr1_bank1 | 0x80800800)); |
62534beb | 404 | |
3943d2ff DE |
405 | |
406 | /* | |
407 | * OK, size detected. Enable second bank if | |
408 | * defined (assumes same type as bank 0) | |
409 | */ | |
410 | #ifdef CONFIG_SDRAM_BANK1 | |
95b602ba SR |
411 | mtsdram(SDRAM0_CFG0, 0); |
412 | mtsdram(SDRAM0_B1CR, mb0cf[i].size | mb0cf[i].reg); | |
413 | mtsdram(SDRAM0_CFG0, CONFIG_SYS_SDRAM0_CFG0); | |
3943d2ff DE |
414 | udelay(10000); |
415 | ||
416 | /* | |
417 | * Check if 2nd bank is really available. | |
418 | * If the size not equal to the size of the first | |
419 | * bank, then disable the 2nd bank completely. | |
420 | */ | |
421 | if (get_ram_size((long *)mb0cf[i].size, mb0cf[i].size) | |
422 | != mb0cf[i].size) { | |
95b602ba SR |
423 | mtsdram(SDRAM0_CFG0, 0); |
424 | mtsdram(SDRAM0_B1CR, 0); | |
425 | mtsdram(SDRAM0_CFG0, CONFIG_SYS_SDRAM0_CFG0); | |
3943d2ff DE |
426 | udelay(10000); |
427 | } else { | |
428 | /* | |
429 | * We have two identical banks, so the size | |
430 | * is twice the bank size | |
431 | */ | |
432 | size = 2 * size; | |
433 | } | |
434 | #endif | |
435 | ||
62534beb | 436 | #ifdef CONFIG_SDRAM_ECC |
3943d2ff | 437 | ecc_init(0, size); |
62534beb SR |
438 | #endif |
439 | ||
5568e613 SR |
440 | /* |
441 | * OK, size detected -> all done | |
442 | */ | |
3943d2ff | 443 | return size; |
5568e613 SR |
444 | } |
445 | } | |
446 | ||
447 | return 0; /* nothing found ! */ | |
448 | } | |
449 | ||
450 | #endif /* CONFIG_440 */ | |
451 | ||
c609719b | 452 | #endif /* CONFIG_SDRAM_BANK0 */ |