via-cuda: Add TREQ, TIP and TACK signal helpers
Introduce some helpers for handling the signalling between VIA and Cuda. This abstraction will be used to add support for Egret devices, which utilize slightly different signalling. Don't invert the sense of the Cuda's active-low signals when storing them in the 'status' variable. Just assert, negate and test those signals using the helpers. The state machine does not need to test its own output signals to figure out what to do next: the next state depends on the Cuda's TREQ output. Just call the TREQ_asserted() helper function to test for that. Similarly, there is no need to store pin directions in the 'status' variable. That was only useful for debugging messages. Tested-by: Stan Johnson <userm57@yahoo.com> Signed-off-by: Finn Thain <fthain@telegraphics.com.au> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
parent
06d7e99408
commit
fd7a65a27c
|
@ -65,6 +65,36 @@ static DEFINE_SPINLOCK(cuda_lock);
|
||||||
#define IER_CLR 0 /* clear bits in IER */
|
#define IER_CLR 0 /* clear bits in IER */
|
||||||
#define SR_INT 0x04 /* Shift register full/empty */
|
#define SR_INT 0x04 /* Shift register full/empty */
|
||||||
|
|
||||||
|
static inline bool TREQ_asserted(u8 portb)
|
||||||
|
{
|
||||||
|
return !(portb & TREQ);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void assert_TIP(void)
|
||||||
|
{
|
||||||
|
out_8(&via[B], in_8(&via[B]) & ~TIP);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void assert_TACK(void)
|
||||||
|
{
|
||||||
|
out_8(&via[B], in_8(&via[B]) & ~TACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void toggle_TACK(void)
|
||||||
|
{
|
||||||
|
out_8(&via[B], in_8(&via[B]) ^ TACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void negate_TACK(void)
|
||||||
|
{
|
||||||
|
out_8(&via[B], in_8(&via[B]) | TACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void negate_TIP_and_TACK(void)
|
||||||
|
{
|
||||||
|
out_8(&via[B], in_8(&via[B]) | TIP | TACK);
|
||||||
|
}
|
||||||
|
|
||||||
static enum cuda_state {
|
static enum cuda_state {
|
||||||
idle,
|
idle,
|
||||||
sent_first_byte,
|
sent_first_byte,
|
||||||
|
@ -262,7 +292,7 @@ static int
|
||||||
__init cuda_init_via(void)
|
__init cuda_init_via(void)
|
||||||
{
|
{
|
||||||
out_8(&via[DIRB], (in_8(&via[DIRB]) | TACK | TIP) & ~TREQ); /* TACK & TIP out */
|
out_8(&via[DIRB], (in_8(&via[DIRB]) | TACK | TIP) & ~TREQ); /* TACK & TIP out */
|
||||||
out_8(&via[B], in_8(&via[B]) | TACK | TIP); /* negate them */
|
negate_TIP_and_TACK();
|
||||||
out_8(&via[ACR] ,(in_8(&via[ACR]) & ~SR_CTRL) | SR_EXT); /* SR data in */
|
out_8(&via[ACR] ,(in_8(&via[ACR]) & ~SR_CTRL) | SR_EXT); /* SR data in */
|
||||||
(void)in_8(&via[SR]); /* clear any left-over data */
|
(void)in_8(&via[SR]); /* clear any left-over data */
|
||||||
#ifdef CONFIG_PPC
|
#ifdef CONFIG_PPC
|
||||||
|
@ -278,10 +308,10 @@ __init cuda_init_via(void)
|
||||||
out_8(&via[IFR], SR_INT);
|
out_8(&via[IFR], SR_INT);
|
||||||
|
|
||||||
/* sync with the CUDA - assert TACK without TIP */
|
/* sync with the CUDA - assert TACK without TIP */
|
||||||
out_8(&via[B], in_8(&via[B]) & ~TACK);
|
assert_TACK();
|
||||||
|
|
||||||
/* wait for the CUDA to assert TREQ in response */
|
/* wait for the CUDA to assert TREQ in response */
|
||||||
WAIT_FOR((in_8(&via[B]) & TREQ) == 0, "CUDA response to sync");
|
WAIT_FOR(TREQ_asserted(in_8(&via[B])), "CUDA response to sync");
|
||||||
|
|
||||||
/* wait for the interrupt and then clear it */
|
/* wait for the interrupt and then clear it */
|
||||||
WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (2)");
|
WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (2)");
|
||||||
|
@ -289,14 +319,13 @@ __init cuda_init_via(void)
|
||||||
out_8(&via[IFR], SR_INT);
|
out_8(&via[IFR], SR_INT);
|
||||||
|
|
||||||
/* finish the sync by negating TACK */
|
/* finish the sync by negating TACK */
|
||||||
out_8(&via[B], in_8(&via[B]) | TACK);
|
negate_TACK();
|
||||||
|
|
||||||
/* wait for the CUDA to negate TREQ and the corresponding interrupt */
|
/* wait for the CUDA to negate TREQ and the corresponding interrupt */
|
||||||
WAIT_FOR(in_8(&via[B]) & TREQ, "CUDA response to sync (3)");
|
WAIT_FOR(!TREQ_asserted(in_8(&via[B])), "CUDA response to sync (3)");
|
||||||
WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (4)");
|
WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (4)");
|
||||||
(void)in_8(&via[SR]);
|
(void)in_8(&via[SR]);
|
||||||
out_8(&via[IFR], SR_INT);
|
out_8(&via[IFR], SR_INT);
|
||||||
out_8(&via[B], in_8(&via[B]) | TIP); /* should be unnecessary */
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -417,13 +446,13 @@ cuda_start(void)
|
||||||
/* assert cuda_state == idle */
|
/* assert cuda_state == idle */
|
||||||
if (current_req == NULL)
|
if (current_req == NULL)
|
||||||
return;
|
return;
|
||||||
if ((in_8(&via[B]) & TREQ) == 0)
|
if (TREQ_asserted(in_8(&via[B])))
|
||||||
return; /* a byte is coming in from the CUDA */
|
return; /* a byte is coming in from the CUDA */
|
||||||
|
|
||||||
/* set the shift register to shift out and send a byte */
|
/* set the shift register to shift out and send a byte */
|
||||||
out_8(&via[ACR], in_8(&via[ACR]) | SR_OUT);
|
out_8(&via[ACR], in_8(&via[ACR]) | SR_OUT);
|
||||||
out_8(&via[SR], current_req->data[0]);
|
out_8(&via[SR], current_req->data[0]);
|
||||||
out_8(&via[B], in_8(&via[B]) & ~TIP);
|
assert_TIP();
|
||||||
cuda_state = sent_first_byte;
|
cuda_state = sent_first_byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,7 +473,7 @@ EXPORT_SYMBOL(cuda_poll);
|
||||||
static irqreturn_t
|
static irqreturn_t
|
||||||
cuda_interrupt(int irq, void *arg)
|
cuda_interrupt(int irq, void *arg)
|
||||||
{
|
{
|
||||||
int status;
|
u8 status;
|
||||||
struct adb_request *req = NULL;
|
struct adb_request *req = NULL;
|
||||||
unsigned char ibuf[16];
|
unsigned char ibuf[16];
|
||||||
int ibuf_len = 0;
|
int ibuf_len = 0;
|
||||||
|
@ -469,13 +498,14 @@ cuda_interrupt(int irq, void *arg)
|
||||||
out_8(&via[IFR], SR_INT);
|
out_8(&via[IFR], SR_INT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
status = (~in_8(&via[B]) & (TIP|TREQ)) | (in_8(&via[ACR]) & SR_OUT);
|
status = in_8(&via[B]) & (TIP | TACK | TREQ);
|
||||||
|
|
||||||
switch (cuda_state) {
|
switch (cuda_state) {
|
||||||
case idle:
|
case idle:
|
||||||
/* CUDA has sent us the first byte of data - unsolicited */
|
/* CUDA has sent us the first byte of data - unsolicited */
|
||||||
(void)in_8(&via[SR]);
|
(void)in_8(&via[SR]);
|
||||||
out_8(&via[B], in_8(&via[B]) & ~TIP);
|
assert_TIP();
|
||||||
cuda_state = reading;
|
cuda_state = reading;
|
||||||
reply_ptr = cuda_rbuf;
|
reply_ptr = cuda_rbuf;
|
||||||
reading_reply = 0;
|
reading_reply = 0;
|
||||||
|
@ -484,22 +514,22 @@ cuda_interrupt(int irq, void *arg)
|
||||||
case awaiting_reply:
|
case awaiting_reply:
|
||||||
/* CUDA has sent us the first byte of data of a reply */
|
/* CUDA has sent us the first byte of data of a reply */
|
||||||
(void)in_8(&via[SR]);
|
(void)in_8(&via[SR]);
|
||||||
out_8(&via[B], in_8(&via[B]) & ~TIP);
|
assert_TIP();
|
||||||
cuda_state = reading;
|
cuda_state = reading;
|
||||||
reply_ptr = current_req->reply;
|
reply_ptr = current_req->reply;
|
||||||
reading_reply = 1;
|
reading_reply = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case sent_first_byte:
|
case sent_first_byte:
|
||||||
if (status == TREQ + TIP + SR_OUT) {
|
if (TREQ_asserted(status)) {
|
||||||
/* collision */
|
/* collision */
|
||||||
out_8(&via[ACR], in_8(&via[ACR]) & ~SR_OUT);
|
out_8(&via[ACR], in_8(&via[ACR]) & ~SR_OUT);
|
||||||
(void)in_8(&via[SR]);
|
(void)in_8(&via[SR]);
|
||||||
out_8(&via[B], in_8(&via[B]) | TIP | TACK);
|
negate_TIP_and_TACK();
|
||||||
cuda_state = idle;
|
cuda_state = idle;
|
||||||
} else {
|
} else {
|
||||||
out_8(&via[SR], current_req->data[1]);
|
out_8(&via[SR], current_req->data[1]);
|
||||||
out_8(&via[B], in_8(&via[B]) ^ TACK);
|
toggle_TACK();
|
||||||
data_index = 2;
|
data_index = 2;
|
||||||
cuda_state = sending;
|
cuda_state = sending;
|
||||||
}
|
}
|
||||||
|
@ -510,7 +540,7 @@ cuda_interrupt(int irq, void *arg)
|
||||||
if (data_index >= req->nbytes) {
|
if (data_index >= req->nbytes) {
|
||||||
out_8(&via[ACR], in_8(&via[ACR]) & ~SR_OUT);
|
out_8(&via[ACR], in_8(&via[ACR]) & ~SR_OUT);
|
||||||
(void)in_8(&via[SR]);
|
(void)in_8(&via[SR]);
|
||||||
out_8(&via[B], in_8(&via[B]) | TACK | TIP);
|
negate_TIP_and_TACK();
|
||||||
req->sent = 1;
|
req->sent = 1;
|
||||||
if (req->reply_expected) {
|
if (req->reply_expected) {
|
||||||
cuda_state = awaiting_reply;
|
cuda_state = awaiting_reply;
|
||||||
|
@ -523,18 +553,18 @@ cuda_interrupt(int irq, void *arg)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
out_8(&via[SR], req->data[data_index++]);
|
out_8(&via[SR], req->data[data_index++]);
|
||||||
out_8(&via[B], in_8(&via[B]) ^ TACK);
|
toggle_TACK();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case reading:
|
case reading:
|
||||||
*reply_ptr++ = in_8(&via[SR]);
|
*reply_ptr++ = in_8(&via[SR]);
|
||||||
if (status == TIP) {
|
if (!TREQ_asserted(status)) {
|
||||||
/* that's all folks */
|
/* that's all folks */
|
||||||
out_8(&via[B], in_8(&via[B]) | TACK | TIP);
|
negate_TIP_and_TACK();
|
||||||
cuda_state = read_done;
|
cuda_state = read_done;
|
||||||
} else {
|
} else {
|
||||||
out_8(&via[B], in_8(&via[B]) ^ TACK);
|
toggle_TACK();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -567,8 +597,8 @@ cuda_interrupt(int irq, void *arg)
|
||||||
ibuf_len = reply_ptr - cuda_rbuf;
|
ibuf_len = reply_ptr - cuda_rbuf;
|
||||||
memcpy(ibuf, cuda_rbuf, ibuf_len);
|
memcpy(ibuf, cuda_rbuf, ibuf_len);
|
||||||
}
|
}
|
||||||
if (status == TREQ) {
|
if (TREQ_asserted(status)) {
|
||||||
out_8(&via[B], in_8(&via[B]) & ~TIP);
|
assert_TIP();
|
||||||
cuda_state = reading;
|
cuda_state = reading;
|
||||||
reply_ptr = cuda_rbuf;
|
reply_ptr = cuda_rbuf;
|
||||||
reading_reply = 0;
|
reading_reply = 0;
|
||||||
|
|
Loading…
Reference in New Issue