^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * arch/powerpc/boot/wii.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Nintendo Wii bootwrapper support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2008-2009 The GameCube Linux Team
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (C) 2008,2009 Albert Herranz
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <stddef.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include "stdio.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include "types.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include "io.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "ops.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "ugecon.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) BSS_STACK(8192);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define HW_REG(x) ((void *)(x))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define EXI_CTRL HW_REG(0x0d800070)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define EXI_CTRL_ENABLE (1<<0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define MEM2_TOP (0x10000000 + 64*1024*1024)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define FIRMWARE_DEFAULT_SIZE (12*1024*1024)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct mipc_infohdr {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) char magic[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) u8 version;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) u32 mem2_boundary;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) u32 ipc_in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) size_t ipc_in_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) u32 ipc_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) size_t ipc_out_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) static int mipc_check_address(u32 pa)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) /* only MEM2 addresses */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) if (pa < 0x10000000 || pa > 0x14000000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) static struct mipc_infohdr *mipc_get_infohdr(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) struct mipc_infohdr **hdrp, *hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) /* 'mini' header pointer is the last word of MEM2 memory */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) hdrp = (struct mipc_infohdr **)0x13fffffc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) if (mipc_check_address((u32)hdrp)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) printf("mini: invalid hdrp %08X\n", (u32)hdrp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) hdr = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) hdr = *hdrp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if (mipc_check_address((u32)hdr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) printf("mini: invalid hdr %08X\n", (u32)hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) hdr = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (memcmp(hdr->magic, "IPC", 3)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) printf("mini: invalid magic\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) hdr = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) return hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) static int mipc_get_mem2_boundary(u32 *mem2_boundary)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) struct mipc_infohdr *hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) hdr = mipc_get_infohdr();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (!hdr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) error = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (mipc_check_address(hdr->mem2_boundary)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) printf("mini: invalid mem2_boundary %08X\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) hdr->mem2_boundary);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) error = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) *mem2_boundary = hdr->mem2_boundary;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) error = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) static void platform_fixups(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) void *mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) u32 reg[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) u32 mem2_boundary;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) int len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) mem = finddevice("/memory");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if (!mem)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) fatal("Can't find memory node\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) /* two ranges of (address, size) words */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) len = getprop(mem, "reg", reg, sizeof(reg));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) if (len != sizeof(reg)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) /* nothing to do */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) /* retrieve MEM2 boundary from 'mini' */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) error = mipc_get_mem2_boundary(&mem2_boundary);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) /* if that fails use a sane value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) mem2_boundary = MEM2_TOP - FIRMWARE_DEFAULT_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (mem2_boundary > reg[2] && mem2_boundary < reg[2] + reg[3]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) reg[3] = mem2_boundary - reg[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) printf("top of MEM2 @ %08X\n", reg[2] + reg[3]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) setprop(mem, "reg", reg, sizeof(reg));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) void platform_init(unsigned long r3, unsigned long r4, unsigned long r5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) u32 heapsize = 24*1024*1024 - (u32)_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) simple_alloc_init(_end, heapsize, 32, 64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) fdt_init(_dtb_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) * 'mini' boots the Broadway processor with EXI disabled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) * We need it enabled before probing for the USB Gecko.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) out_be32(EXI_CTRL, in_be32(EXI_CTRL) | EXI_CTRL_ENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if (ug_probe())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) console_ops.write = ug_console_write;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) platform_ops.fixups = platform_fixups;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)