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 
cuda_readb(cuda_t * dev,int reg)66 static uint8_t cuda_readb (cuda_t *dev, int reg)
67 {
68 	    return *(volatile uint8_t *)(dev->base + reg);
69 }
70 
cuda_writeb(cuda_t * dev,int reg,uint8_t val)71 static void cuda_writeb (cuda_t *dev, int reg, uint8_t val)
72 {
73 	    *(volatile uint8_t *)(dev->base + reg) = val;
74 }
75 
cuda_wait_irq(cuda_t * dev)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 
cuda_request(cuda_t * dev,uint8_t pkt_type,const uint8_t * buf,int buf_len,uint8_t * obuf)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 
cuda_adb_req(void * host,const uint8_t * snd_buf,int len,uint8_t * rcv_buf)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         /* We handle 2 types of ADB packet here:
148                Normal: <type> <status> <data> ...
149                Error : <type> <status> <cmd> (<data> ...)
150            Ideally we should use buffer[1] (status) to determine whether this
151            is a normal or error packet but this requires a corresponding fix
152            in QEMU <= 2.4. Hence we temporarily handle it this way to ease
153            the transition. */
154         if (len > 2 && buffer[2] == snd_buf[0]) {
155             /* Error */
156             pos = buffer + 3;
157             len -= 3;
158         } else {
159             /* Normal */
160             pos = buffer + 2;
161             len -= 2;
162         }
163     } else {
164         pos = buffer + 1;
165         len = -1;
166     }
167     memcpy(rcv_buf, pos, len);
168 
169     return len;
170 }
171 
172 
173 DECLARE_UNNAMED_NODE(ob_cuda, 0, sizeof(int));
174 
175 static cuda_t *main_cuda;
176 
177 static void
ppc32_reset_all(void)178 ppc32_reset_all(void)
179 {
180         uint8_t cmdbuf[2], obuf[64];
181 
182         cmdbuf[0] = CUDA_RESET_SYSTEM;
183         cuda_request(main_cuda, CUDA_PACKET, cmdbuf, sizeof(cmdbuf), obuf);
184 }
185 
186 static void
ppc32_poweroff(void)187 ppc32_poweroff(void)
188 {
189         uint8_t cmdbuf[2], obuf[64];
190 
191         cmdbuf[0] = CUDA_POWERDOWN;
192         cuda_request(main_cuda, CUDA_PACKET, cmdbuf, sizeof(cmdbuf), obuf);
193 }
194 
195 static void
ob_cuda_open(int * idx)196 ob_cuda_open(int *idx)
197 {
198 	RET(-1);
199 }
200 
201 static void
ob_cuda_close(int * idx)202 ob_cuda_close(int *idx)
203 {
204 }
205 
206 NODE_METHODS(ob_cuda) = {
207 	{ "open",		ob_cuda_open		},
208 	{ "close",		ob_cuda_close		},
209 };
210 
211 DECLARE_UNNAMED_NODE(rtc, 0, sizeof(int));
212 
213 static void
rtc_open(int * idx)214 rtc_open(int *idx)
215 {
216 	RET(-1);
217 }
218 
219 /*
220  * get-time ( -- second minute hour day month year )
221  *
222  */
223 
224 static const int days_month[12] =
225 	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
226 static const int days_month_leap[12] =
227 	{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
228 
is_leap(int year)229 static inline int is_leap(int year)
230 {
231 	return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
232 }
233 
234 static  void
rtc_get_time(int * idx)235 rtc_get_time(int *idx)
236 {
237         uint8_t cmdbuf[2], obuf[64];
238 	ucell second, minute, hour, day, month, year;
239 	uint32_t now;
240 	int current;
241 	const int *days;
242 
243         cmdbuf[0] = CUDA_GET_TIME;
244         cuda_request(main_cuda, CUDA_PACKET, cmdbuf, sizeof(cmdbuf), obuf);
245 
246 	/* seconds since 01/01/1904 */
247 
248 	now = (obuf[3] << 24) + (obuf[4] << 16) + (obuf[5] << 8) + obuf[6];
249 
250 	second =  now % 60;
251 	now /= 60;
252 
253 	minute = now % 60;
254 	now /= 60;
255 
256 	hour = now % 24;
257 	now /= 24;
258 
259 	year = now * 100 / 36525;
260 	now -= year * 36525 / 100;
261 	year += 1904;
262 
263 	days = is_leap(year) ?  days_month_leap : days_month;
264 
265 	current = 0;
266 	month = 0;
267 	while (month < 12) {
268 		if (now <= current + days[month]) {
269 			break;
270 		}
271 		current += days[month];
272 		month++;
273 	}
274 	month++;
275 
276 	day = now - current;
277 
278 	PUSH(second);
279 	PUSH(minute);
280 	PUSH(hour);
281 	PUSH(day);
282 	PUSH(month);
283 	PUSH(year);
284 }
285 
286 /*
287  * set-time ( second minute hour day month year -- )
288  *
289  */
290 
291 static  void
rtc_set_time(int * idx)292 rtc_set_time(int *idx)
293 {
294         uint8_t cmdbuf[5], obuf[3];
295 	ucell second, minute, hour, day, month, year;
296 	const int *days;
297 	uint32_t now;
298 	unsigned int nb_days;
299 	int i;
300 
301 	year = POP();
302 	month = POP();
303 	day = POP();
304 	hour = POP();
305 	minute = POP();
306 	second = POP();
307 
308 	days = is_leap(year) ?  days_month_leap : days_month;
309 	nb_days = (year - 1904) * 36525 / 100 + day;
310 	for (i = 0; i < month - 1; i++)
311 		nb_days += days[i];
312 
313 	now = (((nb_days * 24) + hour) * 60 + minute) * 60 + second;
314 
315         cmdbuf[0] = CUDA_SET_TIME;
316 	cmdbuf[1] = now >> 24;
317 	cmdbuf[2] = now >> 16;
318 	cmdbuf[3] = now >> 8;
319 	cmdbuf[4] = now;
320 
321         cuda_request(main_cuda, CUDA_PACKET, cmdbuf, sizeof(cmdbuf), obuf);
322 }
323 
324 NODE_METHODS(rtc) = {
325 	{ "open",		rtc_open		},
326 	{ "get-time",		rtc_get_time		},
327 	{ "set-time",		rtc_set_time		},
328 };
329 
330 static void
rtc_init(char * path)331 rtc_init(char *path)
332 {
333 	phandle_t aliases;
334 	char buf[128];
335 
336 	push_str(path);
337 	fword("find-device");
338 
339 	fword("new-device");
340 
341 	push_str("rtc");
342 	fword("device-name");
343 
344 	push_str("rtc");
345 	fword("device-type");
346 
347 	push_str("rtc");
348 	fword("encode-string");
349 	push_str("compatible");
350 	fword("property");
351 
352 	BIND_NODE_METHODS(get_cur_dev(), rtc);
353 	fword("finish-device");
354 
355 	aliases = find_dev("/aliases");
356 	snprintf(buf, sizeof(buf), "%s/rtc", path);
357 	set_property(aliases, "rtc", buf, strlen(buf) + 1);
358 }
359 
360 static void
powermgt_init(char * path)361 powermgt_init(char *path)
362 {
363 	push_str(path);
364 	fword("find-device");
365 
366 	fword("new-device");
367 
368 	push_str("power-mgt");
369 	fword("device-name");
370 
371 	push_str("power-mgt");
372 	fword("device-type");
373 
374 	push_str("min-consumption-pwm-led");
375 	fword("encode-string");
376 	push_str("mgt-kind");
377 	fword("property");
378 
379 	push_str("cuda");
380 	fword("encode-string");
381 	push_str("compatible");
382 	fword("property");
383 
384 	BIND_NODE_METHODS(get_cur_dev(), rtc);
385 	fword("finish-device");
386 }
387 
cuda_init(const char * path,phys_addr_t base)388 cuda_t *cuda_init (const char *path, phys_addr_t base)
389 {
390 	cuda_t *cuda;
391 	char buf[64];
392 	phandle_t ph, aliases;
393 	int props[2];
394 
395 	base += IO_CUDA_OFFSET;
396 	CUDA_DPRINTF(" base=" FMT_plx "\n", base);
397 	cuda = malloc(sizeof(cuda_t));
398 	if (cuda == NULL)
399 	    return NULL;
400 
401 	fword("new-device");
402 
403 	push_str("via-cuda");
404 	fword("device-name");
405 
406 	push_str("via-cuda");
407 	fword("device-type");
408 
409 	push_str("cuda");
410 	fword("encode-string");
411 	push_str("compatible");
412 	fword("property");
413 
414 	PUSH(1);
415 	fword("encode-int");
416 	push_str("#address-cells");
417 	fword("property");
418 
419 	PUSH(0);
420 	fword("encode-int");
421 	push_str("#size-cells");
422 	fword("property");
423 
424 	PUSH(IO_CUDA_OFFSET);
425 	fword("encode-int");
426 	PUSH(IO_CUDA_SIZE);
427 	fword("encode-int");
428 	fword("encode+");
429 	push_str("reg");
430 	fword("property");
431 
432 	ph = get_cur_dev();
433 
434 	/* on newworld machines the cuda is on interrupt 0x19 */
435 	props[0] = 0x19;
436 	props[1] = 0;
437 	NEWWORLD(set_property(ph, "interrupts", (char *)props, sizeof(props)));
438 	NEWWORLD(set_int_property(ph, "#interrupt-cells", 2));
439 
440 	/* we emulate an oldworld hardware, so we must use
441 	 * non-standard oldworld property (needed by linux 2.6.18)
442 	 */
443 	OLDWORLD(set_int_property(ph, "AAPL,interrupts", 0x12));
444 
445 	BIND_NODE_METHODS(get_cur_dev(), ob_cuda);
446 
447 	aliases = find_dev("/aliases");
448 	snprintf(buf, sizeof(buf), "%s/via-cuda", path);
449 	set_property(aliases, "via-cuda", buf, strlen(buf) + 1);
450 
451 	cuda->base = base;
452 	cuda_writeb(cuda, B, cuda_readb(cuda, B) | TREQ | TIP);
453 #ifdef CONFIG_DRIVER_ADB
454 	cuda->adb_bus = adb_bus_new(cuda, &cuda_adb_req);
455 	if (cuda->adb_bus == NULL) {
456 	    free(cuda);
457 	    return NULL;
458 	}
459 	adb_bus_init(buf, cuda->adb_bus);
460 #endif
461 
462 	rtc_init(buf);
463 	powermgt_init(buf);
464 
465 	main_cuda = cuda;
466 
467 	fword("finish-device");
468 
469 	bind_func("ppc32-power-off", ppc32_poweroff);
470 	feval("['] ppc32-power-off to power-off");
471 	bind_func("ppc32-reset-all", ppc32_reset_all);
472 	feval("['] ppc32-reset-all to reset-all");
473 
474 	return cuda;
475 }
476