From 1dfa375abb95c59830c38697c53fa9a6794a9fb9 Mon Sep 17 00:00:00 2001 From: henryk Date: Sun, 11 Nov 2007 19:24:37 +0000 Subject: Add code modules for tc_fdt, tc_cdiv_sync, tc_cdiv, ssc_picc Almost all of these have not been checked yet, I just copied them over and hot-fixed compile time errors F.e. all ssc usb code has been removed git-svn-id: https://svn.openpcd.org:2342/trunk@323 6dc7ffe9-61d6-0310-9af1-9938baff3ed1 --- openpicc/Makefile | 3 + openpicc/application/dbgu.h | 4 +- openpicc/application/main.c | 3 + openpicc/application/openpicc.h | 4 + openpicc/application/ssc_picc.c | 589 ++++++++++++++++++++++++++++++++++++ openpicc/application/ssc_picc.h | 15 + openpicc/application/tc_cdiv.c | 107 +++++++ openpicc/application/tc_cdiv.h | 27 ++ openpicc/application/tc_cdiv_sync.c | 110 +++++++ openpicc/application/tc_cdiv_sync.h | 6 + openpicc/application/tc_fdt.c | 126 ++++++++ openpicc/application/tc_fdt.h | 9 + openpicc/config/board.h | 13 + 13 files changed, 1015 insertions(+), 1 deletion(-) create mode 100644 openpicc/application/ssc_picc.c create mode 100644 openpicc/application/ssc_picc.h create mode 100644 openpicc/application/tc_cdiv.c create mode 100644 openpicc/application/tc_cdiv.h create mode 100644 openpicc/application/tc_cdiv_sync.c create mode 100644 openpicc/application/tc_cdiv_sync.h create mode 100644 openpicc/application/tc_fdt.c create mode 100644 openpicc/application/tc_fdt.h (limited to 'openpicc') diff --git a/openpicc/Makefile b/openpicc/Makefile index 0993dce..de01b48 100644 --- a/openpicc/Makefile +++ b/openpicc/Makefile @@ -77,6 +77,9 @@ ARM_SRC= \ application/da.c \ application/pll.c \ application/pio_irq.c \ + application/ssc_picc.c \ + application/tc_cdiv_sync.c \ + application/tc_fdt.c \ os/boot/Cstartup_SAM7.c \ os/core/list.c \ os/core/queue.c \ diff --git a/openpicc/application/dbgu.h b/openpicc/application/dbgu.h index 535ea08..65bc25b 100644 --- a/openpicc/application/dbgu.h +++ b/openpicc/application/dbgu.h @@ -1,6 +1,8 @@ #ifndef DBGU_H_ #define DBGU_H_ -#define DEBUGPCRF(...) ; +#define DEBUGPCRF(...) while(0); +#define DEBUGPCR(...) while(0); +#define DEBUGP(...) while(0); #endif /*DBGU_H_*/ diff --git a/openpicc/application/main.c b/openpicc/application/main.c index e722daa..1bd23ae 100644 --- a/openpicc/application/main.c +++ b/openpicc/application/main.c @@ -41,6 +41,7 @@ #include "da.h" #include "pll.h" #include "pio_irq.h" +#include "ssc_picc.h" /**********************************************************************/ static inline void prvSetupHardware (void) @@ -82,6 +83,8 @@ int main (void) prvSetupHardware (); pio_irq_init(); + + ssc_tx_init(); vLedInit(); diff --git a/openpicc/application/openpicc.h b/openpicc/application/openpicc.h index 1ed4273..15f9143 100644 --- a/openpicc/application/openpicc.h +++ b/openpicc/application/openpicc.h @@ -24,6 +24,8 @@ #ifndef __OPENPICC_H__ #define __OPENPICC_H__ +#include "board.h" + typedef unsigned char bool_t; typedef unsigned char u_int8_t; typedef unsigned short u_int16_t; @@ -32,6 +34,8 @@ typedef signed char s_int8_t; typedef signed short s_int16_t; typedef int s_int32_t; +#define int16_t s_int16_t + #define DA_BASELINE 200 #endif/*__OPENPICC_H__*/ diff --git a/openpicc/application/ssc_picc.c b/openpicc/application/ssc_picc.c new file mode 100644 index 0000000..491cb76 --- /dev/null +++ b/openpicc/application/ssc_picc.c @@ -0,0 +1,589 @@ +/* AT91SAM7 SSC controller routines for OpenPICC + * (C) 2006 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * We use SSC for both TX and RX side. + * + * RX side is interconnected with demodulated carrier + * + * TX side is interconnected with load modulation circuitry + */ + +//#undef DEBUG + +#include +#include +#include +#include +#include + +//#include +#include "dbgu.h" +#include "led.h" +#include "board.h" +#include "openpicc.h" + +#include "ssc_picc.h" +#include "tc_cdiv_sync.h" +#include "tc_fdt.h" + +//#define DEBUG_SSC_REFILL + +/* 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_NONE, + SSC_MODE_14443A_SHORT, + SSC_MODE_14443A_STANDARD, + SSC_MODE_14443B, + SSC_MODE_EDGE_ONE_SHOT, + SSC_MODE_CONTINUOUS, +}; + +struct ssc_state { + struct req_ctx *rx_ctx[2]; + enum ssc_mode mode; +}; +static struct ssc_state ssc_state; + +static const u_int16_t ssc_dmasize[] = { + [SSC_MODE_NONE] = 16, + [SSC_MODE_14443A_SHORT] = 16, /* 64 bytes */ + [SSC_MODE_14443A_STANDARD] = 16, /* 64 bytes */ + [SSC_MODE_14443B] = 16, /* 64 bytes */ + [SSC_MODE_EDGE_ONE_SHOT] = 16, /* 64 bytes */ + [SSC_MODE_CONTINUOUS] = 511, /* 2044 bytes */ +}; + +/* This is for four-times oversampling */ +#define ISO14443A_SOF_SAMPLE 0x01 +#define ISO14443A_SOF_LEN 4 + +#define SSC_RX_IRQ_MASK (AT91C_SSC_RXRDY | \ + AT91C_SSC_OVRUN | \ + AT91C_SSC_ENDRX | \ + AT91C_SSC_RXBUFF | \ + AT91C_SSC_RXSYN | \ + AT91C_SSC_CP0 | \ + AT91C_SSC_CP1) + +#define SSC_TX_IRQ_MASK (AT91C_SSC_TXRDY | \ + AT91C_SSC_TXEMPTY | \ + AT91C_SSC_ENDTX | \ + AT91C_SSC_TXBUFE | \ + AT91C_SSC_TXSYN) + +void ssc_rx_mode_set(enum ssc_mode ssc_mode) +{ + u_int8_t data_len=0, num_data=0, sync_len=0; + u_int32_t start_cond=0; + + /* disable Rx and all Rx interrupt sources */ + AT91F_SSC_DisableRx(AT91C_BASE_SSC); + AT91F_SSC_DisableIt(ssc, SSC_RX_IRQ_MASK); + + 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 = 16; + 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 = 32; + num_data = 16; /* FIXME */ + break; + case SSC_MODE_14443B: + /* start sampling at first falling data edge */ + //start_cond = + break; + case SSC_MODE_EDGE_ONE_SHOT: + case SSC_MODE_CONTINUOUS: + /* unfortunately we don't have RD and RF interconnected + * (at least not yet in the current hardware) */ + //start_cond = AT91C_SSC_START_EDGE_RF; + start_cond = AT91C_SSC_START_CONTINOUS; + //AT91C_SSC_START_RISE_RF; + sync_len = 0; + data_len = 32; + num_data = 16; + break; + case SSC_MODE_NONE: + goto out_set_mode; + break; + } + //ssc->SSC_RFMR = AT91C_SSC_MSBF | (data_len-1) & 0x1f | + 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 | + (0x2 << 6) | AT91C_SSC_CKI | start_cond; + + /* Enable Rx DMA */ + AT91F_PDC_EnableRx(rx_pdc); + + /* Enable RX interrupts */ + AT91F_SSC_EnableIt(ssc, AT91C_SSC_OVRUN | AT91C_SSC_CP0 | + AT91C_SSC_ENDRX | AT91C_SSC_RXBUFF); +out_set_mode: + ssc_state.mode = ssc_mode; +} + +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 */ + AT91F_SSC_DisableTx(AT91C_BASE_SSC); + + /* disable all Tx related interrupt sources */ + AT91F_SSC_DisableIt(ssc, SSC_TX_IRQ_MASK); + + switch (ssc_mode) { + case SSC_MODE_14443A_SHORT: + start_cond = AT91C_SSC_START_RISE_RF; + sync_len = 0; + 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 = 32; + num_data = 1; /* FIXME */ + break; + default: + 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; + + AT91F_SSC_EnableIt(ssc, AT91C_SSC_TXSYN); + AT91F_SSC_EnableTx(AT91C_BASE_SSC); +#if 0 + /* Enable RX interrupts */ + AT91F_SSC_EnableIt(ssc, AT91C_SSC_OVRUN | + AT91C_SSC_ENDTX | AT91C_SSC_TXBUFE); + AT91F_PDC_EnableTx(tx_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->data, &opcd_ssc_hdr, sizeof(opcd_ssc_hdr)); +// rctx->tot_len = sizeof(opcd_ssc_hdr); +//} + +#define DEBUG_SSC_REFILL 1 +#ifdef DEBUG_SSC_REFILL +#define DEBUGR(x, args ...) DEBUGPCRF(x, ## args) +#else +#define DEBUGR(x, args ...) +#endif + +static int __ramfunc __ssc_rx_refill(int secondary) +{ + (void)secondary; +// FIXME +/* struct req_ctx *rctx; + + rctx = req_ctx_find_get(1, RCTX_STATE_FREE, RCTX_STATE_SSC_RX_BUSY); + if (!rctx) { + DEBUGP("no_rctx_for_refill! "); + return -1; + } + init_opcdhdr(rctx); + DEBUGR("filling SSC RX%u dma ctx: %u (len=%u) ", secondary, + req_ctx_num(rctx), rctx->size); + rctx->tot_len = ssc_dmasize[ssc_state.mode]*4 + + sizeof(struct openpcd_hdr); + if (secondary) { + AT91F_PDC_SetNextRx(rx_pdc, rctx->data+MAX_HDRSIZE, + ssc_dmasize[ssc_state.mode]); + ssc_state.rx_ctx[1] = rctx; + } else { + AT91F_PDC_SetRx(rx_pdc, rctx->data+MAX_HDRSIZE, + ssc_dmasize[ssc_state.mode]); + ssc_state.rx_ctx[0] = rctx; + } +*/ + tc_cdiv_sync_reset(); + + return 0; +} + +#if 0 +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 + * 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; + DEBUGR("refill "); +#if 1 + rctx = req_ctx_find_get(1, RCTX_STATE_FREE, RCTX_STATE_SSC_RX_BUSY); + DEBUGP("SSC_SR=0x%08x ", ssc->SSC_SR); + if (AT91F_PDC_IsRxEmpty(rx_pdc)) { + DEBUGR("filling primary SSC RX dma ctx: %u (len=%u) ", + req_ctx_num(rctx), rctx->size); + rctx->tot_len = rctx->size; + AT91F_PDC_SetRx(rx_pdc, rctx->data+MAX_HDRSIZE, + (rctx->size-MAX_HDRSIZE)>>2); + ssc_state.rx_ctx[0] = rctx; + + /* If primary is empty, secondary must be empty, too */ + rctx = req_ctx_find_get(1, RCTX_STATE_FREE, + RCTX_STATE_SSC_RX_BUSY); + if (!rctx) { + DEBUGPCRF("no rctx for secondary refill!"); + return -2; + } + init_opcdhdr(rctx); + } + + if (AT91F_PDC_IsNextRxEmpty(rx_pdc)) { + DEBUGR("filling secondary SSC RX dma ctx: %u (len=%u) ", + req_ctx_num(rctx), rctx->size); + rctx->tot_len = rctx->size; + AT91F_PDC_SetNextRx(rx_pdc, rctx->data+MAX_HDRSIZE, + (rctx->size-MAX_HDRSIZE)>2); + 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; + } +#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 +} +#endif + +#define ISO14443A_FDT_SHORT_1 1236 +#define ISO14443A_FDT_SHORT_0 1172 + +static void __ramfunc ssc_irq(void) +{ + u_int32_t ssc_sr = ssc->SSC_SR; +// int i, *tmp, emptyframe = 0; + DEBUGP("ssc_sr=0x%08x, mode=%u: ", ssc_sr, ssc_state.mode); + + if (ssc_sr & AT91C_SSC_ENDRX) { +#if 1 + /* in a one-shot sample, we don't want to keep + * sampling further after having received the first + * packet. */ + if (ssc_state.mode == SSC_MODE_EDGE_ONE_SHOT) { + DEBUGP("DISABLE_RX "); + ssc_rx_stop(); + } + //AT91F_SSC_DisableIt(AT91C_BASE_SSC, SSC_RX_IRQ_MASK); +#endif +#if 0 +/* Experimental start SSC on frame, stop on FFFFFFFF */ + if (ssc_state.mode == SSC_MODE_CONTINUOUS) { + //ssc->SSC_RCMR = (ssc->SSC_RCMR & ~AT91C_SSC_START) | AT91C_SSC_START_CONTINOUS; + tmp = (u_int32_t*)ssc_state.rx_ctx[0]->data; + for(i = ssc_state.rx_ctx[0]->size / 4; i >= 0 ; i--) { + if( *tmp++ == 0xFFFFFFFF ) { + *(tmp-1) = 0xAAAAAAAA; // debug marker + /* No modulation for a long time, stop sampling + * and prepare for next frame */ + DEBUGP("RESTART RX "); + ssc_rx_stop(); + ssc_rx_mode_set(ssc_state.mode); + ssc_rx_start(); + led_toggle(1); + break; + } + } + } +#endif + /* Ignore empty frames */ + if (ssc_state.mode == SSC_MODE_CONTINUOUS) { +// FIXME +// tmp = (u_int32_t*)ssc_state.rx_ctx[0]->data + MAX_HDRSIZE; +// emptyframe = 1; +// for(i = (ssc_state.rx_ctx[0]->size-MAX_HDRSIZE) / 4 - 8/*WTF?*/; i > 0; i--) { +// if( *tmp++ != 0xFFFFFFFF ) { +// DEBUGPCR("NONEMPTY(%08x, %i): %08x", tmp, i, *(tmp-1)); +// emptyframe = 0; +// break; +// } else { +// //DEBUGPCR("DUNNO(%08x, %i): %08x", tmp, i, tmp[i]); +// } +// } + } + //DEBUGP("Sending primary RCTX(%u, len=%u) ", req_ctx_num(ssc_state.rx_ctx[0]), ssc_state.rx_ctx[0]->tot_len); + /* Mark primary RCTX as ready to send for usb */ +// if(!emptyframe) { +// FIXME +// DEBUGP("NONEMPTY"); +// req_ctx_set_state(ssc_state.rx_ctx[0], +// RCTX_STATE_UDP_EP2_PENDING); +// //RCTX_STATE_FREE); +// } else { +// DEBUGP("EMPTY"); +// req_ctx_put(ssc_state.rx_ctx[0]); +// } + + /* 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_RXBUFF) { +// DEBUGP("RXBUFF! "); +// if (ssc_state.rx_ctx[0]) { +// //DEBUGP("Sending secondary RCTX(%u, len=%u) ", req_ctx_num(ssc_state.rx_ctx[0]), ssc_state.rx_ctx[0]->tot_len); +// req_ctx_set_state(ssc_state.rx_ctx[0], +// RCTX_STATE_UDP_EP2_PENDING); +// //RCTX_STATE_FREE); +// } + if (__ssc_rx_refill(0) == -1) + AT91F_SSC_DisableIt(ssc, AT91C_SSC_ENDRX | + AT91C_SSC_RXBUFF | + AT91C_SSC_OVRUN); + } + + if (__ssc_rx_refill(1) == -1) + AT91F_SSC_DisableIt(ssc, AT91C_SSC_ENDRX | + AT91C_SSC_RXBUFF | + AT91C_SSC_OVRUN); + +// udp_refill_ep(2); + +#if 0 + if (__ssc_rx_refill(1) == -1) + AT91F_SSC_DisableIt(ssc, AT91C_SSC_ENDRX | + AT91C_SSC_RXBUFF | + AT91C_SSC_OVRUN); +#endif + } + + if (ssc_sr & AT91C_SSC_OVRUN) + DEBUGP("RX_OVERRUN "); + + if (ssc_sr & AT91C_SSC_CP0) + DEBUGP("CP0 "); + + if (ssc_sr & AT91C_SSC_TXSYN) + DEBUGP("TXSYN "); +#if 0 + led_toggle(1); + + 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: + case SSC_MODE_EDGE_ONE_SHOT: + DEBUGP("ONE_SHOT "); + break; + default: + DEBUGP("UNKNOWN_MODE "); + break; + } + +#endif + DEBUGPCR("I"); + AT91F_AIC_ClearIt(AT91C_ID_SSC); +} + +void ssc_print(void) +{ + DEBUGP("PDC_RPR=0x%08x ", rx_pdc->PDC_RPR); + DEBUGP("PDC_RCR=0x%08x ", rx_pdc->PDC_RCR); + DEBUGP("PDC_RNPR=0x%08x ", rx_pdc->PDC_RNPR); + DEBUGP("PDC_RNCR=0x%08x ", rx_pdc->PDC_RNCR); +} + + +void ssc_rx_unthrottle(void) +{ + AT91F_SSC_EnableIt(ssc, AT91C_SSC_ENDRX | AT91C_SSC_CP0 | + AT91C_SSC_RXBUFF | AT91C_SSC_OVRUN); +} + +void ssc_rx_start(void) +{ + //DEBUGPCRF("starting SSC RX\n"); + + /* Enable Reception */ + AT91F_SSC_EnableIt(ssc, AT91C_SSC_ENDRX | AT91C_SSC_CP0 | + AT91C_SSC_RXBUFF | AT91C_SSC_OVRUN); + AT91F_SSC_EnableRx(AT91C_BASE_SSC); + + /* Clear the flipflop */ + tc_cdiv_sync_reset(); +} + +void ssc_rx_stop(void) +{ + /* Disable reception */ + AT91F_SSC_DisableRx(AT91C_BASE_SSC); +} + +void ssc_tx_init(void) +{ + /* IMPORTANT: Disable PA23 (PWM0) output, since it is connected to + * 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); + + ssc_tx_mode_set(SSC_MODE_14443A_SHORT); +} + +//static int ssc_usb_in(struct req_ctx *rctx) +//{ +// FIXME +// struct openpcd_hdr *poh = (struct openpcd_hdr *) rctx->data; +// +// switch (poh->cmd) { +// case OPENPCD_CMD_SSC_READ: +// /* FIXME: allow host to specify mode */ +// ssc_rx_mode_set(SSC_MODE_EDGE_ONE_SHOT); +// ssc_rx_start(); +// req_ctx_put(rctx); +// return 0; +// break; +// case OPENPCD_CMD_SSC_WRITE: +// /* FIXME: implement this */ +// //ssc_tx_start() +// break; +// default: +// return USB_ERR(USB_ERR_CMD_UNKNOWN); +// break; +// } +// +// return (poh->flags & OPENPCD_FLAG_RESPOND) ? USB_RET_RESPOND : 0; +//} + +void ssc_rx_init(void) +{ + tc_cdiv_sync_init(); + tc_cdiv_sync_enable(); + + rx_pdc = (AT91PS_PDC) &(ssc->SSC_RPR); + + AT91F_SSC_CfgPMC(); + + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, + OPENPICC_SSC_DATA | OPENPICC_SSC_CLOCK | + OPENPICC_PIO_FRAME, + 0); + + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPICC_PIO_SSC_DATA_CONTROL); + AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPICC_PIO_SSC_DATA_CONTROL); + + AT91F_AIC_ConfigureIt(AT91C_ID_SSC, + OPENPICC_IRQ_PRIO_SSC, + AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, (THandler)&ssc_irq); + + /* don't divide clock inside SSC, we do that in tc_cdiv */ + ssc->SSC_CMR = 0; + +#if 0 + ssc->SSC_RCMR = AT91C_SSC_CKS_RK | AT91C_SSC_CKO_NONE | + AT91C_SSC_CKI | AT91C_SSC_START_CONTINOUS; + /* Data bits per Data N = 32-1 + * Data words per Frame = 15-1 (=60 byte)*/ + ssc->SSC_RFMR = 31 | AT91C_SSC_MSBF | (14 << 8); +#endif + + __ssc_rx_refill(0); + __ssc_rx_refill(1); + + ssc_rx_mode_set(SSC_MODE_NONE); +#if 0 + AT91F_PDC_EnableRx(rx_pdc); + + /* Enable RX interrupts */ + AT91F_SSC_EnableIt(ssc, AT91C_SSC_OVRUN | + AT91C_SSC_ENDRX | AT91C_SSC_RXBUFF); +#endif + /* FIXME: This is hardcoded for REQA 0x26 */ + tc_fdt_set(ISO14443A_FDT_SHORT_0); + + AT91F_AIC_EnableIt(AT91C_ID_SSC); + + //usb_hdlr_register(&ssc_usb_in, OPENPCD_CMD_CLS_SSC); + + DEBUGP("\r\n"); +} + +void ssc_fini(void) +{ +// usb_hdlr_unregister(OPENPCD_CMD_CLS_SSC); + AT91F_PDC_DisableRx(rx_pdc); + 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/openpicc/application/ssc_picc.h b/openpicc/application/ssc_picc.h new file mode 100644 index 0000000..a9c87b7 --- /dev/null +++ b/openpicc/application/ssc_picc.h @@ -0,0 +1,15 @@ +#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); +extern void ssc_rx_stop(void); +extern void ssc_rx_unthrottle(void); + +#endif diff --git a/openpicc/application/tc_cdiv.c b/openpicc/application/tc_cdiv.c new file mode 100644 index 0000000..6f06ba5 --- /dev/null +++ b/openpicc/application/tc_cdiv.c @@ -0,0 +1,107 @@ +/* OpenPC TC (Timer / Clock) support code + * (C) 2006 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This idea of this code is to feed the 13.56MHz carrier clock of RC632 + * into TCLK1, which is routed to XC1. Then configure TC0 to divide this + * clock by a configurable divider. + * + */ + +#include +#include +#include + +#include "../openpcd.h" +#include + +static AT91PS_TCB tcb = AT91C_BASE_TCB; + +/* set carrier divider to a specific */ +void tc_cdiv_set_divider(u_int16_t div) +{ + tcb->TCB_TC0.TC_RC = div; + + /* set to 50% duty cycle */ + tcb->TCB_TC0.TC_RA = 1; + tcb->TCB_TC0.TC_RB = 1 + (div >> 1); +} + +void tc_cdiv_phase_add(int16_t inc) +{ + tcb->TCB_TC0.TC_RA = (tcb->TCB_TC0.TC_RA + inc) % tcb->TCB_TC0.TC_RC; + tcb->TCB_TC0.TC_RB = (tcb->TCB_TC0.TC_RB + inc) % tcb->TCB_TC0.TC_RC; + + /* FIXME: can this be done more elegantly? */ + if (tcb->TCB_TC0.TC_RA == 0) { + tcb->TCB_TC0.TC_RA += 1; + tcb->TCB_TC0.TC_RB += 1; + } +} + +void tc_cdiv_init(void) +{ + /* Cfg PA28(TCLK1), PA0(TIOA0), PA1(TIOB0), PA20(TCLK2) as Periph B */ + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, 0, + OPENPCD_PIO_CARRIER_IN | + OPENPCD_PIO_CARRIER_DIV_OUT | + OPENPCD_PIO_CDIV_HELP_OUT | + OPENPCD_PIO_CDIV_HELP_IN); + + AT91F_PMC_EnablePeriphClock(AT91C_BASE_PMC, + ((unsigned int) 1 << AT91C_ID_TC0)); + + /* Enable Clock for TC0 */ + tcb->TCB_TC0.TC_CCR = AT91C_TC_CLKEN; + + /* Connect TCLK1 to XC1, TCLK2 to XC2 */ + tcb->TCB_BMR &= ~(AT91C_TCB_TC1XC1S | AT91C_TCB_TC2XC2S); + tcb->TCB_BMR |= (AT91C_TCB_TC1XC1S_TCLK1 | AT91C_TCB_TC2XC2S_TCLK2); + + /* Clock XC1, Wave mode, Reset on RC comp + * TIOA0 on RA comp = set, * TIOA0 on RC comp = clear, + * TIOB0 on EEVT = set, TIOB0 on RB comp = clear, + * EEVT = XC2 (TIOA0) */ + tcb->TCB_TC0.TC_CMR = AT91C_TC_CLKS_XC1 | AT91C_TC_WAVE | + AT91C_TC_WAVESEL_UP_AUTO | + AT91C_TC_ACPA_SET | AT91C_TC_ACPC_CLEAR | + AT91C_TC_BEEVT_SET | AT91C_TC_BCPB_CLEAR | + AT91C_TC_EEVT_XC2 | AT91C_TC_ETRGEDG_RISING | + AT91C_TC_BSWTRG_CLEAR | AT91C_TC_ASWTRG_CLEAR; + + tc_cdiv_set_divider(128); + + /* Reset to start timers */ + tcb->TCB_BCR = 1; +} + +void tc_cdiv_print(void) +{ + DEBUGP("TCB_BMR=0x%08x ", tcb->TCB_BMR); + DEBUGP("TC0_CV=0x%08x ", tcb->TCB_TC0.TC_CV); + DEBUGP("TC0_CMR=0x%08x ", tcb->TCB_TC0.TC_CMR); + DEBUGPCR("TC0_SR=0x%08x", tcb->TCB_TC0.TC_SR); + + DEBUGPCR("TC0_RA=0x%04x, TC0_RB=0x%04x, TC0_RC=0x%04x", + tcb->TCB_TC0.TC_RA, tcb->TCB_TC0.TC_RB, tcb->TCB_TC0.TC_RC); +} + +void tc_cdiv_fini(void) +{ + tcb->TCB_TC0.TC_CCR = AT91C_TC_CLKDIS; + AT91F_PMC_DisablePeriphClock(AT91C_BASE_PMC, + ((unsigned int) 1 << AT91C_ID_TC0)); +} diff --git a/openpicc/application/tc_cdiv.h b/openpicc/application/tc_cdiv.h new file mode 100644 index 0000000..d5744f9 --- /dev/null +++ b/openpicc/application/tc_cdiv.h @@ -0,0 +1,27 @@ +#ifndef _TC_CDIV_H +#define _TC_CDIV_H + +#include "openpicc.h" +#include +#include + +static AT91PS_TCB tcb; + +extern void tc_cdiv_phase_add(int16_t inc); +extern void tc_cdiv_set_divider(u_int16_t div); + +static inline void tc_cdiv_phase_inc(void) +{ + tc_cdiv_phase_add(1); +} + +static inline void tc_cdiv_phase_dec(void) +{ + tc_cdiv_phase_add(-1); +} + +extern void tc_cdiv_print(void); +extern void tc_cdiv_init(void); +extern void tc_cdiv_fini(void); + +#endif diff --git a/openpicc/application/tc_cdiv_sync.c b/openpicc/application/tc_cdiv_sync.c new file mode 100644 index 0000000..486e93b --- /dev/null +++ b/openpicc/application/tc_cdiv_sync.c @@ -0,0 +1,110 @@ +/* Synchronize TC_CDIV divided sample clock with the SOF of the packet */ + +#include +#include +#include "dbgu.h" +#include "pio_irq.h" +#include "openpicc.h" + +#define USE_IRQ + +static u_int8_t enabled; + +#if 0 +static void pio_data_change(u_int32_t pio) +{ + (void)pio; + DEBUGP("PIO_FRAME_IRQ: "); + /* we get one interrupt for each change. If now, after the + * change the level is high, then it must have been a rising + * edge */ + if (*AT91C_PIOA_PDSR & OPENPICC_PIO_FRAME) { + *AT91C_TC0_CCR = AT91C_TC_SWTRG; + DEBUGPCR("CDIV_SYNC_FLIP SWTRG CV=0x%08x", + *AT91C_TC0_CV); + } else + DEBUGPCR(""); +} + +#else + +static void __ramfunc cdsync_cb(void) +{ + DEBUGP("PIO_IRQ: "); + if (*AT91C_PIOA_ISR & OPENPICC_PIO_FRAME) { + DEBUGP("PIO_FRAME_IRQ: "); + /* we get one interrupt for each change. If now, after the + * change the level is high, then it must have been a rising + * edge */ + if (*AT91C_PIOA_PDSR & OPENPICC_PIO_FRAME) { + *AT91C_TC0_CCR = AT91C_TC_SWTRG; + DEBUGPCR("CDIV_SYNC_FLIP SWTRG CV=0x%08x", + *AT91C_TC0_CV); + } else + DEBUGPCR(""); + } else + DEBUGPCR(""); +} +#endif + +void tc_cdiv_sync_reset(void) +{ + if (enabled) { + u_int32_t tmp = *AT91C_PIOA_ISR; + (void)tmp; + volatile int i; + DEBUGPCRF("CDIV_SYNC_FLOP"); + + /* reset the hardware flipflop */ + AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, + OPENPICC_PIO_SSC_DATA_CONTROL); + for (i = 0; i < 0xff; i++) ; + AT91F_PIO_SetOutput(AT91C_BASE_PIOA, + OPENPICC_PIO_SSC_DATA_CONTROL); + } +} + +void tc_cdiv_sync_disable(void) +{ + enabled = 0; + *AT91C_PIOA_IDR = OPENPICC_PIO_FRAME; +} + +void tc_cdiv_sync_enable(void) +{ + enabled = 1; + + DEBUGPCRF("CDIV_SYNC_ENABLE "); + tc_cdiv_sync_reset(); + *AT91C_PIOA_IER = OPENPICC_PIO_FRAME; +} + +extern void (*fiq_handler)(void); +void tc_cdiv_sync_init(void) +{ + DEBUGPCRF("initializing"); + + enabled = 0; + + AT91F_PIOA_CfgPMC(); + +#ifdef USE_IRQ + /* Configure IRQ */ + AT91F_AIC_ConfigureIt(AT91C_ID_PIOA, + AT91C_AIC_PRIOR_HIGHEST, + AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, (THandler)&cdsync_cb); +#else + /* Configure FIQ */ + AT91F_AIC_ConfigureIt(AT91C_ID_FIQ, + //0, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, &cdsync_cb); + 0, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, (THandler)&fiq_handler); + /* enable fast forcing for PIOA interrupt */ + *AT91C_AIC_FFER = (1 << AT91C_ID_PIOA); + + /* register pio irq handler */ + pio_irq_register(OPENPICC_PIO_FRAME, &pio_data_change); +#endif + AT91F_AIC_EnableIt(AT91C_ID_PIOA); + + tc_cdiv_sync_disable(); +} diff --git a/openpicc/application/tc_cdiv_sync.h b/openpicc/application/tc_cdiv_sync.h new file mode 100644 index 0000000..0101321 --- /dev/null +++ b/openpicc/application/tc_cdiv_sync.h @@ -0,0 +1,6 @@ +#ifndef _TC_CDIV_SYNC_H +#define _TC_CDIV_SYNC_H +extern void tc_cdiv_sync_enable(void); +extern void tc_cdiv_sync_init(void); +extern void tc_cdiv_sync_reset(void); +#endif diff --git a/openpicc/application/tc_fdt.c b/openpicc/application/tc_fdt.c new file mode 100644 index 0000000..55da9ca --- /dev/null +++ b/openpicc/application/tc_fdt.c @@ -0,0 +1,126 @@ +/* OpenPICC TC (Timer / Clock) support code + * (C) 2006 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + + +/* PICC Simulator Side: + * In order to support responding to synchronous frames (REQA/WUPA/ANTICOL), + * we need a second Timer/Counter (TC2). This unit is reset by an external + * event (rising edge of modulation pause PCD->PICC, falling edge of + * demodulated data) connected to TIOB2, and counts up to a configurable + * number of carrier clock cycles (RA). Once the RA value is reached, TIOA2 + * will see a rising edge. This rising edge will be interconnected to TF (Tx + * Frame) of the SSC to start transmitting our synchronous response. + * + */ + +#include +#include +#include "dbgu.h" + +#include "openpicc.h" +#include "tc_cdiv.h" +#include "tc_fdt.h" + +static AT91PS_TC tcfdt = AT91C_BASE_TC2; + +void tc_fdt_set(u_int16_t count) +{ + tcfdt->TC_RA = count; +} + + +/* 'count' number of carrier cycles after the last modulation pause, + * we deem the frame to have ended */ +void tc_frame_end_set(u_int16_t count) +{ + tcfdt->TC_RB = count; +} + +static void tc_fdt_irq(void) +{ + u_int32_t sr = tcfdt->TC_SR; + DEBUGP("tc_fdt_irq: TC2_SR=0x%08x TC2_CV=0x%08x ", + sr, tcfdt->TC_CV); + + if (sr & AT91C_TC_ETRGS) { + DEBUGP("Ext_trigger "); + } + if (sr & AT91C_TC_CPAS) { + DEBUGP("FDT_expired "); + /* FIXME: if we are in anticol / sync mode, + * we could do software triggering of SSC TX, + * but IIRC the hardware does this by TF */ + } + if (sr & AT91C_TC_CPBS) { + DEBUGP("Frame_end "); + /* FIXME: stop ssc (in continuous mode), + * take care of preparing synchronous response if + * we operate in anticol mode.*/ + } + if (sr & AT91C_TC_CPCS) { + DEBUGP("Compare_C "); + } + DEBUGPCR(""); +} + +void tc_fdt_print(void) +{ + DEBUGP("TC2_CV=0x%08x ", tcfdt->TC_CV); + DEBUGP("TC2_CMR=0x%08x ", tcfdt->TC_CMR); + DEBUGP("TC2_SR=0x%08x ", tcfdt->TC_SR); + DEBUGP("TC2_RA=0x%04x, TC2_RB=0x%04x, TC2_RC=0x%04x", + tcfdt->TC_RA, tcfdt->TC_RB, tcfdt->TC_RC); +} + +void tc_fdt_init(void) +{ + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, AT91C_PA15_TF, + AT91C_PA26_TIOA2 | AT91C_PA27_TIOB2); + AT91F_PMC_EnablePeriphClock(AT91C_BASE_PMC, + ((unsigned int) 1 << AT91C_ID_TC2)); + /* Enable Clock for TC2 */ + tcfdt->TC_CCR = AT91C_TC_CLKEN; + + tcfdt->TC_RC = 0xffff; + tc_frame_end_set(128*2); + + /* Clock XC1, Wave Mode, No automatic reset on RC comp + * TIOA2 in RA comp = set, TIOA2 on RC comp = clear, + * TIOA2 on EEVT = clear + * TIOB2 as input, EEVT = TIOB2, Reset/Trigger on EEVT */ + tcfdt->TC_CMR = AT91C_TC_CLKS_XC1 | AT91C_TC_WAVE | + AT91C_TC_WAVESEL_UP | + AT91C_TC_ACPA_SET | AT91C_TC_ACPC_CLEAR | + AT91C_TC_AEEVT_CLEAR | + AT91C_TC_BEEVT_NONE | AT91C_TC_BCPB_NONE | + AT91C_TC_EEVT_TIOB | AT91C_TC_ETRGEDG_FALLING | + AT91C_TC_ENETRG | AT91C_TC_CPCSTOP ; + + /* Reset to start timers */ + tcb->TCB_BCR = 1; + + AT91F_AIC_ConfigureIt(AT91C_ID_TC2, + OPENPCD_IRQ_PRIO_TC_FDT, + AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, &tc_fdt_irq); + AT91F_AIC_EnableIt(AT91C_ID_TC2); + + tcfdt->TC_IER = AT91C_TC_CPAS | AT91C_TC_CPBS | AT91C_TC_CPCS | + AT91C_TC_ETRGS; +} + diff --git a/openpicc/application/tc_fdt.h b/openpicc/application/tc_fdt.h new file mode 100644 index 0000000..b39b935 --- /dev/null +++ b/openpicc/application/tc_fdt.h @@ -0,0 +1,9 @@ +#ifndef _TC_FDT_H +#define _TC_FDT_H + +#include + +extern void tc_fdt_init(void); +extern void tc_fdt_set(u_int16_t count); + +#endif diff --git a/openpicc/config/board.h b/openpicc/config/board.h index 065c26d..80ae94b 100644 --- a/openpicc/config/board.h +++ b/openpicc/config/board.h @@ -61,6 +61,19 @@ #define OPENPICC_PIO_PLL_INHIBIT AT91C_PIO_PA24 #define OPENPICC_PIO_PLL_LOCK AT91C_PIO_PA4 +#define OPENPICC_MOD_PWM AT91C_PA23_PWM0 +#define OPENPICC_MOD_SSC AT91C_PA17_TD +#define OPENPICC_SSC_DATA AT91C_PA18_RD +#define OPENPICC_SSC_CLOCK AT91C_PA19_RK + +#define OPENPICC_PIO_FRAME AT91C_PIO_PA20 +#define OPENPICC_PIO_SSC_DATA_CONTROL AT91C_PIO_PA21 +#define OPENPICC_PIO_AB_DETECT AT91C_PIO_PA22 +#define OPENPICC_PIO_PLL_INHIBIT AT91C_PIO_PA24 + +#define OPENPICC_IRQ_PRIO_SSC (AT91C_AIC_PRIOR_HIGHEST-1) +#define OPENPCD_IRQ_PRIO_TC_FDT (AT91C_AIC_PRIOR_LOWEST+3) + /*-----------------*/ /* task priorities */ /*-----------------*/ -- cgit v1.2.3