Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / drivers / cuda.c
1 #include "config.h"
2 #include "libopenbios/bindings.h"
3 #include "drivers/drivers.h"
4 #include "libc/byteorder.h"
5 #include "libc/vsprintf.h"
6
7 #include "macio.h"
8 #include "cuda.h"
9
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
17
18 #define IO_CUDA_OFFSET  0x00016000
19 #define IO_CUDA_SIZE    0x00002000
20
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 */
39
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) */
44
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 */
49
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 */
54
55 #define CUDA_BUF_SIZE 16
56
57 #define ADB_PACKET      0
58 #define CUDA_PACKET     1
59
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
65
66 static uint8_t cuda_readb (cuda_t *dev, int reg)
67 {
68             return *(volatile uint8_t *)(dev->base + reg);
69 }
70
71 static void cuda_writeb (cuda_t *dev, int reg, uint8_t val)
72 {
73             *(volatile uint8_t *)(dev->base + reg) = val;
74 }
75
76 static void cuda_wait_irq (cuda_t *dev)
77 {
78     int val;
79
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;
86     }
87 }
88
89
90
91 static int cuda_request (cuda_t *dev, uint8_t pkt_type, const uint8_t *buf,
92                          int buf_len, uint8_t *obuf)
93 {
94     int i, obuf_len, val;
95
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);
106         }
107     }
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);
112
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);
126         }
127         cuda_writeb(dev, B, cuda_readb(dev, B) | TIP | TACK);
128
129         cuda_wait_irq(dev);
130         cuda_readb(dev, SR);
131     }
132 //    CUDA_DPRINTF("Got len: %d\n", obuf_len);
133
134     return obuf_len;
135 }
136
137
138
139 static int cuda_adb_req (void *host, const uint8_t *snd_buf, int len,
140                          uint8_t *rcv_buf)
141 {
142     uint8_t buffer[CUDA_BUF_SIZE], *pos;
143
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;
152     }
153     memcpy(rcv_buf, pos, len);
154
155     return len;
156 }
157
158
159 DECLARE_UNNAMED_NODE(ob_cuda, INSTALL_OPEN, sizeof(int));
160
161 static cuda_t *main_cuda;
162
163 static void
164 ppc32_reset_all(void)
165 {
166         uint8_t cmdbuf[2], obuf[64];
167
168         cmdbuf[0] = CUDA_RESET_SYSTEM;
169         cuda_request(main_cuda, CUDA_PACKET, cmdbuf, sizeof(cmdbuf), obuf);
170 }
171
172 static void
173 ppc32_poweroff(void)
174 {
175         uint8_t cmdbuf[2], obuf[64];
176
177         cmdbuf[0] = CUDA_POWERDOWN;
178         cuda_request(main_cuda, CUDA_PACKET, cmdbuf, sizeof(cmdbuf), obuf);
179 }
180
181 static void
182 ob_cuda_initialize (int *idx)
183 {
184         phandle_t ph=get_cur_dev();
185         int props[2];
186
187         push_str("via-cuda");
188         fword("device-type");
189
190         set_int_property(ph, "#address-cells", 1);
191         set_int_property(ph, "#size-cells", 0);
192
193         set_property(ph, "compatible", "cuda", 5);
194
195         props[0] = __cpu_to_be32(IO_CUDA_OFFSET);
196         props[1] = __cpu_to_be32(IO_CUDA_SIZE);
197
198         set_property(ph, "reg", (char *)&props, sizeof(props));
199
200         /* on newworld machines the cuda is on interrupt 0x19 */
201
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));
206
207         /* we emulate an oldworld hardware, so we must use
208          * non-standard oldworld property (needed by linux 2.6.18)
209          */
210
211         OLDWORLD(set_int_property(ph, "AAPL,interrupts", 0x12));
212
213         bind_func("ppc32-reset-all", ppc32_reset_all);
214         push_str("' ppc32-reset-all to reset-all");
215         fword("eval");
216 }
217
218 static void
219 ob_cuda_open(int *idx)
220 {
221         RET(-1);
222 }
223
224 static void
225 ob_cuda_close(int *idx)
226 {
227 }
228
229 NODE_METHODS(ob_cuda) = {
230         { NULL,                 ob_cuda_initialize      },
231         { "open",               ob_cuda_open            },
232         { "close",              ob_cuda_close           },
233 };
234
235 DECLARE_UNNAMED_NODE(rtc, INSTALL_OPEN, sizeof(int));
236
237 static void
238 rtc_open(int *idx)
239 {
240         RET(-1);
241 }
242
243 /*
244  * get-time ( -- second minute hour day month year )
245  *
246  */
247
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 };
252
253 static inline int is_leap(int year)
254 {
255         return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
256 }
257
258 static  void
259 rtc_get_time(int *idx)
260 {
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;
266
267         cmdbuf[0] = CUDA_GET_TIME;
268         cuda_request(main_cuda, CUDA_PACKET, cmdbuf, sizeof(cmdbuf), obuf);
269
270         /* seconds since 01/01/1904 */
271
272         now = (obuf[3] << 24) + (obuf[4] << 16) + (obuf[5] << 8) + obuf[6];
273
274         second =  now % 60;
275         now /= 60;
276
277         minute = now % 60;
278         now /= 60;
279
280         hour = now % 24;
281         now /= 24;
282
283         year = now * 100 / 36525;
284         now -= year * 36525 / 100;
285         year += 1904;
286
287         days = is_leap(year) ?  days_month_leap : days_month;
288
289         current = 0;
290         month = 0;
291         while (month < 12) {
292                 if (now <= current + days[month]) {
293                         break;
294                 }
295                 current += days[month];
296                 month++;
297         }
298         month++;
299
300         day = now - current;
301
302         PUSH(second);
303         PUSH(minute);
304         PUSH(hour);
305         PUSH(day);
306         PUSH(month);
307         PUSH(year);
308 }
309
310 /*
311  * set-time ( second minute hour day month year -- )
312  *
313  */
314
315 static  void
316 rtc_set_time(int *idx)
317 {
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;
324
325         year = POP();
326         month = POP();
327         day = POP();
328         hour = POP();
329         minute = POP();
330         second = POP();
331
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];
336
337         now = (((nb_days * 24) + hour) * 60 + minute) * 60 + second;
338
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;
344
345         cuda_request(main_cuda, CUDA_PACKET, cmdbuf, sizeof(cmdbuf), obuf);
346 }
347
348 NODE_METHODS(rtc) = {
349         { "open",               rtc_open                },
350         { "get-time",           rtc_get_time            },
351         { "set-time",           rtc_set_time            },
352 };
353
354 static void
355 rtc_init(char *path)
356 {
357         phandle_t ph, aliases;
358         char buf[64];
359
360         snprintf(buf, sizeof(buf), "%s/rtc", path);
361         REGISTER_NAMED_NODE(rtc, buf);
362
363         ph = find_dev(buf);
364         set_property(ph, "device_type", "rtc", 4);
365         set_property(ph, "compatible", "rtc", 4);
366
367         aliases = find_dev("/aliases");
368         set_property(aliases, "rtc", buf, strlen(buf) + 1);
369
370 }
371
372 static void
373 powermgt_init(char *path)
374 {
375         phandle_t ph;
376         char buf[64];
377
378         snprintf(buf, sizeof(buf), "%s/power-mgt", path);
379         REGISTER_NAMED_NODE(rtc, buf);
380
381         ph = find_dev(buf);
382         set_property(ph, "device_type", "power-mgt", 10);
383         set_property(ph, "compatible", "power-mgt", 10);
384 }
385
386 cuda_t *cuda_init (const char *path, phys_addr_t base)
387 {
388         cuda_t *cuda;
389         char buf[64];
390         phandle_t aliases;
391
392         base += IO_CUDA_OFFSET;
393         CUDA_DPRINTF(" base=" FMT_plx "\n", base);
394         cuda = malloc(sizeof(cuda_t));
395         if (cuda == NULL)
396             return NULL;
397
398         snprintf(buf, sizeof(buf), "%s/via-cuda", path);
399         REGISTER_NAMED_NODE(ob_cuda, buf);
400
401         aliases = find_dev("/aliases");
402         set_property(aliases, "via-cuda", buf, strlen(buf) + 1);
403
404         cuda->base = base;
405         cuda_writeb(cuda, B, cuda_readb(cuda, B) | TREQ | TIP);
406 #ifdef CONFIG_DRIVER_ADB
407         cuda->adb_bus = adb_bus_new(cuda, &cuda_adb_req);
408         if (cuda->adb_bus == NULL) {
409             free(cuda);
410             return NULL;
411         }
412         adb_bus_init(buf, cuda->adb_bus);
413 #endif
414
415         rtc_init(buf);
416         powermgt_init(buf);
417
418         main_cuda = cuda;
419
420         device_end();
421         bind_func("poweroff", ppc32_poweroff);
422
423         return cuda;
424 }