18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * arch/powerpc/boot/wii.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Nintendo Wii bootwrapper support 68c2ecf20Sopenharmony_ci * Copyright (C) 2008-2009 The GameCube Linux Team 78c2ecf20Sopenharmony_ci * Copyright (C) 2008,2009 Albert Herranz 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <stddef.h> 118c2ecf20Sopenharmony_ci#include "stdio.h" 128c2ecf20Sopenharmony_ci#include "types.h" 138c2ecf20Sopenharmony_ci#include "io.h" 148c2ecf20Sopenharmony_ci#include "ops.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "ugecon.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ciBSS_STACK(8192); 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define HW_REG(x) ((void *)(x)) 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define EXI_CTRL HW_REG(0x0d800070) 238c2ecf20Sopenharmony_ci#define EXI_CTRL_ENABLE (1<<0) 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define MEM2_TOP (0x10000000 + 64*1024*1024) 268c2ecf20Sopenharmony_ci#define FIRMWARE_DEFAULT_SIZE (12*1024*1024) 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistruct mipc_infohdr { 308c2ecf20Sopenharmony_ci char magic[3]; 318c2ecf20Sopenharmony_ci u8 version; 328c2ecf20Sopenharmony_ci u32 mem2_boundary; 338c2ecf20Sopenharmony_ci u32 ipc_in; 348c2ecf20Sopenharmony_ci size_t ipc_in_size; 358c2ecf20Sopenharmony_ci u32 ipc_out; 368c2ecf20Sopenharmony_ci size_t ipc_out_size; 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic int mipc_check_address(u32 pa) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci /* only MEM2 addresses */ 428c2ecf20Sopenharmony_ci if (pa < 0x10000000 || pa > 0x14000000) 438c2ecf20Sopenharmony_ci return -EINVAL; 448c2ecf20Sopenharmony_ci return 0; 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic struct mipc_infohdr *mipc_get_infohdr(void) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci struct mipc_infohdr **hdrp, *hdr; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci /* 'mini' header pointer is the last word of MEM2 memory */ 528c2ecf20Sopenharmony_ci hdrp = (struct mipc_infohdr **)0x13fffffc; 538c2ecf20Sopenharmony_ci if (mipc_check_address((u32)hdrp)) { 548c2ecf20Sopenharmony_ci printf("mini: invalid hdrp %08X\n", (u32)hdrp); 558c2ecf20Sopenharmony_ci hdr = NULL; 568c2ecf20Sopenharmony_ci goto out; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci hdr = *hdrp; 608c2ecf20Sopenharmony_ci if (mipc_check_address((u32)hdr)) { 618c2ecf20Sopenharmony_ci printf("mini: invalid hdr %08X\n", (u32)hdr); 628c2ecf20Sopenharmony_ci hdr = NULL; 638c2ecf20Sopenharmony_ci goto out; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci if (memcmp(hdr->magic, "IPC", 3)) { 668c2ecf20Sopenharmony_ci printf("mini: invalid magic\n"); 678c2ecf20Sopenharmony_ci hdr = NULL; 688c2ecf20Sopenharmony_ci goto out; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ciout: 728c2ecf20Sopenharmony_ci return hdr; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic int mipc_get_mem2_boundary(u32 *mem2_boundary) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci struct mipc_infohdr *hdr; 788c2ecf20Sopenharmony_ci int error; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci hdr = mipc_get_infohdr(); 818c2ecf20Sopenharmony_ci if (!hdr) { 828c2ecf20Sopenharmony_ci error = -1; 838c2ecf20Sopenharmony_ci goto out; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (mipc_check_address(hdr->mem2_boundary)) { 878c2ecf20Sopenharmony_ci printf("mini: invalid mem2_boundary %08X\n", 888c2ecf20Sopenharmony_ci hdr->mem2_boundary); 898c2ecf20Sopenharmony_ci error = -EINVAL; 908c2ecf20Sopenharmony_ci goto out; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci *mem2_boundary = hdr->mem2_boundary; 938c2ecf20Sopenharmony_ci error = 0; 948c2ecf20Sopenharmony_ciout: 958c2ecf20Sopenharmony_ci return error; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic void platform_fixups(void) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci void *mem; 1028c2ecf20Sopenharmony_ci u32 reg[4]; 1038c2ecf20Sopenharmony_ci u32 mem2_boundary; 1048c2ecf20Sopenharmony_ci int len; 1058c2ecf20Sopenharmony_ci int error; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci mem = finddevice("/memory"); 1088c2ecf20Sopenharmony_ci if (!mem) 1098c2ecf20Sopenharmony_ci fatal("Can't find memory node\n"); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci /* two ranges of (address, size) words */ 1128c2ecf20Sopenharmony_ci len = getprop(mem, "reg", reg, sizeof(reg)); 1138c2ecf20Sopenharmony_ci if (len != sizeof(reg)) { 1148c2ecf20Sopenharmony_ci /* nothing to do */ 1158c2ecf20Sopenharmony_ci goto out; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* retrieve MEM2 boundary from 'mini' */ 1198c2ecf20Sopenharmony_ci error = mipc_get_mem2_boundary(&mem2_boundary); 1208c2ecf20Sopenharmony_ci if (error) { 1218c2ecf20Sopenharmony_ci /* if that fails use a sane value */ 1228c2ecf20Sopenharmony_ci mem2_boundary = MEM2_TOP - FIRMWARE_DEFAULT_SIZE; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if (mem2_boundary > reg[2] && mem2_boundary < reg[2] + reg[3]) { 1268c2ecf20Sopenharmony_ci reg[3] = mem2_boundary - reg[2]; 1278c2ecf20Sopenharmony_ci printf("top of MEM2 @ %08X\n", reg[2] + reg[3]); 1288c2ecf20Sopenharmony_ci setprop(mem, "reg", reg, sizeof(reg)); 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ciout: 1328c2ecf20Sopenharmony_ci return; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_civoid platform_init(unsigned long r3, unsigned long r4, unsigned long r5) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci u32 heapsize = 24*1024*1024 - (u32)_end; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci simple_alloc_init(_end, heapsize, 32, 64); 1408c2ecf20Sopenharmony_ci fdt_init(_dtb_start); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci /* 1438c2ecf20Sopenharmony_ci * 'mini' boots the Broadway processor with EXI disabled. 1448c2ecf20Sopenharmony_ci * We need it enabled before probing for the USB Gecko. 1458c2ecf20Sopenharmony_ci */ 1468c2ecf20Sopenharmony_ci out_be32(EXI_CTRL, in_be32(EXI_CTRL) | EXI_CTRL_ENABLE); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (ug_probe()) 1498c2ecf20Sopenharmony_ci console_ops.write = ug_console_write; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci platform_ops.fixups = platform_fixups; 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 154