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
- * a 6805 microprocessor core which controls the ADB (Apple Desktop
6
- * Bus) which connects to the keyboard and mouse. The CUDA also
7
- * controls system power and the RTC (real time clock) chip.
5
+ * The Cuda or Egret is a 6805 microcontroller interfaced to the 6522 VIA.
6
+ * This MCU controls system power, Parameter RAM, Real Time Clock and the
7
+ * Apple Desktop Bus (ADB) that connects to the keyboard and mouse.
8
8
*
9
9
* Copyright (C) 1996 Paul Mackerras.
10
10
*/
@@ -50,10 +50,27 @@ static DEFINE_SPINLOCK(cuda_lock);
50
50
#define IER (14*RS) /* Interrupt enable register */
51
51
#define ANH (15*RS) /* A-side data, no handshake */
52
52
53
- /* Bits in B data register: all active low */
54
- #define TREQ 0x08 /* Transfer request (input) */
55
- #define TACK 0x10 /* Transfer acknowledge (output) */
56
- #define TIP 0x20 /* Transfer in progress (output) */
53
+ /*
54
+ * When the Cuda design replaced the Egret, some signal names and
55
+ * logic sense changed. They all serve the same purposes, however.
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
75
/* Bits in ACR */
59
76
#define SR_CTRL 0x1c /* Shift register control bits */
@@ -65,19 +82,49 @@ static DEFINE_SPINLOCK(cuda_lock);
65
82
#define IER_CLR 0 /* clear bits in IER */
66
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
98
static inline bool TREQ_asserted (u8 portb )
69
99
{
70
100
return !(portb & TREQ );
71
101
}
72
102
73
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
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
130
static inline void toggle_TACK (void )
@@ -87,12 +134,20 @@ static inline void toggle_TACK(void)
87
134
88
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
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
153
static enum cuda_state {
@@ -155,6 +210,7 @@ int __init find_via_cuda(void)
155
210
156
211
via = via1 ;
157
212
cuda_state = idle ;
213
+ mcu_is_egret = false;
158
214
159
215
err = cuda_init_via ();
160
216
if (err ) {
@@ -251,7 +307,7 @@ static int __init via_cuda_start(void)
251
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
312
cuda_fully_inited = 1 ;
257
313
return 0 ;
@@ -276,6 +332,33 @@ cuda_probe(void)
276
332
}
277
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
362
#define WAIT_FOR (cond , what ) \
280
363
do { \
281
364
int x; \
@@ -291,17 +374,22 @@ cuda_probe(void)
291
374
static int
292
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
377
#ifdef CONFIG_PPC
299
378
out_8 (& via [IER ], 0x7f ); /* disable interrupts from VIA */
300
379
(void )in_8 (& via [IER ]);
301
380
#else
302
381
out_8 (& via [IER ], SR_INT ); /* disable SR interrupt from VIA */
303
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
393
/* delay 4ms and then clear any pending interrupt */
306
394
mdelay (4 );
307
395
(void )in_8 (& via [SR ]);
@@ -453,7 +541,10 @@ cuda_start(void)
453
541
/* set the shift register to shift out and send a byte */
454
542
out_8 (& via [ACR ], in_8 (& via [ACR ]) | SR_OUT );
455
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
548
cuda_state = sent_first_byte ;
458
549
}
459
550
@@ -500,16 +591,17 @@ cuda_interrupt(int irq, void *arg)
500
591
501
592
switch (cuda_state ) {
502
593
case idle :
503
- /* CUDA has sent us the first byte of data - unsolicited */
594
+ /* System controller has unsolicited data for us */
504
595
(void )in_8 (& via [SR ]);
596
+ idle_state :
505
597
assert_TIP ();
506
598
cuda_state = reading ;
507
599
reply_ptr = cuda_rbuf ;
508
600
reading_reply = 0 ;
509
601
break ;
510
602
511
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
605
(void )in_8 (& via [SR ]);
514
606
assert_TIP ();
515
607
cuda_state = reading ;
@@ -524,9 +616,14 @@ cuda_interrupt(int irq, void *arg)
524
616
(void )in_8 (& via [SR ]);
525
617
negate_TIP_and_TACK ();
526
618
cuda_state = idle ;
619
+ /* Egret does not raise an "aborted" interrupt */
620
+ if (mcu_is_egret )
621
+ goto idle_state ;
527
622
} else {
528
623
out_8 (& via [SR ], current_req -> data [data_index ++ ]);
529
624
toggle_TACK ();
625
+ if (mcu_is_egret )
626
+ assert_TACK ();
530
627
cuda_state = sending ;
531
628
}
532
629
break ;
@@ -550,6 +647,8 @@ cuda_interrupt(int irq, void *arg)
550
647
} else {
551
648
out_8 (& via [SR ], req -> data [data_index ++ ]);
552
649
toggle_TACK ();
650
+ if (mcu_is_egret )
651
+ assert_TACK ();
553
652
}
554
653
break ;
555
654
@@ -560,16 +659,24 @@ cuda_interrupt(int irq, void *arg)
560
659
else
561
660
* reply_ptr ++ = in_8 (& via [SR ]);
562
661
if (!TREQ_asserted (status )) {
662
+ if (mcu_is_egret )
663
+ assert_TACK ();
563
664
/* that's all folks */
564
665
negate_TIP_and_TACK ();
565
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
670
} else {
567
671
toggle_TACK ();
672
+ if (mcu_is_egret )
673
+ negate_TACK ();
568
674
}
569
675
break ;
570
676
571
677
case read_done :
572
678
(void )in_8 (& via [SR ]);
679
+ read_done_state :
573
680
if (reading_reply ) {
574
681
req = current_req ;
575
682
req -> reply_len = reply_ptr - req -> reply ;
@@ -645,6 +752,12 @@ cuda_input(unsigned char *buf, int nb)
645
752
#endif /* CONFIG_ADB */
646
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
761
default :
649
762
print_hex_dump (KERN_INFO , "cuda_input: " , DUMP_PREFIX_NONE , 32 , 1 ,
650
763
buf , nb , false);
0 commit comments