aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/boot/prpmc2800.c
diff options
context:
space:
mode:
authorMark A. Greer <mgreer@mvista.com>2007-05-11 20:58:18 -0400
committerPaul Mackerras <paulus@samba.org>2007-05-11 21:32:50 -0400
commitc368d921daed3c7cfba9752a45b2a8804cd54128 (patch)
treed171b490634300a31f5cc5a0136b49fdb110ae80 /arch/powerpc/boot/prpmc2800.c
parent3f456cc18f63bebdf71d788098c72d7ecd83c9b6 (diff)
[POWERPC] Add bootwrapper support for Motorola PrPMC2800 platform
The Motorola PrPMC280 and PrPMC2800 processor modules sit on an F101 or PrPMC2800 baseboard, respectively. There are several variants of each type of processor module which can have different amounts of memory, amounts of FLASH, cpu frequencies, and an mv64360 or an mv64362. The bootwrapper code for that platform reads VPD from an I2C EEPROM to determine the processor module variant. From the variant, the amount of memory, etc. is determined and the device tree is updated accordingly. If the variant cannot be determined (e.g., corrupted VPD or a previously unknown variant), the property values already in the device tree are used. Also, the firmware for those platforms does not completely configure the mv64x60 host bridge so that configuration is done here. Signed-off-by: Mark A. Greer <mgreer@mvista.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/boot/prpmc2800.c')
-rw-r--r--arch/powerpc/boot/prpmc2800.c577
1 files changed, 577 insertions, 0 deletions
diff --git a/arch/powerpc/boot/prpmc2800.c b/arch/powerpc/boot/prpmc2800.c
new file mode 100644
index 000000000000..f428bac10d4a
--- /dev/null
+++ b/arch/powerpc/boot/prpmc2800.c
@@ -0,0 +1,577 @@
1/*
2 * Motorola ECC prpmc280/f101 & prpmc2800/f101e platform code.
3 *
4 * Author: Mark A. Greer <mgreer@mvista.com>
5 *
6 * 2007 (c) MontaVista, Software, Inc. This file is licensed under
7 * the terms of the GNU General Public License version 2. This program
8 * is licensed "as is" without any warranty of any kind, whether express
9 * or implied.
10 */
11
12#include <stdarg.h>
13#include <stddef.h>
14#include "types.h"
15#include "elf.h"
16#include "page.h"
17#include "string.h"
18#include "stdio.h"
19#include "io.h"
20#include "ops.h"
21#include "gunzip_util.h"
22#include "mv64x60.h"
23
24extern char _end[];
25extern char _vmlinux_start[], _vmlinux_end[];
26extern char _dtb_start[], _dtb_end[];
27
28extern void udelay(long delay);
29
30#define KB 1024U
31#define MB (KB*KB)
32#define GB (KB*MB)
33#define MHz (1000U*1000U)
34#define GHz (1000U*MHz)
35
36#define BOARD_MODEL "PrPMC2800"
37#define BOARD_MODEL_MAX 32 /* max strlen(BOARD_MODEL) + 1 */
38
39#define EEPROM2_ADDR 0xa4
40#define EEPROM3_ADDR 0xa8
41
42BSS_STACK(16*KB);
43
44static u8 *bridge_base;
45
46typedef enum {
47 BOARD_MODEL_PRPMC280,
48 BOARD_MODEL_PRPMC2800,
49} prpmc2800_board_model;
50
51typedef enum {
52 BRIDGE_TYPE_MV64360,
53 BRIDGE_TYPE_MV64362,
54} prpmc2800_bridge_type;
55
56struct prpmc2800_board_info {
57 prpmc2800_board_model model;
58 char variant;
59 prpmc2800_bridge_type bridge_type;
60 u8 subsys0;
61 u8 subsys1;
62 u8 vpd4;
63 u8 vpd4_mask;
64 u32 core_speed;
65 u32 mem_size;
66 u32 boot_flash;
67 u32 user_flash;
68};
69
70static struct prpmc2800_board_info prpmc2800_board_info[] = {
71 {
72 .model = BOARD_MODEL_PRPMC280,
73 .variant = 'a',
74 .bridge_type = BRIDGE_TYPE_MV64360,
75 .subsys0 = 0xff,
76 .subsys1 = 0xff,
77 .vpd4 = 0x00,
78 .vpd4_mask = 0x0f,
79 .core_speed = 1*GHz,
80 .mem_size = 512*MB,
81 .boot_flash = 1*MB,
82 .user_flash = 64*MB,
83 },
84 {
85 .model = BOARD_MODEL_PRPMC280,
86 .variant = 'b',
87 .bridge_type = BRIDGE_TYPE_MV64362,
88 .subsys0 = 0xff,
89 .subsys1 = 0xff,
90 .vpd4 = 0x01,
91 .vpd4_mask = 0x0f,
92 .core_speed = 1*GHz,
93 .mem_size = 512*MB,
94 .boot_flash = 0,
95 .user_flash = 0,
96 },
97 {
98 .model = BOARD_MODEL_PRPMC280,
99 .variant = 'c',
100 .bridge_type = BRIDGE_TYPE_MV64360,
101 .subsys0 = 0xff,
102 .subsys1 = 0xff,
103 .vpd4 = 0x02,
104 .vpd4_mask = 0x0f,
105 .core_speed = 733*MHz,
106 .mem_size = 512*MB,
107 .boot_flash = 1*MB,
108 .user_flash = 64*MB,
109 },
110 {
111 .model = BOARD_MODEL_PRPMC280,
112 .variant = 'd',
113 .bridge_type = BRIDGE_TYPE_MV64360,
114 .subsys0 = 0xff,
115 .subsys1 = 0xff,
116 .vpd4 = 0x03,
117 .vpd4_mask = 0x0f,
118 .core_speed = 1*GHz,
119 .mem_size = 1*GB,
120 .boot_flash = 1*MB,
121 .user_flash = 64*MB,
122 },
123 {
124 .model = BOARD_MODEL_PRPMC280,
125 .variant = 'e',
126 .bridge_type = BRIDGE_TYPE_MV64360,
127 .subsys0 = 0xff,
128 .subsys1 = 0xff,
129 .vpd4 = 0x04,
130 .vpd4_mask = 0x0f,
131 .core_speed = 1*GHz,
132 .mem_size = 512*MB,
133 .boot_flash = 1*MB,
134 .user_flash = 64*MB,
135 },
136 {
137 .model = BOARD_MODEL_PRPMC280,
138 .variant = 'f',
139 .bridge_type = BRIDGE_TYPE_MV64362,
140 .subsys0 = 0xff,
141 .subsys1 = 0xff,
142 .vpd4 = 0x05,
143 .vpd4_mask = 0x0f,
144 .core_speed = 733*MHz,
145 .mem_size = 128*MB,
146 .boot_flash = 1*MB,
147 .user_flash = 0,
148 },
149 {
150 .model = BOARD_MODEL_PRPMC280,
151 .variant = 'g',
152 .bridge_type = BRIDGE_TYPE_MV64360,
153 .subsys0 = 0xff,
154 .subsys1 = 0xff,
155 .vpd4 = 0x06,
156 .vpd4_mask = 0x0f,
157 .core_speed = 1*GHz,
158 .mem_size = 256*MB,
159 .boot_flash = 1*MB,
160 .user_flash = 0,
161 },
162 {
163 .model = BOARD_MODEL_PRPMC280,
164 .variant = 'h',
165 .bridge_type = BRIDGE_TYPE_MV64360,
166 .subsys0 = 0xff,
167 .subsys1 = 0xff,
168 .vpd4 = 0x07,
169 .vpd4_mask = 0x0f,
170 .core_speed = 1*GHz,
171 .mem_size = 1*GB,
172 .boot_flash = 1*MB,
173 .user_flash = 64*MB,
174 },
175 {
176 .model = BOARD_MODEL_PRPMC2800,
177 .variant = 'a',
178 .bridge_type = BRIDGE_TYPE_MV64360,
179 .subsys0 = 0xb2,
180 .subsys1 = 0x8c,
181 .vpd4 = 0x00,
182 .vpd4_mask = 0x00,
183 .core_speed = 1*GHz,
184 .mem_size = 512*MB,
185 .boot_flash = 2*MB,
186 .user_flash = 64*MB,
187 },
188 {
189 .model = BOARD_MODEL_PRPMC2800,
190 .variant = 'b',
191 .bridge_type = BRIDGE_TYPE_MV64362,
192 .subsys0 = 0xb2,
193 .subsys1 = 0x8d,
194 .vpd4 = 0x00,
195 .vpd4_mask = 0x00,
196 .core_speed = 1*GHz,
197 .mem_size = 512*MB,
198 .boot_flash = 0,
199 .user_flash = 0,
200 },
201 {
202 .model = BOARD_MODEL_PRPMC2800,
203 .variant = 'c',
204 .bridge_type = BRIDGE_TYPE_MV64360,
205 .subsys0 = 0xb2,
206 .subsys1 = 0x8e,
207 .vpd4 = 0x00,
208 .vpd4_mask = 0x00,
209 .core_speed = 733*MHz,
210 .mem_size = 512*MB,
211 .boot_flash = 2*MB,
212 .user_flash = 64*MB,
213 },
214 {
215 .model = BOARD_MODEL_PRPMC2800,
216 .variant = 'd',
217 .bridge_type = BRIDGE_TYPE_MV64360,
218 .subsys0 = 0xb2,
219 .subsys1 = 0x8f,
220 .vpd4 = 0x00,
221 .vpd4_mask = 0x00,
222 .core_speed = 1*GHz,
223 .mem_size = 1*GB,
224 .boot_flash = 2*MB,
225 .user_flash = 64*MB,
226 },
227 {
228 .model = BOARD_MODEL_PRPMC2800,
229 .variant = 'e',
230 .bridge_type = BRIDGE_TYPE_MV64360,
231 .subsys0 = 0xa2,
232 .subsys1 = 0x8a,
233 .vpd4 = 0x00,
234 .vpd4_mask = 0x00,
235 .core_speed = 1*GHz,
236 .mem_size = 512*MB,
237 .boot_flash = 2*MB,
238 .user_flash = 64*MB,
239 },
240 {
241 .model = BOARD_MODEL_PRPMC2800,
242 .variant = 'f',
243 .bridge_type = BRIDGE_TYPE_MV64362,
244 .subsys0 = 0xa2,
245 .subsys1 = 0x8b,
246 .vpd4 = 0x00,
247 .vpd4_mask = 0x00,
248 .core_speed = 733*MHz,
249 .mem_size = 128*MB,
250 .boot_flash = 2*MB,
251 .user_flash = 0,
252 },
253 {
254 .model = BOARD_MODEL_PRPMC2800,
255 .variant = 'g',
256 .bridge_type = BRIDGE_TYPE_MV64360,
257 .subsys0 = 0xa2,
258 .subsys1 = 0x8c,
259 .vpd4 = 0x00,
260 .vpd4_mask = 0x00,
261 .core_speed = 1*GHz,
262 .mem_size = 2*GB,
263 .boot_flash = 2*MB,
264 .user_flash = 64*MB,
265 },
266 {
267 .model = BOARD_MODEL_PRPMC2800,
268 .variant = 'h',
269 .bridge_type = BRIDGE_TYPE_MV64360,
270 .subsys0 = 0xa2,
271 .subsys1 = 0x8d,
272 .vpd4 = 0x00,
273 .vpd4_mask = 0x00,
274 .core_speed = 733*MHz,
275 .mem_size = 1*GB,
276 .boot_flash = 2*MB,
277 .user_flash = 64*MB,
278 },
279};
280
281static struct prpmc2800_board_info *prpmc2800_get_board_info(u8 *vpd)
282{
283 struct prpmc2800_board_info *bip;
284 int i;
285
286 for (i=0,bip=prpmc2800_board_info; i<ARRAY_SIZE(prpmc2800_board_info);
287 i++,bip++)
288 if ((vpd[0] == bip->subsys0) && (vpd[1] == bip->subsys1)
289 && ((vpd[4] & bip->vpd4_mask) == bip->vpd4))
290 return bip;
291
292 return NULL;
293}
294
295/* Get VPD from i2c eeprom 2, then match it to a board info entry */
296static struct prpmc2800_board_info *prpmc2800_get_bip(void)
297{
298 struct prpmc2800_board_info *bip;
299 u8 vpd[5];
300 int rc;
301
302 if (mv64x60_i2c_open())
303 fatal("Error: Can't open i2c device\n\r");
304
305 /* Get VPD from i2c eeprom-2 */
306 memset(vpd, 0, sizeof(vpd));
307 rc = mv64x60_i2c_read(EEPROM2_ADDR, vpd, 0x1fde, 2, sizeof(vpd));
308 if (rc < 0)
309 fatal("Error: Couldn't read eeprom2\n\r");
310 mv64x60_i2c_close();
311
312 /* Get board type & related info */
313 bip = prpmc2800_get_board_info(vpd);
314 if (bip == NULL) {
315 printf("Error: Unsupported board or corrupted VPD:\n\r");
316 printf(" 0x%x 0x%x 0x%x 0x%x 0x%x\n\r",
317 vpd[0], vpd[1], vpd[2], vpd[3], vpd[4]);
318 printf("Using device tree defaults...\n\r");
319 }
320
321 return bip;
322}
323
324static void prpmc2800_bridge_setup(u32 mem_size)
325{
326 u32 i, v[12], enables, acc_bits;
327 u32 pci_base_hi, pci_base_lo, size, buf[2];
328 unsigned long cpu_base;
329 int rc;
330 void *devp;
331 u8 *bridge_pbase, is_coherent;
332 struct mv64x60_cpu2pci_win *tbl;
333
334 bridge_pbase = mv64x60_get_bridge_pbase();
335 is_coherent = mv64x60_is_coherent();
336
337 if (is_coherent)
338 acc_bits = MV64x60_PCI_ACC_CNTL_SNOOP_WB
339 | MV64x60_PCI_ACC_CNTL_SWAP_NONE
340 | MV64x60_PCI_ACC_CNTL_MBURST_32_BYTES
341 | MV64x60_PCI_ACC_CNTL_RDSIZE_32_BYTES;
342 else
343 acc_bits = MV64x60_PCI_ACC_CNTL_SNOOP_NONE
344 | MV64x60_PCI_ACC_CNTL_SWAP_NONE
345 | MV64x60_PCI_ACC_CNTL_MBURST_128_BYTES
346 | MV64x60_PCI_ACC_CNTL_RDSIZE_256_BYTES;
347
348 mv64x60_config_ctlr_windows(bridge_base, bridge_pbase, is_coherent);
349 mv64x60_config_pci_windows(bridge_base, bridge_pbase, 0, 0, mem_size,
350 acc_bits);
351
352 /* Get the cpu -> pci i/o & mem mappings from the device tree */
353 devp = finddevice("/mv64x60/pci@80000000");
354 if (devp == NULL)
355 fatal("Error: Missing /mv64x60/pci@80000000"
356 " device tree node\n\r");
357
358 rc = getprop(devp, "ranges", v, sizeof(v));
359 if (rc != sizeof(v))
360 fatal("Error: Can't find /mv64x60/pci@80000000/ranges"
361 " property\n\r");
362
363 /* Get the cpu -> pci i/o & mem mappings from the device tree */
364 devp = finddevice("/mv64x60");
365 if (devp == NULL)
366 fatal("Error: Missing /mv64x60 device tree node\n\r");
367
368 enables = in_le32((u32 *)(bridge_base + MV64x60_CPU_BAR_ENABLE));
369 enables |= 0x0007fe00; /* Disable all cpu->pci windows */
370 out_le32((u32 *)(bridge_base + MV64x60_CPU_BAR_ENABLE), enables);
371
372 for (i=0; i<12; i+=6) {
373 switch (v[i] & 0xff000000) {
374 case 0x01000000: /* PCI I/O Space */
375 tbl = mv64x60_cpu2pci_io;
376 break;
377 case 0x02000000: /* PCI MEM Space */
378 tbl = mv64x60_cpu2pci_mem;
379 break;
380 default:
381 continue;
382 }
383
384 pci_base_hi = v[i+1];
385 pci_base_lo = v[i+2];
386 cpu_base = v[i+3];
387 size = v[i+5];
388
389 buf[0] = cpu_base;
390 buf[1] = size;
391
392 if (!dt_xlate_addr(devp, buf, sizeof(buf), &cpu_base))
393 fatal("Error: Can't translate PCI address 0x%x\n\r",
394 (u32)cpu_base);
395
396 mv64x60_config_cpu2pci_window(bridge_base, 0, pci_base_hi,
397 pci_base_lo, cpu_base, size, tbl);
398 }
399
400 enables &= ~0x00000600; /* Enable cpu->pci0 i/o, cpu->pci0 mem0 */
401 out_le32((u32 *)(bridge_base + MV64x60_CPU_BAR_ENABLE), enables);
402}
403
404static void prpmc2800_fixups(void)
405{
406 u32 v[2], l, mem_size;
407 int rc;
408 void *devp;
409 char model[BOARD_MODEL_MAX];
410 struct prpmc2800_board_info *bip;
411
412 bip = prpmc2800_get_bip(); /* Get board info based on VPD */
413
414 mem_size = (bip) ? bip->mem_size : mv64x60_get_mem_size(bridge_base);
415 prpmc2800_bridge_setup(mem_size); /* Do necessary bridge setup */
416
417 /* If the VPD doesn't match what we know about, just use the
418 * defaults already in the device tree.
419 */
420 if (!bip)
421 return;
422
423 /* Know the board type so override device tree defaults */
424 /* Set /model appropriately */
425 devp = finddevice("/");
426 if (devp == NULL)
427 fatal("Error: Missing '/' device tree node\n\r");
428 memset(model, 0, BOARD_MODEL_MAX);
429 strncpy(model, BOARD_MODEL, BOARD_MODEL_MAX - 2);
430 l = strlen(model);
431 if (bip->model == BOARD_MODEL_PRPMC280)
432 l--;
433 model[l++] = bip->variant;
434 model[l++] = '\0';
435 setprop(devp, "model", model, l);
436
437 /* Set /cpus/PowerPC,7447/clock-frequency */
438 devp = finddevice("/cpus/PowerPC,7447");
439 if (devp == NULL)
440 fatal("Error: Missing proper /cpus device tree node\n\r");
441 v[0] = bip->core_speed;
442 setprop(devp, "clock-frequency", &v[0], sizeof(v[0]));
443
444 /* Set /memory/reg size */
445 devp = finddevice("/memory");
446 if (devp == NULL)
447 fatal("Error: Missing /memory device tree node\n\r");
448 v[0] = 0;
449 v[1] = bip->mem_size;
450 setprop(devp, "reg", v, sizeof(v));
451
452 /* Update /mv64x60/model, if this is a mv64362 */
453 if (bip->bridge_type == BRIDGE_TYPE_MV64362) {
454 devp = finddevice("/mv64x60");
455 if (devp == NULL)
456 fatal("Error: Missing /mv64x60 device tree node\n\r");
457 setprop(devp, "model", "mv64362", strlen("mv64362") + 1);
458 }
459
460 /* Set User FLASH size */
461 devp = finddevice("/mv64x60/flash@a0000000");
462 if (devp == NULL)
463 fatal("Error: Missing User FLASH device tree node\n\r");
464 rc = getprop(devp, "reg", v, sizeof(v));
465 if (rc != sizeof(v))
466 fatal("Error: Can't find User FLASH reg property\n\r");
467 v[1] = bip->user_flash;
468 setprop(devp, "reg", v, sizeof(v));
469}
470
471#define MV64x60_MPP_CNTL_0 0xf000
472#define MV64x60_MPP_CNTL_2 0xf008
473#define MV64x60_GPP_IO_CNTL 0xf100
474#define MV64x60_GPP_LEVEL_CNTL 0xf110
475#define MV64x60_GPP_VALUE_SET 0xf118
476
477static void prpmc2800_reset(void)
478{
479 u32 temp;
480
481 udelay(5000000);
482
483 if (bridge_base != 0) {
484 temp = in_le32((u32 *)(bridge_base + MV64x60_MPP_CNTL_0));
485 temp &= 0xFFFF0FFF;
486 out_le32((u32 *)(bridge_base + MV64x60_MPP_CNTL_0), temp);
487
488 temp = in_le32((u32 *)(bridge_base + MV64x60_GPP_LEVEL_CNTL));
489 temp |= 0x00000004;
490 out_le32((u32 *)(bridge_base + MV64x60_GPP_LEVEL_CNTL), temp);
491
492 temp = in_le32((u32 *)(bridge_base + MV64x60_GPP_IO_CNTL));
493 temp |= 0x00000004;
494 out_le32((u32 *)(bridge_base + MV64x60_GPP_IO_CNTL), temp);
495
496 temp = in_le32((u32 *)(bridge_base + MV64x60_MPP_CNTL_2));
497 temp &= 0xFFFF0FFF;
498 out_le32((u32 *)(bridge_base + MV64x60_MPP_CNTL_2), temp);
499
500 temp = in_le32((u32 *)(bridge_base + MV64x60_GPP_LEVEL_CNTL));
501 temp |= 0x00080000;
502 out_le32((u32 *)(bridge_base + MV64x60_GPP_LEVEL_CNTL), temp);
503
504 temp = in_le32((u32 *)(bridge_base + MV64x60_GPP_IO_CNTL));
505 temp |= 0x00080000;
506 out_le32((u32 *)(bridge_base + MV64x60_GPP_IO_CNTL), temp);
507
508 out_le32((u32 *)(bridge_base + MV64x60_GPP_VALUE_SET),
509 0x00080004);
510 }
511
512 for (;;);
513}
514
515#define HEAP_SIZE (16*MB)
516static struct gunzip_state gzstate;
517
518void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
519 unsigned long r6, unsigned long r7)
520{
521 struct elf_info ei;
522 char *heap_start, *dtb;
523 int dt_size = _dtb_end - _dtb_start;
524 void *vmlinuz_addr = _vmlinux_start;
525 unsigned long vmlinuz_size = _vmlinux_end - _vmlinux_start;
526 char elfheader[256];
527
528 if (dt_size <= 0) /* No fdt */
529 exit();
530
531 /*
532 * Start heap after end of the kernel (after decompressed to
533 * address 0) or the end of the zImage, whichever is higher.
534 * That's so things allocated by simple_alloc won't overwrite
535 * any part of the zImage and the kernel won't overwrite the dtb
536 * when decompressed & relocated.
537 */
538 gunzip_start(&gzstate, vmlinuz_addr, vmlinuz_size);
539 gunzip_exactly(&gzstate, elfheader, sizeof(elfheader));
540
541 if (!parse_elf32(elfheader, &ei))
542 exit();
543
544 heap_start = (char *)(ei.memsize + ei.elfoffset); /* end of kernel*/
545 heap_start = max(heap_start, (char *)_end); /* end of zImage */
546
547 if ((unsigned)simple_alloc_init(heap_start, HEAP_SIZE, 2*KB, 16)
548 > (128*MB))
549 exit();
550
551 /* Relocate dtb to safe area past end of zImage & kernel */
552 dtb = malloc(dt_size);
553 if (!dtb)
554 exit();
555 memmove(dtb, _dtb_start, dt_size);
556 if (ft_init(dtb, dt_size, 16))
557 exit();
558
559 bridge_base = mv64x60_get_bridge_base();
560
561 platform_ops.fixups = prpmc2800_fixups;
562 platform_ops.exit = prpmc2800_reset;
563
564 if (serial_console_init() < 0)
565 exit();
566}
567
568/* _zimage_start called very early--need to turn off external interrupts */
569asm (" .globl _zimage_start\n\
570 _zimage_start:\n\
571 mfmsr 10\n\
572 rlwinm 10,10,0,~(1<<15) /* Clear MSR_EE */\n\
573 sync\n\
574 mtmsr 10\n\
575 isync\n\
576 b _zimage_start_lib\n\
577");