xref: /openbmc/linux/arch/powerpc/boot/ugecon.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1*2874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
226054c95SAlbert Herranz /*
326054c95SAlbert Herranz  * arch/powerpc/boot/ugecon.c
426054c95SAlbert Herranz  *
526054c95SAlbert Herranz  * USB Gecko bootwrapper console.
626054c95SAlbert Herranz  * Copyright (C) 2008-2009 The GameCube Linux Team
726054c95SAlbert Herranz  * Copyright (C) 2008,2009 Albert Herranz
826054c95SAlbert Herranz  */
926054c95SAlbert Herranz 
1026054c95SAlbert Herranz #include <stddef.h>
1126054c95SAlbert Herranz #include "stdio.h"
1226054c95SAlbert Herranz #include "types.h"
1326054c95SAlbert Herranz #include "io.h"
1426054c95SAlbert Herranz #include "ops.h"
1526054c95SAlbert Herranz 
1626054c95SAlbert Herranz 
1726054c95SAlbert Herranz #define EXI_CLK_32MHZ           5
1826054c95SAlbert Herranz 
1926054c95SAlbert Herranz #define EXI_CSR                 0x00
2026054c95SAlbert Herranz #define   EXI_CSR_CLKMASK       (0x7<<4)
2126054c95SAlbert Herranz #define     EXI_CSR_CLK_32MHZ   (EXI_CLK_32MHZ<<4)
2226054c95SAlbert Herranz #define   EXI_CSR_CSMASK        (0x7<<7)
2326054c95SAlbert Herranz #define     EXI_CSR_CS_0        (0x1<<7)  /* Chip Select 001 */
2426054c95SAlbert Herranz 
2526054c95SAlbert Herranz #define EXI_CR                  0x0c
2626054c95SAlbert Herranz #define   EXI_CR_TSTART         (1<<0)
2726054c95SAlbert Herranz #define   EXI_CR_WRITE		(1<<2)
2826054c95SAlbert Herranz #define   EXI_CR_READ_WRITE     (2<<2)
2926054c95SAlbert Herranz #define   EXI_CR_TLEN(len)      (((len)-1)<<4)
3026054c95SAlbert Herranz 
3126054c95SAlbert Herranz #define EXI_DATA                0x10
3226054c95SAlbert Herranz 
3326054c95SAlbert Herranz 
3426054c95SAlbert Herranz /* virtual address base for input/output, retrieved from device tree */
3526054c95SAlbert Herranz static void *ug_io_base;
3626054c95SAlbert Herranz 
3726054c95SAlbert Herranz 
ug_io_transaction(u32 in)3826054c95SAlbert Herranz static u32 ug_io_transaction(u32 in)
3926054c95SAlbert Herranz {
4026054c95SAlbert Herranz 	u32 *csr_reg = ug_io_base + EXI_CSR;
4126054c95SAlbert Herranz 	u32 *data_reg = ug_io_base + EXI_DATA;
4226054c95SAlbert Herranz 	u32 *cr_reg = ug_io_base + EXI_CR;
4326054c95SAlbert Herranz 	u32 csr, data, cr;
4426054c95SAlbert Herranz 
4526054c95SAlbert Herranz 	/* select */
4626054c95SAlbert Herranz 	csr = EXI_CSR_CLK_32MHZ | EXI_CSR_CS_0;
4726054c95SAlbert Herranz 	out_be32(csr_reg, csr);
4826054c95SAlbert Herranz 
4926054c95SAlbert Herranz 	/* read/write */
5026054c95SAlbert Herranz 	data = in;
5126054c95SAlbert Herranz 	out_be32(data_reg, data);
5226054c95SAlbert Herranz 	cr = EXI_CR_TLEN(2) | EXI_CR_READ_WRITE | EXI_CR_TSTART;
5326054c95SAlbert Herranz 	out_be32(cr_reg, cr);
5426054c95SAlbert Herranz 
5526054c95SAlbert Herranz 	while (in_be32(cr_reg) & EXI_CR_TSTART)
5626054c95SAlbert Herranz 		barrier();
5726054c95SAlbert Herranz 
5826054c95SAlbert Herranz 	/* deselect */
5926054c95SAlbert Herranz 	out_be32(csr_reg, 0);
6026054c95SAlbert Herranz 
6126054c95SAlbert Herranz 	data = in_be32(data_reg);
6226054c95SAlbert Herranz 	return data;
6326054c95SAlbert Herranz }
6426054c95SAlbert Herranz 
ug_is_txfifo_ready(void)6526054c95SAlbert Herranz static int ug_is_txfifo_ready(void)
6626054c95SAlbert Herranz {
6726054c95SAlbert Herranz 	return ug_io_transaction(0xc0000000) & 0x04000000;
6826054c95SAlbert Herranz }
6926054c95SAlbert Herranz 
ug_raw_putc(char ch)7026054c95SAlbert Herranz static void ug_raw_putc(char ch)
7126054c95SAlbert Herranz {
7226054c95SAlbert Herranz 	ug_io_transaction(0xb0000000 | (ch << 20));
7326054c95SAlbert Herranz }
7426054c95SAlbert Herranz 
ug_putc(char ch)7526054c95SAlbert Herranz static void ug_putc(char ch)
7626054c95SAlbert Herranz {
7726054c95SAlbert Herranz 	int count = 16;
7826054c95SAlbert Herranz 
7926054c95SAlbert Herranz 	if (!ug_io_base)
8026054c95SAlbert Herranz 		return;
8126054c95SAlbert Herranz 
8226054c95SAlbert Herranz 	while (!ug_is_txfifo_ready() && count--)
8326054c95SAlbert Herranz 		barrier();
84698cd335SAlbert Herranz 	if (count >= 0)
8526054c95SAlbert Herranz 		ug_raw_putc(ch);
8626054c95SAlbert Herranz }
8726054c95SAlbert Herranz 
ug_console_write(const char * buf,int len)8826054c95SAlbert Herranz void ug_console_write(const char *buf, int len)
8926054c95SAlbert Herranz {
9026054c95SAlbert Herranz 	char *b = (char *)buf;
9126054c95SAlbert Herranz 
9226054c95SAlbert Herranz 	while (len--) {
9326054c95SAlbert Herranz 		if (*b == '\n')
9426054c95SAlbert Herranz 			ug_putc('\r');
9526054c95SAlbert Herranz 		ug_putc(*b++);
9626054c95SAlbert Herranz 	}
9726054c95SAlbert Herranz }
9826054c95SAlbert Herranz 
ug_is_adapter_present(void)9926054c95SAlbert Herranz static int ug_is_adapter_present(void)
10026054c95SAlbert Herranz {
10126054c95SAlbert Herranz 	if (!ug_io_base)
10226054c95SAlbert Herranz 		return 0;
10326054c95SAlbert Herranz 	return ug_io_transaction(0x90000000) == 0x04700000;
10426054c95SAlbert Herranz }
10526054c95SAlbert Herranz 
ug_grab_exi_io_base(void)10626054c95SAlbert Herranz static void *ug_grab_exi_io_base(void)
10726054c95SAlbert Herranz {
10826054c95SAlbert Herranz 	u32 v;
10926054c95SAlbert Herranz 	void *devp;
11026054c95SAlbert Herranz 
11126054c95SAlbert Herranz 	devp = find_node_by_compatible(NULL, "nintendo,flipper-exi");
11226054c95SAlbert Herranz 	if (devp == NULL)
11326054c95SAlbert Herranz 		goto err_out;
11426054c95SAlbert Herranz 	if (getprop(devp, "virtual-reg", &v, sizeof(v)) != sizeof(v))
11526054c95SAlbert Herranz 		goto err_out;
11626054c95SAlbert Herranz 
11726054c95SAlbert Herranz 	return (void *)v;
11826054c95SAlbert Herranz 
11926054c95SAlbert Herranz err_out:
12026054c95SAlbert Herranz 	return NULL;
12126054c95SAlbert Herranz }
12226054c95SAlbert Herranz 
ug_probe(void)12326054c95SAlbert Herranz void *ug_probe(void)
12426054c95SAlbert Herranz {
12526054c95SAlbert Herranz 	void *exi_io_base;
12626054c95SAlbert Herranz 	int i;
12726054c95SAlbert Herranz 
12826054c95SAlbert Herranz 	exi_io_base = ug_grab_exi_io_base();
12926054c95SAlbert Herranz 	if (!exi_io_base)
13026054c95SAlbert Herranz 		return NULL;
13126054c95SAlbert Herranz 
13226054c95SAlbert Herranz 	/* look for a usbgecko on memcard slots A and B */
13326054c95SAlbert Herranz 	for (i = 0; i < 2; i++) {
13426054c95SAlbert Herranz 		ug_io_base = exi_io_base + 0x14 * i;
13526054c95SAlbert Herranz 		if (ug_is_adapter_present())
13626054c95SAlbert Herranz 			break;
13726054c95SAlbert Herranz 	}
13826054c95SAlbert Herranz 	if (i == 2)
13926054c95SAlbert Herranz 		ug_io_base = NULL;
14026054c95SAlbert Herranz 	return ug_io_base;
14126054c95SAlbert Herranz }
14226054c95SAlbert Herranz 
143