16cdd2417SAlbert Herranz /* 26cdd2417SAlbert Herranz * arch/powerpc/boot/wii.c 36cdd2417SAlbert Herranz * 46cdd2417SAlbert Herranz * Nintendo Wii bootwrapper support 56cdd2417SAlbert Herranz * Copyright (C) 2008-2009 The GameCube Linux Team 66cdd2417SAlbert Herranz * Copyright (C) 2008,2009 Albert Herranz 76cdd2417SAlbert Herranz * 86cdd2417SAlbert Herranz * This program is free software; you can redistribute it and/or 96cdd2417SAlbert Herranz * modify it under the terms of the GNU General Public License 106cdd2417SAlbert Herranz * as published by the Free Software Foundation; either version 2 116cdd2417SAlbert Herranz * of the License, or (at your option) any later version. 126cdd2417SAlbert Herranz * 136cdd2417SAlbert Herranz */ 146cdd2417SAlbert Herranz 156cdd2417SAlbert Herranz #include <stddef.h> 166cdd2417SAlbert Herranz #include "stdio.h" 176cdd2417SAlbert Herranz #include "types.h" 186cdd2417SAlbert Herranz #include "io.h" 196cdd2417SAlbert Herranz #include "ops.h" 206cdd2417SAlbert Herranz 216cdd2417SAlbert Herranz #include "ugecon.h" 226cdd2417SAlbert Herranz 236cdd2417SAlbert Herranz BSS_STACK(8192); 246cdd2417SAlbert Herranz 256cdd2417SAlbert Herranz #define HW_REG(x) ((void *)(x)) 266cdd2417SAlbert Herranz 276cdd2417SAlbert Herranz #define EXI_CTRL HW_REG(0x0d800070) 286cdd2417SAlbert Herranz #define EXI_CTRL_ENABLE (1<<0) 296cdd2417SAlbert Herranz 3002d748a9SAlbert Herranz #define MEM2_TOP (0x10000000 + 64*1024*1024) 3102d748a9SAlbert Herranz #define FIRMWARE_DEFAULT_SIZE (12*1024*1024) 3202d748a9SAlbert Herranz 3302d748a9SAlbert Herranz 3402d748a9SAlbert Herranz struct mipc_infohdr { 3502d748a9SAlbert Herranz char magic[3]; 3602d748a9SAlbert Herranz u8 version; 3702d748a9SAlbert Herranz u32 mem2_boundary; 3802d748a9SAlbert Herranz u32 ipc_in; 3902d748a9SAlbert Herranz size_t ipc_in_size; 4002d748a9SAlbert Herranz u32 ipc_out; 4102d748a9SAlbert Herranz size_t ipc_out_size; 4202d748a9SAlbert Herranz }; 4302d748a9SAlbert Herranz 4402d748a9SAlbert Herranz static int mipc_check_address(u32 pa) 4502d748a9SAlbert Herranz { 4602d748a9SAlbert Herranz /* only MEM2 addresses */ 4702d748a9SAlbert Herranz if (pa < 0x10000000 || pa > 0x14000000) 4802d748a9SAlbert Herranz return -EINVAL; 4902d748a9SAlbert Herranz return 0; 5002d748a9SAlbert Herranz } 5102d748a9SAlbert Herranz 5202d748a9SAlbert Herranz static struct mipc_infohdr *mipc_get_infohdr(void) 5302d748a9SAlbert Herranz { 5402d748a9SAlbert Herranz struct mipc_infohdr **hdrp, *hdr; 5502d748a9SAlbert Herranz 5602d748a9SAlbert Herranz /* 'mini' header pointer is the last word of MEM2 memory */ 5702d748a9SAlbert Herranz hdrp = (struct mipc_infohdr **)0x13fffffc; 5802d748a9SAlbert Herranz if (mipc_check_address((u32)hdrp)) { 5902d748a9SAlbert Herranz printf("mini: invalid hdrp %08X\n", (u32)hdrp); 6002d748a9SAlbert Herranz hdr = NULL; 6102d748a9SAlbert Herranz goto out; 6202d748a9SAlbert Herranz } 6302d748a9SAlbert Herranz 6402d748a9SAlbert Herranz hdr = *hdrp; 6502d748a9SAlbert Herranz if (mipc_check_address((u32)hdr)) { 6602d748a9SAlbert Herranz printf("mini: invalid hdr %08X\n", (u32)hdr); 6702d748a9SAlbert Herranz hdr = NULL; 6802d748a9SAlbert Herranz goto out; 6902d748a9SAlbert Herranz } 7002d748a9SAlbert Herranz if (memcmp(hdr->magic, "IPC", 3)) { 7102d748a9SAlbert Herranz printf("mini: invalid magic\n"); 7202d748a9SAlbert Herranz hdr = NULL; 7302d748a9SAlbert Herranz goto out; 7402d748a9SAlbert Herranz } 7502d748a9SAlbert Herranz 7602d748a9SAlbert Herranz out: 7702d748a9SAlbert Herranz return hdr; 7802d748a9SAlbert Herranz } 7902d748a9SAlbert Herranz 8002d748a9SAlbert Herranz static int mipc_get_mem2_boundary(u32 *mem2_boundary) 8102d748a9SAlbert Herranz { 8202d748a9SAlbert Herranz struct mipc_infohdr *hdr; 8302d748a9SAlbert Herranz int error; 8402d748a9SAlbert Herranz 8502d748a9SAlbert Herranz hdr = mipc_get_infohdr(); 8602d748a9SAlbert Herranz if (!hdr) { 8702d748a9SAlbert Herranz error = -1; 8802d748a9SAlbert Herranz goto out; 8902d748a9SAlbert Herranz } 9002d748a9SAlbert Herranz 9102d748a9SAlbert Herranz if (mipc_check_address(hdr->mem2_boundary)) { 9202d748a9SAlbert Herranz printf("mini: invalid mem2_boundary %08X\n", 9302d748a9SAlbert Herranz hdr->mem2_boundary); 9402d748a9SAlbert Herranz error = -EINVAL; 9502d748a9SAlbert Herranz goto out; 9602d748a9SAlbert Herranz } 9702d748a9SAlbert Herranz *mem2_boundary = hdr->mem2_boundary; 9802d748a9SAlbert Herranz error = 0; 9902d748a9SAlbert Herranz out: 10002d748a9SAlbert Herranz return error; 10102d748a9SAlbert Herranz 10202d748a9SAlbert Herranz } 10302d748a9SAlbert Herranz 10402d748a9SAlbert Herranz static void platform_fixups(void) 10502d748a9SAlbert Herranz { 10602d748a9SAlbert Herranz void *mem; 10702d748a9SAlbert Herranz u32 reg[4]; 10802d748a9SAlbert Herranz u32 mem2_boundary; 10902d748a9SAlbert Herranz int len; 11002d748a9SAlbert Herranz int error; 11102d748a9SAlbert Herranz 11202d748a9SAlbert Herranz mem = finddevice("/memory"); 11302d748a9SAlbert Herranz if (!mem) 11402d748a9SAlbert Herranz fatal("Can't find memory node\n"); 11502d748a9SAlbert Herranz 11602d748a9SAlbert Herranz /* two ranges of (address, size) words */ 11702d748a9SAlbert Herranz len = getprop(mem, "reg", reg, sizeof(reg)); 11802d748a9SAlbert Herranz if (len != sizeof(reg)) { 11902d748a9SAlbert Herranz /* nothing to do */ 12002d748a9SAlbert Herranz goto out; 12102d748a9SAlbert Herranz } 12202d748a9SAlbert Herranz 12302d748a9SAlbert Herranz /* retrieve MEM2 boundary from 'mini' */ 12402d748a9SAlbert Herranz error = mipc_get_mem2_boundary(&mem2_boundary); 12502d748a9SAlbert Herranz if (error) { 12602d748a9SAlbert Herranz /* if that fails use a sane value */ 12702d748a9SAlbert Herranz mem2_boundary = MEM2_TOP - FIRMWARE_DEFAULT_SIZE; 12802d748a9SAlbert Herranz } 12902d748a9SAlbert Herranz 13002d748a9SAlbert Herranz if (mem2_boundary > reg[2] && mem2_boundary < reg[2] + reg[3]) { 13102d748a9SAlbert Herranz reg[3] = mem2_boundary - reg[2]; 13202d748a9SAlbert Herranz printf("top of MEM2 @ %08X\n", reg[2] + reg[3]); 13302d748a9SAlbert Herranz setprop(mem, "reg", reg, sizeof(reg)); 13402d748a9SAlbert Herranz } 13502d748a9SAlbert Herranz 13602d748a9SAlbert Herranz out: 13702d748a9SAlbert Herranz return; 13802d748a9SAlbert Herranz } 13902d748a9SAlbert Herranz 1406cdd2417SAlbert Herranz void platform_init(unsigned long r3, unsigned long r4, unsigned long r5) 1416cdd2417SAlbert Herranz { 1426cdd2417SAlbert Herranz u32 heapsize = 24*1024*1024 - (u32)_end; 1436cdd2417SAlbert Herranz 1446cdd2417SAlbert Herranz simple_alloc_init(_end, heapsize, 32, 64); 1456cdd2417SAlbert Herranz fdt_init(_dtb_start); 1466cdd2417SAlbert Herranz 1476cdd2417SAlbert Herranz /* 1486cdd2417SAlbert Herranz * 'mini' boots the Broadway processor with EXI disabled. 1496cdd2417SAlbert Herranz * We need it enabled before probing for the USB Gecko. 1506cdd2417SAlbert Herranz */ 1516cdd2417SAlbert Herranz out_be32(EXI_CTRL, in_be32(EXI_CTRL) | EXI_CTRL_ENABLE); 1526cdd2417SAlbert Herranz 1536cdd2417SAlbert Herranz if (ug_probe()) 1546cdd2417SAlbert Herranz console_ops.write = ug_console_write; 15502d748a9SAlbert Herranz 15602d748a9SAlbert Herranz platform_ops.fixups = platform_fixups; 1576cdd2417SAlbert Herranz } 1586cdd2417SAlbert Herranz 159