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 30*02d748a9SAlbert Herranz #define MEM2_TOP (0x10000000 + 64*1024*1024) 31*02d748a9SAlbert Herranz #define FIRMWARE_DEFAULT_SIZE (12*1024*1024) 32*02d748a9SAlbert Herranz 33*02d748a9SAlbert Herranz 34*02d748a9SAlbert Herranz struct mipc_infohdr { 35*02d748a9SAlbert Herranz char magic[3]; 36*02d748a9SAlbert Herranz u8 version; 37*02d748a9SAlbert Herranz u32 mem2_boundary; 38*02d748a9SAlbert Herranz u32 ipc_in; 39*02d748a9SAlbert Herranz size_t ipc_in_size; 40*02d748a9SAlbert Herranz u32 ipc_out; 41*02d748a9SAlbert Herranz size_t ipc_out_size; 42*02d748a9SAlbert Herranz }; 43*02d748a9SAlbert Herranz 44*02d748a9SAlbert Herranz static int mipc_check_address(u32 pa) 45*02d748a9SAlbert Herranz { 46*02d748a9SAlbert Herranz /* only MEM2 addresses */ 47*02d748a9SAlbert Herranz if (pa < 0x10000000 || pa > 0x14000000) 48*02d748a9SAlbert Herranz return -EINVAL; 49*02d748a9SAlbert Herranz return 0; 50*02d748a9SAlbert Herranz } 51*02d748a9SAlbert Herranz 52*02d748a9SAlbert Herranz static struct mipc_infohdr *mipc_get_infohdr(void) 53*02d748a9SAlbert Herranz { 54*02d748a9SAlbert Herranz struct mipc_infohdr **hdrp, *hdr; 55*02d748a9SAlbert Herranz 56*02d748a9SAlbert Herranz /* 'mini' header pointer is the last word of MEM2 memory */ 57*02d748a9SAlbert Herranz hdrp = (struct mipc_infohdr **)0x13fffffc; 58*02d748a9SAlbert Herranz if (mipc_check_address((u32)hdrp)) { 59*02d748a9SAlbert Herranz printf("mini: invalid hdrp %08X\n", (u32)hdrp); 60*02d748a9SAlbert Herranz hdr = NULL; 61*02d748a9SAlbert Herranz goto out; 62*02d748a9SAlbert Herranz } 63*02d748a9SAlbert Herranz 64*02d748a9SAlbert Herranz hdr = *hdrp; 65*02d748a9SAlbert Herranz if (mipc_check_address((u32)hdr)) { 66*02d748a9SAlbert Herranz printf("mini: invalid hdr %08X\n", (u32)hdr); 67*02d748a9SAlbert Herranz hdr = NULL; 68*02d748a9SAlbert Herranz goto out; 69*02d748a9SAlbert Herranz } 70*02d748a9SAlbert Herranz if (memcmp(hdr->magic, "IPC", 3)) { 71*02d748a9SAlbert Herranz printf("mini: invalid magic\n"); 72*02d748a9SAlbert Herranz hdr = NULL; 73*02d748a9SAlbert Herranz goto out; 74*02d748a9SAlbert Herranz } 75*02d748a9SAlbert Herranz 76*02d748a9SAlbert Herranz out: 77*02d748a9SAlbert Herranz return hdr; 78*02d748a9SAlbert Herranz } 79*02d748a9SAlbert Herranz 80*02d748a9SAlbert Herranz static int mipc_get_mem2_boundary(u32 *mem2_boundary) 81*02d748a9SAlbert Herranz { 82*02d748a9SAlbert Herranz struct mipc_infohdr *hdr; 83*02d748a9SAlbert Herranz int error; 84*02d748a9SAlbert Herranz 85*02d748a9SAlbert Herranz hdr = mipc_get_infohdr(); 86*02d748a9SAlbert Herranz if (!hdr) { 87*02d748a9SAlbert Herranz error = -1; 88*02d748a9SAlbert Herranz goto out; 89*02d748a9SAlbert Herranz } 90*02d748a9SAlbert Herranz 91*02d748a9SAlbert Herranz if (mipc_check_address(hdr->mem2_boundary)) { 92*02d748a9SAlbert Herranz printf("mini: invalid mem2_boundary %08X\n", 93*02d748a9SAlbert Herranz hdr->mem2_boundary); 94*02d748a9SAlbert Herranz error = -EINVAL; 95*02d748a9SAlbert Herranz goto out; 96*02d748a9SAlbert Herranz } 97*02d748a9SAlbert Herranz *mem2_boundary = hdr->mem2_boundary; 98*02d748a9SAlbert Herranz error = 0; 99*02d748a9SAlbert Herranz out: 100*02d748a9SAlbert Herranz return error; 101*02d748a9SAlbert Herranz 102*02d748a9SAlbert Herranz } 103*02d748a9SAlbert Herranz 104*02d748a9SAlbert Herranz static void platform_fixups(void) 105*02d748a9SAlbert Herranz { 106*02d748a9SAlbert Herranz void *mem; 107*02d748a9SAlbert Herranz u32 reg[4]; 108*02d748a9SAlbert Herranz u32 mem2_boundary; 109*02d748a9SAlbert Herranz int len; 110*02d748a9SAlbert Herranz int error; 111*02d748a9SAlbert Herranz 112*02d748a9SAlbert Herranz mem = finddevice("/memory"); 113*02d748a9SAlbert Herranz if (!mem) 114*02d748a9SAlbert Herranz fatal("Can't find memory node\n"); 115*02d748a9SAlbert Herranz 116*02d748a9SAlbert Herranz /* two ranges of (address, size) words */ 117*02d748a9SAlbert Herranz len = getprop(mem, "reg", reg, sizeof(reg)); 118*02d748a9SAlbert Herranz if (len != sizeof(reg)) { 119*02d748a9SAlbert Herranz /* nothing to do */ 120*02d748a9SAlbert Herranz goto out; 121*02d748a9SAlbert Herranz } 122*02d748a9SAlbert Herranz 123*02d748a9SAlbert Herranz /* retrieve MEM2 boundary from 'mini' */ 124*02d748a9SAlbert Herranz error = mipc_get_mem2_boundary(&mem2_boundary); 125*02d748a9SAlbert Herranz if (error) { 126*02d748a9SAlbert Herranz /* if that fails use a sane value */ 127*02d748a9SAlbert Herranz mem2_boundary = MEM2_TOP - FIRMWARE_DEFAULT_SIZE; 128*02d748a9SAlbert Herranz } 129*02d748a9SAlbert Herranz 130*02d748a9SAlbert Herranz if (mem2_boundary > reg[2] && mem2_boundary < reg[2] + reg[3]) { 131*02d748a9SAlbert Herranz reg[3] = mem2_boundary - reg[2]; 132*02d748a9SAlbert Herranz printf("top of MEM2 @ %08X\n", reg[2] + reg[3]); 133*02d748a9SAlbert Herranz setprop(mem, "reg", reg, sizeof(reg)); 134*02d748a9SAlbert Herranz } 135*02d748a9SAlbert Herranz 136*02d748a9SAlbert Herranz out: 137*02d748a9SAlbert Herranz return; 138*02d748a9SAlbert Herranz } 139*02d748a9SAlbert 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; 155*02d748a9SAlbert Herranz 156*02d748a9SAlbert Herranz platform_ops.fixups = platform_fixups; 1576cdd2417SAlbert Herranz } 1586cdd2417SAlbert Herranz 159