162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * arch/powerpc/boot/wii.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Nintendo Wii bootwrapper support 662306a36Sopenharmony_ci * Copyright (C) 2008-2009 The GameCube Linux Team 762306a36Sopenharmony_ci * Copyright (C) 2008,2009 Albert Herranz 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <stddef.h> 1162306a36Sopenharmony_ci#include "stdio.h" 1262306a36Sopenharmony_ci#include "types.h" 1362306a36Sopenharmony_ci#include "io.h" 1462306a36Sopenharmony_ci#include "ops.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "ugecon.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ciBSS_STACK(8192); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define HW_REG(x) ((void *)(x)) 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define EXI_CTRL HW_REG(0x0d800070) 2362306a36Sopenharmony_ci#define EXI_CTRL_ENABLE (1<<0) 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define MEM2_TOP (0x10000000 + 64*1024*1024) 2662306a36Sopenharmony_ci#define FIRMWARE_DEFAULT_SIZE (12*1024*1024) 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistruct mipc_infohdr { 3062306a36Sopenharmony_ci char magic[3]; 3162306a36Sopenharmony_ci u8 version; 3262306a36Sopenharmony_ci u32 mem2_boundary; 3362306a36Sopenharmony_ci u32 ipc_in; 3462306a36Sopenharmony_ci size_t ipc_in_size; 3562306a36Sopenharmony_ci u32 ipc_out; 3662306a36Sopenharmony_ci size_t ipc_out_size; 3762306a36Sopenharmony_ci}; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic int mipc_check_address(u32 pa) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci /* only MEM2 addresses */ 4262306a36Sopenharmony_ci if (pa < 0x10000000 || pa > 0x14000000) 4362306a36Sopenharmony_ci return -EINVAL; 4462306a36Sopenharmony_ci return 0; 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic struct mipc_infohdr *mipc_get_infohdr(void) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci struct mipc_infohdr **hdrp, *hdr; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci /* 'mini' header pointer is the last word of MEM2 memory */ 5262306a36Sopenharmony_ci hdrp = (struct mipc_infohdr **)0x13fffffc; 5362306a36Sopenharmony_ci if (mipc_check_address((u32)hdrp)) { 5462306a36Sopenharmony_ci printf("mini: invalid hdrp %08X\n", (u32)hdrp); 5562306a36Sopenharmony_ci hdr = NULL; 5662306a36Sopenharmony_ci goto out; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci hdr = *hdrp; 6062306a36Sopenharmony_ci if (mipc_check_address((u32)hdr)) { 6162306a36Sopenharmony_ci printf("mini: invalid hdr %08X\n", (u32)hdr); 6262306a36Sopenharmony_ci hdr = NULL; 6362306a36Sopenharmony_ci goto out; 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci if (memcmp(hdr->magic, "IPC", 3)) { 6662306a36Sopenharmony_ci printf("mini: invalid magic\n"); 6762306a36Sopenharmony_ci hdr = NULL; 6862306a36Sopenharmony_ci goto out; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ciout: 7262306a36Sopenharmony_ci return hdr; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic int mipc_get_mem2_boundary(u32 *mem2_boundary) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci struct mipc_infohdr *hdr; 7862306a36Sopenharmony_ci int error; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci hdr = mipc_get_infohdr(); 8162306a36Sopenharmony_ci if (!hdr) { 8262306a36Sopenharmony_ci error = -1; 8362306a36Sopenharmony_ci goto out; 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (mipc_check_address(hdr->mem2_boundary)) { 8762306a36Sopenharmony_ci printf("mini: invalid mem2_boundary %08X\n", 8862306a36Sopenharmony_ci hdr->mem2_boundary); 8962306a36Sopenharmony_ci error = -EINVAL; 9062306a36Sopenharmony_ci goto out; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci *mem2_boundary = hdr->mem2_boundary; 9362306a36Sopenharmony_ci error = 0; 9462306a36Sopenharmony_ciout: 9562306a36Sopenharmony_ci return error; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic void platform_fixups(void) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci void *mem; 10262306a36Sopenharmony_ci u32 reg[4]; 10362306a36Sopenharmony_ci u32 mem2_boundary; 10462306a36Sopenharmony_ci int len; 10562306a36Sopenharmony_ci int error; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci mem = finddevice("/memory"); 10862306a36Sopenharmony_ci if (!mem) 10962306a36Sopenharmony_ci fatal("Can't find memory node\n"); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci /* two ranges of (address, size) words */ 11262306a36Sopenharmony_ci len = getprop(mem, "reg", reg, sizeof(reg)); 11362306a36Sopenharmony_ci if (len != sizeof(reg)) { 11462306a36Sopenharmony_ci /* nothing to do */ 11562306a36Sopenharmony_ci goto out; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci /* retrieve MEM2 boundary from 'mini' */ 11962306a36Sopenharmony_ci error = mipc_get_mem2_boundary(&mem2_boundary); 12062306a36Sopenharmony_ci if (error) { 12162306a36Sopenharmony_ci /* if that fails use a sane value */ 12262306a36Sopenharmony_ci mem2_boundary = MEM2_TOP - FIRMWARE_DEFAULT_SIZE; 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (mem2_boundary > reg[2] && mem2_boundary < reg[2] + reg[3]) { 12662306a36Sopenharmony_ci reg[3] = mem2_boundary - reg[2]; 12762306a36Sopenharmony_ci printf("top of MEM2 @ %08X\n", reg[2] + reg[3]); 12862306a36Sopenharmony_ci setprop(mem, "reg", reg, sizeof(reg)); 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ciout: 13262306a36Sopenharmony_ci return; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_civoid platform_init(unsigned long r3, unsigned long r4, unsigned long r5) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci u32 heapsize = 24*1024*1024 - (u32)_end; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci simple_alloc_init(_end, heapsize, 32, 64); 14062306a36Sopenharmony_ci fdt_init(_dtb_start); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* 14362306a36Sopenharmony_ci * 'mini' boots the Broadway processor with EXI disabled. 14462306a36Sopenharmony_ci * We need it enabled before probing for the USB Gecko. 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_ci out_be32(EXI_CTRL, in_be32(EXI_CTRL) | EXI_CTRL_ENABLE); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (ug_probe()) 14962306a36Sopenharmony_ci console_ops.write = ug_console_write; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci platform_ops.fixups = platform_fixups; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 154