Whoops, over-eagerly removed a conditional in the STM code
[savezelda.git] / loader / ios.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 #include "loader.h"
6
7
8 // Low-level IPC access.
9
10 static u32 ipc_read(u32 reg)
11 {
12         return read32(0x0d000000 + 4*reg);
13 }
14
15 static void ipc_write(u32 reg, u32 value)
16 {
17         write32(0x0d000000 + 4*reg, value);
18 }
19
20 static void ipc_bell(u32 w)
21 {
22         ipc_write(1, (ipc_read(1) & 0x30) | w);
23 }
24
25 static void ipc_wait_ack(void)
26 {
27         while ((ipc_read(1) & 0x22) != 0x22)
28                 ;
29 }
30
31 static void ipc_wait_reply(void)
32 {
33         while ((ipc_read(1) & 0x14) != 0x14)
34                 ;
35 }
36
37 static void ipc_irq_ack(void)
38 {
39         ipc_write(12, 0x40000000);
40 }
41
42
43 // Mid-level IPC access.
44
45 static struct {
46         u32 cmd;
47         int result;
48         int fd;
49         u32 arg[5];
50
51         u32 user[8];
52 } ipc __attribute__((aligned(64)));
53
54 static void ipc_send_request(void)
55 {
56         sync_after_write(&ipc, 0x40);
57
58         ipc_write(0, virt_to_phys(&ipc));
59         ipc_bell(1);
60
61         ipc_wait_ack();
62
63         ipc_bell(2);
64         ipc_irq_ack();
65 }
66
67 static void ipc_recv_reply(void)
68 {
69         for (;;) {
70                 u32 reply;
71
72                 ipc_wait_reply();
73
74                 reply = ipc_read(2);
75                 ipc_bell(4);
76
77                 ipc_irq_ack();
78                 ipc_bell(8);
79
80                 if (reply == virt_to_phys(&ipc))
81                         break;
82         }
83
84         sync_before_read(&ipc, sizeof ipc);
85 }
86
87
88 // High-level IPC access.
89
90 int ios_open(const char *filename, u32 mode)
91 {
92         sync_after_write(filename, strlen(filename) + 1);
93         memset(&ipc, 0, sizeof ipc);
94
95         ipc.cmd = 1;
96         ipc.fd = 0;
97         ipc.arg[0] = virt_to_phys(filename);
98         ipc.arg[1] = mode;
99
100         ipc_send_request();
101         ipc_recv_reply();
102
103         return ipc.result;
104 }
105
106 int ios_close(int fd)
107 {
108         memset(&ipc, 0, sizeof ipc);
109
110         ipc.cmd = 2;
111         ipc.fd = fd;
112
113         ipc_send_request();
114         ipc_recv_reply();
115
116         return ipc.result;
117 }
118
119 #if 0
120 int ios_read(int fd, void *data, u32 len)
121 {
122         memset(&ipc, 0, sizeof ipc);
123
124         ipc.cmd = 3;
125         ipc.fd = fd;
126         ipc.arg[0] = virt_to_phys(data);
127         ipc.arg[1] = len;
128
129         ipc_send_request();
130         ipc_recv_reply();
131
132         if (data)
133                 sync_before_read(data, len);
134
135         return ipc.result;
136 }
137
138 int ios_seek(int fd, int where, int whence)
139 {
140         memset(&ipc, 0, sizeof ipc);
141
142         ipc.cmd = 5;
143         ipc.fd = fd;
144         ipc.arg[0] = where;
145         ipc.arg[1] = whence;
146
147         ipc_send_request();
148         ipc_recv_reply();
149
150         return ipc.result;
151 }
152 #endif
153
154 int ios_ioctl(int fd, u32 n, const void *in, u32 inlen, void *out, u32 outlen)
155 {
156         memset(&ipc, 0, sizeof ipc);
157
158         if (in)
159                 sync_after_write(in, inlen);
160         if (out)
161                 sync_after_write(out, outlen);
162
163         ipc.cmd = 6;
164         ipc.fd = fd;
165         ipc.arg[0] = n;
166         ipc.arg[1] = virt_to_phys(in);
167         ipc.arg[2] = inlen;
168         ipc.arg[3] = virt_to_phys(out);
169         ipc.arg[4] = outlen;
170
171         ipc_send_request();
172         ipc_recv_reply();
173
174         if (out)
175                 sync_before_read(out, outlen);
176
177         return ipc.result;
178 }
179
180 int ios_ioctlv(int fd, u32 n, u32 in_count, u32 out_count, struct ioctlv *vec)
181 {
182         u32 i;
183
184         memset(&ipc, 0, sizeof ipc);
185
186         for (i = 0; i < in_count + out_count; i++)
187                 if (vec[i].data) {
188                         sync_after_write(vec[i].data, vec[i].len);
189                         vec[i].data = (void *)virt_to_phys(vec[i].data);
190                 }
191
192         sync_after_write(vec, (in_count + out_count) * sizeof *vec);
193
194         ipc.cmd = 7;
195         ipc.fd = fd;
196         ipc.arg[0] = n;
197         ipc.arg[1] = in_count;
198         ipc.arg[2] = out_count;
199         ipc.arg[3] = virt_to_phys(vec);
200
201         ipc_send_request();
202         ipc_recv_reply();
203
204         for (i = in_count; i < in_count + out_count; i++)
205                 if (vec[i].data) {
206                         vec[i].data = phys_to_virt((u32)vec[i].data);
207                         sync_before_read(vec[i].data, vec[i].len);
208                 }
209
210         return ipc.result;
211 }
212
213
214 // Cleanup any old state.
215
216 static void ipc_cleanup_reply(void)
217 {
218         if ((ipc_read(1) & 0x14) != 0x14)
219                 return;
220
221         ipc_read(2);
222         ipc_bell(4);
223
224         ipc_irq_ack();
225         ipc_bell(8);
226 }
227
228 static void ipc_cleanup_request(void)
229 {
230         if ((ipc_read(1) & 0x22) == 0x22)
231                 ipc_bell(2);
232 }
233
234 static void releasse_old_stm_callback(void)
235 {
236         *((u32 *)0x80000018) = 0x00000014;
237         sync_after_write((void*)0x80000014, 8);
238
239         int fd = ios_open("/dev/stm/immediate",0);
240         if (fd < 0) {
241                 printf("STM Immediate open failed!\n");
242                 return;
243         }
244
245         int err = ios_ioctl(fd, 0x3002, 0, 0, 0, 0);
246         if (err < 0 && err != -6)
247                 printf("Eventhook release failed with code %d\n", err);
248
249         ios_close(fd);
250 }
251
252 void reset_ios(void)
253 {
254         int i;
255
256         //printf("Flushing IPC transactions");
257         for (i = 0; i < 10; i++) {
258                 ipc_cleanup_request();
259                 ipc_cleanup_reply();
260                 ipc_irq_ack();
261                 udelay(1000);
262                 //printf(".");
263         }
264         //printf(" Done.\n");
265
266         //printf("Closing file descriptors...");
267         for (i = 0; i < 32; i++)
268                 ios_close(i);
269         //printf(" Done.\n");
270
271         releasse_old_stm_callback();
272 }