diff options
Diffstat (limited to 'drivers/macintosh/via-cuda.c')
-rw-r--r-- | drivers/macintosh/via-cuda.c | 155 |
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 | ||
95 | static bool mcu_is_egret; | ||
96 | #endif | ||
97 | |||
68 | static inline bool TREQ_asserted(u8 portb) | 98 | static 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 | ||
73 | static inline void assert_TIP(void) | 103 | static 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 | |||
112 | static 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 | ||
78 | static inline void assert_TACK(void) | 121 | static 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 | ||
83 | static inline void toggle_TACK(void) | 130 | static inline void toggle_TACK(void) |
@@ -87,12 +134,20 @@ static inline void toggle_TACK(void) | |||
87 | 134 | ||
88 | static inline void negate_TACK(void) | 135 | static 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 | ||
93 | static inline void negate_TIP_and_TACK(void) | 144 | static 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 | ||
98 | static enum cuda_state { | 153 | static 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 | ||
335 | static 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) | |||
291 | static int | 374 | static 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]); |
596 | idle_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]); |
679 | read_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); |