Tidy cell types and format strings
[openbios.git] / drivers / cuda.c
blob3a57c7d05718ca126d5cda9ef17fafe3f87e0e5e
1 #include "config.h"
2 #include "libopenbios/bindings.h"
3 #include "drivers/drivers.h"
4 #include "libc/byteorder.h"
5 #include "libc/vsprintf.h"
7 #include "macio.h"
8 #include "cuda.h"
10 //#define DEBUG_CUDA
11 #ifdef DEBUG_CUDA
12 #define CUDA_DPRINTF(fmt, args...) \
13 do { printk("CUDA - %s: " fmt, __func__ , ##args); } while (0)
14 #else
15 #define CUDA_DPRINTF(fmt, args...) do { } while (0)
16 #endif
18 #define IO_CUDA_OFFSET 0x00016000
19 #define IO_CUDA_SIZE 0x00002000
21 /* VIA registers - spaced 0x200 bytes apart */
22 #define RS 0x200 /* skip between registers */
23 #define B 0 /* B-side data */
24 #define A RS /* A-side data */
25 #define DIRB (2*RS) /* B-side direction (1=output) */
26 #define DIRA (3*RS) /* A-side direction (1=output) */
27 #define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */
28 #define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */
29 #define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */
30 #define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */
31 #define T2CL (8*RS) /* Timer 2 ctr/latch (low 8 bits) */
32 #define T2CH (9*RS) /* Timer 2 counter (high 8 bits) */
33 #define SR (10*RS) /* Shift register */
34 #define ACR (11*RS) /* Auxiliary control register */
35 #define PCR (12*RS) /* Peripheral control register */
36 #define IFR (13*RS) /* Interrupt flag register */
37 #define IER (14*RS) /* Interrupt enable register */
38 #define ANH (15*RS) /* A-side data, no handshake */
40 /* Bits in B data register: all active low */
41 #define TREQ 0x08 /* Transfer request (input) */
42 #define TACK 0x10 /* Transfer acknowledge (output) */
43 #define TIP 0x20 /* Transfer in progress (output) */
45 /* Bits in ACR */
46 #define SR_CTRL 0x1c /* Shift register control bits */
47 #define SR_EXT 0x0c /* Shift on external clock */
48 #define SR_OUT 0x10 /* Shift out if 1 */
50 /* Bits in IFR and IER */
51 #define IER_SET 0x80 /* set bits in IER */
52 #define IER_CLR 0 /* clear bits in IER */
53 #define SR_INT 0x04 /* Shift register full/empty */
55 #define CUDA_BUF_SIZE 16
57 #define ADB_PACKET 0
58 #define CUDA_PACKET 1
60 /* CUDA commands (2nd byte) */
61 #define CUDA_GET_TIME 0x03
62 #define CUDA_SET_TIME 0x09
63 #define CUDA_POWERDOWN 0x0a
64 #define CUDA_RESET_SYSTEM 0x11
66 static uint8_t cuda_readb (cuda_t *dev, int reg)
68 return *(volatile uint8_t *)(dev->base + reg);
71 static void cuda_writeb (cuda_t *dev, int reg, uint8_t val)
73 *(volatile uint8_t *)(dev->base + reg) = val;
76 static void cuda_wait_irq (cuda_t *dev)
78 int val;
80 // CUDA_DPRINTF("\n");
81 for(;;) {
82 val = cuda_readb(dev, IFR);
83 cuda_writeb(dev, IFR, val & 0x7f);
84 if (val & SR_INT)
85 break;
91 static int cuda_request (cuda_t *dev, uint8_t pkt_type, const uint8_t *buf,
92 int buf_len, uint8_t *obuf)
94 int i, obuf_len, val;
96 cuda_writeb(dev, ACR, cuda_readb(dev, ACR) | SR_OUT);
97 cuda_writeb(dev, SR, pkt_type);
98 cuda_writeb(dev, B, cuda_readb(dev, B) & ~TIP);
99 if (buf) {
100 //CUDA_DPRINTF("Send buf len: %d\n", buf_len);
101 /* send 'buf' */
102 for(i = 0; i < buf_len; i++) {
103 cuda_wait_irq(dev);
104 cuda_writeb(dev, SR, buf[i]);
105 cuda_writeb(dev, B, cuda_readb(dev, B) ^ TACK);
108 cuda_wait_irq(dev);
109 cuda_writeb(dev, ACR, cuda_readb(dev, ACR) & ~SR_OUT);
110 cuda_readb(dev, SR);
111 cuda_writeb(dev, B, cuda_readb(dev, B) | TIP | TACK);
113 obuf_len = 0;
114 if (obuf) {
115 cuda_wait_irq(dev);
116 cuda_readb(dev, SR);
117 cuda_writeb(dev, B, cuda_readb(dev, B) & ~TIP);
118 for(;;) {
119 cuda_wait_irq(dev);
120 val = cuda_readb(dev, SR);
121 if (obuf_len < CUDA_BUF_SIZE)
122 obuf[obuf_len++] = val;
123 if (cuda_readb(dev, B) & TREQ)
124 break;
125 cuda_writeb(dev, B, cuda_readb(dev, B) ^ TACK);
127 cuda_writeb(dev, B, cuda_readb(dev, B) | TIP | TACK);
129 cuda_wait_irq(dev);
130 cuda_readb(dev, SR);
132 // CUDA_DPRINTF("Got len: %d\n", obuf_len);
134 return obuf_len;
139 static int cuda_adb_req (void *host, const uint8_t *snd_buf, int len,
140 uint8_t *rcv_buf)
142 uint8_t buffer[CUDA_BUF_SIZE], *pos;
144 // CUDA_DPRINTF("len: %d %02x\n", len, snd_buf[0]);
145 len = cuda_request(host, ADB_PACKET, snd_buf, len, buffer);
146 if (len > 1 && buffer[0] == ADB_PACKET) {
147 pos = buffer + 2;
148 len -= 2;
149 } else {
150 pos = buffer + 1;
151 len = -1;
153 memcpy(rcv_buf, pos, len);
155 return len;
159 DECLARE_UNNAMED_NODE(ob_cuda, INSTALL_OPEN, sizeof(int));
161 static cuda_t *main_cuda;
163 static void
164 ppc32_reset_all(void)
166 uint8_t cmdbuf[2], obuf[64];
168 cmdbuf[0] = CUDA_RESET_SYSTEM;
169 cuda_request(main_cuda, CUDA_PACKET, cmdbuf, sizeof(cmdbuf), obuf);
172 static void
173 ppc32_poweroff(void)
175 uint8_t cmdbuf[2], obuf[64];
177 cmdbuf[0] = CUDA_POWERDOWN;
178 cuda_request(main_cuda, CUDA_PACKET, cmdbuf, sizeof(cmdbuf), obuf);
181 static void
182 ob_cuda_initialize (int *idx)
184 phandle_t ph=get_cur_dev();
185 int props[2];
187 push_str("via-cuda");
188 fword("device-type");
190 set_int_property(ph, "#address-cells", 1);
191 set_int_property(ph, "#size-cells", 0);
193 set_property(ph, "compatible", "cuda", 5);
195 props[0] = __cpu_to_be32(IO_CUDA_OFFSET);
196 props[1] = __cpu_to_be32(IO_CUDA_SIZE);
198 set_property(ph, "reg", (char *)&props, sizeof(props));
200 /* on newworld machines the cuda is on interrupt 0x19 */
202 props[0] = 0x19;
203 props[1] = 0;
204 NEWWORLD(set_property(ph, "interrupts", (char *)props, sizeof(props)));
205 NEWWORLD(set_int_property(ph, "#interrupt-cells", 2));
207 /* we emulate an oldworld hardware, so we must use
208 * non-standard oldworld property (needed by linux 2.6.18)
211 OLDWORLD(set_int_property(ph, "AAPL,interrupts", 0x12));
213 bind_func("ppc32-reset-all", ppc32_reset_all);
214 push_str("' ppc32-reset-all to reset-all");
215 fword("eval");
218 static void
219 ob_cuda_open(int *idx)
221 RET(-1);
224 static void
225 ob_cuda_close(int *idx)
229 NODE_METHODS(ob_cuda) = {
230 { NULL, ob_cuda_initialize },
231 { "open", ob_cuda_open },
232 { "close", ob_cuda_close },
235 DECLARE_UNNAMED_NODE(rtc, INSTALL_OPEN, sizeof(int));
237 static void
238 rtc_open(int *idx)
240 RET(-1);
244 * get-time ( -- second minute hour day month year )
248 static const int days_month[12] =
249 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
250 static const int days_month_leap[12] =
251 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
253 static inline int is_leap(int year)
255 return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
258 static void
259 rtc_get_time(int *idx)
261 uint8_t cmdbuf[2], obuf[64];
262 ucell second, minute, hour, day, month, year;
263 uint32_t now;
264 int current;
265 const int *days;
267 cmdbuf[0] = CUDA_GET_TIME;
268 cuda_request(main_cuda, CUDA_PACKET, cmdbuf, sizeof(cmdbuf), obuf);
270 /* seconds since 01/01/1904 */
272 now = (obuf[3] << 24) + (obuf[4] << 16) + (obuf[5] << 8) + obuf[6];
274 second = now % 60;
275 now /= 60;
277 minute = now % 60;
278 now /= 60;
280 hour = now % 24;
281 now /= 24;
283 year = now * 100 / 36525;
284 now -= year * 36525 / 100;
285 year += 1904;
287 days = is_leap(year) ? days_month_leap : days_month;
289 current = 0;
290 month = 0;
291 while (month < 12) {
292 if (now <= current + days[month]) {
293 break;
295 current += days[month];
296 month++;
298 month++;
300 day = now - current;
302 PUSH(second);
303 PUSH(minute);
304 PUSH(hour);
305 PUSH(day);
306 PUSH(month);
307 PUSH(year);
311 * set-time ( second minute hour day month year -- )
315 static void
316 rtc_set_time(int *idx)
318 uint8_t cmdbuf[5], obuf[3];
319 ucell second, minute, hour, day, month, year;
320 const int *days;
321 uint32_t now;
322 unsigned int nb_days;
323 int i;
325 year = POP();
326 month = POP();
327 day = POP();
328 hour = POP();
329 minute = POP();
330 second = POP();
332 days = is_leap(year) ? days_month_leap : days_month;
333 nb_days = (year - 1904) * 36525 / 100 + day;
334 for (i = 0; i < month - 1; i++)
335 nb_days += days[i];
337 now = (((nb_days * 24) + hour) * 60 + minute) * 60 + second;
339 cmdbuf[0] = CUDA_SET_TIME;
340 cmdbuf[1] = now >> 24;
341 cmdbuf[2] = now >> 16;
342 cmdbuf[3] = now >> 8;
343 cmdbuf[4] = now;
345 cuda_request(main_cuda, CUDA_PACKET, cmdbuf, sizeof(cmdbuf), obuf);
348 NODE_METHODS(rtc) = {
349 { "open", rtc_open },
350 { "get-time", rtc_get_time },
351 { "set-time", rtc_set_time },
354 static void
355 rtc_init(char *path)
357 phandle_t ph, aliases;
358 char buf[64];
360 snprintf(buf, sizeof(buf), "%s/rtc", path);
361 REGISTER_NAMED_NODE(rtc, buf);
363 ph = find_dev(buf);
364 set_property(ph, "device_type", "rtc", 4);
365 set_property(ph, "compatible", "rtc", 4);
367 aliases = find_dev("/aliases");
368 set_property(aliases, "rtc", buf, strlen(buf) + 1);
372 cuda_t *cuda_init (const char *path, phys_addr_t base)
374 cuda_t *cuda;
375 char buf[64];
376 phandle_t aliases;
378 base += IO_CUDA_OFFSET;
379 CUDA_DPRINTF(" base=" FMT_plx "\n", base);
380 cuda = malloc(sizeof(cuda_t));
381 if (cuda == NULL)
382 return NULL;
384 snprintf(buf, sizeof(buf), "%s/via-cuda", path);
385 REGISTER_NAMED_NODE(ob_cuda, buf);
387 aliases = find_dev("/aliases");
388 set_property(aliases, "via-cuda", buf, strlen(buf) + 1);
390 cuda->base = base;
391 cuda_writeb(cuda, B, cuda_readb(cuda, B) | TREQ | TIP);
392 #ifdef CONFIG_DRIVER_ADB
393 cuda->adb_bus = adb_bus_new(cuda, &cuda_adb_req);
394 if (cuda->adb_bus == NULL) {
395 free(cuda);
396 return NULL;
398 adb_bus_init(buf, cuda->adb_bus);
399 #endif
401 rtc_init(buf);
403 main_cuda = cuda;
405 device_end();
406 bind_func("poweroff", ppc32_poweroff);
408 return cuda;