Skip to content

Commit d23eee8

Browse files
Finn Thainmpe
authored andcommitted
via-cuda: Add support for Egret system controller
The Egret system controller was the predecessor to the Cuda and the differences are minor. On Cuda, byte acknowledgement requires one transition of the TACK signal; on Egret two are needed. On Cuda, TIP is active low; on Egret it is active high. And Cuda raises certain interrupts that Egret omits. Accomodating these differences complicates the Cuda driver slightly but avoids a lot of duplication (see next patch). Tested-by: Stan Johnson <[email protected]> Signed-off-by: Finn Thain <[email protected]> Signed-off-by: Michael Ellerman <[email protected]>
1 parent 97ced1a commit d23eee8

File tree

1 file changed

+134
-21
lines changed

1 file changed

+134
-21
lines changed

drivers/macintosh/via-cuda.c

Lines changed: 134 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
/*
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.
34
*
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.
88
*
99
* Copyright (C) 1996 Paul Mackerras.
1010
*/
@@ -50,10 +50,27 @@ static DEFINE_SPINLOCK(cuda_lock);
5050
#define IER (14*RS) /* Interrupt enable register */
5151
#define ANH (15*RS) /* A-side data, no handshake */
5252

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 */
5774

5875
/* Bits in ACR */
5976
#define SR_CTRL 0x1c /* Shift register control bits */
@@ -65,19 +82,49 @@ static DEFINE_SPINLOCK(cuda_lock);
6582
#define IER_CLR 0 /* clear bits in IER */
6683
#define SR_INT 0x04 /* Shift register full/empty */
6784

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+
6898
static inline bool TREQ_asserted(u8 portb)
6999
{
70100
return !(portb & TREQ);
71101
}
72102

73103
static inline void assert_TIP(void)
74104
{
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));
76119
}
77120

78121
static inline void assert_TACK(void)
79122
{
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);
81128
}
82129

83130
static inline void toggle_TACK(void)
@@ -87,12 +134,20 @@ static inline void toggle_TACK(void)
87134

88135
static inline void negate_TACK(void)
89136
{
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);
91142
}
92143

93144
static inline void negate_TIP_and_TACK(void)
94145
{
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);
96151
}
97152

98153
static enum cuda_state {
@@ -155,6 +210,7 @@ int __init find_via_cuda(void)
155210

156211
via = via1;
157212
cuda_state = idle;
213+
mcu_is_egret = false;
158214

159215
err = cuda_init_via();
160216
if (err) {
@@ -251,7 +307,7 @@ static int __init via_cuda_start(void)
251307
return -EAGAIN;
252308
}
253309

254-
pr_info("Macintosh CUDA driver v0.5 for Unified ADB.\n");
310+
pr_info("Macintosh Cuda and Egret driver.\n");
255311

256312
cuda_fully_inited = 1;
257313
return 0;
@@ -276,6 +332,33 @@ cuda_probe(void)
276332
}
277333
#endif /* CONFIG_ADB */
278334

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+
279362
#define WAIT_FOR(cond, what) \
280363
do { \
281364
int x; \
@@ -291,17 +374,22 @@ cuda_probe(void)
291374
static int
292375
__init cuda_init_via(void)
293376
{
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 */
298377
#ifdef CONFIG_PPC
299378
out_8(&via[IER], 0x7f); /* disable interrupts from VIA */
300379
(void)in_8(&via[IER]);
301380
#else
302381
out_8(&via[IER], SR_INT); /* disable SR interrupt from VIA */
303382
#endif
304383

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+
305393
/* delay 4ms and then clear any pending interrupt */
306394
mdelay(4);
307395
(void)in_8(&via[SR]);
@@ -453,7 +541,10 @@ cuda_start(void)
453541
/* set the shift register to shift out and send a byte */
454542
out_8(&via[ACR], in_8(&via[ACR]) | SR_OUT);
455543
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();
457548
cuda_state = sent_first_byte;
458549
}
459550

@@ -500,16 +591,17 @@ cuda_interrupt(int irq, void *arg)
500591

501592
switch (cuda_state) {
502593
case idle:
503-
/* CUDA has sent us the first byte of data - unsolicited */
594+
/* System controller has unsolicited data for us */
504595
(void)in_8(&via[SR]);
596+
idle_state:
505597
assert_TIP();
506598
cuda_state = reading;
507599
reply_ptr = cuda_rbuf;
508600
reading_reply = 0;
509601
break;
510602

511603
case awaiting_reply:
512-
/* CUDA has sent us the first byte of data of a reply */
604+
/* System controller has reply data for us */
513605
(void)in_8(&via[SR]);
514606
assert_TIP();
515607
cuda_state = reading;
@@ -524,9 +616,14 @@ cuda_interrupt(int irq, void *arg)
524616
(void)in_8(&via[SR]);
525617
negate_TIP_and_TACK();
526618
cuda_state = idle;
619+
/* Egret does not raise an "aborted" interrupt */
620+
if (mcu_is_egret)
621+
goto idle_state;
527622
} else {
528623
out_8(&via[SR], current_req->data[data_index++]);
529624
toggle_TACK();
625+
if (mcu_is_egret)
626+
assert_TACK();
530627
cuda_state = sending;
531628
}
532629
break;
@@ -550,6 +647,8 @@ cuda_interrupt(int irq, void *arg)
550647
} else {
551648
out_8(&via[SR], req->data[data_index++]);
552649
toggle_TACK();
650+
if (mcu_is_egret)
651+
assert_TACK();
553652
}
554653
break;
555654

@@ -560,16 +659,24 @@ cuda_interrupt(int irq, void *arg)
560659
else
561660
*reply_ptr++ = in_8(&via[SR]);
562661
if (!TREQ_asserted(status)) {
662+
if (mcu_is_egret)
663+
assert_TACK();
563664
/* that's all folks */
564665
negate_TIP_and_TACK();
565666
cuda_state = read_done;
667+
/* Egret does not raise a "read done" interrupt */
668+
if (mcu_is_egret)
669+
goto read_done_state;
566670
} else {
567671
toggle_TACK();
672+
if (mcu_is_egret)
673+
negate_TACK();
568674
}
569675
break;
570676

571677
case read_done:
572678
(void)in_8(&via[SR]);
679+
read_done_state:
573680
if (reading_reply) {
574681
req = current_req;
575682
req->reply_len = reply_ptr - req->reply;
@@ -645,6 +752,12 @@ cuda_input(unsigned char *buf, int nb)
645752
#endif /* CONFIG_ADB */
646753
break;
647754

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+
648761
default:
649762
print_hex_dump(KERN_INFO, "cuda_input: ", DUMP_PREFIX_NONE, 32, 1,
650763
buf, nb, false);

0 commit comments

Comments
 (0)