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
This commit is contained in:
henryk 2007-11-11 19:24:37 +00:00
parent 9d397dfbbe
commit 1dfa375abb
13 changed files with 1015 additions and 1 deletions

View File

@ -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 \

View File

@ -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_*/

View File

@ -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();

View File

@ -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__*/

View File

@ -0,0 +1,589 @@
/* AT91SAM7 SSC controller routines for OpenPICC
* (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
*
* 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 <errno.h>
#include <string.h>
#include <sys/types.h>
#include <AT91SAM7.h>
#include <lib_AT91SAM7.h>
//#include <os/usb_handler.h>
#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));
}

View File

@ -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

View File

@ -0,0 +1,107 @@
/* OpenPC TC (Timer / Clock) support code
* (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
*
* 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 <lib_AT91SAM7.h>
#include <AT91SAM7.h>
#include <os/dbgu.h>
#include "../openpcd.h"
#include <os/tc_cdiv.h>
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));
}

View File

@ -0,0 +1,27 @@
#ifndef _TC_CDIV_H
#define _TC_CDIV_H
#include "openpicc.h"
#include <sys/types.h>
#include <lib_AT91SAM7.h>
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

View File

@ -0,0 +1,110 @@
/* Synchronize TC_CDIV divided sample clock with the SOF of the packet */
#include <lib_AT91SAM7.h>
#include <AT91SAM7.h>
#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();
}

View File

@ -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

View File

@ -0,0 +1,126 @@
/* OpenPICC TC (Timer / Clock) support code
* (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
*
* 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 <lib_AT91SAM7.h>
#include <AT91SAM7.h>
#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;
}

View File

@ -0,0 +1,9 @@
#ifndef _TC_FDT_H
#define _TC_FDT_H
#include <sys/types.h>
extern void tc_fdt_init(void);
extern void tc_fdt_set(u_int16_t count);
#endif

View File

@ -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 */
/*-----------------*/