summaryrefslogtreecommitdiff
path: root/openpcd
diff options
context:
space:
mode:
author(no author) <(no author)@6dc7ffe9-61d6-0310-9af1-9938baff3ed1>2006-08-23 20:24:39 +0000
committer(no author) <(no author)@6dc7ffe9-61d6-0310-9af1-9938baff3ed1>2006-08-23 20:24:39 +0000
commit2c41370aeb9aa7a15d0dd12374a35240347f39a7 (patch)
treeba2ae29895adcffb30727f0661644886d4b50a55 /openpcd
parent16e8b89e01418f5f78f8b04ab94238df2c06162c (diff)
add SSC code mostly for PICC side. This needs to be separated cleanly later.
git-svn-id: https://svn.openpcd.org:2342/trunk@124 6dc7ffe9-61d6-0310-9af1-9938baff3ed1
Diffstat (limited to 'openpcd')
-rw-r--r--openpcd/firmware/include/AT91SAM7.h6
-rw-r--r--openpcd/firmware/src/ssc.c227
2 files changed, 197 insertions, 36 deletions
diff --git a/openpcd/firmware/include/AT91SAM7.h b/openpcd/firmware/include/AT91SAM7.h
index 2bc8558..56b738e 100644
--- a/openpcd/firmware/include/AT91SAM7.h
+++ b/openpcd/firmware/include/AT91SAM7.h
@@ -841,7 +841,8 @@ typedef struct _AT91S_SSC {
AT91_REG Reserved1[2]; //
AT91_REG SSC_RSHR; // Receive Sync Holding Register
AT91_REG SSC_TSHR; // Transmit Sync Holding Register
- AT91_REG Reserved2[2]; //
+ AT91_REG SSC_RC0R; // Receive Compare 0 Register
+ AT91_REG SSC_RC1R; // Receive Compare 1 Register
AT91_REG SSC_SR; // Status Register
AT91_REG SSC_IER; // Interrupt Enable Register
AT91_REG SSC_IDR; // Interrupt Disable Register
@@ -904,6 +905,7 @@ typedef struct _AT91S_SSC {
// -------- SSC_TCMR : (SSC Offset: 0x18) SSC Transmit Clock Mode Register --------
// -------- SSC_TFMR : (SSC Offset: 0x1c) SSC Transmit Frame Mode Register --------
#define AT91C_SSC_DATDEF ((unsigned int) 0x1 << 5) // (SSC) Data Default Value
+#define AT91C_SSC_MSBF ((unsigned int) 0x1 << 7) // (SSC) MSB First
#define AT91C_SSC_FSDEN ((unsigned int) 0x1 << 23) // (SSC) Frame Sync Data Enable
// -------- SSC_SR : (SSC Offset: 0x40) SSC Status Register --------
#define AT91C_SSC_TXRDY ((unsigned int) 0x1 << 0) // (SSC) Transmit Ready
@@ -914,6 +916,8 @@ typedef struct _AT91S_SSC {
#define AT91C_SSC_OVRUN ((unsigned int) 0x1 << 5) // (SSC) Receive Overrun
#define AT91C_SSC_ENDRX ((unsigned int) 0x1 << 6) // (SSC) End of Reception
#define AT91C_SSC_RXBUFF ((unsigned int) 0x1 << 7) // (SSC) Receive Buffer Full
+#define AT91C_SSC_CP0 ((unsigned int) 0x1 << 8) // (SSC) Compare 0
+#define AT91C_SSC_CP1 ((unsigned int) 0x1 << 9) // (SSC) Compare 1
#define AT91C_SSC_TXSYN ((unsigned int) 0x1 << 10) // (SSC) Transmit Sync
#define AT91C_SSC_RXSYN ((unsigned int) 0x1 << 11) // (SSC) Receive Sync
#define AT91C_SSC_TXENA ((unsigned int) 0x1 << 16) // (SSC) Transmit Enable
diff --git a/openpcd/firmware/src/ssc.c b/openpcd/firmware/src/ssc.c
index e79eda8..1a4de70 100644
--- a/openpcd/firmware/src/ssc.c
+++ b/openpcd/firmware/src/ssc.c
@@ -9,7 +9,9 @@
*/
#include <errno.h>
+#include <string.h>
#include <sys/types.h>
+#include <AT91SAM7.h>
#include <lib_AT91SAM7.h>
#include <openpcd.h>
@@ -17,24 +19,141 @@
#include "openpcd.h"
#include "dbgu.h"
-static AT91PS_SSC ssc = AT91C_BASE_SSC;
+/* definitions for four-times oversampling */
+#define REQA 0x10410441
+#define WUPA 0x04041041
+
+static const AT91PS_SSC ssc = AT91C_BASE_SSC;
static AT91PS_PDC rx_pdc;
+enum ssc_mode {
+ SSC_MODE_14443A_SHORT,
+ SSC_MODE_14443A_STANDARD,
+ SSC_MODE_14443B,
+};
+
struct ssc_state {
struct req_ctx *rx_ctx[2];
+ enum ssc_mode mode;
};
-
static struct ssc_state ssc_state;
+/* This is for four-times oversampling */
+#define ISO14443A_SOF_SAMPLE 0x08
+#define ISO14443A_SOF_LEN 4
+
+static void ssc_rx_mode_set(enum ssc_mode ssc_mode)
+{
+ u_int8_t data_len, num_data, sync_len;
+ u_int32_t start_cond;
+
+ /* disable Rx */
+ ssc->SSC_CR = AT91C_SSC_RXDIS;
+
+ /* disable all Rx related interrupt sources */
+ AT91F_SSC_DisableIt(ssc, ssc->SSC_IDR = AT91C_SSC_RXRDY |
+ AT91C_SSC_OVRUN | AT91C_SSC_ENDRX |
+ AT91C_SSC_RXBUFF | AT91C_SSC_RXSYN |
+ AT91C_SSC_CP0 | AT91C_SSC_CP1);
+
+ switch (ssc_mode) {
+ case SSC_MODE_14443A_SHORT:
+ start_cond = AT91C_SSC_START_0;
+ sync_len = ISO14443A_SOF_LEN;
+ ssc->SSC_RC0R = ISO14443A_SOF_SAMPLE;
+ data_len = 32;
+ num_data = 1;
+ break;
+ case SSC_MODE_14443A_STANDARD:
+ start_cond = AT91C_SSC_START_0;
+ sync_len = ISO14443A_SOF_LEN;
+ ssc->SSC_RC0R = ISO14443A_SOF_SAMPLE;
+ data_len = 1;
+ num_data = 1; /* FIXME */
+ break;
+ case SSC_MODE_14443B:
+ /* start sampling at first falling data edge */
+ //start_cond =
+ break;
+ }
+ ssc->SSC_RFMR = (data_len-1) & 0x1f |
+ (((num_data-1) & 0x0f) << 8) |
+ (((sync_len-1) & 0x0f) << 16);
+ ssc->SSC_RCMR = AT91C_SSC_CKS_RK | AT91C_SSC_CKO_NONE | start_cond;
+
+ /* Enable RX interrupts */
+ AT91F_SSC_EnableIt(ssc, AT91C_SSC_OVRUN);
+ //AT91C_SSC_ENDRX | AT91C_SSC_RXBUFF);
+
+ ssc_state.mode = ssc_mode;
+
+ AT91F_PDC_EnableRx(rx_pdc);
+}
+
+static void ssc_tx_mode_set(enum ssc_mode ssc_mode)
+{
+ u_int8_t data_len, num_data, sync_len;
+ u_int32_t start_cond;
+
+ /* disable Tx */
+ ssc->SSC_CR = AT91C_SSC_TXDIS;
+
+ /* disable all Tx related interrupt sources */
+ ssc->SSC_IDR = AT91C_SSC_TXRDY | AT91C_SSC_TXEMPTY | AT91C_SSC_ENDTX |
+ AT91C_SSC_TXBUFE | AT91C_SSC_TXSYN;
+
+ switch (ssc_mode) {
+ case SSC_MODE_14443A_SHORT:
+ start_cond = AT91C_SSC_START_RISE_RF;
+ sync_len = ISO14443A_SOF_LEN;
+ data_len = 32;
+ num_data = 1;
+ break;
+ case SSC_MODE_14443A_STANDARD:
+ start_cond = AT91C_SSC_START_0;
+ sync_len = ISO14443A_SOF_LEN;
+ ssc->SSC_RC0R = ISO14443A_SOF_SAMPLE;
+ data_len = 1;
+ num_data = 1; /* FIXME */
+ break;
+ }
+ ssc->SSC_TFMR = (data_len-1) & 0x1f |
+ (((num_data-1) & 0x0f) << 8) |
+ (((sync_len-1) & 0x0f) << 16);
+ ssc->SSC_TCMR = AT91C_SSC_CKS_RK | AT91C_SSC_CKO_NONE | start_cond;
+
+#if 0
+ /* Enable RX interrupts */
+ AT91F_SSC_EnableIt(ssc, AT91C_SSC_OVRUN |
+ AT91C_SSC_ENDRX | AT91C_SSC_RXBUFF);
+ AT91F_PDC_EnableRx(rx_pdc);
+
+ ssc_state.mode = ssc_mode;
+#endif
+}
+
+
+
+
static struct openpcd_hdr opcd_ssc_hdr = {
.cmd = OPENPCD_CMD_SSC_READ,
};
static inline void init_opcdhdr(struct req_ctx *rctx)
{
- memcpy(&rctx->tx.data[0], rctx, sizeof(rctx));
+ memcpy(&rctx->tx.data[0], &opcd_ssc_hdr, sizeof(opcd_ssc_hdr));
+ rctx->tx.tot_len = MAX_HDRSIZE + MAX_REQSIZE -1;
}
+#ifdef DEBUG_SSC_REFILL
+#define DEBUGR(x, args ...) DEBUGPCRF(x, ## args)
+#else
+#define DEBUGR(x, args ...)
+#endif
+
+static char dmabuf1[512];
+static char dmabuf2[512];
+
/* Try to refill RX dma descriptors. Return values:
* 0) no dma descriptors empty
* 1) filled next/secondary descriptor
@@ -44,6 +163,7 @@ static inline void init_opcdhdr(struct req_ctx *rctx)
*/
static int8_t ssc_rx_refill(void)
{
+#if 0
struct req_ctx *rctx;
rctx = req_ctx_find_get(RCTX_STATE_FREE, RCTX_STATE_SSC_RX_BUSY);
@@ -51,12 +171,12 @@ static int8_t ssc_rx_refill(void)
DEBUGPCRF("no rctx for refill!");
return -1;
}
+ init_opcdhdr(rctx);
if (AT91F_PDC_IsRxEmpty(rx_pdc)) {
- init_opcdhdr(rctx);
- DEBUGPCRF("filling primary SSC RX dma ctx");
+ DEBUGR("filling primary SSC RX dma ctx");
AT91F_PDC_SetRx(rx_pdc, &rctx->rx.data[MAX_HDRSIZE],
- MAX_REQSIZE);
+ (sizeof(rctx->rx.data)-MAX_HDRSIZE)>>2);
ssc_state.rx_ctx[0] = rctx;
/* If primary is empty, secondary must be empty, too */
@@ -66,13 +186,13 @@ static int8_t ssc_rx_refill(void)
DEBUGPCRF("no rctx for secondary refill!");
return -2;
}
+ init_opcdhdr(rctx);
}
if (AT91F_PDC_IsNextRxEmpty(rx_pdc)) {
- DEBUGPCRF("filling secondary SSC RX dma ctx");
- init_opcdhdr(rctx);
+ DEBUGR("filling secondary SSC RX dma ctx");
AT91F_PDC_SetNextRx(rx_pdc, &rctx->rx.data[MAX_HDRSIZE],
- MAX_REQSIZE);
+ (sizeof(rctx->rx.data)-MAX_HDRSIZE)>2);
ssc_state.rx_ctx[1] = rctx;
return 2;
} else {
@@ -81,48 +201,85 @@ static int8_t ssc_rx_refill(void)
req_ctx_put(rctx);
return 0;
}
+#else
+ if (AT91F_PDC_IsRxEmpty(rx_pdc))
+ AT91F_PDC_SetRx(rx_pdc, dmabuf1, sizeof(dmabuf1)>>2);
+
+ if (AT91F_PDC_IsNextRxEmpty(rx_pdc))
+ AT91F_PDC_SetNextRx(rx_pdc, dmabuf2, sizeof(dmabuf2)>>2);
+ else
+ DEBUGPCRF("prim/secnd DMA busy, can't refill");
+#endif
}
+#define ISO14443A_FDT_SHORT_1 1236
+#define ISO14443A_FDT_SHORT_0 1172
+
static void ssc_irq(void)
{
u_int32_t ssc_sr = ssc->SSC_SR;
- DEBUGPCRF("ssc_sr=0x%08x", ssc_sr);
-
- if (ssc_sr & (AT91C_SSC_ENDRX | AT91C_SSC_TXBUFE)) {
- /* Mark primary RCTX as ready to send for usb */
- req_ctx_set_state(ssc_state.rx_ctx[0],
- RCTX_STATE_UDP_EP2_PENDING);
- /* second buffer gets propagated to primary */
- ssc_state.rx_ctx[0] = ssc_state.rx_ctx[1];
- ssc_state.rx_ctx[1] = NULL;
-
- if (ssc_sr & AT91C_SSC_TXBUFE) {
- DEBUGPCRF("TXBUFE, shouldn't happen!");
- req_ctx_set_state(ssc_state.rx_ctx[0],
+ DEBUGP("ssc_sr=0x%08x: ", ssc_sr);
+
+ if (ssc_sr & AT91C_SSC_OVRUN)
+ DEBUGP("RX OVERRUN ");
+
+ switch (ssc_state.mode) {
+ case SSC_MODE_14443A_SHORT:
+ if (ssc_sr & AT91C_SSC_RXSYN)
+ DEBUGP("RXSYN ");
+ if (ssc_sr & AT91C_SSC_RXRDY) {
+ u_int32_t sample = ssc->SSC_RHR;
+ DEBUGP("RXRDY=0x%08x ", sample);
+ /* Try to set FDT compare register ASAP */
+ if (sample == REQA) {
+ tc_fdt_set(ISO14443A_FDT_SHORT_0);
+ /* FIXME: prepare and configure ATQA response */
+ } else if (sample == WUPA) {
+ tc_fdt_set(ISO14443A_FDT_SHORT_1);
+ /* FIXME: prepare and configure ATQA response */
+ } else
+ DEBUGP("<== unknown ");
+ }
+ break;
+
+ case SSC_MODE_14443A_STANDARD:
+
+ if (ssc_sr & (AT91C_SSC_ENDRX | AT91C_SSC_RXBUFF)) {
+#if 0
+ /* Mark primary RCTX as ready to send for usb */
+ req_ctx_set_state(ssc_state.rx_ctx[0],
RCTX_STATE_UDP_EP2_PENDING);
+ /* second buffer gets propagated to primary */
+ ssc_state.rx_ctx[0] = ssc_state.rx_ctx[1];
+ ssc_state.rx_ctx[1] = NULL;
+#endif
+
+ if (ssc_sr & AT91C_SSC_RXBUFF) {
+ DEBUGPCRF("RXBUFF, shouldn't happen!");
+#if 0
+ req_ctx_set_state(ssc_state.rx_ctx[0],
+ RCTX_STATE_UDP_EP2_PENDING);
+#endif
+ }
+ if (ssc_rx_refill() == -1)
+ AT91F_AIC_DisableIt(ssc, AT91C_SSC_ENDRX |
+ AT91C_SSC_RXBUFF |
+ AT91C_SSC_OVRUN);
}
- if (ssc_rx_refill() == -1)
- AT91F_AIC_DisableIt(ssc, AT91C_SSC_ENDRX |
- AT91C_SSC_TXBUFE |
- AT91C_SSC_OVRUN);
+ break;
}
-
- if (ssc_sr & AT91C_SSC_OVRUN)
- DEBUGPCRF("Rx Overrun, shouldn't happen!");
}
void ssc_rx_unthrottle(void)
{
- AT91F_AIC_EnableIt(ssc, AT91C_SSC_ENDRX |
- AT91C_SSC_TXBUFE | AT91C_SSC_OVRUN);
+ AT91F_SSC_EnableIt(ssc, AT91C_SSC_ENDRX |
+ AT91C_SSC_RXBUFF | AT91C_SSC_OVRUN);
}
void ssc_rx_start(void)
{
DEBUGPCRF("starting SSC RX\n");
- /* 're'fill DMA descriptors */
- //ssc_rx_refill();
/* Enable Reception */
AT91F_SSC_EnableRx(ssc);
@@ -179,8 +336,8 @@ void ssc_rx_init(void)
ssc->SSC_RCMR = AT91C_SSC_CKS_RK | AT91C_SSC_CKO_NONE |
AT91C_SSC_START_CONTINOUS;
- /* Data bits per Data N = 32-1, Data words per Frame = 16-1*/
- ssc->SSC_RFMR = 31 | AT91C_SSC_MSBF | (15 << 8);
+ /* Data bits per Data N = 32-1, Data words per Frame = 15-1 (=60 byte)*/
+ ssc->SSC_RFMR = 31 | AT91C_SSC_MSBF | (14 << 8);
/* Enable RX interrupts */
AT91F_SSC_EnableIt(ssc, AT91C_SSC_OVRUN |
personal git repositories of Harald Welte. Your mileage may vary