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