Initial commit
[savezelda.git] / loader / usbgecko.c
1 // Copyright 2008-2009  Segher Boessenkool  <segher@kernel.crashing.org>
2 // This code is licensed to you under the terms of the GNU GPL, version 2;
3 // see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
4
5 // Based on code:
6 //      Copyright (c) 2008 - Nuke - <wiinuke@gmail.com>
7
8 #include "loader.h"
9
10
11 static void exi_write(u32 addr, u32 x)
12 {
13         write32(0x0d006800 + addr, x);
14 }
15
16 static u32 exi_read(u32 addr)
17 {
18         return read32(0x0d006800 + addr);
19 }
20
21 #define EXI_CH1_STATUS  0x14
22 #define EXI_CH1_CONTROL 0x20
23 #define EXI_CH1_DATA    0x24
24
25
26 static void usbgecko_deselect_device(void)
27 {
28         exi_write(EXI_CH1_STATUS, 0);
29 }
30
31 static void usbgecko_select_device(void)
32 {
33         // device 0, 16MHz
34         exi_write(EXI_CH1_STATUS, 0xc0);
35 }
36
37 static void usbgecko_wait_for_transfer_complete(void)
38 {
39         while (exi_read(EXI_CH1_CONTROL) & 1)
40                 ;
41 }
42
43
44 u8 usbgecko_flash_read8(u32 offset)
45 {
46         u8 x;
47
48         usbgecko_deselect_device();
49
50         usbgecko_select_device();
51         exi_write(EXI_CH1_DATA, 0xf0000000 | (offset << 9));
52         exi_write(EXI_CH1_CONTROL, 0x35); // 4 bytes immediate write
53         usbgecko_wait_for_transfer_complete();
54
55         usbgecko_select_device();
56         exi_write(EXI_CH1_CONTROL, 0x39); // 4 bytes immediate read/write
57         usbgecko_wait_for_transfer_complete();
58
59         x = exi_read(EXI_CH1_DATA) >> 23;
60
61         usbgecko_deselect_device();
62
63         return x;
64 }
65
66 u32 usbgecko_flash_read32(u32 offset)
67 {
68         u32 x, i;
69
70         x = 0;
71         for (i = 0; i < 4; i++)
72                 x = (x << 8) | usbgecko_flash_read8(offset++);
73
74         return x;
75 }
76
77
78
79 static int usbgecko_console_enabled = 0;
80
81 static u32 usbgecko_command(u32 command)
82 {
83         u32 x;
84
85         usbgecko_select_device();
86         exi_write(EXI_CH1_DATA, command);
87         exi_write(EXI_CH1_CONTROL, 0x19); // 2 bytes immediate read/write
88         usbgecko_wait_for_transfer_complete();
89
90         x = exi_read(EXI_CH1_DATA);
91
92         usbgecko_deselect_device();
93
94         return x;
95 }
96
97 int usbgecko_checkgecko(void)
98 {
99         return usbgecko_command(0x90000000) == 0x04700000;
100 }
101
102 void usbgecko_console_putc(u8 c)
103 {
104         u32 x;
105
106         if (!usbgecko_console_enabled)
107                 return;
108
109         if (c == '\n')
110                 usbgecko_console_putc('\r');
111
112         x = usbgecko_command(0xb0000000 | (c << 20));
113 }
114
115 static void usbgecko_flush(void)
116 {
117         u32 x;
118
119         do {
120                 x = usbgecko_command(0xa0000000);
121         } while (x & 0x08000000);
122 }
123
124 void usbgecko_init(void)
125 {
126         if (!usbgecko_checkgecko())
127                 return;
128
129         usbgecko_console_enabled = 1;
130         usbgecko_flush();
131 }