From 301bbc3a4d80ab26fe0ac09a139d9c6ea0f997ee Mon Sep 17 00:00:00 2001 From: Christian Mauderer Date: Tue, 24 Nov 2020 10:47:11 +0100 Subject: bsps/shared: Copy fsl-edma from mpc55xx This is a preparation for making the driver universal. Update #4180 --- bsps/include/fsl/edma.h | 329 +++++++++++++++++++ bsps/include/fsl/regs-edma.h | 710 +++++++++++++++++++++++++++++++++++++++++ bsps/shared/dev/dma/fsl-edma.c | 329 +++++++++++++++++++ 3 files changed, 1368 insertions(+) create mode 100644 bsps/include/fsl/edma.h create mode 100644 bsps/include/fsl/regs-edma.h create mode 100644 bsps/shared/dev/dma/fsl-edma.c diff --git a/bsps/include/fsl/edma.h b/bsps/include/fsl/edma.h new file mode 100644 index 0000000000..8b7d65d3b6 --- /dev/null +++ b/bsps/include/fsl/edma.h @@ -0,0 +1,329 @@ +/** + * @file + * + * @ingroup RTEMSBSPsPowerPCMPC55XX + * + * @brief Enhanced Direct Memory Access (eDMA). + */ + +/* + * Copyright (c) 2008-2013 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifndef LIBCPU_POWERPC_MPC55XX_EDMA_H +#define LIBCPU_POWERPC_MPC55XX_EDMA_H + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if MPC55XX_CHIP_FAMILY == 551 + #define EDMA_CHANNEL_COUNT 16U +#elif MPC55XX_CHIP_FAMILY == 564 + #define EDMA_CHANNEL_COUNT 16U +#elif MPC55XX_CHIP_FAMILY == 567 + #define EDMA_CHANNEL_COUNT 96U +#else + #define EDMA_CHANNEL_COUNT 64U +#endif + +#define EDMA_MODULE_COUNT ((EDMA_CHANNEL_COUNT + 63U) / 64U) + +#define EDMA_CHANNELS_PER_MODULE 64U + +#if EDMA_MODULE_COUNT == 1 + #define EDMA_TCD_BY_CHANNEL_INDEX(channel_index) \ + (&EDMA.TCD[(channel_index)]) +#elif EDMA_MODULE_COUNT == 2 + #define EDMA_TCD_BY_CHANNEL_INDEX(channel_index) \ + ((channel_index) < EDMA_CHANNELS_PER_MODULE ? \ + &EDMA_A.TCD[(channel_index)] \ + : &EDMA_B.TCD[(channel_index) - EDMA_CHANNELS_PER_MODULE]) +#else + #error "unsupported module count" +#endif + +/* FIXME: These values are only valid for the MPC5566 and MPC5674F */ +typedef enum { + EDMA_EQADC_A_FISR0_CFFF0 = 0, + EDMA_EQADC_A_FISR0_RFDF0 = 1, + EDMA_EQADC_A_FISR1_CFFF1 = 2, + EDMA_EQADC_A_FISR1_RFDF1 = 3, + EDMA_EQADC_A_FISR2_CFFF2 = 4, + EDMA_EQADC_A_FISR2_RFDF2 = 5, + EDMA_EQADC_A_FISR3_CFFF3 = 6, + EDMA_EQADC_A_FISR3_RFDF3 = 7, + EDMA_EQADC_A_FISR4_CFFF4 = 8, + EDMA_EQADC_A_FISR4_RFDF4 = 9, + EDMA_EQADC_A_FISR5_CFFF5 = 10, + EDMA_EQADC_A_FISR5_RFDF5 = 11, + EDMA_DSPI_B_SR_TFFF = 12, + EDMA_DSPI_B_SR_RFDF = 13, + EDMA_DSPI_C_SR_TFFF = 14, + EDMA_DSPI_C_SR_RFDF = 15, + EDMA_DSPI_D_SR_TFFF = 16, + EDMA_DSPI_D_SR_RFDF = 17, + EDMA_ESCI_A_COMBTX = 18, + EDMA_ESCI_A_COMBRX = 19, + EDMA_EMIOS_GFR_F0 = 20, + EDMA_EMIOS_GFR_F1 = 21, + EDMA_EMIOS_GFR_F2 = 22, + EDMA_EMIOS_GFR_F3 = 23, + EDMA_EMIOS_GFR_F4 = 24, + EDMA_EMIOS_GFR_F8 = 25, + EDMA_EMIOS_GFR_F9 = 26, + EDMA_ETPU_CDTRSR_A_DTRS0 = 27, + EDMA_ETPU_CDTRSR_A_DTRS1 = 28, + EDMA_ETPU_CDTRSR_A_DTRS2 = 29, + EDMA_ETPU_CDTRSR_A_DTRS14 = 30, + EDMA_ETPU_CDTRSR_A_DTRS15 = 31, + EDMA_DSPI_A_SR_TFFF = 32, + EDMA_DSPI_A_SR_RFDF = 33, + EDMA_ESCI_B_COMBTX = 34, + EDMA_ESCI_B_COMBRX = 35, + EDMA_EMIOS_GFR_F6 = 36, + EDMA_EMIOS_GFR_F7 = 37, + EDMA_EMIOS_GFR_F10 = 38, + EDMA_EMIOS_GFR_F11 = 39, + EDMA_EMIOS_GFR_F16 = 40, + EDMA_EMIOS_GFR_F17 = 41, + EDMA_EMIOS_GFR_F18 = 42, + EDMA_EMIOS_GFR_F19 = 43, + EDMA_ETPU_CDTRSR_A_DTRS12 = 44, + EDMA_ETPU_CDTRSR_A_DTRS13 = 45, + EDMA_ETPU_CDTRSR_A_DTRS28 = 46, + EDMA_ETPU_CDTRSR_A_DTRS29 = 47, + EDMA_SIU_EISR_EIF0 = 48, + EDMA_SIU_EISR_EIF1 = 49, + EDMA_SIU_EISR_EIF2 = 50, + EDMA_SIU_EISR_EIF3 = 51, + EDMA_ETPU_CDTRSR_B_DTRS0 = 52, + EDMA_ETPU_CDTRSR_B_DTRS1 = 53, + EDMA_ETPU_CDTRSR_B_DTRS2 = 54, + EDMA_ETPU_CDTRSR_B_DTRS3 = 55, + EDMA_ETPU_CDTRSR_B_DTRS12 = 56, + EDMA_ETPU_CDTRSR_B_DTRS13 = 57, + EDMA_ETPU_CDTRSR_B_DTRS14 = 58, + EDMA_ETPU_CDTRSR_B_DTRS15 = 59, + EDMA_ETPU_CDTRSR_B_DTRS28 = 60, + EDMA_ETPU_CDTRSR_B_DTRS29 = 61, + EDMA_ETPU_CDTRSR_B_DTRS30 = 62, + EDMA_ETPU_CDTRSR_B_DTRS31 = 63 + #if MPC55XX_CHIP_FAMILY == 567 + , + EDMA_EQADC_B_FISR0_CFFF0 = 64 + 0, + EDMA_EQADC_B_FISR0_RFDF0 = 64 + 1, + EDMA_EQADC_B_FISR1_CFFF1 = 64 + 2, + EDMA_EQADC_B_FISR1_RFDF1 = 64 + 3, + EDMA_EQADC_B_FISR2_CFFF2 = 64 + 4, + EDMA_EQADC_B_FISR2_RFDF2 = 64 + 5, + EDMA_EQADC_B_FISR3_CFFF3 = 64 + 6, + EDMA_EQADC_B_FISR3_RFDF3 = 64 + 7, + EDMA_EQADC_B_FISR4_CFFF4 = 64 + 8, + EDMA_EQADC_B_FISR4_RFDF4 = 64 + 9, + EDMA_EQADC_B_FISR5_CFFF5 = 64 + 10, + EDMA_EQADC_B_FISR5_RFDF5 = 64 + 11, + EDMA_DECFILTER_A_IB = 64 + 12, + EDMA_DECFILTER_A_OB = 64 + 13, + EDMA_DECFILTER_B_IB = 64 + 14, + EDMA_DECFILTER_B_OB = 64 + 15, + EDMA_DECFILTER_C_IB = 64 + 16, + EDMA_DECFILTER_C_OB = 64 + 17, + EDMA_DECFILTER_D_IB = 64 + 18, + EDMA_DECFILTER_D_OB = 64 + 19, + EDMA_DECFILTER_E_IB = 64 + 20, + EDMA_DECFILTER_E_OB = 64 + 21, + EDMA_DECFILTER_F_IB = 64 + 22, + EDMA_DECFILTER_F_OB = 64 + 23, + EDMA_DECFILTER_G_IB = 64 + 24, + EDMA_DECFILTER_G_OB = 64 + 25, + EDMA_DECFILTER_H_IB = 64 + 26, + EDMA_DECFILTER_H_OB = 64 + 27 + #endif +} edma_channel; + +typedef struct edma_channel_context { + rtems_chain_node node; + volatile struct tcd_t *edma_tcd; + void (*done)(struct edma_channel_context *, uint32_t); +} edma_channel_context; + +void mpc55xx_edma_init(void); + +/** + * @brief Obtains an eDMA channel. + * + * @retval RTEMS_SUCCESSFUL Successful operation. + * @retval RTEMS_RESOURCE_IN_USE The channel is already in use. + */ +rtems_status_code mpc55xx_edma_obtain_channel_by_tcd( + volatile struct tcd_t *edma_tcd +); + +void mpc55xx_edma_release_channel_by_tcd(volatile struct tcd_t *edma_tcd); + +/** + * @brief Obtains an eDMA channel and registers the channel context. + * + * The done handler of the channel context will be called + * - during minor or major loop completions if interrupts are enabled in the + * corresponding TCD, or + * - in case a channel error occurs. + * + * An error status value not equal to zero indicates an error. + * + * @retval RTEMS_SUCCESSFUL Successful operation. + * @retval RTEMS_RESOURCE_IN_USE The channel is already in use. + * @retval RTEMS_IO_ERROR Unable to install interrupt handler for this channel. + */ +rtems_status_code mpc55xx_edma_obtain_channel( + edma_channel_context *ctx, + unsigned irq_priority +); + +void mpc55xx_edma_release_channel(edma_channel_context *ctx); + +/** + * @brief Copies a source TCD to an eDMA TCD. + * + * The DONE flag of the eDMA TCD is cleared before the actual copy operation. + * This enables the setting of channel link or scatter/gather options. + * + * This function can be used to start the channel if the START flags is + * set in the source TCD. + */ +void mpc55xx_edma_copy( + volatile struct tcd_t *edma_tcd, + const struct tcd_t *source_tcd +); + +/** + * @brief Copies a source TCD to an eDMA TCD and enables hardware requests. + * + * The DONE flag of the eDMA TCD is cleared before the actual copy operation. + * This enables the setting of channel link or scatter/gather options. + */ +void mpc55xx_edma_copy_and_enable_hardware_requests( + volatile struct tcd_t *edma_tcd, + const struct tcd_t *source_tcd +); + +void mpc55xx_edma_sg_link( + volatile struct tcd_t *edma_tcd, + const struct tcd_t *source_tcd +); + +static inline volatile struct EDMA_tag *mpc55xx_edma_by_tcd( + volatile struct tcd_t *edma_tcd +) +{ + return (volatile struct EDMA_tag *) + ((uintptr_t) edma_tcd & ~(uintptr_t) 0x1fff); +} + +static inline unsigned mpc55xx_edma_channel_by_tcd( + volatile struct tcd_t *edma_tcd +) +{ + volatile struct EDMA_tag *edma = mpc55xx_edma_by_tcd(edma_tcd); + + return edma_tcd - &edma->TCD[0]; +} + +static inline void mpc55xx_edma_enable_hardware_requests( + volatile struct tcd_t *edma_tcd +) +{ + volatile struct EDMA_tag *edma = mpc55xx_edma_by_tcd(edma_tcd); + unsigned channel = edma_tcd - &edma->TCD[0]; + + edma->SERQR.R = (uint8_t) channel; +} + +static inline void mpc55xx_edma_disable_hardware_requests( + volatile struct tcd_t *edma_tcd +) +{ + volatile struct EDMA_tag *edma = mpc55xx_edma_by_tcd(edma_tcd); + unsigned channel = edma_tcd - &edma->TCD[0]; + + edma->CERQR.R = (uint8_t) channel; +} + +static inline void mpc55xx_edma_enable_error_interrupts( + volatile struct tcd_t *edma_tcd +) +{ + volatile struct EDMA_tag *edma = mpc55xx_edma_by_tcd(edma_tcd); + unsigned channel = edma_tcd - &edma->TCD[0]; + + edma->SEEIR.R = (uint8_t) channel; +} + +static inline void mpc55xx_edma_disable_error_interrupts( + volatile struct tcd_t *edma_tcd +) +{ + volatile struct EDMA_tag *edma = mpc55xx_edma_by_tcd(edma_tcd); + unsigned channel = edma_tcd - &edma->TCD[0]; + + edma->CEEIR.R = (uint8_t) channel; +} + +static inline void mpc55xx_edma_set_start( + volatile struct tcd_t *edma_tcd +) +{ + volatile struct EDMA_tag *edma = mpc55xx_edma_by_tcd(edma_tcd); + unsigned channel = edma_tcd - &edma->TCD[0]; + + edma->SSBR.R = (uint8_t) channel; +} + +static inline void mpc55xx_edma_clear_done( + volatile struct tcd_t *edma_tcd +) +{ + volatile struct EDMA_tag *edma = mpc55xx_edma_by_tcd(edma_tcd); + unsigned channel = edma_tcd - &edma->TCD[0]; + + edma->CDSBR.R = (uint8_t) channel; +} + +static inline void mpc55xx_edma_clear_interrupts( + volatile struct tcd_t *edma_tcd +) +{ + volatile struct EDMA_tag *edma = mpc55xx_edma_by_tcd(edma_tcd); + unsigned channel = edma_tcd - &edma->TCD[0]; + + edma->CIRQR.R = (uint8_t) channel; +} + +static inline bool mpc55xx_edma_is_done( + volatile struct tcd_t *edma_tcd +) +{ + return edma_tcd->BMF.B.DONE; +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LIBCPU_POWERPC_MPC55XX_EDMA_H */ diff --git a/bsps/include/fsl/regs-edma.h b/bsps/include/fsl/regs-edma.h new file mode 100644 index 0000000000..fda47dc1e6 --- /dev/null +++ b/bsps/include/fsl/regs-edma.h @@ -0,0 +1,710 @@ +/** + * @file + * + * @ingroup RTEMSBSPsPowerPCMPC55XX + */ + +/* + * Copyright (c) 2011 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +/********************************************************************* + * + * Copyright: + * Freescale Semiconductor, INC. All Rights Reserved. + * You are hereby granted a copyright license to use, modify, and + * distribute the SOFTWARE so long as this entire notice is + * retained without alteration in any modified and/or redistributed + * versions, and that such modified versions are clearly identified + * as such. No licenses are granted by implication, estoppel or + * otherwise under any patents or trademarks of Freescale + * Semiconductor, Inc. This software is provided on an "AS IS" + * basis and without warranty. + * + * To the maximum extent permitted by applicable law, Freescale + * Semiconductor DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, + * INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A + * PARTICULAR PURPOSE AND ANY WARRANTY AGAINST INFRINGEMENT WITH + * REGARD TO THE SOFTWARE (INCLUDING ANY MODIFIED VERSIONS THEREOF) + * AND ANY ACCOMPANYING WRITTEN MATERIALS. + * + * To the maximum extent permitted by applicable law, IN NO EVENT + * SHALL Freescale Semiconductor BE LIABLE FOR ANY DAMAGES WHATSOEVER + * (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, + * BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER + * PECUNIARY LOSS) ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE. + * + * Freescale Semiconductor assumes no responsibility for the + * maintenance and support of this software + * + ********************************************************************/ + +#ifndef LIBCPU_POWERPC_MPC55XX_REGS_EDMA_H +#define LIBCPU_POWERPC_MPC55XX_REGS_EDMA_H + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/****************************************************************************/ +/* MODULE : eDMA */ +/****************************************************************************/ + struct EDMA_tag { + union EDMA_CR_tag { + uint32_t R; + struct { +#if MPC55XX_CHIP_FAMILY == 566 || MPC55XX_CHIP_FAMILY == 567 + uint32_t:14; + uint32_t CX:1; + uint32_t ECX:1; +#else + uint32_t:16; +#endif + uint32_t GRP3PRI:2; + uint32_t GRP2PRI:2; + uint32_t GRP1PRI:2; + uint32_t GRP0PRI:2; +#if MPC55XX_CHIP_FAMILY == 566 || MPC55XX_CHIP_FAMILY == 567 + uint32_t EMLM:1; + uint32_t CLM:1; + uint32_t HALT:1; + uint32_t HOE:1; +#else + uint32_t:4; +#endif + uint32_t ERGA:1; + uint32_t ERCA:1; + uint32_t EDBG:1; + uint32_t EBW:1; + } B; + } CR; /* Control Register */ + + union { + uint32_t R; + struct { + uint32_t VLD:1; +#if MPC55XX_CHIP_FAMILY == 566 || MPC55XX_CHIP_FAMILY == 567 + uint32_t:14; + uint32_t ECX:1; +#else + uint32_t:15; +#endif + uint32_t GPE:1; + uint32_t CPE:1; + uint32_t ERRCHN:6; + uint32_t SAE:1; + uint32_t SOE:1; + uint32_t DAE:1; + uint32_t DOE:1; + uint32_t NCE:1; + uint32_t SGE:1; + uint32_t SBE:1; + uint32_t DBE:1; + } B; + } ESR; /* Error Status Register */ + + union { + uint32_t R; + struct { + uint32_t ERQ63:1; + uint32_t ERQ62:1; + uint32_t ERQ61:1; + uint32_t ERQ60:1; + uint32_t ERQ59:1; + uint32_t ERQ58:1; + uint32_t ERQ57:1; + uint32_t ERQ56:1; + uint32_t ERQ55:1; + uint32_t ERQ54:1; + uint32_t ERQ53:1; + uint32_t ERQ52:1; + uint32_t ERQ51:1; + uint32_t ERQ50:1; + uint32_t ERQ49:1; + uint32_t ERQ48:1; + uint32_t ERQ47:1; + uint32_t ERQ46:1; + uint32_t ERQ45:1; + uint32_t ERQ44:1; + uint32_t ERQ43:1; + uint32_t ERQ42:1; + uint32_t ERQ41:1; + uint32_t ERQ40:1; + uint32_t ERQ39:1; + uint32_t ERQ38:1; + uint32_t ERQ37:1; + uint32_t ERQ36:1; + uint32_t ERQ35:1; + uint32_t ERQ34:1; + uint32_t ERQ33:1; + uint32_t ERQ32:1; + } B; + } ERQRH; /* DMA Enable Request Register High */ + + union { + uint32_t R; + struct { + uint32_t ERQ31:1; + uint32_t ERQ30:1; + uint32_t ERQ29:1; + uint32_t ERQ28:1; + uint32_t ERQ27:1; + uint32_t ERQ26:1; + uint32_t ERQ25:1; + uint32_t ERQ24:1; + uint32_t ERQ23:1; + uint32_t ERQ22:1; + uint32_t ERQ21:1; + uint32_t ERQ20:1; + uint32_t ERQ19:1; + uint32_t ERQ18:1; + uint32_t ERQ17:1; + uint32_t ERQ16:1; + uint32_t ERQ15:1; + uint32_t ERQ14:1; + uint32_t ERQ13:1; + uint32_t ERQ12:1; + uint32_t ERQ11:1; + uint32_t ERQ10:1; + uint32_t ERQ09:1; + uint32_t ERQ08:1; + uint32_t ERQ07:1; + uint32_t ERQ06:1; + uint32_t ERQ05:1; + uint32_t ERQ04:1; + uint32_t ERQ03:1; + uint32_t ERQ02:1; + uint32_t ERQ01:1; + uint32_t ERQ00:1; + } B; + } ERQRL; /* DMA Enable Request Register Low */ + + union { + uint32_t R; + struct { + uint32_t EEI63:1; + uint32_t EEI62:1; + uint32_t EEI61:1; + uint32_t EEI60:1; + uint32_t EEI59:1; + uint32_t EEI58:1; + uint32_t EEI57:1; + uint32_t EEI56:1; + uint32_t EEI55:1; + uint32_t EEI54:1; + uint32_t EEI53:1; + uint32_t EEI52:1; + uint32_t EEI51:1; + uint32_t EEI50:1; + uint32_t EEI49:1; + uint32_t EEI48:1; + uint32_t EEI47:1; + uint32_t EEI46:1; + uint32_t EEI45:1; + uint32_t EEI44:1; + uint32_t EEI43:1; + uint32_t EEI42:1; + uint32_t EEI41:1; + uint32_t EEI40:1; + uint32_t EEI39:1; + uint32_t EEI38:1; + uint32_t EEI37:1; + uint32_t EEI36:1; + uint32_t EEI35:1; + uint32_t EEI34:1; + uint32_t EEI33:1; + uint32_t EEI32:1; + } B; + } EEIRH; /* DMA Enable Error Interrupt Register High */ + + union { + uint32_t R; + struct { + uint32_t EEI31:1; + uint32_t EEI30:1; + uint32_t EEI29:1; + uint32_t EEI28:1; + uint32_t EEI27:1; + uint32_t EEI26:1; + uint32_t EEI25:1; + uint32_t EEI24:1; + uint32_t EEI23:1; + uint32_t EEI22:1; + uint32_t EEI21:1; + uint32_t EEI20:1; + uint32_t EEI19:1; + uint32_t EEI18:1; + uint32_t EEI17:1; + uint32_t EEI16:1; + uint32_t EEI15:1; + uint32_t EEI14:1; + uint32_t EEI13:1; + uint32_t EEI12:1; + uint32_t EEI11:1; + uint32_t EEI10:1; + uint32_t EEI09:1; + uint32_t EEI08:1; + uint32_t EEI07:1; + uint32_t EEI06:1; + uint32_t EEI05:1; + uint32_t EEI04:1; + uint32_t EEI03:1; + uint32_t EEI02:1; + uint32_t EEI01:1; + uint32_t EEI00:1; + } B; + } EEIRL; /* DMA Enable Error Interrupt Register Low */ + + union { /* DMA Set Enable Request Register */ + uint8_t R; + struct { + uint8_t NOP:1; + uint8_t SERQ:7; + } B; + } SERQR; + + union { /* DMA Clear Enable Request Register */ + uint8_t R; + struct { + uint8_t NOP:1; + uint8_t CERQ:7; + } B; + } CERQR; + + union { /* DMA Set Enable Error Interrupt Register */ + uint8_t R; + struct { + uint8_t NOP:1; + uint8_t SEEI:7; + } B; + } SEEIR; + + union { /* DMA Clear Enable Error Interrupt Register */ + uint8_t R; + struct { + uint8_t NOP:1; + uint8_t CEEI:7; + } B; + } CEEIR; + + union { /* DMA Clear Interrupt Request Register */ + uint8_t R; + struct { + uint8_t NOP:1; + uint8_t CINT:7; + } B; + } CIRQR; + + union { /* DMA Clear error Register */ + uint8_t R; + struct { + uint8_t NOP:1; + uint8_t CERR:7; + } B; + } CER; + + union { /* Set Start Bit Register */ + uint8_t R; + struct { + uint8_t NOP:1; + uint8_t SSB:7; + } B; + } SSBR; + + union { /* Clear Done Status Bit Register */ + uint8_t R; + struct { + uint8_t NOP:1; + uint8_t CDSB:7; + } B; + } CDSBR; + + union { + uint32_t R; + struct { + uint32_t INT63:1; + uint32_t INT62:1; + uint32_t INT61:1; + uint32_t INT60:1; + uint32_t INT59:1; + uint32_t INT58:1; + uint32_t INT57:1; + uint32_t INT56:1; + uint32_t INT55:1; + uint32_t INT54:1; + uint32_t INT53:1; + uint32_t INT52:1; + uint32_t INT51:1; + uint32_t INT50:1; + uint32_t INT49:1; + uint32_t INT48:1; + uint32_t INT47:1; + uint32_t INT46:1; + uint32_t INT45:1; + uint32_t INT44:1; + uint32_t INT43:1; + uint32_t INT42:1; + uint32_t INT41:1; + uint32_t INT40:1; + uint32_t INT39:1; + uint32_t INT38:1; + uint32_t INT37:1; + uint32_t INT36:1; + uint32_t INT35:1; + uint32_t INT34:1; + uint32_t INT33:1; + uint32_t INT32:1; + } B; + } IRQRH; /* DMA Interrupt Request High */ + + union { + uint32_t R; + struct { + uint32_t INT31:1; + uint32_t INT30:1; + uint32_t INT29:1; + uint32_t INT28:1; + uint32_t INT27:1; + uint32_t INT26:1; + uint32_t INT25:1; + uint32_t INT24:1; + uint32_t INT23:1; + uint32_t INT22:1; + uint32_t INT21:1; + uint32_t INT20:1; + uint32_t INT19:1; + uint32_t INT18:1; + uint32_t INT17:1; + uint32_t INT16:1; + uint32_t INT15:1; + uint32_t INT14:1; + uint32_t INT13:1; + uint32_t INT12:1; + uint32_t INT11:1; + uint32_t INT10:1; + uint32_t INT09:1; + uint32_t INT08:1; + uint32_t INT07:1; + uint32_t INT06:1; + uint32_t INT05:1; + uint32_t INT04:1; + uint32_t INT03:1; + uint32_t INT02:1; + uint32_t INT01:1; + uint32_t INT00:1; + } B; + } IRQRL; /* DMA Interrupt Request Low */ + + union { + uint32_t R; + struct { + uint32_t ERR63:1; + uint32_t ERR62:1; + uint32_t ERR61:1; + uint32_t ERR60:1; + uint32_t ERR59:1; + uint32_t ERR58:1; + uint32_t ERR57:1; + uint32_t ERR56:1; + uint32_t ERR55:1; + uint32_t ERR54:1; + uint32_t ERR53:1; + uint32_t ERR52:1; + uint32_t ERR51:1; + uint32_t ERR50:1; + uint32_t ERR49:1; + uint32_t ERR48:1; + uint32_t ERR47:1; + uint32_t ERR46:1; + uint32_t ERR45:1; + uint32_t ERR44:1; + uint32_t ERR43:1; + uint32_t ERR42:1; + uint32_t ERR41:1; + uint32_t ERR40:1; + uint32_t ERR39:1; + uint32_t ERR38:1; + uint32_t ERR37:1; + uint32_t ERR36:1; + uint32_t ERR35:1; + uint32_t ERR34:1; + uint32_t ERR33:1; + uint32_t ERR32:1; + } B; + } ERH; /* DMA Error High */ + + union { + uint32_t R; + struct { + uint32_t ERR31:1; + uint32_t ERR30:1; + uint32_t ERR29:1; + uint32_t ERR28:1; + uint32_t ERR27:1; + uint32_t ERR26:1; + uint32_t ERR25:1; + uint32_t ERR24:1; + uint32_t ERR23:1; + uint32_t ERR22:1; + uint32_t ERR21:1; + uint32_t ERR20:1; + uint32_t ERR19:1; + uint32_t ERR18:1; + uint32_t ERR17:1; + uint32_t ERR16:1; + uint32_t ERR15:1; + uint32_t ERR14:1; + uint32_t ERR13:1; + uint32_t ERR12:1; + uint32_t ERR11:1; + uint32_t ERR10:1; + uint32_t ERR09:1; + uint32_t ERR08:1; + uint32_t ERR07:1; + uint32_t ERR06:1; + uint32_t ERR05:1; + uint32_t ERR04:1; + uint32_t ERR03:1; + uint32_t ERR02:1; + uint32_t ERR01:1; + uint32_t ERR00:1; + } B; + } ERL; /* DMA Error Low */ + +#if MPC55XX_CHIP_FAMILY == 566 || MPC55XX_CHIP_FAMILY == 567 + union { /* hardware request status high */ + uint32_t R; + struct { + uint32_t HRS63:1; + uint32_t HRS62:1; + uint32_t HRS61:1; + uint32_t HRS60:1; + uint32_t HRS59:1; + uint32_t HRS58:1; + uint32_t HRS57:1; + uint32_t HRS56:1; + uint32_t HRS55:1; + uint32_t HRS54:1; + uint32_t HRS53:1; + uint32_t HRS52:1; + uint32_t HRS51:1; + uint32_t HRS50:1; + uint32_t HRS49:1; + uint32_t HRS48:1; + uint32_t HRS47:1; + uint32_t HRS46:1; + uint32_t HRS45:1; + uint32_t HRS44:1; + uint32_t HRS43:1; + uint32_t HRS42:1; + uint32_t HRS41:1; + uint32_t HRS40:1; + uint32_t HRS39:1; + uint32_t HRS38:1; + uint32_t HRS37:1; + uint32_t HRS36:1; + uint32_t HRS35:1; + uint32_t HRS34:1; + uint32_t HRS33:1; + uint32_t HRS32:1; + } B; + } HRSH; + + union { /* hardware request status low */ + uint32_t R; + struct { + uint32_t HRS31:1; + uint32_t HRS30:1; + uint32_t HRS29:1; + uint32_t HRS28:1; + uint32_t HRS27:1; + uint32_t HRS26:1; + uint32_t HRS25:1; + uint32_t HRS24:1; + uint32_t HRS23:1; + uint32_t HRS22:1; + uint32_t HRS21:1; + uint32_t HRS20:1; + uint32_t HRS19:1; + uint32_t HRS18:1; + uint32_t HRS17:1; + uint32_t HRS16:1; + uint32_t HRS15:1; + uint32_t HRS14:1; + uint32_t HRS13:1; + uint32_t HRS12:1; + uint32_t HRS11:1; + uint32_t HRS10:1; + uint32_t HRS09:1; + uint32_t HRS08:1; + uint32_t HRS07:1; + uint32_t HRS06:1; + uint32_t HRS05:1; + uint32_t HRS04:1; + uint32_t HRS03:1; + uint32_t HRS02:1; + uint32_t HRS01:1; + uint32_t HRS00:1; + } B; + } HRSL; + + uint32_t eDMA_reserved0038[50]; /* 0x0038-0x00FF */ +#else + uint32_t edma_reserved1[52]; +#endif + + union { + uint8_t R; + struct { + uint8_t ECP:1; +#if MPC55XX_CHIP_FAMILY == 566 || MPC55XX_CHIP_FAMILY == 567 + uint8_t DPA:1; +#else + uint8_t:1; +#endif + uint8_t GRPPRI:2; + uint8_t CHPRI:4; + } B; + } CPR[64]; + + uint32_t edma_reserved2[944]; + +/****************************************************************************/ +/* DMA2 Transfer Control Descriptor */ +/****************************************************************************/ + struct tcd_t { + uint32_t SADDR; /* source address */ + + /* Source and destination fields */ + union tcd_SDF_tag { + uint32_t R; + struct { + uint16_t SMOD:5; /* source address modulo */ + uint16_t SSIZE:3; /* source transfer size */ + uint16_t DMOD:5; /* destination address modulo */ + uint16_t DSIZE:3; /* destination transfer size */ + int16_t SOFF; /* signed source address offset */ + } B; + } SDF; + + uint32_t NBYTES; /* inner (“minor”) byte count */ + + int32_t SLAST; /* last destination address adjustment, or + scatter/gather address (if e_sg = 1) */ + + uint32_t DADDR; /* destination address */ + + /* CITER and destination fields */ + union tcd_CDF_tag { + uint32_t R; + struct { + uint16_t CITERE_LINK:1; + uint16_t CITER:15; + int16_t DOFF; /* signed destination address offset */ + } B; + struct { + uint16_t CITERE_LINK:1; + uint16_t CITERLINKCH:6; + uint16_t CITER:9; + int16_t DOFF; + } B_ALT; + struct { + uint16_t CITER; + int16_t DOFF; + } B_NOLINK; + } CDF; + + int32_t DLAST_SGA; + + /* BITER and misc fields */ + union tcd_BMF_tag { + uint32_t R; + struct { + uint32_t BITERE_LINK:1; /* beginning ("major") iteration count */ + uint32_t BITER:15; + uint32_t BWC:2; /* bandwidth control */ + uint32_t MAJORLINKCH:6; /* enable channel-to-channel link */ + uint32_t DONE:1; /* channel done */ + uint32_t ACTIVE:1; /* channel active */ + uint32_t MAJORE_LINK:1; /* enable channel-to-channel link */ + uint32_t E_SG:1; /* enable scatter/gather descriptor */ + uint32_t D_REQ:1; /* disable ipd_req when done */ + uint32_t INT_HALF:1; /* interrupt on citer = (biter >> 1) */ + uint32_t INT_MAJ:1; /* interrupt on major loop completion */ + uint32_t START:1; /* explicit channel start */ + } B; + struct { + uint32_t BITERE_LINK:1; + uint32_t BITERLINKCH:6; + uint32_t BITER:9; + uint32_t BWC:2; + uint32_t MAJORLINKCH:6; + uint32_t DONE:1; + uint32_t ACTIVE:1; + uint32_t MAJORE_LINK:1; + uint32_t E_SG:1; + uint32_t D_REQ:1; + uint32_t INT_HALF:1; + uint32_t INT_MAJ:1; + uint32_t START:1; + } B_ALT; + struct { + uint16_t BITER; + uint16_t BWC:2; + uint16_t MAJORLINKCH:6; + uint16_t DONE:1; + uint16_t ACTIVE:1; + uint16_t MAJORE_LINK:1; + uint16_t E_SG:1; + uint16_t D_REQ:1; + uint16_t INT_HALF:1; + uint16_t INT_MAJ:1; + uint16_t START:1; + } B_NOLINK; + } BMF; + } TCD[64]; /* transfer_control_descriptor */ + }; + +#ifndef __cplusplus + static const struct tcd_t EDMA_TCD_DEFAULT = { + .SADDR = 0, + .SDF = { .R = 0 }, + .NBYTES = 0, + .SLAST = 0, + .DADDR = 0, + .CDF = { .R = 0 }, + .DLAST_SGA = 0, + .BMF = { .R = 0 } + }; +#endif /* __cplusplus */ + +#define EDMA_TCD_BITER_MASK 0x7fff + +#define EDMA_TCD_BITER_SIZE (EDMA_TCD_BITER_MASK + 1) + +#define EDMA_TCD_BITER_LINKED_MASK 0x1ff + +#define EDMA_TCD_BITER_LINKED_SIZE (EDMA_TCD_BITER_LINKED_MASK + 1) + +#define EDMA_TCD_LINK_AND_BITER(link, biter) \ + (((link) << 9) + ((biter) & EDMA_TCD_BITER_LINKED_MASK)) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LIBCPU_POWERPC_MPC55XX_REGS_EDMA_H */ diff --git a/bsps/shared/dev/dma/fsl-edma.c b/bsps/shared/dev/dma/fsl-edma.c new file mode 100644 index 0000000000..c34624ed10 --- /dev/null +++ b/bsps/shared/dev/dma/fsl-edma.c @@ -0,0 +1,329 @@ +/** + * @file + * + * @ingroup RTEMSBSPsPowerPCMPC55XX + * + * @brief Enhanced Direct Memory Access (eDMA). + */ + +/* + * Copyright (c) 2008-2013 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include +#include + +#include + +#include +#include +#include + +#define EDMA_CHANNELS_PER_GROUP 32U + +#define EDMA_GROUP_COUNT ((EDMA_CHANNEL_COUNT + 31U) / 32U) + +#define EDMA_GROUP_INDEX(channel) ((channel) / EDMA_CHANNELS_PER_GROUP) + +#define EDMA_GROUP_BIT(channel) (1U << ((channel) % EDMA_CHANNELS_PER_GROUP)) + +#define EDMA_MODULE_INDEX(channel) ((channel) / EDMA_CHANNELS_PER_MODULE) + +static uint32_t edma_channel_occupation [EDMA_GROUP_COUNT]; + +static RTEMS_CHAIN_DEFINE_EMPTY(edma_channel_chain); + +static unsigned edma_channel_index_of_tcd(volatile struct tcd_t *edma_tcd) +{ + volatile struct EDMA_tag *edma = mpc55xx_edma_by_tcd(edma_tcd); + unsigned channel = edma_tcd - &edma->TCD[0]; + +#if EDMA_MODULE_COUNT == 1 + return channel; +#elif EDMA_MODULE_COUNT == 2 + return channel + (&EDMA_A == edma ? 0 : EDMA_CHANNELS_PER_MODULE); +#else + #error "unsupported module count" +#endif +} + +static volatile struct EDMA_tag *edma_get_regs_by_module(unsigned module) +{ +#if EDMA_MODULE_COUNT == 1 + return &EDMA; +#elif EDMA_MODULE_COUNT == 2 + return module == 0 ? &EDMA_A : &EDMA_B; +#else + #error "unsupported module count" +#endif +} + +static uint32_t edma_bit_array_set(unsigned channel, uint32_t *bit_array) +{ + unsigned array = channel / 32; + uint32_t bit = 1U << (channel % 32); + uint32_t previous = bit_array [array]; + + bit_array [array] = previous | bit; + + return previous; +} + +static uint32_t edma_bit_array_clear(unsigned channel, uint32_t *bit_array) +{ + unsigned array = channel / 32; + uint32_t bit = 1U << (channel % 32); + uint32_t previous = bit_array [array]; + + bit_array [array] = previous & ~bit; + + return previous; +} + +static void edma_interrupt_handler(void *arg) +{ + edma_channel_context *ctx = arg; + + mpc55xx_edma_clear_interrupts(ctx->edma_tcd); + + (*ctx->done)(ctx, 0); +} + +static void edma_interrupt_error_handler(void *arg) +{ + rtems_chain_control *chain = &edma_channel_chain; + rtems_chain_node *node = rtems_chain_first(chain); + uint32_t error_channels [] = { +#if EDMA_GROUP_COUNT >= 1 + EDMA.ERL.R +#endif +#if EDMA_GROUP_COUNT >= 2 + , EDMA.ERH.R +#endif +#if EDMA_GROUP_COUNT >= 3 + , EDMA_B.ERL.R +#endif + }; + uint32_t error_status [] = { +#if EDMA_GROUP_COUNT >= 1 + EDMA.ESR.R +#endif +#if EDMA_GROUP_COUNT >= 3 + , EDMA_B.ESR.R +#endif + }; + +#if EDMA_GROUP_COUNT >= 1 + EDMA.ERL.R = error_channels [0]; +#endif +#if EDMA_GROUP_COUNT >= 2 + EDMA.ERH.R = error_channels [1]; +#endif +#if EDMA_GROUP_COUNT >= 3 + EDMA_B.ERL.R = error_channels [2]; +#endif + + while (!rtems_chain_is_tail(chain, node)) { + edma_channel_context *ctx = (edma_channel_context *) node; + unsigned channel_index = edma_channel_index_of_tcd(ctx->edma_tcd); + unsigned group_index = EDMA_GROUP_INDEX(channel_index); + unsigned group_bit = EDMA_GROUP_BIT(channel_index); + + if ((error_channels [group_index] & group_bit) != 0) { + unsigned module_index = EDMA_MODULE_INDEX(channel_index); + + (*ctx->done)(ctx, error_status [module_index]); + } + + node = rtems_chain_next(node); + } +} + +void mpc55xx_edma_init(void) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + unsigned channel_remaining = EDMA_CHANNEL_COUNT; + unsigned module = 0; + unsigned group = 0; + + for (module = 0; module < EDMA_MODULE_COUNT; ++module) { + volatile struct EDMA_tag *edma = edma_get_regs_by_module(module); + unsigned channel_count = channel_remaining < EDMA_CHANNELS_PER_MODULE ? + channel_remaining : EDMA_CHANNELS_PER_MODULE; + unsigned channel = 0; + + channel_remaining -= channel_count; + + /* Disable requests */ + edma->CERQR.B.CERQ = 0x40; + + /* Arbitration mode: group round robin, channel fixed */ + edma->CR.B.ERGA = 1; + edma->CR.B.ERCA = 0; + for (channel = 0; channel < channel_count; ++channel) { + volatile struct tcd_t *tcd = &edma->TCD [channel]; + edma->CPR [channel].R = 0x80U | (channel & 0xfU); + + /* Initialize TCD, stop channel first */ + tcd->BMF.R = 0; + tcd->SADDR = 0; + tcd->SDF.R = 0; + tcd->NBYTES = 0; + tcd->SLAST = 0; + tcd->DADDR = 0; + tcd->CDF.R = 0; + tcd->DLAST_SGA = 0; + } + + /* Clear interrupt requests */ + edma->CIRQR.B.CINT = 0x40; + edma->CER.B.CERR = 0x40; + } + + for (group = 0; group < EDMA_GROUP_COUNT; ++group) { + sc = mpc55xx_interrupt_handler_install( + MPC55XX_IRQ_EDMA_ERROR(group), + "eDMA Error", + RTEMS_INTERRUPT_UNIQUE, + MPC55XX_INTC_DEFAULT_PRIORITY, + edma_interrupt_error_handler, + NULL + ); + if (sc != RTEMS_SUCCESSFUL) { + bsp_fatal(MPC55XX_FATAL_EDMA_IRQ_INSTALL); + } + } +} + +rtems_status_code mpc55xx_edma_obtain_channel_by_tcd( + volatile struct tcd_t *edma_tcd +) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + unsigned channel_index = edma_channel_index_of_tcd(edma_tcd); + rtems_interrupt_level level; + uint32_t channel_occupation; + + rtems_interrupt_disable(level); + channel_occupation = edma_bit_array_set( + channel_index, + &edma_channel_occupation [0] + ); + rtems_interrupt_enable(level); + + if ((channel_occupation & EDMA_GROUP_BIT(channel_index)) != 0) { + sc = RTEMS_RESOURCE_IN_USE; + } + + return sc; +} + +void mpc55xx_edma_release_channel_by_tcd(volatile struct tcd_t *edma_tcd) +{ + unsigned channel_index = edma_channel_index_of_tcd(edma_tcd); + rtems_interrupt_level level; + + rtems_interrupt_disable(level); + edma_bit_array_clear(channel_index, &edma_channel_occupation [0]); + rtems_interrupt_enable(level); + + mpc55xx_edma_disable_hardware_requests(edma_tcd); + mpc55xx_edma_disable_error_interrupts(edma_tcd); +} + +rtems_status_code mpc55xx_edma_obtain_channel( + edma_channel_context *ctx, + unsigned irq_priority +) +{ + rtems_status_code sc = mpc55xx_edma_obtain_channel_by_tcd(ctx->edma_tcd); + if (sc == RTEMS_SUCCESSFUL) { + unsigned channel_index = edma_channel_index_of_tcd(ctx->edma_tcd); + + sc = mpc55xx_interrupt_handler_install( + MPC55XX_IRQ_EDMA(channel_index), + "eDMA Channel", + RTEMS_INTERRUPT_SHARED, + irq_priority, + edma_interrupt_handler, + ctx + ); + if (sc == RTEMS_SUCCESSFUL) { + rtems_chain_prepend(&edma_channel_chain, &ctx->node); + mpc55xx_edma_enable_error_interrupts(ctx->edma_tcd); + } else { + mpc55xx_edma_release_channel_by_tcd(ctx->edma_tcd); + sc = RTEMS_IO_ERROR; + } + } + + return sc; +} + +void mpc55xx_edma_release_channel(edma_channel_context *ctx) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + unsigned channel_index = edma_channel_index_of_tcd(ctx->edma_tcd); + + mpc55xx_edma_release_channel_by_tcd(ctx->edma_tcd); + rtems_chain_extract(&ctx->node); + + sc = rtems_interrupt_handler_remove( + MPC55XX_IRQ_EDMA(channel_index), + edma_interrupt_handler, + ctx + ); + if (sc != RTEMS_SUCCESSFUL) { + bsp_fatal(MPC55XX_FATAL_EDMA_IRQ_REMOVE); + } +} + +void mpc55xx_edma_copy( + volatile struct tcd_t *edma_tcd, + const struct tcd_t *source_tcd +) +{ + /* Clear DONE flag */ + edma_tcd->BMF.R = 0; + + edma_tcd->SADDR = source_tcd->SADDR; + edma_tcd->SDF.R = source_tcd->SDF.R; + edma_tcd->NBYTES = source_tcd->NBYTES; + edma_tcd->SLAST = source_tcd->SLAST; + edma_tcd->DADDR = source_tcd->DADDR; + edma_tcd->CDF.R = source_tcd->CDF.R; + edma_tcd->DLAST_SGA = source_tcd->DLAST_SGA; + edma_tcd->BMF.R = source_tcd->BMF.R; +} + +void mpc55xx_edma_copy_and_enable_hardware_requests( + volatile struct tcd_t *edma_tcd, + const struct tcd_t *source_tcd +) +{ + mpc55xx_edma_copy(edma_tcd, source_tcd); + mpc55xx_edma_enable_hardware_requests(edma_tcd); +} + +void mpc55xx_edma_sg_link( + volatile struct tcd_t *edma_tcd, + const struct tcd_t *source_tcd +) +{ + edma_tcd->DLAST_SGA = (int32_t) source_tcd; + edma_tcd->BMF.B.E_SG = 1; + + if (!edma_tcd->BMF.B.E_SG) { + mpc55xx_edma_copy(edma_tcd, source_tcd); + } +} -- cgit v1.2.3