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