summaryrefslogtreecommitdiff
path: root/openpcd
diff options
context:
space:
mode:
author(no author) <(no author)@6dc7ffe9-61d6-0310-9af1-9938baff3ed1>2006-08-08 20:12:50 +0000
committer(no author) <(no author)@6dc7ffe9-61d6-0310-9af1-9938baff3ed1>2006-08-08 20:12:50 +0000
commit7907a1087e02fca450df732aa664f3dc6c0f9252 (patch)
tree3c24c6cb8acf31a243919fbbacf2ae0739068b69 /openpcd
parentbc7d72bf05d8e84c207f9be30abab23b3023408f (diff)
add SSC code
git-svn-id: https://svn.openpcd.org:2342/trunk@88 6dc7ffe9-61d6-0310-9af1-9938baff3ed1
Diffstat (limited to 'openpcd')
-rw-r--r--openpcd/firmware/Makefile2
-rw-r--r--openpcd/firmware/src/ssc.c157
-rw-r--r--openpcd/firmware/src/ssc.h13
3 files changed, 171 insertions, 1 deletions
diff --git a/openpcd/firmware/Makefile b/openpcd/firmware/Makefile
index f9bc515..387a1c0 100644
--- a/openpcd/firmware/Makefile
+++ b/openpcd/firmware/Makefile
@@ -75,7 +75,7 @@ SRC =
SRCARM = lib/lib_AT91SAM7.c src/pcd_enumerate.c src/fifo.c src/dbgu.c \
src/led.c src/rc632.c src/rc632_highlevel.c src/req_ctx.c \
src/trigger.c src/main.c src/syscalls.c src/pwm.c src/tc.c \
- src/usb_handler.c \
+ src/usb_handler.c src/ssc.c \
src/$(TARGET).c src/start/Cstartup_SAM7.c
SRCARM += src/rfid_layer2_iso14443a.c
diff --git a/openpcd/firmware/src/ssc.c b/openpcd/firmware/src/ssc.c
new file mode 100644
index 0000000..5be7171
--- /dev/null
+++ b/openpcd/firmware/src/ssc.c
@@ -0,0 +1,157 @@
+/* AT91SAM7 SSC controller routines for OpenPCD
+ * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
+ *
+ * We use SSC for both TX and RX side.
+ *
+ * RX side is interconnected with MFOUT of RC632
+ *
+ * TX side is interconnected with MFIN of RC632
+ */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <lib_AT91SAM7.h>
+
+#include "openpcd.h"
+#include "dbgu.h"
+
+static AT91PS_SSC ssc = AT91C_BASE_SSC;
+static AT91PS_PDC rx_pdc;
+
+struct ssc_state {
+ struct req_ctx *rx_ctx[2];
+};
+
+static struct ssc_state ssc_state;
+
+/* Try to refill RX dma descriptors. Return values:
+ * 0) no dma descriptors empty
+ * 1) filled next/secondary descriptor
+ * 2) filled both primary and secondary descriptor
+ * -1) no free request contexts to use
+ * -2) only one free request context, but two free descriptors
+ */
+static int8_t ssc_rx_refill(void)
+{
+ struct req_ctx *rctx;
+
+ rctx = req_ctx_find_get(RCTX_STATE_FREE, RCTX_STATE_SSC_RX_BUSY);
+ if (!rctx) {
+ DEBUGPCRF("no rctx for refill!");
+ return -1;
+ }
+
+ if (AT91F_PDC_IsRxEmpty(rx_pdc)) {
+ DEBUGPCRF("filling primary SSC RX dma ctx");
+ AT91F_PDC_SetRx(rx_pdc, &rctx->rx.data[MAX_HDRSIZE],
+ MAX_REQSIZE);
+ ssc_state.rx_ctx[0] = rctx;
+
+ /* If primary is empty, secondary must be empty, too */
+ rctx = req_ctx_find_get(RCTX_STATE_FREE,
+ RCTX_STATE_SSC_RX_BUSY);
+ if (!rctx) {
+ DEBUGPCRF("no rctx for secondary refill!");
+ return -2;
+ }
+ }
+
+ if (AT91F_PDC_IsNextRxEmpty(rx_pdc)) {
+ DEBUGPCRF("filling secondary SSC RX dma ctx");
+ AT91F_PDC_SetNextRx(rx_pdc, &rctx->rx.data[MAX_HDRSIZE],
+ MAX_REQSIZE);
+ ssc_state.rx_ctx[1] = rctx;
+ return 2;
+ } else {
+ /* we were unable to fill*/
+ DEBUGPCRF("prim/secnd DMA busy, can't refill");
+ req_ctx_put(rctx);
+ return 0;
+ }
+}
+
+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],
+ RCTX_STATE_UDP_EP2_PENDING);
+ }
+ ssc_rx_refill();
+ }
+
+ if (ssc_sr & AT91C_SSC_OVRUN)
+ DEBUGPCRF("Rx Overrun, shouldn't happen!");
+}
+
+void ssc_rx_start(void)
+{
+ DEBUGPCRF("starting SSC RX\n");
+ /* 're'fill DMA descriptors */
+ //ssc_rx_refill();
+
+ /* Enable Reception */
+ AT91F_SSC_EnableRx(ssc);
+}
+
+void ssc_rx_stop(void)
+{
+ /* Disable reception */
+ AT91F_SSC_DisableRx(ssc);
+}
+
+void ssc_tx_init(void)
+{
+ /* IMPORTANT: Disable PA23 (PWM0) output, since it is connected to
+ * PA17 !! */
+ AT91F_PIO_CfgInput(AT91C_BASE_PIOA, OPENPCD_PIO_MFIN_PWM);
+ AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, OPENPCD_PIO_MFIN_SSC_TX |
+ OPENPCD_PIO_MFOUT_SSC_RX | OPENPCD_PIO_SSP_CKIN,
+ 0);
+}
+
+void ssc_rx_init(void)
+{
+ rx_pdc = (AT91PS_PDC) &(ssc->SSC_RPR);
+
+ AT91F_SSC_CfgPMC();
+ AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_SSC,
+ OPENPCD_IRQ_PRIO_SSC,
+ AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, &ssc_irq);
+ AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_SSC);
+
+ /* Reset */
+ ssc->SSC_CR = AT91C_SSC_SWRST;
+
+ /* don't divide clock */
+ ssc->SSC_CMR = 0;
+
+ 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);
+
+ /* Enable RX interrupts */
+ AT91F_SSC_EnableIt(ssc, AT91C_SSC_OVRUN |
+ AT91C_SSC_ENDRX | AT91C_SSC_RXBUFF);
+}
+
+void ssc_fini(void)
+{
+ AT91F_SSC_DisableTx(ssc);
+ AT91F_SSC_DisableRx(ssc);
+ AT91F_SSC_DisableIt(ssc, 0xfff);
+ AT91F_PMC_DisablePeriphClock(AT91C_BASE_PMC,
+ ((unsigned int) 1 << AT91C_ID_SSC));
+}
diff --git a/openpcd/firmware/src/ssc.h b/openpcd/firmware/src/ssc.h
new file mode 100644
index 0000000..73450ab
--- /dev/null
+++ b/openpcd/firmware/src/ssc.h
@@ -0,0 +1,13 @@
+#ifndef _SSC_H
+#define _SSC_H
+
+extern void ssc_rx_start(void);
+extern void ssc_rx_stop(void);
+
+/* Rx/Tx initialization separate, since Tx disables PWM output ! */
+extern void ssc_tx_init(void);
+extern void ssc_rx_init(void);
+
+extern void ssc_fini(void);
+
+#endif
personal git repositories of Harald Welte. Your mileage may vary