]>
Commit | Line | Data |
---|---|---|
99d8b23b MF |
1 | /* |
2 | * (C) Copyright 2009 | |
3 | * Matthias Fuchs, esd gmbh germany, matthias.fuchs@esd.eu | |
4 | * | |
5 | * See file CREDITS for list of people who contributed to this | |
6 | * project. | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public License as | |
10 | * published by the Free Software Foundation; either version 2 of | |
11 | * the License, or (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | * MA 02111-1307 USA | |
22 | */ | |
23 | ||
24 | #include <common.h> | |
25 | #include <libfdt.h> | |
26 | #include <fdt_support.h> | |
27 | #include <asm/processor.h> | |
28 | #include <asm/io.h> | |
09887762 | 29 | #include <asm/ppc4xx-gpio.h> |
99d8b23b MF |
30 | #include <asm/4xx_pci.h> |
31 | #include <command.h> | |
32 | #include <malloc.h> | |
33 | ||
34 | /* | |
35 | * PMC405-DE cpld registers | |
36 | * - all registers are 8 bit | |
37 | * - all registers are on 32 bit addesses | |
38 | */ | |
39 | struct pmc405de_cpld { | |
40 | /* cpld design version */ | |
41 | u8 version; | |
42 | u8 reserved0[3]; | |
43 | ||
44 | /* misc. status lines */ | |
45 | u8 status; | |
46 | u8 reserved1[3]; | |
47 | ||
48 | /* | |
49 | * gated control flags | |
50 | * gate bit(s) must be written with '1' to | |
51 | * access control flag | |
52 | */ | |
53 | u8 control; | |
54 | u8 reserved2[3]; | |
55 | }; | |
56 | ||
57 | #define CPLD_VERSION_MASK 0x0f | |
58 | #define CPLD_CONTROL_POSTLED_N 0x01 | |
59 | #define CPLD_CONTROL_POSTLED_GATE 0x02 | |
60 | #define CPLD_CONTROL_RESETOUT_N 0x40 | |
61 | #define CPLD_CONTROL_RESETOUT_N_GATE 0x80 | |
62 | ||
63 | DECLARE_GLOBAL_DATA_PTR; | |
64 | ||
65 | extern void __ft_board_setup(void *blob, bd_t *bd); | |
66 | extern void pll_write(u32 a, u32 b); | |
67 | ||
68 | static int wait_for_pci_ready_done; | |
69 | ||
70 | static int is_monarch(void); | |
71 | static int pci_is_66mhz(void); | |
72 | static int board_revision(void); | |
73 | static int cpld_revision(void); | |
74 | static void upd_plb_pci_div(u32 pllmr0, u32 pllmr1, u32 div); | |
75 | ||
76 | int board_early_init_f(void) | |
77 | { | |
78 | u32 pllmr0, pllmr1; | |
79 | ||
80 | /* | |
81 | * check M66EN and patch PLB:PCI divider for 66MHz PCI | |
82 | * | |
83 | * fCPU==333MHz && fPCI==66MHz (PLBDiv==3 && M66EN==1): PLB/PCI=1 | |
84 | * fCPU==333MHz && fPCI==33MHz (PLBDiv==3 && M66EN==0): PLB/PCI=2 | |
85 | * fCPU==133|266MHz && fPCI==66MHz (PLBDiv==1|2 && M66EN==1): PLB/PCI=2 | |
86 | * fCPU==133|266MHz && fPCI==33MHz (PLBDiv==1|2 && M66EN==0): PLB/PCI=3 | |
87 | * | |
88 | * calling upd_plb_pci_div() may end in calling pll_write() which will | |
89 | * do a chip reset and never return. | |
90 | */ | |
91 | pllmr0 = mfdcr(CPC0_PLLMR0); | |
92 | pllmr1 = mfdcr(CPC0_PLLMR1); | |
93 | ||
94 | if ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) == PLLMR0_CPU_PLB_DIV_3) { | |
95 | /* fCPU=333MHz, fPLB=111MHz */ | |
96 | if (pci_is_66mhz()) | |
97 | upd_plb_pci_div(pllmr0, pllmr1, PLLMR0_PCI_PLB_DIV_1); | |
98 | else | |
99 | upd_plb_pci_div(pllmr0, pllmr1, PLLMR0_PCI_PLB_DIV_2); | |
100 | } else { | |
101 | /* fCPU=133|266MHz, fPLB=133MHz */ | |
102 | if (pci_is_66mhz()) | |
103 | upd_plb_pci_div(pllmr0, pllmr1, PLLMR0_PCI_PLB_DIV_2); | |
104 | else | |
105 | upd_plb_pci_div(pllmr0, pllmr1, PLLMR0_PCI_PLB_DIV_3); | |
106 | } | |
107 | ||
108 | /* | |
109 | * IRQ 25 (EXT IRQ 0) PCI-INTA#; active low; level sensitive | |
110 | * IRQ 26 (EXT IRQ 1) PCI-INTB#; active low; level sensitive | |
111 | * IRQ 27 (EXT IRQ 2) PCI-INTC#; active low; level sensitive | |
112 | * IRQ 28 (EXT IRQ 3) PCI-INTD#; active low; level sensitive | |
113 | * IRQ 29 (EXT IRQ 4) ETH0-PHY-IRQ#; active low; level sensitive | |
114 | * IRQ 30 (EXT IRQ 5) ETH1-PHY-IRQ#; active low; level sensitive | |
115 | * IRQ 31 (EXT IRQ 6) PLD-IRQ#; active low; level sensitive | |
116 | */ | |
952e7760 SR |
117 | mtdcr(UIC0SR, 0xFFFFFFFF); /* clear all ints */ |
118 | mtdcr(UIC0ER, 0x00000000); /* disable all ints */ | |
119 | mtdcr(UIC0CR, 0x00000000); /* set all to be non-critical*/ | |
120 | mtdcr(UIC0PR, 0xFFFFFF80); /* set int polarities */ | |
121 | mtdcr(UIC0TR, 0x10000000); /* set int trigger levels */ | |
122 | mtdcr(UIC0VCR, 0x00000001); /* set vect base=0, INT0 highest prio */ | |
123 | mtdcr(UIC0SR, 0xFFFFFFFF); /* clear all ints */ | |
99d8b23b MF |
124 | |
125 | /* | |
126 | * EBC Configuration Register: | |
127 | * - set ready timeout to 512 ebc-clks -> ca. 15 us | |
128 | * - EBC lines are always driven | |
129 | */ | |
d1c3b275 | 130 | mtebc(EBC0_CFG, 0xa8400000); |
99d8b23b MF |
131 | |
132 | return 0; | |
133 | } | |
134 | ||
135 | static void upd_plb_pci_div(u32 pllmr0, u32 pllmr1, u32 div) | |
136 | { | |
137 | if ((pllmr0 & PLLMR0_PCI_TO_PLB_MASK) != div) | |
138 | pll_write((pllmr0 & ~PLLMR0_PCI_TO_PLB_MASK) | div, pllmr1); | |
139 | } | |
140 | ||
141 | int misc_init_r(void) | |
142 | { | |
143 | int i; | |
144 | struct ppc4xx_gpio *gpio0 = (struct ppc4xx_gpio *)GPIO_BASE; | |
145 | struct pmc405de_cpld *cpld = | |
146 | (struct pmc405de_cpld *)CONFIG_SYS_CPLD_BASE; | |
147 | ||
148 | if (!is_monarch()) { | |
149 | /* PCI configuration done: release EREADY */ | |
150 | setbits_be32(&gpio0->or, CONFIG_SYS_GPIO_EREADY); | |
151 | setbits_be32(&gpio0->tcr, CONFIG_SYS_GPIO_EREADY); | |
152 | } | |
153 | ||
154 | /* turn off POST LED */ | |
155 | out_8(&cpld->control, | |
156 | CPLD_CONTROL_POSTLED_N | CPLD_CONTROL_POSTLED_GATE); | |
157 | ||
158 | /* turn on LEDs: RUN, A, B */ | |
159 | clrbits_be32(&gpio0->or, | |
160 | CONFIG_SYS_GPIO_LEDRUN_N | | |
161 | CONFIG_SYS_GPIO_LEDA_N | | |
162 | CONFIG_SYS_GPIO_LEDB_N); | |
163 | ||
164 | for (i=0; i < 200; i++) | |
165 | udelay(1000); | |
166 | ||
167 | /* turn off LEDs: A, B */ | |
168 | setbits_be32(&gpio0->or, | |
169 | CONFIG_SYS_GPIO_LEDA_N | | |
170 | CONFIG_SYS_GPIO_LEDB_N); | |
171 | ||
172 | return (0); | |
173 | } | |
174 | ||
175 | static int is_monarch(void) | |
176 | { | |
177 | struct ppc4xx_gpio *gpio0 = (struct ppc4xx_gpio *)GPIO_BASE; | |
178 | return (in_be32(&gpio0->ir) & CONFIG_SYS_GPIO_MONARCH_N) == 0; | |
179 | } | |
180 | ||
181 | static int pci_is_66mhz(void) | |
182 | { | |
183 | struct ppc4xx_gpio *gpio0 = (struct ppc4xx_gpio *)GPIO_BASE; | |
184 | return (in_be32(&gpio0->ir) & CONFIG_SYS_GPIO_M66EN); | |
185 | } | |
186 | ||
187 | static int board_revision(void) | |
188 | { | |
189 | struct ppc4xx_gpio *gpio0 = (struct ppc4xx_gpio *)GPIO_BASE; | |
190 | return ((in_be32(&gpio0->ir) & CONFIG_SYS_GPIO_HWREV_MASK) >> | |
191 | CONFIG_SYS_GPIO_HWREV_SHIFT); | |
192 | } | |
193 | ||
194 | static int cpld_revision(void) | |
195 | { | |
196 | struct pmc405de_cpld *cpld = | |
197 | (struct pmc405de_cpld *)CONFIG_SYS_CPLD_BASE; | |
198 | return ((in_8(&cpld->version) & CPLD_VERSION_MASK)); | |
199 | } | |
200 | ||
201 | /* | |
202 | * Check Board Identity | |
203 | */ | |
204 | int checkboard(void) | |
205 | { | |
206 | puts("Board: esd GmbH - PMC-CPU/405-DE"); | |
207 | ||
208 | gd->board_type = board_revision(); | |
209 | printf(", Rev 1.%ld, ", gd->board_type); | |
210 | ||
211 | if (!is_monarch()) | |
212 | puts("non-"); | |
213 | ||
214 | printf("monarch, PCI=%s MHz, PLD-Rev 1.%d\n", | |
215 | pci_is_66mhz() ? "66" : "33", cpld_revision()); | |
216 | ||
217 | return 0; | |
218 | } | |
219 | ||
220 | ||
221 | static void wait_for_pci_ready(void) | |
222 | { | |
223 | struct ppc4xx_gpio *gpio0 = (struct ppc4xx_gpio *)GPIO_BASE; | |
224 | int i; | |
225 | char *s = getenv("pcidelay"); | |
226 | ||
227 | /* only wait once */ | |
228 | if (wait_for_pci_ready_done) | |
229 | return; | |
230 | ||
231 | /* | |
232 | * We have our own handling of the pcidelay variable. | |
233 | * Using CONFIG_PCI_BOOTDELAY enables pausing for host | |
234 | * and adapter devices. For adapter devices we do not | |
235 | * want this. | |
236 | */ | |
237 | if (s) { | |
238 | int ms = simple_strtoul(s, NULL, 10); | |
239 | printf("PCI: Waiting for %d ms\n", ms); | |
240 | for (i=0; i<ms; i++) | |
241 | udelay(1000); | |
242 | } | |
243 | ||
244 | if (!(in_be32(&gpio0->ir) & CONFIG_SYS_GPIO_EREADY)) { | |
245 | printf("PCI: Waiting for EREADY (CTRL-C to skip) ... "); | |
246 | while (1) { | |
247 | if (ctrlc()) { | |
248 | puts("abort\n"); | |
249 | break; | |
250 | } | |
251 | if (in_be32(&gpio0->ir) & CONFIG_SYS_GPIO_EREADY) { | |
252 | printf("done\n"); | |
253 | break; | |
254 | } | |
255 | } | |
256 | } | |
257 | ||
258 | wait_for_pci_ready_done = 1; | |
259 | } | |
260 | ||
261 | /* | |
262 | * Overwrite weak is_pci_host() | |
263 | * | |
264 | * This routine is called to determine if a pci scan should be | |
265 | * performed. With various hardware environments (especially cPCI and | |
266 | * PPMC) it's insufficient to depend on the state of the arbiter enable | |
267 | * bit in the strap register, or generic host/adapter assumptions. | |
268 | * | |
269 | * Return 0 for adapter mode, non-zero for host (monarch) mode. | |
270 | */ | |
271 | int is_pci_host(struct pci_controller *hose) | |
272 | { | |
273 | char *s; | |
274 | ||
275 | if (!is_monarch()) { | |
276 | /* | |
277 | * Overwrite PCI identification when running in | |
278 | * non-monarch mode | |
279 | * This should be moved into pci_target_init() | |
280 | * when it is sometimes available for 405 CPUs | |
281 | */ | |
282 | pci_write_config_word(PCIDEVID_405GP, | |
283 | PCI_SUBSYSTEM_ID, | |
284 | CONFIG_SYS_PCI_SUBSYS_ID_NONMONARCH); | |
285 | pci_write_config_word(PCIDEVID_405GP, | |
286 | PCI_CLASS_SUB_CODE, | |
287 | CONFIG_SYS_PCI_CLASSCODE_NONMONARCH); | |
288 | } | |
289 | ||
290 | s = getenv("pciscan"); | |
291 | if (s == NULL) { | |
292 | if (is_monarch()) { | |
293 | wait_for_pci_ready(); | |
294 | return 1; | |
295 | } else { | |
296 | return 0; | |
297 | } | |
298 | } else { | |
299 | if (!strcmp(s, "yes")) | |
300 | return 1; | |
301 | } | |
302 | ||
303 | return 0; | |
304 | } | |
305 | ||
306 | /* | |
307 | * Overwrite weak pci_pre_init() | |
308 | * | |
309 | * The default implementation enables the 405EP | |
310 | * internal PCI arbiter. We do not want that | |
311 | * on a PMC module. | |
312 | */ | |
313 | int pci_pre_init(struct pci_controller *hose) | |
314 | { | |
315 | return 1; | |
316 | } | |
317 | ||
318 | #if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP) | |
319 | void ft_board_setup(void *blob, bd_t *bd) | |
320 | { | |
321 | int rc; | |
322 | ||
323 | __ft_board_setup(blob, bd); | |
324 | ||
325 | /* | |
326 | * Disable PCI in non-monarch mode. | |
327 | */ | |
328 | if (!is_monarch()) { | |
329 | rc = fdt_find_and_setprop(blob, "/plb/pci@ec000000", "status", | |
330 | "disabled", sizeof("disabled"), 1); | |
331 | if (rc) { | |
332 | printf("Unable to update property status in PCI node, " | |
333 | "err=%s\n", | |
334 | fdt_strerror(rc)); | |
335 | } | |
336 | } | |
337 | } | |
338 | #endif /* defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP) */ | |
339 | ||
340 | #if defined(CONFIG_SYS_EEPROM_WREN) | |
341 | /* Input: <dev_addr> I2C address of EEPROM device to enable. | |
342 | * <state> -1: deliver current state | |
343 | * 0: disable write | |
344 | * 1: enable write | |
345 | * Returns: -1: wrong device address | |
346 | * 0: dis-/en- able done | |
347 | * 0/1: current state if <state> was -1. | |
348 | */ | |
349 | int eeprom_write_enable(unsigned dev_addr, int state) | |
350 | { | |
351 | struct ppc4xx_gpio *gpio0 = (struct ppc4xx_gpio *)GPIO_BASE; | |
352 | ||
353 | if (CONFIG_SYS_I2C_EEPROM_ADDR != dev_addr) { | |
354 | return -1; | |
355 | } else { | |
356 | switch (state) { | |
357 | case 1: | |
358 | /* Enable write access, clear bit GPIO0. */ | |
359 | clrbits_be32(&gpio0->or, CONFIG_SYS_GPIO_EEPROM_WP); | |
360 | state = 0; | |
361 | break; | |
362 | case 0: | |
363 | /* Disable write access, set bit GPIO0. */ | |
364 | setbits_be32(&gpio0->or, CONFIG_SYS_GPIO_EEPROM_WP); | |
365 | state = 0; | |
366 | break; | |
367 | default: | |
368 | /* Read current status back. */ | |
369 | state = (0 == (in_be32(&gpio0->or) & | |
370 | CONFIG_SYS_GPIO_EEPROM_WP)); | |
371 | break; | |
372 | } | |
373 | } | |
374 | return state; | |
375 | } | |
376 | ||
54841ab5 | 377 | int do_eep_wren(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
99d8b23b MF |
378 | { |
379 | int query = argc == 1; | |
380 | int state = 0; | |
381 | ||
382 | if (query) { | |
383 | /* Query write access state. */ | |
384 | state = eeprom_write_enable(CONFIG_SYS_I2C_EEPROM_ADDR, - 1); | |
385 | if (state < 0) { | |
386 | puts("Query of write access state failed.\n"); | |
387 | } else { | |
388 | printf("Write access for device 0x%0x is %sabled.\n", | |
389 | CONFIG_SYS_I2C_EEPROM_ADDR, | |
390 | state ? "en" : "dis"); | |
391 | state = 0; | |
392 | } | |
393 | } else { | |
394 | if ('0' == argv[1][0]) { | |
395 | /* Disable write access. */ | |
396 | state = eeprom_write_enable( | |
397 | CONFIG_SYS_I2C_EEPROM_ADDR, 0); | |
398 | } else { | |
399 | /* Enable write access. */ | |
400 | state = eeprom_write_enable( | |
401 | CONFIG_SYS_I2C_EEPROM_ADDR, 1); | |
402 | } | |
403 | if (state < 0) | |
404 | puts ("Setup of write access state failed.\n"); | |
405 | } | |
406 | ||
407 | return state; | |
408 | } | |
409 | ||
410 | U_BOOT_CMD(eepwren, 2, 0, do_eep_wren, | |
411 | "Enable / disable / query EEPROM write access", | |
412 | "" | |
413 | ); | |
414 | #endif /* #if defined(CONFIG_SYS_EEPROM_WREN) */ | |
415 | ||
416 | #if defined(CONFIG_PRAM) | |
417 | #include <environment.h> | |
418 | extern env_t *env_ptr; | |
419 | ||
54841ab5 | 420 | int do_painit(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
99d8b23b MF |
421 | { |
422 | u32 pram, nextbase, base; | |
423 | char *v; | |
424 | u32 param; | |
425 | ulong *lptr; | |
426 | ||
427 | v = getenv("pram"); | |
428 | if (v) | |
429 | pram = simple_strtoul(v, NULL, 10); | |
430 | else { | |
431 | printf("Error: pram undefined. Please define pram in KiB\n"); | |
432 | return 1; | |
433 | } | |
434 | ||
435 | base = gd->bd->bi_memsize; | |
436 | #if defined(CONFIG_LOGBUFFER) | |
437 | base -= LOGBUFF_LEN + LOGBUFF_OVERHEAD; | |
438 | #endif | |
439 | /* | |
440 | * gd->bd->bi_memsize == physical ram size - CONFIG_SYS_MM_TOP_HIDE | |
441 | */ | |
442 | param = base - (pram << 10); | |
443 | printf("PARAM: @%08x\n", param); | |
444 | debug("memsize=0x%08x, base=0x%08x\n", gd->bd->bi_memsize, base); | |
445 | ||
446 | /* clear entire PA ram */ | |
447 | memset((void*)param, 0, (pram << 10)); | |
448 | ||
449 | /* reserve 4k for pointer field */ | |
450 | nextbase = base - 4096; | |
451 | lptr = (ulong*)(base); | |
452 | ||
453 | /* | |
454 | * *(--lptr) = item_size; | |
455 | * *(--lptr) = base - item_base = distance from field top; | |
456 | */ | |
457 | ||
458 | /* env is first (4k aligned) */ | |
459 | nextbase -= ((CONFIG_ENV_SIZE + 4096 - 1) & ~(4096 - 1)); | |
460 | memcpy((void*)nextbase, env_ptr, CONFIG_ENV_SIZE); | |
461 | *(--lptr) = CONFIG_ENV_SIZE; /* size */ | |
462 | *(--lptr) = base - nextbase; /* offset | type=0 */ | |
463 | ||
464 | /* free section */ | |
465 | *(--lptr) = nextbase - param; /* size */ | |
466 | *(--lptr) = (base - param) | 126; /* offset | type=126 */ | |
467 | ||
468 | /* terminate pointer field */ | |
469 | *(--lptr) = crc32(0, (void*)(base - 0x10), 0x10); | |
470 | *(--lptr) = 0; /* offset=0 -> terminator */ | |
471 | return 0; | |
472 | } | |
473 | U_BOOT_CMD( | |
474 | painit, 1, 1, do_painit, | |
475 | "prepare PciAccess system", | |
476 | "" | |
477 | ); | |
478 | #endif /* CONFIG_PRAM */ | |
479 | ||
54841ab5 | 480 | int do_selfreset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
99d8b23b MF |
481 | { |
482 | struct ppc4xx_gpio *gpio0 = (struct ppc4xx_gpio *)GPIO_BASE; | |
483 | setbits_be32(&gpio0->tcr, CONFIG_SYS_GPIO_SELFRST_N); | |
484 | return 0; | |
485 | } | |
486 | U_BOOT_CMD( | |
487 | selfreset, 1, 1, do_selfreset, | |
488 | "assert self-reset# signal", | |
489 | "" | |
490 | ); | |
491 | ||
54841ab5 | 492 | int do_resetout(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
99d8b23b MF |
493 | { |
494 | struct pmc405de_cpld *cpld = | |
495 | (struct pmc405de_cpld *)CONFIG_SYS_CPLD_BASE; | |
496 | ||
497 | if (argc > 1) { | |
498 | if (argv[1][0] == '0') { | |
499 | /* assert */ | |
500 | printf("PMC-RESETOUT# asserted\n"); | |
501 | out_8(&cpld->control, | |
502 | CPLD_CONTROL_RESETOUT_N_GATE); | |
503 | } else { | |
504 | /* deassert */ | |
505 | printf("PMC-RESETOUT# deasserted\n"); | |
506 | out_8(&cpld->control, | |
507 | CPLD_CONTROL_RESETOUT_N | | |
508 | CPLD_CONTROL_RESETOUT_N_GATE); | |
509 | } | |
510 | } else { | |
511 | printf("PMC-RESETOUT# is %s\n", | |
512 | (in_8(&cpld->control) & CPLD_CONTROL_RESETOUT_N) ? | |
513 | "inactive" : "active"); | |
514 | } | |
515 | return 0; | |
516 | } | |
517 | U_BOOT_CMD( | |
518 | resetout, 2, 1, do_resetout, | |
519 | "assert PMC-RESETOUT# signal", | |
520 | "" | |
521 | ); |