summaryrefslogtreecommitdiff
path: root/openpicc
diff options
context:
space:
mode:
Diffstat (limited to 'openpicc')
-rw-r--r--openpicc/application/pio_irq.c2
-rw-r--r--openpicc/application/ssc_picc.c45
-rw-r--r--openpicc/config/board.h1
-rw-r--r--openpicc/os/boot/boot.s24
4 files changed, 65 insertions, 7 deletions
diff --git a/openpicc/application/pio_irq.c b/openpicc/application/pio_irq.c
index 5359bbf..3a753d4 100644
--- a/openpicc/application/pio_irq.c
+++ b/openpicc/application/pio_irq.c
@@ -68,7 +68,7 @@ extern void fiq_handler(void);
/* Will be used in pio_irq_demux_secondary below and contains the PIO_ISR value
* from when the FIQ was raised */
-u_int32_t pio_irq_isr_value;
+volatile u_int32_t pio_irq_isr_value;
/* low-level handler, used by Cstartup_app.S PIOA fast forcing and
diff --git a/openpicc/application/ssc_picc.c b/openpicc/application/ssc_picc.c
index de2121d..a5f1075 100644
--- a/openpicc/application/ssc_picc.c
+++ b/openpicc/application/ssc_picc.c
@@ -44,6 +44,7 @@
#include "tc_cdiv_sync.h"
#include "tc_fdt.h"
+#include "pio_irq.h"
#include "usb_print.h"
#include "iso14443_layer3a.h"
@@ -170,6 +171,14 @@ out_set_mode:
ssc_state.mode = ssc_mode;
}
+/* For some reason AT91C_SSC_START_RISE_RF (or AT91C_SSC_START_HIGH_RF or ...) doesn't
+ * work as a start condition. Instead we'll configure TF as a PIO input pin, enable
+ * a PIO change interrupt, have Fast Forcing enabled for the PIO change interrupt and
+ * then activate the SSC TX in the FIQ handler on rising TF. ssc_tx_pending is queried
+ * by the fiq handler to see whether to start the transmitter. */
+#define USE_SSC_TX_TF_WORKAROUND
+volatile u_int32_t ssc_tx_pending = 0;
+void ssc_tf_irq(u_int32_t pio);
void ssc_tx_start(ssc_dma_tx_buffer_t *buf)
{
u_int8_t data_len, num_data, sync_len;
@@ -181,16 +190,19 @@ void ssc_tx_start(ssc_dma_tx_buffer_t *buf)
/* disable all Tx related interrupt sources */
AT91F_SSC_DisableIt(ssc, SSC_TX_IRQ_MASK);
+#ifdef USE_SSC_TX_TF_WORKAROUND
+ start_cond = AT91C_SSC_START_CONTINOUS;
+#else
start_cond = AT91C_SSC_START_RISE_RF;
- sync_len = 0;
- ssc->SSC_RC0R = 0;
+#endif
+ sync_len = 1;
data_len = 32;
num_data = buf->len/(data_len/8); /* FIXME This is broken for more than 64 bytes */
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;
+ ssc->SSC_TCMR = 0x01 | AT91C_SSC_CKO_NONE | start_cond;
AT91F_PDC_SetTx(tx_pdc, buf->data, num_data);
@@ -200,10 +212,28 @@ void ssc_tx_start(ssc_dma_tx_buffer_t *buf)
/* Enable DMA */
AT91F_PDC_EnableTx(tx_pdc);
/* Start Transmission */
+#ifndef USE_SSC_TX_TF_WORKAROUND
AT91F_SSC_EnableTx(AT91C_BASE_SSC);
+#else
+ ssc_tx_pending = 1;
+ pio_irq_enable(OPENPICC_SSC_TF);
+ if(AT91F_PIO_IsInputSet(AT91C_BASE_PIOA, OPENPICC_SSC_TF)) {
+ /* TF was probably already high when we enabled the PIO change interrupt for it. */
+ ssc_tf_irq(OPENPICC_SSC_TF);
+ }
+#endif
}
-
+#ifdef USE_SSC_TX_TF_WORKAROUND
+void ssc_tf_irq(u_int32_t pio) {
+ (void)pio;
+ pio_irq_disable(OPENPICC_SSC_TF);
+ if(ssc_tx_pending) { /* Transmit has not yet been started by the FIQ */
+ AT91F_SSC_EnableTx(AT91C_BASE_SSC);
+ ssc_tx_pending = 0;
+ }
+}
+#endif
//static struct openpcd_hdr opcd_ssc_hdr = {
@@ -429,8 +459,11 @@ void ssc_tx_init(void)
* PA17 !! */
AT91F_PIO_CfgInput(AT91C_BASE_PIOA, OPENPICC_MOD_PWM);
AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, OPENPICC_MOD_SSC |
- OPENPICC_SSC_DATA | OPENPICC_SSC_DATA |
- AT91C_PIO_PA15, 0);
+ OPENPICC_SSC_CLOCK | OPENPICC_SSC_TF, 0);
+#ifdef USE_SSC_TX_TF_WORKAROUND
+ AT91F_PIO_CfgInput(AT91C_BASE_PIOA, OPENPICC_SSC_TF);
+ pio_irq_register(OPENPICC_SSC_TF, ssc_tf_irq);
+#endif
tx_pdc = (AT91PS_PDC) &(ssc->SSC_RPR);
}
diff --git a/openpicc/config/board.h b/openpicc/config/board.h
index 61eab3c..8f8e59a 100644
--- a/openpicc/config/board.h
+++ b/openpicc/config/board.h
@@ -65,6 +65,7 @@
#define OPENPICC_MOD_SSC AT91C_PA17_TD
#define OPENPICC_SSC_DATA AT91C_PA18_RD
#define OPENPICC_SSC_CLOCK AT91C_PA19_RK
+#define OPENPICC_SSC_TF AT91C_PIO_PA15
#define OPENPICC_PIO_FRAME AT91C_PIO_PA20
#define OPENPICC_PIO_SSC_DATA_CONTROL AT91C_PIO_PA21
diff --git a/openpicc/os/boot/boot.s b/openpicc/os/boot/boot.s
index cedd3ee..43c4885 100644
--- a/openpicc/os/boot/boot.s
+++ b/openpicc/os/boot/boot.s
@@ -4,6 +4,7 @@
.extern exit
.extern AT91F_LowLevelInit
.extern pio_irq_isr_value
+ .extern ssc_tx_pending
.text
.code 32
@@ -45,10 +46,13 @@
.equ AT91C_BASE_PIOA, 0xFFFFF400
.equ AT91C_BASE_TC0, 0xFFFA0000
.equ AT91C_BASE_SSC, 0xFFFD4000
+.equ SSC_CR, 0x0
.equ SSC_RCMR, 0x10
+.equ SSC_CR_TXEN, 0x100
.equ AT91C_TC_SWTRG, (1 << 2)
.equ AT91C_TC_CLKEN, (1 << 0)
.equ PIO_DATA, (1 << 27)
+.equ PIO_SSC_TF, (1 << 15)
.equ PIOA_SODR, 0x30
.equ PIOA_CODR, 0x34
.equ PIOA_PDSR, 0x3c
@@ -219,6 +223,26 @@ my_fiq_handler:
movne r11, #PIO_DATA
strne r11, [r10, #PIOA_IDR] /* disable further PIO_DATA FIQ */
+ tst r8, #PIO_SSC_TF /* check for SSC Transmit Frame signal */
+ ldrne r11, [r10, #PIOA_PDSR]
+ tstne r11, #PIO_SSC_TF /* check for SSC_TF == 1 */
+
+ movne r11, #PIO_SSC_TF
+ strne r11, [r10, #PIOA_IDR] /* disable further SSC_TF FIQ */
+
+ ldrne r11, =ssc_tx_pending
+ ldrne r8, [r11]
+ tstne r8, #0x01 /* Check whether a TX is pending */
+
+ beq .no_ssc
+ mov r8, #0x00
+ str r8, [r11] /* Set ssc_tx_pending to 0 */
+
+ ldr r11, =AT91C_BASE_SSC
+ mov r8, #SSC_CR_TXEN
+ str r8, [r11, #SSC_CR] /* Write TXEN to SSC_CR, enables tx */
+
+.no_ssc:
/* Trigger PIO_SECONDARY_IRQ */
mov r11, #PIO_SECONDARY_IRQ_BIT
ldr r8, =AT91C_BASE_AIC
personal git repositories of Harald Welte. Your mileage may vary