diff options
| 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 | 
| commit | 7907a1087e02fca450df732aa664f3dc6c0f9252 (patch) | |
| tree | 3c24c6cb8acf31a243919fbbacf2ae0739068b69 | |
| parent | bc7d72bf05d8e84c207f9be30abab23b3023408f (diff) | |
add SSC code
git-svn-id: https://svn.openpcd.org:2342/trunk@88 6dc7ffe9-61d6-0310-9af1-9938baff3ed1
| -rw-r--r-- | openpcd/firmware/Makefile | 2 | ||||
| -rw-r--r-- | openpcd/firmware/src/ssc.c | 157 | ||||
| -rw-r--r-- | openpcd/firmware/src/ssc.h | 13 | 
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 | 
