Merge master.kernel.org:/pub/scm/linux/kernel/git/lethal/sh64-2.6
[linux-2.6] / arch / powerpc / boot / prpmc2800.c
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
24 extern char _end[];
25 extern char _vmlinux_start[], _vmlinux_end[];
26 extern char _dtb_start[], _dtb_end[];
27
28 extern 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
42 BSS_STACK(16*KB);
43
44 static u8 *bridge_base;
45
46 typedef enum {
47         BOARD_MODEL_PRPMC280,
48         BOARD_MODEL_PRPMC2800,
49 } prpmc2800_board_model;
50
51 typedef enum {
52         BRIDGE_TYPE_MV64360,
53         BRIDGE_TYPE_MV64362,
54 } prpmc2800_bridge_type;
55
56 struct 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
70 static 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
281 static 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 */
296 static 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
324 static 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
404 static 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
477 static 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)
516 static struct gunzip_state gzstate;
517
518 void 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 */
569 asm ("  .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 ");