Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | // SPDX-License-Identifier: GPL-2.0-or-later /* * arch/powerpc/boot/ugecon.c * * USB Gecko bootwrapper console. * Copyright (C) 2008-2009 The GameCube Linux Team * Copyright (C) 2008,2009 Albert Herranz */ #include <stddef.h> #include "stdio.h" #include "types.h" #include "io.h" #include "ops.h" #define EXI_CLK_32MHZ 5 #define EXI_CSR 0x00 #define EXI_CSR_CLKMASK (0x7<<4) #define EXI_CSR_CLK_32MHZ (EXI_CLK_32MHZ<<4) #define EXI_CSR_CSMASK (0x7<<7) #define EXI_CSR_CS_0 (0x1<<7) /* Chip Select 001 */ #define EXI_CR 0x0c #define EXI_CR_TSTART (1<<0) #define EXI_CR_WRITE (1<<2) #define EXI_CR_READ_WRITE (2<<2) #define EXI_CR_TLEN(len) (((len)-1)<<4) #define EXI_DATA 0x10 /* virtual address base for input/output, retrieved from device tree */ static void *ug_io_base; static u32 ug_io_transaction(u32 in) { u32 *csr_reg = ug_io_base + EXI_CSR; u32 *data_reg = ug_io_base + EXI_DATA; u32 *cr_reg = ug_io_base + EXI_CR; u32 csr, data, cr; /* select */ csr = EXI_CSR_CLK_32MHZ | EXI_CSR_CS_0; out_be32(csr_reg, csr); /* read/write */ data = in; out_be32(data_reg, data); cr = EXI_CR_TLEN(2) | EXI_CR_READ_WRITE | EXI_CR_TSTART; out_be32(cr_reg, cr); while (in_be32(cr_reg) & EXI_CR_TSTART) barrier(); /* deselect */ out_be32(csr_reg, 0); data = in_be32(data_reg); return data; } static int ug_is_txfifo_ready(void) { return ug_io_transaction(0xc0000000) & 0x04000000; } static void ug_raw_putc(char ch) { ug_io_transaction(0xb0000000 | (ch << 20)); } static void ug_putc(char ch) { int count = 16; if (!ug_io_base) return; while (!ug_is_txfifo_ready() && count--) barrier(); if (count >= 0) ug_raw_putc(ch); } void ug_console_write(const char *buf, int len) { char *b = (char *)buf; while (len--) { if (*b == '\n') ug_putc('\r'); ug_putc(*b++); } } static int ug_is_adapter_present(void) { if (!ug_io_base) return 0; return ug_io_transaction(0x90000000) == 0x04700000; } static void *ug_grab_exi_io_base(void) { u32 v; void *devp; devp = find_node_by_compatible(NULL, "nintendo,flipper-exi"); if (devp == NULL) goto err_out; if (getprop(devp, "virtual-reg", &v, sizeof(v)) != sizeof(v)) goto err_out; return (void *)v; err_out: return NULL; } void *ug_probe(void) { void *exi_io_base; int i; exi_io_base = ug_grab_exi_io_base(); if (!exi_io_base) return NULL; /* look for a usbgecko on memcard slots A and B */ for (i = 0; i < 2; i++) { ug_io_base = exi_io_base + 0x14 * i; if (ug_is_adapter_present()) break; } if (i == 2) ug_io_base = NULL; return ug_io_base; } |