From ae1cb6d0d72b16c7d7c8c2a7194aeb51d8c6642f Mon Sep 17 00:00:00 2001 From: gdisirio Date: Mon, 10 Jun 2013 11:43:41 +0000 Subject: DSPI and DMA-MUX support for SPC5xx. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@5830 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/platforms/SPC5xx/DSPI_v1/spi_lld.c | 101 ++++++++++++++++++++++- os/hal/platforms/SPC5xx/DSPI_v1/spi_lld.h | 121 +++++++++++++++++++++++++++- os/hal/platforms/SPC5xx/EDMA_v1/spc5_edma.c | 21 ++++- os/hal/platforms/SPC5xx/EDMA_v1/spc5_edma.h | 23 +++++- 4 files changed, 260 insertions(+), 6 deletions(-) (limited to 'os/hal/platforms/SPC5xx') diff --git a/os/hal/platforms/SPC5xx/DSPI_v1/spi_lld.c b/os/hal/platforms/SPC5xx/DSPI_v1/spi_lld.c index f4c0bef9e..fd7222509 100644 --- a/os/hal/platforms/SPC5xx/DSPI_v1/spi_lld.c +++ b/os/hal/platforms/SPC5xx/DSPI_v1/spi_lld.c @@ -78,6 +78,13 @@ SPIDriver SPID3; SPIDriver SPID4; #endif +/** + * @brief SPID5 driver identifier. + */ +#if SPC5_SPI_USE_DSPI4 || defined(__DOXYGEN__) +SPIDriver SPID5; +#endif + /*===========================================================================*/ /* Driver local variables and types. */ /*===========================================================================*/ @@ -186,6 +193,32 @@ static const edma_channel_config_t spi_dspi3_rx_dma_config = { }; #endif /* SPC5_SPI_USE_DSPI3 */ +#if SPC5_SPI_USE_DSPI4 || defined(__DOXYGEN__) +/** + * @brief DMA configuration for DSPI4 TX1. + */ +static const edma_channel_config_t spi_dspi4_tx1_dma_config = { + SPC5_DSPI4_TX1_DMA_DEV_ID, SPC5_SPI_DSPI4_DMA_PRIO, SPC5_SPI_DSPI4_DMA_IRQ_PRIO, + spi_serve_tx_irq, spi_serve_dma_error_irq, &SPID5 +}; + +/** + * @brief DMA configuration for DSPI4 TX2. + */ +static const edma_channel_config_t spi_dspi4_tx2_dma_config = { + SPC5_DSPI4_TX2_DMA_DEV_ID, SPC5_SPI_DSPI4_DMA_PRIO, SPC5_SPI_DSPI4_DMA_IRQ_PRIO, + spi_serve_tx_irq, spi_serve_dma_error_irq, &SPID5 +}; + +/** + * @brief DMA configuration for DSPI4 RX. + */ +static const edma_channel_config_t spi_dspi4_rx_dma_config = { + SPC5_DSPI4_RX_DMA_DEV_ID, SPC5_SPI_DSPI4_DMA_PRIO, SPC5_SPI_DSPI4_DMA_IRQ_PRIO, + spi_serve_rx_irq, spi_serve_dma_error_irq, &SPID5 +}; +#endif /* SPC5_SPI_USE_DSPI4 */ + /*===========================================================================*/ /* Driver local functions. */ /*===========================================================================*/ @@ -699,6 +732,35 @@ CH_IRQ_HANDLER(SPC5_DSPI3_TFFF_HANDLER) { } #endif /* SPC5_SPI_USE_DSPI3 */ +#if SPC5_SPI_USE_DSPI4 || defined(__DOXYGEN__) +#if !defined(SPC5_DSPI4_TFFF_HANDLER) +#error "SPC5_DSPI4_TFFF_HANDLER not defined" +#endif +/** + * @brief DSPI4 TFFF interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(SPC5_DSPI4_TFFF_HANDLER) { + + CH_IRQ_PROLOGUE(); + + chSysLockFromIsr(); + + /* Interrupt served and back to DMA mode.*/ + SPC5_DSPI4.RSER.B.TFFFDIRS = 1; + SPC5_DSPI4.SR.B.TFFF = 1; + + /* Pushing last frame.*/ + SPC5_DSPI4.PUSHR.R = (SPID5.config->pushr | SPID5.tx_last | SPC5_PUSHR_EOQ) & + ~SPC5_PUSHR_CONT; + + chSysUnlockFromIsr(); + + CH_IRQ_EPILOGUE(); +} +#endif /* SPC5_SPI_USE_DSPI4 */ + /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ @@ -717,8 +779,10 @@ void spi_lld_init(void) { SPID1.tx1_channel = EDMA_ERROR; SPID1.tx2_channel = EDMA_ERROR; SPID1.rx_channel = EDMA_ERROR; + SPC5_DSPI0_ENABLE_CLOCK(); SPC5_DSPI0.MCR.R = SPC5_MCR_MSTR | SPC5_MCR_HALT | SPC5_MCR_MDIS | SPC5_SPI_DSPI0_MCR; + SPC5_DSPI0_DISABLE_CLOCK(); INTC.PSR[SPC5_DSPI0_TFFF_NUMBER].R = SPC5_SPI_DSPI0_IRQ_PRIO; #endif /* SPC5_SPI_USE_DSPI0 */ @@ -729,8 +793,10 @@ void spi_lld_init(void) { SPID2.tx1_channel = EDMA_ERROR; SPID2.tx2_channel = EDMA_ERROR; SPID2.rx_channel = EDMA_ERROR; + SPC5_DSPI1_ENABLE_CLOCK(); SPC5_DSPI1.MCR.R = SPC5_MCR_MSTR | SPC5_MCR_HALT | SPC5_MCR_MDIS | SPC5_SPI_DSPI1_MCR; + SPC5_DSPI1_DISABLE_CLOCK(); INTC.PSR[SPC5_DSPI1_TFFF_NUMBER].R = SPC5_SPI_DSPI1_IRQ_PRIO; #endif /* SPC5_SPI_USE_DSPI1 */ @@ -741,22 +807,40 @@ void spi_lld_init(void) { SPID3.tx1_channel = EDMA_ERROR; SPID3.tx2_channel = EDMA_ERROR; SPID3.rx_channel = EDMA_ERROR; + SPC5_DSPI2_ENABLE_CLOCK(); SPC5_DSPI2.MCR.R = SPC5_MCR_MSTR | SPC5_MCR_HALT | SPC5_MCR_MDIS | SPC5_SPI_DSPI2_MCR; + SPC5_DSPI2_DISABLE_CLOCK(); INTC.PSR[SPC5_DSPI2_TFFF_NUMBER].R = SPC5_SPI_DSPI2_IRQ_PRIO; #endif /* SPC5_SPI_USE_DSPI2 */ -#if SPC5_SPI_USE_DSPI03 +#if SPC5_SPI_USE_DSPI3 /* Driver initialization.*/ spiObjectInit(&SPID4); SPID4.dspi = &SPC5_DSPI3; SPID4.tx1_channel = EDMA_ERROR; SPID4.tx2_channel = EDMA_ERROR; SPID4.rx_channel = EDMA_ERROR; + SPC5_DSPI3_ENABLE_CLOCK(); SPC5_DSPI3.MCR.R = SPC5_MCR_MSTR | SPC5_MCR_HALT | SPC5_MCR_MDIS | SPC5_SPI_DSPI3_MCR; + SPC5_DSPI3_DISABLE_CLOCK(); INTC.PSR[SPC5_DSPI3_TFFF_NUMBER].R = SPC5_SPI_DSPI3_IRQ_PRIO; #endif /* SPC5_SPI_USE_DSPI3 */ + +#if SPC5_SPI_USE_DSPI4 + /* Driver initialization.*/ + spiObjectInit(&SPID5); + SPID5.dspi = &SPC5_DSPI4; + SPID5.tx1_channel = EDMA_ERROR; + SPID5.tx2_channel = EDMA_ERROR; + SPID5.rx_channel = EDMA_ERROR; + SPC5_DSPI4_ENABLE_CLOCK(); + SPC5_DSPI4.MCR.R = SPC5_MCR_MSTR | SPC5_MCR_HALT | SPC5_MCR_MDIS | + SPC5_SPI_DSPI4_MCR; + SPC5_DSPI4_DISABLE_CLOCK(); + INTC.PSR[SPC5_DSPI4_TFFF_NUMBER].R = SPC5_SPI_DSPI4_IRQ_PRIO; +#endif /* SPC5_SPI_USE_DSPI4 */ } /** @@ -810,6 +894,15 @@ void spi_lld_start(SPIDriver *spip) { } #endif /* SPC5_SPI_USE_DSPI3 */ +#if SPC5_SPI_USE_DSPI4 + if (&SPID5 == spip) { + SPC5_DSPI4_ENABLE_CLOCK(); + spip->tx1_channel = edmaChannelAllocate(&spi_dspi4_tx1_dma_config); + spip->tx2_channel = edmaChannelAllocate(&spi_dspi4_tx2_dma_config); + spip->rx_channel = edmaChannelAllocate(&spi_dspi4_rx_dma_config); + } +#endif /* SPC5_SPI_USE_DSPI5 */ + chDbgAssert((spip->tx1_channel != EDMA_ERROR) && (spip->tx2_channel != EDMA_ERROR) && (spip->rx_channel != EDMA_ERROR), @@ -870,6 +963,12 @@ void spi_lld_stop(SPIDriver *spip) { SPC5_DSPI3_DISABLE_CLOCK(); } #endif /* SPC5_SPI_USE_DSPI3 */ + +#if SPC5_SPI_USE_DSPI4 + if (&SPID5 == spip) { + SPC5_DSPI4_DISABLE_CLOCK(); + } +#endif /* SPC5_SPI_USE_DSPI4 */ } } diff --git a/os/hal/platforms/SPC5xx/DSPI_v1/spi_lld.h b/os/hal/platforms/SPC5xx/DSPI_v1/spi_lld.h index dd92d06e3..1f4b62572 100644 --- a/os/hal/platforms/SPC5xx/DSPI_v1/spi_lld.h +++ b/os/hal/platforms/SPC5xx/DSPI_v1/spi_lld.h @@ -386,6 +386,116 @@ #if !defined(SPC5_SPI_DSPI3_IRQ_PRIO) || defined(__DOXYGEN__) #define SPC5_SPI_DSPI3_IRQ_PRIO 10 #endif + +/** + * @brief DSPI0 peripheral configuration when started. + * @note The default configuration is 1 (always run) in run mode and + * 2 (only halt) in low power mode. The defaults of the run modes + * are defined in @p hal_lld.h. + */ +#if !defined(SPC5_SPI_DSPI0_START_PCTL) || defined(__DOXYGEN__) +#define SPC5_SPI_DSPI0_START_PCTL (SPC5_ME_PCTL_RUN(1) | \ + SPC5_ME_PCTL_LP(2)) +#endif + +/** + * @brief DSPI0 peripheral configuration when stopped. + * @note The default configuration is 0 (never run) in run mode and + * 0 (never run) in low power mode. The defaults of the run modes + * are defined in @p hal_lld.h. + */ +#if !defined(SPC5_SPI_DSPI0_STOP_PCTL) || defined(__DOXYGEN__) +#define SPC5_SPI_DSPI0_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \ + SPC5_ME_PCTL_LP(0)) +#endif + +/** + * @brief DSPI1 peripheral configuration when started. + * @note The default configuration is 1 (always run) in run mode and + * 2 (only halt) in low power mode. The defaults of the run modes + * are defined in @p hal_lld.h. + */ +#if !defined(SPC5_SPI_DSPI1_START_PCTL) || defined(__DOXYGEN__) +#define SPC5_SPI_DSPI1_START_PCTL (SPC5_ME_PCTL_RUN(1) | \ + SPC5_ME_PCTL_LP(2)) +#endif + +/** + * @brief DSPI1 peripheral configuration when stopped. + * @note The default configuration is 0 (never run) in run mode and + * 0 (never run) in low power mode. The defaults of the run modes + * are defined in @p hal_lld.h. + */ +#if !defined(SPC5_SPI_DSPI1_STOP_PCTL) || defined(__DOXYGEN__) +#define SPC5_SPI_DSPI1_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \ + SPC5_ME_PCTL_LP(0)) +#endif + +/** + * @brief DSPI2 peripheral configuration when started. + * @note The default configuration is 1 (always run) in run mode and + * 2 (only halt) in low power mode. The defaults of the run modes + * are defined in @p hal_lld.h. + */ +#if !defined(SPC5_SPI_DSPI2_START_PCTL) || defined(__DOXYGEN__) +#define SPC5_SPI_DSPI2_START_PCTL (SPC5_ME_PCTL_RUN(1) | \ + SPC5_ME_PCTL_LP(2)) +#endif + +/** + * @brief DSPI2 peripheral configuration when stopped. + * @note The default configuration is 0 (never run) in run mode and + * 0 (never run) in low power mode. The defaults of the run modes + * are defined in @p hal_lld.h. + */ +#if !defined(SPC5_SPI_DSPI2_STOP_PCTL) || defined(__DOXYGEN__) +#define SPC5_SPI_DSPI2_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \ + SPC5_ME_PCTL_LP(0)) +#endif + +/** + * @brief DSPI3 peripheral configuration when started. + * @note The default configuration is 1 (always run) in run mode and + * 2 (only halt) in low power mode. The defaults of the run modes + * are defined in @p hal_lld.h. + */ +#if !defined(SPC5_SPI_DSPI3_START_PCTL) || defined(__DOXYGEN__) +#define SPC5_SPI_DSPI3_START_PCTL (SPC5_ME_PCTL_RUN(1) | \ + SPC5_ME_PCTL_LP(2)) +#endif + +/** + * @brief DSPI3 peripheral configuration when stopped. + * @note The default configuration is 0 (never run) in run mode and + * 0 (never run) in low power mode. The defaults of the run modes + * are defined in @p hal_lld.h. + */ +#if !defined(SPC5_SPI_DSPI3_STOP_PCTL) || defined(__DOXYGEN__) +#define SPC5_SPI_DSPI3_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \ + SPC5_ME_PCTL_LP(0)) +#endif + +/** + * @brief DSPI4 peripheral configuration when started. + * @note The default configuration is 1 (always run) in run mode and + * 2 (only halt) in low power mode. The defaults of the run modes + * are defined in @p hal_lld.h. + */ +#if !defined(SPC5_SPI_DSPI4_START_PCTL) || defined(__DOXYGEN__) +#define SPC5_SPI_DSPI4_START_PCTL (SPC5_ME_PCTL_RUN(1) | \ + SPC5_ME_PCTL_LP(2)) +#endif + +/** + * @brief DSPI4 peripheral configuration when stopped. + * @note The default configuration is 0 (never run) in run mode and + * 0 (never run) in low power mode. The defaults of the run modes + * are defined in @p hal_lld.h. + */ +#if !defined(SPC5_SPI_DSPI4_STOP_PCTL) || defined(__DOXYGEN__) +#define SPC5_SPI_DSPI4_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \ + SPC5_ME_PCTL_LP(0)) +#endif /** @} */ /*===========================================================================*/ @@ -408,8 +518,13 @@ #error "DSPI3 not present in the selected device" #endif +#if SPC5_SPI_USE_DSPI4 && !SPC5_HAS_DSPI4 +#error "DSPI4 not present in the selected device" +#endif + #if !SPC5_SPI_USE_DSPI0 && !SPC5_SPI_USE_DSPI1 && \ - !SPC5_SPI_USE_DSPI2 && !SPC5_SPI_USE_DSPI3 + !SPC5_SPI_USE_DSPI2 && !SPC5_SPI_USE_DSPI3 && \ + !SPC5_SPI_USE_DSPI4 #error "SPI driver activated but no DSPI peripheral assigned" #endif @@ -547,6 +662,10 @@ extern SPIDriver SPID3; extern SPIDriver SPID4; #endif +#if SPC5_SPI_USE_DSPI4 && !defined(__DOXYGEN__) +extern SPIDriver SPID5; +#endif + #ifdef __cplusplus extern "C" { #endif diff --git a/os/hal/platforms/SPC5xx/EDMA_v1/spc5_edma.c b/os/hal/platforms/SPC5xx/EDMA_v1/spc5_edma.c index a0538ca78..3561a73e7 100644 --- a/os/hal/platforms/SPC5xx/EDMA_v1/spc5_edma.c +++ b/os/hal/platforms/SPC5xx/EDMA_v1/spc5_edma.c @@ -1314,12 +1314,22 @@ edma_channel_t edmaChannelAllocate(const edma_channel_config_t *ccfg) { "edmaChannelAllocate"); #if SPC5_EDMA_HAS_MUX - /* TODO: MUX handling.*/ - channel = 0; + /* Searching for a free channel, we have the MUX so any channel is + acceptable.*/ + for (channel = 0; channel < SPC5_EDMA_NCHANNELS; channel++) + if (channels[channel] == NULL) + break; + if (channel >= SPC5_EDMA_NCHANNELS) + return EDMA_ERROR; /* No free channels. */ + + /* Programming the MUX.*/ + SPC5_DMAMUX.CHCONFIG[channel].R = (uint8_t)(0x80 | ccfg->dma_periph); #else /* !SPC5_EDMA_HAS_MUX */ + /* There is no MUX so we can just check that the specified channels is + available.*/ channel = (edma_channel_t)ccfg->dma_periph; if (channels[channel] != NULL) - return EDMA_ERROR; /* Already taken.*/ + return EDMA_ERROR; /* Already taken. */ #endif /* !SPC5_EDMA_HAS_MUX */ /* Associating the configuration to the channel.*/ @@ -1354,6 +1364,11 @@ void edmaChannelRelease(edma_channel_t channel) { /* Enforcing a stop.*/ edmaChannelStop(channel); +#if SPC5_EDMA_HAS_MUX + /* Disabling the MUX slot.*/ + SPC5_DMAMUX.CHCONFIG[channel].R = 0; +#endif + /* Clearing ISR sources for the channel.*/ SPC5_EDMA.CIRQR.R = channel; SPC5_EDMA.CEEIR.R = channel; diff --git a/os/hal/platforms/SPC5xx/EDMA_v1/spc5_edma.h b/os/hal/platforms/SPC5xx/EDMA_v1/spc5_edma.h index 2830556f5..97437fbac 100644 --- a/os/hal/platforms/SPC5xx/EDMA_v1/spc5_edma.h +++ b/os/hal/platforms/SPC5xx/EDMA_v1/spc5_edma.h @@ -609,6 +609,22 @@ typedef struct { edma_tcd_t TCD[64]; } edma_t; +#if SPC5_EDMA_HAS_MUX || defined(__DOXYGEN__) +/** + * @brief Type of a DMA-MUX peripheral. + */ +typedef struct { + union { + vuint8_t R; + struct { + vuint8_t ENBL:1; + vuint8_t TRIG:1; + vuint8_t SOURCE:6; + } B; + } CHCONFIG[SPC5_EDMA_NCHANNELS]; +} dma_mux_t; +#endif /* SPC5_EDMA_HAS_MUX */ + /** * @brief DMA callback type. * @@ -650,12 +666,17 @@ typedef struct { /*===========================================================================*/ /** - * @name eDMA units references + * @name Peripherals references + * * @{ */ #if SPC5_HAS_EDMA || defined(__DOXYGEN__) #define SPC5_EDMA (*(edma_t *)0xFFF44000U) #endif + +#if SPC5_EDMA_HAS_MUX || defined(__DOXYGEN__) +#define SPC5_DMAMUX (*(dma_mux_t *)0xFFFDC000UL) +#endif /** @} */ /** -- cgit v1.2.3