summaryrefslogtreecommitdiffstats
path: root/drivers/macintosh/via-cuda.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/macintosh/via-cuda.c')
-rw-r--r--drivers/macintosh/via-cuda.c155
1 files changed, 134 insertions, 21 deletions
diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
index 57fb20dcb9dd..1a742bd9f612 100644
--- a/drivers/macintosh/via-cuda.c
+++ b/drivers/macintosh/via-cuda.c
@@ -1,10 +1,10 @@
1/* 1/*
2 * Device driver for the via-cuda on Apple Powermacs. 2 * Device driver for the Cuda and Egret system controllers found on PowerMacs
3 * and 68k Macs.
3 * 4 *
4 * The VIA (versatile interface adapter) interfaces to the CUDA, 5 * The Cuda or Egret is a 6805 microcontroller interfaced to the 6522 VIA.
5 * a 6805 microprocessor core which controls the ADB (Apple Desktop 6 * This MCU controls system power, Parameter RAM, Real Time Clock and the
6 * Bus) which connects to the keyboard and mouse. The CUDA also 7 * Apple Desktop Bus (ADB) that connects to the keyboard and mouse.
7 * controls system power and the RTC (real time clock) chip.
8 * 8 *
9 * Copyright (C) 1996 Paul Mackerras. 9 * Copyright (C) 1996 Paul Mackerras.
10 */ 10 */
@@ -50,10 +50,27 @@ static DEFINE_SPINLOCK(cuda_lock);
50#define IER (14*RS) /* Interrupt enable register */ 50#define IER (14*RS) /* Interrupt enable register */
51#define ANH (15*RS) /* A-side data, no handshake */ 51#define ANH (15*RS) /* A-side data, no handshake */
52 52
53/* Bits in B data register: all active low */ 53/*
54#define TREQ 0x08 /* Transfer request (input) */ 54 * When the Cuda design replaced the Egret, some signal names and
55#define TACK 0x10 /* Transfer acknowledge (output) */ 55 * logic sense changed. They all serve the same purposes, however.
56#define TIP 0x20 /* Transfer in progress (output) */ 56 *
57 * VIA pin | Egret pin
58 * ----------------+------------------------------------------
59 * PB3 (input) | Transceiver session (active low)
60 * PB4 (output) | VIA full (active high)
61 * PB5 (output) | System session (active high)
62 *
63 * VIA pin | Cuda pin
64 * ----------------+------------------------------------------
65 * PB3 (input) | Transfer request (active low)
66 * PB4 (output) | Byte acknowledge (active low)
67 * PB5 (output) | Transfer in progress (active low)
68 */
69
70/* Bits in Port B data register */
71#define TREQ 0x08 /* Transfer request */
72#define TACK 0x10 /* Transfer acknowledge */
73#define TIP 0x20 /* Transfer in progress */
57 74
58/* Bits in ACR */ 75/* Bits in ACR */
59#define SR_CTRL 0x1c /* Shift register control bits */ 76#define SR_CTRL 0x1c /* Shift register control bits */
@@ -65,6 +82,19 @@ static DEFINE_SPINLOCK(cuda_lock);
65#define IER_CLR 0 /* clear bits in IER */ 82#define IER_CLR 0 /* clear bits in IER */
66#define SR_INT 0x04 /* Shift register full/empty */ 83#define SR_INT 0x04 /* Shift register full/empty */
67 84
85/* Duration of byte acknowledgement pulse (us) */
86#define EGRET_TACK_ASSERTED_DELAY 300
87#define EGRET_TACK_NEGATED_DELAY 400
88
89/* Interval from interrupt to start of session (us) */
90#define EGRET_SESSION_DELAY 450
91
92#ifdef CONFIG_PPC
93#define mcu_is_egret false
94#else
95static bool mcu_is_egret;
96#endif
97
68static inline bool TREQ_asserted(u8 portb) 98static inline bool TREQ_asserted(u8 portb)
69{ 99{
70 return !(portb & TREQ); 100 return !(portb & TREQ);
@@ -72,12 +102,29 @@ static inline bool TREQ_asserted(u8 portb)
72 102
73static inline void assert_TIP(void) 103static inline void assert_TIP(void)
74{ 104{
75 out_8(&via[B], in_8(&via[B]) & ~TIP); 105 if (mcu_is_egret) {
106 udelay(EGRET_SESSION_DELAY);
107 out_8(&via[B], in_8(&via[B]) | TIP);
108 } else
109 out_8(&via[B], in_8(&via[B]) & ~TIP);
110}
111
112static inline void assert_TIP_and_TACK(void)
113{
114 if (mcu_is_egret) {
115 udelay(EGRET_SESSION_DELAY);
116 out_8(&via[B], in_8(&via[B]) | TIP | TACK);
117 } else
118 out_8(&via[B], in_8(&via[B]) & ~(TIP | TACK));
76} 119}
77 120
78static inline void assert_TACK(void) 121static inline void assert_TACK(void)
79{ 122{
80 out_8(&via[B], in_8(&via[B]) & ~TACK); 123 if (mcu_is_egret) {
124 udelay(EGRET_TACK_NEGATED_DELAY);
125 out_8(&via[B], in_8(&via[B]) | TACK);
126 } else
127 out_8(&via[B], in_8(&via[B]) & ~TACK);
81} 128}
82 129
83static inline void toggle_TACK(void) 130static inline void toggle_TACK(void)
@@ -87,12 +134,20 @@ static inline void toggle_TACK(void)
87 134
88static inline void negate_TACK(void) 135static inline void negate_TACK(void)
89{ 136{
90 out_8(&via[B], in_8(&via[B]) | TACK); 137 if (mcu_is_egret) {
138 udelay(EGRET_TACK_ASSERTED_DELAY);
139 out_8(&via[B], in_8(&via[B]) & ~TACK);
140 } else
141 out_8(&via[B], in_8(&via[B]) | TACK);
91} 142}
92 143
93static inline void negate_TIP_and_TACK(void) 144static inline void negate_TIP_and_TACK(void)
94{ 145{
95 out_8(&via[B], in_8(&via[B]) | TIP | TACK); 146 if (mcu_is_egret) {
147 udelay(EGRET_TACK_ASSERTED_DELAY);
148 out_8(&via[B], in_8(&via[B]) & ~(TIP | TACK));
149 } else
150 out_8(&via[B], in_8(&via[B]) | TIP | TACK);
96} 151}
97 152
98static enum cuda_state { 153static enum cuda_state {
@@ -155,6 +210,7 @@ int __init find_via_cuda(void)
155 210
156 via = via1; 211 via = via1;
157 cuda_state = idle; 212 cuda_state = idle;
213 mcu_is_egret = false;
158 214
159 err = cuda_init_via(); 215 err = cuda_init_via();
160 if (err) { 216 if (err) {
@@ -251,7 +307,7 @@ static int __init via_cuda_start(void)
251 return -EAGAIN; 307 return -EAGAIN;
252 } 308 }
253 309
254 pr_info("Macintosh CUDA driver v0.5 for Unified ADB.\n"); 310 pr_info("Macintosh Cuda and Egret driver.\n");
255 311
256 cuda_fully_inited = 1; 312 cuda_fully_inited = 1;
257 return 0; 313 return 0;
@@ -276,6 +332,33 @@ cuda_probe(void)
276} 332}
277#endif /* CONFIG_ADB */ 333#endif /* CONFIG_ADB */
278 334
335static int __init sync_egret(void)
336{
337 if (TREQ_asserted(in_8(&via[B]))) {
338 /* Complete the inbound transfer */
339 assert_TIP_and_TACK();
340 while (1) {
341 negate_TACK();
342 mdelay(1);
343 (void)in_8(&via[SR]);
344 assert_TACK();
345 if (!TREQ_asserted(in_8(&via[B])))
346 break;
347 }
348 negate_TIP_and_TACK();
349 } else if (in_8(&via[B]) & TIP) {
350 /* Terminate the outbound transfer */
351 negate_TACK();
352 assert_TACK();
353 mdelay(1);
354 negate_TIP_and_TACK();
355 }
356 /* Clear shift register interrupt */
357 if (in_8(&via[IFR]) & SR_INT)
358 (void)in_8(&via[SR]);
359 return 0;
360}
361
279#define WAIT_FOR(cond, what) \ 362#define WAIT_FOR(cond, what) \
280 do { \ 363 do { \
281 int x; \ 364 int x; \
@@ -291,10 +374,6 @@ cuda_probe(void)
291static int 374static int
292__init cuda_init_via(void) 375__init cuda_init_via(void)
293{ 376{
294 out_8(&via[DIRB], (in_8(&via[DIRB]) | TACK | TIP) & ~TREQ); /* TACK & TIP out */
295 negate_TIP_and_TACK();
296 out_8(&via[ACR] ,(in_8(&via[ACR]) & ~SR_CTRL) | SR_EXT); /* SR data in */
297 (void)in_8(&via[SR]); /* clear any left-over data */
298#ifdef CONFIG_PPC 377#ifdef CONFIG_PPC
299 out_8(&via[IER], 0x7f); /* disable interrupts from VIA */ 378 out_8(&via[IER], 0x7f); /* disable interrupts from VIA */
300 (void)in_8(&via[IER]); 379 (void)in_8(&via[IER]);
@@ -302,6 +381,15 @@ __init cuda_init_via(void)
302 out_8(&via[IER], SR_INT); /* disable SR interrupt from VIA */ 381 out_8(&via[IER], SR_INT); /* disable SR interrupt from VIA */
303#endif 382#endif
304 383
384 out_8(&via[DIRB], (in_8(&via[DIRB]) | TACK | TIP) & ~TREQ); /* TACK & TIP out */
385 out_8(&via[ACR], (in_8(&via[ACR]) & ~SR_CTRL) | SR_EXT); /* SR data in */
386 (void)in_8(&via[SR]); /* clear any left-over data */
387
388 if (mcu_is_egret)
389 return sync_egret();
390
391 negate_TIP_and_TACK();
392
305 /* delay 4ms and then clear any pending interrupt */ 393 /* delay 4ms and then clear any pending interrupt */
306 mdelay(4); 394 mdelay(4);
307 (void)in_8(&via[SR]); 395 (void)in_8(&via[SR]);
@@ -453,7 +541,10 @@ cuda_start(void)
453 /* set the shift register to shift out and send a byte */ 541 /* set the shift register to shift out and send a byte */
454 out_8(&via[ACR], in_8(&via[ACR]) | SR_OUT); 542 out_8(&via[ACR], in_8(&via[ACR]) | SR_OUT);
455 out_8(&via[SR], current_req->data[data_index++]); 543 out_8(&via[SR], current_req->data[data_index++]);
456 assert_TIP(); 544 if (mcu_is_egret)
545 assert_TIP_and_TACK();
546 else
547 assert_TIP();
457 cuda_state = sent_first_byte; 548 cuda_state = sent_first_byte;
458} 549}
459 550
@@ -500,8 +591,9 @@ cuda_interrupt(int irq, void *arg)
500 591
501 switch (cuda_state) { 592 switch (cuda_state) {
502 case idle: 593 case idle:
503 /* CUDA has sent us the first byte of data - unsolicited */ 594 /* System controller has unsolicited data for us */
504 (void)in_8(&via[SR]); 595 (void)in_8(&via[SR]);
596idle_state:
505 assert_TIP(); 597 assert_TIP();
506 cuda_state = reading; 598 cuda_state = reading;
507 reply_ptr = cuda_rbuf; 599 reply_ptr = cuda_rbuf;
@@ -509,7 +601,7 @@ cuda_interrupt(int irq, void *arg)
509 break; 601 break;
510 602
511 case awaiting_reply: 603 case awaiting_reply:
512 /* CUDA has sent us the first byte of data of a reply */ 604 /* System controller has reply data for us */
513 (void)in_8(&via[SR]); 605 (void)in_8(&via[SR]);
514 assert_TIP(); 606 assert_TIP();
515 cuda_state = reading; 607 cuda_state = reading;
@@ -524,9 +616,14 @@ cuda_interrupt(int irq, void *arg)
524 (void)in_8(&via[SR]); 616 (void)in_8(&via[SR]);
525 negate_TIP_and_TACK(); 617 negate_TIP_and_TACK();
526 cuda_state = idle; 618 cuda_state = idle;
619 /* Egret does not raise an "aborted" interrupt */
620 if (mcu_is_egret)
621 goto idle_state;
527 } else { 622 } else {
528 out_8(&via[SR], current_req->data[data_index++]); 623 out_8(&via[SR], current_req->data[data_index++]);
529 toggle_TACK(); 624 toggle_TACK();
625 if (mcu_is_egret)
626 assert_TACK();
530 cuda_state = sending; 627 cuda_state = sending;
531 } 628 }
532 break; 629 break;
@@ -550,6 +647,8 @@ cuda_interrupt(int irq, void *arg)
550 } else { 647 } else {
551 out_8(&via[SR], req->data[data_index++]); 648 out_8(&via[SR], req->data[data_index++]);
552 toggle_TACK(); 649 toggle_TACK();
650 if (mcu_is_egret)
651 assert_TACK();
553 } 652 }
554 break; 653 break;
555 654
@@ -560,16 +659,24 @@ cuda_interrupt(int irq, void *arg)
560 else 659 else
561 *reply_ptr++ = in_8(&via[SR]); 660 *reply_ptr++ = in_8(&via[SR]);
562 if (!TREQ_asserted(status)) { 661 if (!TREQ_asserted(status)) {
662 if (mcu_is_egret)
663 assert_TACK();
563 /* that's all folks */ 664 /* that's all folks */
564 negate_TIP_and_TACK(); 665 negate_TIP_and_TACK();
565 cuda_state = read_done; 666 cuda_state = read_done;
667 /* Egret does not raise a "read done" interrupt */
668 if (mcu_is_egret)
669 goto read_done_state;
566 } else { 670 } else {
567 toggle_TACK(); 671 toggle_TACK();
672 if (mcu_is_egret)
673 negate_TACK();
568 } 674 }
569 break; 675 break;
570 676
571 case read_done: 677 case read_done:
572 (void)in_8(&via[SR]); 678 (void)in_8(&via[SR]);
679read_done_state:
573 if (reading_reply) { 680 if (reading_reply) {
574 req = current_req; 681 req = current_req;
575 req->reply_len = reply_ptr - req->reply; 682 req->reply_len = reply_ptr - req->reply;
@@ -645,6 +752,12 @@ cuda_input(unsigned char *buf, int nb)
645#endif /* CONFIG_ADB */ 752#endif /* CONFIG_ADB */
646 break; 753 break;
647 754
755 case TIMER_PACKET:
756 /* Egret sends these periodically. Might be useful as a 'heartbeat'
757 * to trigger a recovery for the VIA shift register errata.
758 */
759 break;
760
648 default: 761 default:
649 print_hex_dump(KERN_INFO, "cuda_input: ", DUMP_PREFIX_NONE, 32, 1, 762 print_hex_dump(KERN_INFO, "cuda_input: ", DUMP_PREFIX_NONE, 32, 1,
650 buf, nb, false); 763 buf, nb, false);