diff --git a/arch/mips/include/pic32mz/irq.h b/arch/mips/include/pic32mz/irq.h index 06d36b0d067..bf811690e60 100644 --- a/arch/mips/include/pic32mz/irq.h +++ b/arch/mips/include/pic32mz/irq.h @@ -52,7 +52,7 @@ #elif defined(CHIP_PIC32MZEF) # include #else -# error "Unknown PIC32MZ family +# error "Unknown PIC32MZ family" #endif /**************************************************************************** diff --git a/arch/mips/src/pic32mz/Make.defs b/arch/mips/src/pic32mz/Make.defs index b6d9f24caa8..140b408c447 100644 --- a/arch/mips/src/pic32mz/Make.defs +++ b/arch/mips/src/pic32mz/Make.defs @@ -111,3 +111,8 @@ endif ifeq ($(CONFIG_PIC32MZ_ETHERNET),y) CHIP_CSRCS += pic32mz-ethernet.c endif + +ifeq ($(CONFIG_PIC32MZ_DMA),y) +CHIP_CSRCS += pic32mz-dma.c +endif + diff --git a/arch/mips/src/pic32mz/hardware/pic32mz-dma.h b/arch/mips/src/pic32mz/hardware/pic32mz-dma.h index 76095ca8ba7..9d8e597cdbe 100644 --- a/arch/mips/src/pic32mz/hardware/pic32mz-dma.h +++ b/arch/mips/src/pic32mz/hardware/pic32mz-dma.h @@ -52,7 +52,7 @@ ********************************************************************************************/ /* DMA Channel Offsets **********************************************************************/ -#define PIC32MZ_DMACHn_OFFSET(n) (0x0060 + 00c0 *(n)) +#define PIC32MZ_DMACHn_OFFSET(n) (0x0060 + 0xc0 *(n)) # define PIC32MZ_DMACH0_OFFSET 0x0060 # define PIC32MZ_DMACH1_OFFSET 0x0120 # define PIC32MZ_DMACH2_OFFSET 0x01e0 @@ -386,6 +386,7 @@ # define PIC32MZ_DMACH2_DATCLR (PIC32MZ_DMACH2_K1BASE+PIC32MZ_DMACH_DATCLR_OFFSET) # define PIC32MZ_DMACH2_DATSET (PIC32MZ_DMACH2_K1BASE+PIC32MZ_DMACH_DATSET_OFFSET) # define PIC32MZ_DMACH2_DATINV (PIC32MZ_DMACH2_K1BASE+PIC32MZ_DMACH_DATINV_OFFSET) +#endif #if CHIP_NDMACH > 3 # define PIC32MZ_DMACH3_CON (PIC32MZ_DMACH3_K1BASE+PIC32MZ_DMACH_CON_OFFSET) @@ -658,8 +659,8 @@ /* DMA Status Register */ #define DMA_STAT_DMACH_SHIFT (0) /* Bits 0-1: DMA channel */ -#define DMA_STAT_DMACH_MASK (3 << DMA_STAT_DMACH_SHIFT) -#define DMA_STAT_RDWR (1 << 3) /* Bit 3: Read/write status */ +#define DMA_STAT_DMACH_MASK (7 << DMA_STAT_DMACH_SHIFT) +#define DMA_STAT_RDWR (1 << 31) /* Bit 31: Read/write status */ /* DMA Address Register -- This register contains a 32-bit address value */ @@ -737,6 +738,10 @@ #define DMACH_INT_CHDDIE (1 << 21) /* Bit 21: Channel destination done interrupt enable */ #define DMACH_INT_CHSHIE (1 << 22) /* Bit 22: Channel source half empty interrupt enable */ #define DMACH_INT_CHSDIE (1 << 23) /* Bit 23: Channel source done interrupt enable */ +#define DMACH_INT_FLAGS_SHIFT (0) /* Bits 0-7: Channel Interrupt flags */ +#define DMACH_INT_FLAGS_MASK (0xff << DMACH_INT_FLAGS_SHIFT) +#define DMACH_INT_EN_SHIFT (16) /* Bits 16-23: Channel Interrupt Enable events */ +#define DMACH_INT_EN_MASK (0xff << DMACH_INT_EN_SHIFT) /* DMA Channel Source Start Address Register -- This register contains a 32-bit address value */ /* DMA Channel Destination Start Address Register -- This register contains a 32-bit address value */ @@ -762,7 +767,7 @@ /* DMA Channel Cell Pointer Register -- 16 bits of byte transferred data */ -#define DMACH_DPCR_MASK 0x0000ffff +#define DMACH_CPTR_MASK 0x0000ffff /* DMA Channel Pattern Data Register -- 16 bits of pattern data */ diff --git a/arch/mips/src/pic32mz/hardware/pic32mz-memorymap.h b/arch/mips/src/pic32mz/hardware/pic32mz-memorymap.h index 6ccfd667222..850648661f9 100644 --- a/arch/mips/src/pic32mz/hardware/pic32mz-memorymap.h +++ b/arch/mips/src/pic32mz/hardware/pic32mz-memorymap.h @@ -47,7 +47,7 @@ #elif defined(CONFIG_ARCH_CHIP_PIC32MZEF) # include "hardware/pic32mzef-memorymap.h" #else -# error Unknown PIC32MZ family +# error "Unknown PIC32MZ family" #endif #endif /* __ARCH_MIPS_SRC_PIC32MZ_HARDWARE_PIC32MZ_MEMORYMAP_H */ diff --git a/arch/mips/src/pic32mz/pic32mz-dma.c b/arch/mips/src/pic32mz/pic32mz-dma.c new file mode 100644 index 00000000000..f4f8ffa6e4e --- /dev/null +++ b/arch/mips/src/pic32mz/pic32mz-dma.c @@ -0,0 +1,980 @@ +/**************************************************************************** + * arch/mips/src/pic32mz/chip/pic32mz-dma.c + * + * Copyright (C) 2019 Abdelatif Guettouche. All rights reserved. + * Author: Abdelatif Guettouche + * + * This file is a part of NuttX: + * + * Copyright (C) 2019 Gregory Nutt. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include + +#include "up_arch.h" +#include "up_internal.h" +#include "sched/sched.h" + +#include "hardware/pic32mz-dma.h" +#include "pic32mz-dma.h" + +#ifdef CONFIG_PIC32MZ_DMA + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Convert a virtual address to a physical address */ + +#define VIRT2PHY(a) ((a) & 0x1FFFFFFF) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure describes one DMA channel */ + +struct pic32mz_dmach_s +{ + uint8_t chan; /* DMA channel number (0-8) */ + uint8_t irq; /* DMA channel IRQ number */ + uint32_t base; /* DMA register channel base address */ + bool inuse; /* true: The DMA channel is in use */ + dma_callback_t callback; /* Callback invoked when the DMA completes */ + void *arg; /* Argument passed to callback function */ + struct pic32mz_dma_chcfg_s cfg; /* Channel's config */ +}; + +/* This structure describes the state of the DMA controller */ + +struct pic32mz_dmac_s +{ + /* Protects the channels' table */ + + sem_t chsem; + + /* Describes all DMA channels */ + + struct pic32mz_dmach_s dmachs[CHIP_NDMACH]; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void pic32mz_dma_takesem(struct pic32mz_dmac_s *dmac); +static inline void pic32mz_dma_givesem(struct pic32mz_dmac_s *dmac); + +static inline uint32_t pic32mz_dma_getreg(FAR struct pic32mz_dmach_s *dmach, + uint8_t offset); +static inline void pic32mz_dma_putreg(FAR struct pic32mz_dmach_s *dmach, + uint8_t offset, uint32_t value); +static inline void pic32mz_dma_modifyreg(FAR struct pic32mz_dmach_s *dmach, + uint8_t offset, + uint32_t clrbits, uint32_t setbits); +static inline uint32_t pic32mz_dma_getglobal(uint8_t offset); +static inline void pic32mz_dma_putglobal(uint8_t offset, uint32_t value); + +static inline void pic32mz_dma_enable(FAR struct pic32mz_dmach_s *dmach); +static inline void pic32mz_dma_disable(FAR struct pic32mz_dmach_s *dmach); +static inline void pic32mz_dma_priority(FAR struct pic32mz_dmach_s *dmach, + uint8_t priority); +static inline void pic32mz_dma_srcaddr(FAR struct pic32mz_dmach_s *dmach, + uint32_t addr); +static inline void pic32mz_dma_destaddr(FAR struct pic32mz_dmach_s *dmach, + uint32_t addr); +static inline void pic32mz_dma_srcsize(FAR struct pic32mz_dmach_s *dmach, + uint16_t size); +static inline void pic32mz_dma_destsize(FAR struct pic32mz_dmach_s *dmach, + uint16_t size); +static inline void pic32mz_dma_cellsize(FAR struct pic32mz_dmach_s *dmach, + uint16_t size); +static inline void pic32mz_dma_startirq(FAR struct pic32mz_dmach_s *dmach, + int irq); +static inline void pic32mz_dma_forcestart(FAR struct pic32mz_dmach_s *dmach); +static inline void pic32mz_dma_abortirq(FAR struct pic32mz_dmach_s *dmach, + int irq); +static inline void pic32mz_dma_forceabort(FAR struct pic32mz_dmach_s *dmach); + +static inline void pic32mz_dma_intctrl(FAR struct pic32mz_dmach_s *dmach, + uint32_t cfg); +static inline void pic32mz_dma_intclr(FAR struct pic32mz_dmach_s *dmach); +static int pic32mz_dma_interrupt(int irq, void *context, FAR void *arg); + +static void pic32mz_dma_mode(FAR struct pic32mz_dmach_s *dmach, + enum pic32mz_dma_chmode_e mode); +static void pic32mz_dma_config(FAR struct pic32mz_dmach_s *dmach, + FAR const struct pic32mz_dma_chcfg_s *cfg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* This array describes the state of each DMA */ + +static struct pic32mz_dmac_s g_dmac = +{ + .dmachs = + { + { + .chan = 0, + .irq = PIC32MZ_IRQ_DMA0, + .base = PIC32MZ_DMACH0_K1BASE, + }, + { + .chan = 1, + .irq = PIC32MZ_IRQ_DMA1, + .base = PIC32MZ_DMACH1_K1BASE, + }, + { + .chan = 2, + .irq = PIC32MZ_IRQ_DMA2, + .base = PIC32MZ_DMACH2_K1BASE, + }, + { + .chan = 3, + .irq = PIC32MZ_IRQ_DMA3, + .base = PIC32MZ_DMACH3_K1BASE, + }, + { + .chan = 4, + .irq = PIC32MZ_IRQ_DMA4, + .base = PIC32MZ_DMACH4_K1BASE, + }, + { + .chan = 5, + .irq = PIC32MZ_IRQ_DMA5, + .base = PIC32MZ_DMACH5_K1BASE, + }, + { + .chan = 6, + .irq = PIC32MZ_IRQ_DMA6, + .base = PIC32MZ_DMACH6_K1BASE, + }, + { + .chan = 7, + .irq = PIC32MZ_IRQ_DMA7, + .base = PIC32MZ_DMACH7_K1BASE, + }, + } +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pic32mz_dma_takesem + * + * Description: + * Take the exclusive access, waiting as necessary + * + ****************************************************************************/ + +static void pic32mz_dma_takesem(struct pic32mz_dmac_s *dmac) +{ + int ret; + + do + { + /* Take the semaphore (perhaps waiting) */ + + ret = nxsem_wait(&dmac->chsem); + + /* The only case that an error should occur here is if the wait was + * awakened by a signal. + */ + + DEBUGASSERT(ret == OK || ret == -EINTR); + } + while (ret == -EINTR); +} + +/**************************************************************************** + * Name: pic32mz_dma_givesem + * + * Description: + * Release the semaphore + * + ****************************************************************************/ + +static inline void pic32mz_dma_givesem(struct pic32mz_dmac_s *dmac) +{ + (void)nxsem_post(&dmac->chsem); +} + +/**************************************************************************** + * Name: pic32mz_dma_getreg + * + * Description: + * Get a 32-bit register value by offset + * + ****************************************************************************/ + +static inline uint32_t pic32mz_dma_getreg(FAR struct pic32mz_dmach_s *dmach, + uint8_t offset) +{ + return getreg32(dmach->base + offset); +} + +/**************************************************************************** + * Name: pic32mz_dma_putreg + * + * Description: + * Put a 32-bit register value by offset + * + ****************************************************************************/ + +static inline void pic32mz_dma_putreg(FAR struct pic32mz_dmach_s *dmach, + uint8_t offset, uint32_t value) +{ + putreg32(value, dmach->base + offset); +} + +/**************************************************************************** + * Name: pic32mz_dma_modifyreg + * + * Description: + * Modify a 32-bit register value by offset + * + ****************************************************************************/ + +static inline void pic32mz_dma_modifyreg(FAR struct pic32mz_dmach_s *dmach, + uint8_t offset, + uint32_t clrbits, uint32_t setbits) +{ + modifyreg32(dmach->base + offset, clrbits, setbits); +} + +/**************************************************************************** + * Name: pic32mz_dma_getglobal + * + * Description: + * Get a 32-bit global register value by offset + * + ****************************************************************************/ + +static inline uint32_t pic32mz_dma_getglobal(uint8_t offset) +{ + return getreg32(PIC32MZ_DMA_K1BASE + offset); +} + +/**************************************************************************** + * Name: pic32mz_dma_putglobal + * + * Description: + * Put a 32-bit global register value by offset + * + ****************************************************************************/ + +static inline void pic32mz_dma_putglobal(uint8_t offset, uint32_t value) +{ + putreg32(value, PIC32MZ_DMA_K1BASE + offset); +} + +/**************************************************************************** + * Name: pic32mz_dma_enable + * + * Description: + * Enable the DMA channel. + * + ****************************************************************************/ + +static inline void pic32mz_dma_enable(FAR struct pic32mz_dmach_s *dmach) +{ + pic32mz_dma_putreg(dmach, PIC32MZ_DMA_CONSET_OFFSET, DMACH_CON_CHEN); +} + +/**************************************************************************** + * Name: pic32mz_dma_disable + * + * Description: + * Disable the DMA channel. + * + ****************************************************************************/ + +static inline void pic32mz_dma_disable(FAR struct pic32mz_dmach_s *dmach) +{ + pic32mz_dma_putreg(dmach, PIC32MZ_DMA_CONCLR_OFFSET, DMACH_CON_CHEN); +} + +/**************************************************************************** + * Name: pic32mz_dma_priority + * + * Description: + * Set the channel's priority. + * + ****************************************************************************/ + +static inline void pic32mz_dma_priority(FAR struct pic32mz_dmach_s *dmach, + uint8_t priority) +{ + /* Highest priority is 3. */ + + if (priority <= 3) + { + pic32mz_dma_modifyreg(dmach, PIC32MZ_DMA_CON_OFFSET, + DMACH_CON_CHPRI_MASK, + priority << DMACH_CON_CHPRI_SHIFT); + } +} + +/**************************************************************************** + * Name: pic32mz_dma_srcaddr + * + * Description: + * Set the channel's source address. + * + ****************************************************************************/ + +static inline void pic32mz_dma_srcaddr(FAR struct pic32mz_dmach_s *dmach, + uint32_t addr) +{ + pic32mz_dma_putreg(dmach, PIC32MZ_DMACH_SSA_OFFSET, VIRT2PHY(addr)); +} + +/**************************************************************************** + * Name: pic32mz_dma_destaddr + * + * Description: + * Set the channel's destination address. + * + ****************************************************************************/ + +static inline void pic32mz_dma_destaddr(FAR struct pic32mz_dmach_s *dmach, + uint32_t addr) +{ + pic32mz_dma_putreg(dmach, PIC32MZ_DMACH_DSA_OFFSET, VIRT2PHY(addr)); +} + +/**************************************************************************** + * Name: pic32mz_dma_srcsize + * + * Description: + * Set the channel's source size. + * + ****************************************************************************/ + +static inline void pic32mz_dma_srcsize(FAR struct pic32mz_dmach_s *dmach, + uint16_t size) +{ + pic32mz_dma_putreg(dmach, PIC32MZ_DMACH_SSIZ_OFFSET, size); +} + +/**************************************************************************** + * Name: pic32mz_dma_destsize + * + * Description: + * Set the channel's destination size. + * + ****************************************************************************/ + +static inline void pic32mz_dma_destsize(FAR struct pic32mz_dmach_s *dmach, + uint16_t size) +{ + pic32mz_dma_putreg(dmach, PIC32MZ_DMACH_DSIZ_OFFSET, size); +} + +/**************************************************************************** + * Name: pic32mz_dma_cellsize + * + * Description: + * Set the channel's cell size. + * + ****************************************************************************/ + +static inline void pic32mz_dma_cellsize(FAR struct pic32mz_dmach_s *dmach, + uint16_t size) +{ + pic32mz_dma_putreg(dmach, PIC32MZ_DMACH_CSIZ_OFFSET, size); +} + +/**************************************************************************** + * Name: pic32mz_dma_startirq + * + * Description: + * Set the channel's start irq. + * + ****************************************************************************/ + +static inline void pic32mz_dma_startirq(FAR struct pic32mz_dmach_s *dmach, + int irq) +{ + /* Enable start irq matching. */ + + pic32mz_dma_putreg(dmach, PIC32MZ_DMACH_ECONSET_OFFSET, DMACH_ECON_SIRQEN); + + /* Clear the field before setting it. */ + + pic32mz_dma_modifyreg(dmach, PIC32MZ_DMACH_ECON_OFFSET, + DMACH_ECON_CHSIRQ_MASK, + irq << DMACH_ECON_CHSIRQ_SHIFT); +} + +/**************************************************************************** + * Name: pic32mz_dma_forcestart + * + * Description: + * Initiate the transfer by software. + * + ****************************************************************************/ + +static inline void pic32mz_dma_forcestart(FAR struct pic32mz_dmach_s *dmach) +{ + pic32mz_dma_putreg(dmach, PIC32MZ_DMACH_ECONSET_OFFSET, DMACH_ECON_CFORCE); +} + +/**************************************************************************** + * Name: pic32mz_dma_abortirq + * + * Description: + * Set the channel's abort irq. + * + ****************************************************************************/ + +static inline void pic32mz_dma_abortirq(FAR struct pic32mz_dmach_s *dmach, + int irq) +{ + /* Enable start irq matching. */ + + pic32mz_dma_putreg(dmach, PIC32MZ_DMACH_ECONSET_OFFSET, DMACH_ECON_AIRQEN); + + /* Clear the field before setting it. */ + + pic32mz_dma_modifyreg(dmach, PIC32MZ_DMACH_ECON_OFFSET, + DMACH_ECON_CHAIRQ_MASK, + irq << DMACH_ECON_CHAIRQ_SHIFT); +} + +/**************************************************************************** + * Name: pic32mz_dma_forceabort + * + * Description: + * Initiate the transfer by software. + * + ****************************************************************************/ + +static inline void pic32mz_dma_forceabort(FAR struct pic32mz_dmach_s *dmach) +{ + pic32mz_dma_putreg(dmach, PIC32MZ_DMACH_ECONSET_OFFSET, DMACH_ECON_CABORT); +} + +/**************************************************************************** + * Name: pic32mz_dma_intclr + * + * Description: + * Clears the channel's interrupt flags. + * + ****************************************************************************/ + +static inline void pic32mz_dma_intclr(FAR struct pic32mz_dmach_s *dmach) +{ + pic32mz_dma_putreg(dmach, PIC32MZ_DMACH_INTCLR_OFFSET, + DMACH_INT_FLAGS_MASK); +} + +/**************************************************************************** + * Name: pic32mz_dma_intctrl + * + * Description: + * Enables the different interrupt's flags. + * + ****************************************************************************/ + +static inline void pic32mz_dma_intctrl(FAR struct pic32mz_dmach_s *dmach, + uint32_t cfg) +{ + /* Clear all interrupts flags */ + + pic32mz_dma_intclr(dmach); + + /* Disable previous interrupts */ + + pic32mz_dma_putreg(dmach, PIC32MZ_DMACH_INTCLR_OFFSET, + DMACH_INT_EN_MASK); + + /* Enable the interrupts requested. */ + + pic32mz_dma_putreg(dmach, PIC32MZ_DMACH_INTSET_OFFSET, cfg); +} + +/**************************************************************************** + * Name: pic32mz_dma_interrupt + * + * Description: + * DMA interrupt handler. + * + ****************************************************************************/ + +static int pic32mz_dma_interrupt(int irq, void *context, FAR void *arg) +{ + struct pic32mz_dmach_s *dmach; + uint8_t status; + int chndx = 0; + + /* Get the channel structure from the irq. */ + + chndx = irq - PIC32MZ_IRQ_DMA0; + dmach = &g_dmac.dmachs[chndx]; + + /* Get the interrupt status. */ + + status = (uint8_t)(pic32mz_dma_getreg(dmach, PIC32MZ_DMACH_INT_OFFSET) & + DMACH_INT_FLAGS_MASK); + + /* Clear the interrupt flags. */ + + pic32mz_dma_intclr(dmach); + + /* Invoke the callback. */ + + if (dmach->callback) + { + dmach->callback(dmach, status, dmach->arg); + } + + return OK; +} + +/**************************************************************************** + * Name: pic32mz_dma_mode + * + * Description: + * Set the channel's mode + * + ****************************************************************************/ + +static void pic32mz_dma_mode(FAR struct pic32mz_dmach_s *dmach, + enum pic32mz_dma_chmode_e mode) +{ + if (mode & PIC32MZ_DMA_MODE_BASIC) + { + /* Basic mode doesn't need any config */ + } + + if (mode & PIC32MZ_DMA_MODE_AUTOEN) + { + pic32mz_dma_putreg(dmach, PIC32MZ_DMACH_CONSET_OFFSET, DMACH_CON_CHAEN); + } +} + +/**************************************************************************** + * Name: pic32mz_dma_config + * + * Description: + * Config the DMA channel + * + ****************************************************************************/ + +static void pic32mz_dma_config(FAR struct pic32mz_dmach_s *dmach, + FAR const struct pic32mz_dma_chcfg_s *cfg) +{ + /* Set the channel's priority */ + + pic32mz_dma_priority(dmach, cfg->priority); + + /* Set the channel's start and abort IRQs if they are specified */ + + if (cfg->startirq != PIC32MZ_DMA_NOEVENT) + { + pic32mz_dma_startirq(dmach, cfg->startirq); + } + + if (cfg->abortirq != PIC32MZ_DMA_NOEVENT) + { + pic32mz_dma_abortirq(dmach, cfg->abortirq); + } + + /* Set the interrupt event(s) */ + + pic32mz_dma_intctrl(dmach, cfg->event); + + /* Set the cahnnel's mode */ + + pic32mz_dma_mode(dmach, cfg->mode); + + /* Copy the config */ + + dmach->cfg = *cfg; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pic32mz_dma_sample + * + * Description: + * Sample DMA register contents + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA +void pic32mz_dma_sample(DMA_HANDLE handle, struct pic32mz_dmaregs_s *regs) +{ + struct pic32mz_dmach_s *dmach = (struct pic32mz_dmach_s *)handle; + irqstate_t flags; + + flags = enter_critical_section(); + + regs->gbl.con = pic32mz_dma_getglobal(PIC32MZ_DMA_CON_OFFSET); + regs->gbl.stat = pic32mz_dma_getglobal(PIC32MZ_DMA_STAT_OFFSET); + regs->gbl.addr = pic32mz_dma_getglobal(PIC32MZ_DMA_ADDR_OFFSET); + + regs->crc.con = pic32mz_dma_getglobal(PIC32MZ_DMA_CRCCON_OFFSET); + regs->crc.data = pic32mz_dma_getglobal(PIC32MZ_DMA_CRCDATA_OFFSET); + regs->crc.xor = pic32mz_dma_getglobal(PIC32MZ_DMA_CRCXOR_OFFSET); + + regs->ch.con = pic32mz_dma_getreg(dmach, PIC32MZ_DMACH_CON_OFFSET); + regs->ch.econ = pic32mz_dma_getreg(dmach, PIC32MZ_DMACH_ECON_OFFSET); + regs->ch.intcon = pic32mz_dma_getreg(dmach, PIC32MZ_DMACH_INT_OFFSET); + regs->ch.ssa = pic32mz_dma_getreg(dmach, PIC32MZ_DMACH_SSA_OFFSET); + regs->ch.dsa = pic32mz_dma_getreg(dmach, PIC32MZ_DMACH_DSA_OFFSET); + regs->ch.ssiz = pic32mz_dma_getreg(dmach, PIC32MZ_DMACH_SSIZ_OFFSET); + regs->ch.dsiz = pic32mz_dma_getreg(dmach, PIC32MZ_DMACH_DSIZ_OFFSET); + regs->ch.sptr = pic32mz_dma_getreg(dmach, PIC32MZ_DMACH_SPTR_OFFSET); + regs->ch.dptr = pic32mz_dma_getreg(dmach, PIC32MZ_DMACH_DPTR_OFFSET); + regs->ch.csiz = pic32mz_dma_getreg(dmach, PIC32MZ_DMACH_CSIZ_OFFSET); + regs->ch.cptr = pic32mz_dma_getreg(dmach, PIC32MZ_DMACH_CPTR_OFFSET); + regs->ch.dat = pic32mz_dma_getreg(dmach, PIC32MZ_DMACH_DAT_OFFSET); + + leave_critical_section(flags); +} +#endif + +/**************************************************************************** + * Name: pic32mz_dma_dump + * + * Description: + * Dump previously sampled DMA register contents + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA +void pic32mz_dma_dump(DMA_HANDLE handle, const struct pic32mz_dmaregs_s *regs, + const char *msg) +{ + struct pic32mz_dmach_s *dmach = (struct pic32mz_dmach_s *)handle; + + dmainfo("DMA Registers: %s\n", msg); + dmainfo(" DMACON: %08x\n", regs->gbl.con); + dmainfo(" DMASTAT: %08x\n", regs->gbl.stat); + dmainfo(" DMAADDR: %08x\n", regs->gbl.addr); + + dmainfo(" DCRCCON: %08x\n", regs->crc.con); + dmainfo(" DCRCDATA: %08x\n", regs->crc.data); + dmainfo(" DCRCXOR: %08x\n", regs->crc.xor); + + dmainfo(" DCHCON[%08x]: %08x\n", dmach->base + PIC32MZ_DMACH_CON_OFFSET, + regs->gbl.con); + dmainfo(" DCHECON[%08x]: %08x\n", dmach->base + PIC32MZ_DMACH_ECON_OFFSET, + regs->gbl.stat); + dmainfo(" DCHINT[%08x]: %08x\n", dmach->base + PIC32MZ_DMACH_INT_OFFSET, + regs->gbl.addr); + dmainfo(" DCHSSA[%08x]: %08x\n", dmach->base + PIC32MZ_DMACH_SSA_OFFSET, + regs->crc.con); + dmainfo(" DCHDSA[%08x]: %08x\n", dmach->base + PIC32MZ_DMACH_DSA_OFFSET, + regs->crc.data); + dmainfo(" DCHSSIZ[%08x]: %08x\n", dmach->base + PIC32MZ_DMACH_SSIZ_OFFSET, + regs->crc.xor); + dmainfo(" DCHDSIZ[%08x]: %08x\n", dmach->base + PIC32MZ_DMACH_DSIZ_OFFSET, + regs->gbl.con); + dmainfo(" DCHSPTR[%08x]: %08x\n", dmach->base + PIC32MZ_DMACH_SPTR_OFFSET, + regs->gbl.stat); + dmainfo(" DCHDPTR[%08x]: %08x\n", dmach->base + PIC32MZ_DMACH_DPTR_OFFSET, + regs->gbl.addr); + dmainfo(" DCHCSIZ[%08x]: %08x\n", dmach->base + PIC32MZ_DMACH_CSIZ_OFFSET, + regs->crc.con); + dmainfo(" DCHCPTR[%08x]: %08x\n", dmach->base + PIC32MZ_DMACH_CPTR_OFFSET, + regs->crc.data); + dmainfo(" DCHDAT[%08x]: %08x\n", dmach->base + PIC32MZ_DMACH_DAT_OFFSET, + regs->crc.xor); +} +#endif + +/**************************************************************************** + * Name: pic32mz_dma_initialize + * + * Description: + * Initialize the DMA subsystem. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void weak_function up_dma_initialize(void) +{ + struct pic32mz_dmach_s *dmach; + int i; + + /* Initialize each DMA channel. */ + + for (i = 0; i < CHIP_NDMACH; i++) + { + dmach = &g_dmac.dmachs[i]; + + dmach->inuse = false; + + /* Attach DMA interrupt vectors. */ + + (void)irq_attach(dmach->irq, pic32mz_dma_interrupt, NULL); + + /* Disable the DMA channel. */ + + pic32mz_dma_disable(dmach); + + /* Set channel priority to zero. */ + + pic32mz_dma_priority(dmach, 0); + + /* Clear any pending interrupts */ + + pic32mz_dma_intclr(dmach); + up_clrpend_irq(dmach->irq); + + /* Enable the IRQ. */ + + up_enable_irq(dmach->irq); + } + + /* Enable the DMA module. */ + + pic32mz_dma_putglobal(PIC32MZ_DMA_CONSET_OFFSET, DMA_CON_ON); + + /* Initialize the semaphore. */ + + nxsem_init(&g_dmac.chsem, 0, 1); +} + +/**************************************************************************** + * Name: pic32mz_dma_alloc + * + * Description: + * Allocate a DMA channel. This function sets aside a DMA channel and gives + * the caller exclusive access to the DMA channel. + * + * Returned Value: + * On success, this function returns a non-NULL, void* DMA channel handle. + * NULL is returned on any failure. + * This function can fail only if no DMA channel is available. + * + ****************************************************************************/ + +DMA_HANDLE pic32mz_dma_alloc(const struct pic32mz_dma_chcfg_s *cfg) +{ + struct pic32mz_dmach_s *dmach = NULL; + unsigned int chndx; + + /* Search for an available DMA channel */ + + pic32mz_dma_takesem(&g_dmac); + for (chndx = 0; chndx < CHIP_NDMACH; chndx++) + { + struct pic32mz_dmach_s *candidate = &g_dmac.dmachs[chndx]; + + if (!candidate->inuse) + { + dmach = candidate; + dmach->inuse = true; + + DEBUGASSERT(chndx == dmach->chan); + + /* Clear any pending interrupts on the channel */ + + pic32mz_dma_intclr(dmach); + up_clrpend_irq(dmach->irq); + + /* Disable the channel */ + + pic32mz_dma_disable(dmach); + + /* Config this channel */ + + pic32mz_dma_config(dmach, cfg); + + break; + } + } + + pic32mz_dma_givesem(&g_dmac); + + /* Show the result of the allocation */ + + if (dmach != NULL) + { + dmainfo("CH%d: returning dmach: %p\n", dmach->chan, dmach); + } + else + { + dmaerr("ERROR: Failed to allocate a DMA channel\n"); + } + + return (DMA_HANDLE)dmach; +} + +/**************************************************************************** + * Name: pic32mz_dma_free + * + * Description: + * Release a DMA channel. + * NOTE: The 'handle' used in this argument must NEVER be used again until + * pic32mz_dma_alloc() is called again to re-gain a valid handle. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void pic32mz_dma_free(DMA_HANDLE handle) +{ + struct pic32mz_dmach_s *dmach = (struct pic32mz_dmach_s *)handle; + + DEBUGASSERT(handle != NULL); + + /* Mark the channel as no longer in use */ + + dmach->inuse = false; + + /* Disable the channel */ + + pic32mz_dma_disable(dmach); + + /* Clear any pending interrupt */ + + pic32mz_dma_intclr(dmach); + up_clrpend_irq(dmach->irq); +} + +/**************************************************************************** + * Name: pic32mz_dma_xfrsetup + * + * Description: + * Configure DMA for one transfer. + * + ****************************************************************************/ + +int pic32mz_dma_xfrsetup(DMA_HANDLE handle, + FAR const struct pic32mz_dma_xfrcfg_s *cfg) +{ + struct pic32mz_dmach_s *dmach = (struct pic32mz_dmach_s *)handle; + + DEBUGASSERT(dmach != NULL); + + /* Set source and destination addresses */ + + pic32mz_dma_srcaddr(dmach, cfg->srcaddr); + pic32mz_dma_destaddr(dmach, cfg->destaddr); + + /* Set transfer size (source, destination and cell) */ + + pic32mz_dma_srcsize(dmach, cfg->srcsize); + pic32mz_dma_destsize(dmach, cfg->destsize); + pic32mz_dma_cellsize(dmach, cfg->cellsize); + + return OK; +} + +/**************************************************************************** + * Name: pic32mz_dma_start + * + * Description: + * Start the DMA transfer + * + ****************************************************************************/ + +int pic32mz_dma_start(DMA_HANDLE handle, dma_callback_t callback, void *arg) +{ + struct pic32mz_dmach_s *dmach = (struct pic32mz_dmach_s *)handle; + + DEBUGASSERT(dmach != NULL); + + /* Save the callback info */ + + dmach->callback = callback; + dmach->arg = arg; + + /* Enable the channel */ + + pic32mz_dma_enable(dmach); + + /* If no event is set to start the channel, force it */ + + if (dmach->cfg.startirq == PIC32MZ_DMA_NOEVENT) + { + pic32mz_dma_forcestart(dmach); + } + + return OK; +} + +/**************************************************************************** + * Name: pic32mz_dma_stop + * + * Description: + * Cancel the DMA. + * After pic32mz_dma_stop() is called, the DMA channel is reset + * and pic32mz_dma_xfrsetup() must be called before pic32mz_dma_start() + * can be called again. + * + ****************************************************************************/ + +void pic32mz_dma_stop(DMA_HANDLE handle) +{ + struct pic32mz_dmach_s *dmach = (struct pic32mz_dmach_s *)handle; + + DEBUGASSERT(dmach != NULL); + + /* Abort the transfer and disable the channel */ + + pic32mz_dma_forceabort(dmach); + pic32mz_dma_disable(dmach); + + /* Clear any pending interrupts */ + + pic32mz_dma_intclr(dmach); + up_clrpend_irq(dmach->irq); +} + +#endif /* CONFIG_PIC32MZ_DMA */ diff --git a/arch/mips/src/pic32mz/pic32mz-dma.h b/arch/mips/src/pic32mz/pic32mz-dma.h index 3bea2172eee..c23c5c24c80 100644 --- a/arch/mips/src/pic32mz/pic32mz-dma.h +++ b/arch/mips/src/pic32mz/pic32mz-dma.h @@ -1,7 +1,7 @@ /************************************************************************************ - * arch/mips/src/pic32mx/pic32mx-dma.h + * arch/mips/src/pic32mz/pic32mz-dma.h * - * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2015, 2019 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -36,6 +36,40 @@ #ifndef __ARCH_MIPS_SRC_PIC32MZ_PIC32MZ_DMA_H #define __ARCH_MIPS_SRC_PIC32MZ_PIC32MZ_DMA_H +/* General Usage: + * + * 1. Allocate a DMA channel + * + * DMA_HANDLE handle; + * handle = pic32mz_dma_alloc(chcfg); + * + * where chcfg is the channel's configuration (see struct pic32mz_dma_chcfg) + * + * 2. Setup the transfer + * + * struct pic32mz_dma_xfrcfg_s xfrcfg; + * xfrcfg.srcaddr = ...; + * xfrcfg.destaddr = ...; + * etc. + * + * pic32mz_dma_xfrsetup(handle, xfrcfg); + * + * 3. Start the transfer + * + * pic32mz_dma_start(handle, callback, arg); + * + * If a start irq is set this function will only enable the channel. + * The transfer will be controlled by the start irq. + * If no start irq is specified then the a force start is performed. + * + * 4. Stop and free the channel + * + * The DMA channel can be aborted if an abort irq is set. + * Alternatively, call to pic32mz_dma_stop will force the abort. + * + * pic32mz_dma_free will free the channel and make it available. + */ + /************************************************************************************ * Included Files ************************************************************************************/ @@ -46,49 +80,129 @@ #include #include +#include "hardware/pic32mz-dma.h" + /************************************************************************************ * Pre-processor Definitions ************************************************************************************/ -/************************************************************************************ +/* Interrupt type arguments for pic32mz_dma_intctrl. */ + +#define PIC32MZ_DMA_INT_SRCDONE DMACH_INT_CHSDIE +#define PIC32MZ_DMA_INT_SRCHALF DMACH_INT_CHSHIE +#define PIC32MZ_DMA_INT_DESTDONE DMACH_INT_CHDDIE +#define PIC32MZ_DMA_INT_DESTHALF DMACH_INT_CHDHIE +#define PIC32MZ_DMA_INT_BLOCKDONE DMACH_INT_CHBCIE +#define PIC32MZ_DMA_INT_CELLDONE DMACH_INT_CHCCIE +#define PIC32MZ_DMA_INT_ABORT DMACH_INT_CHTAIE +#define PIC32MZ_DMA_INT_ERR DMACH_INT_CHERIE +#define PIC32MZ_DMA_INT_DISABLE (0) + +/* This is used when setting a channel with no start/abort event */ + +#define PIC32MZ_DMA_NOEVENT (NR_IRQS + 1) + +/******************************************************************************* * Public Types - ************************************************************************************/ + * + ******************************************************************************/ #ifndef __ASSEMBLY__ typedef FAR void *DMA_HANDLE; -typedef void (*dma_callback_t)(DMA_HANDLE handle, void *arg, int result); +typedef void (*dma_callback_t)(DMA_HANDLE handle, uint8_t status, void *arg); -/* The following is used for sampling DMA registers when CONFIG DEBUG_DMA is selected */ +enum pic32mz_dma_chmode_e +{ + PIC32MZ_DMA_MODE_BASIC = 1 << 0U, /* Basic transfert mode */ + PIC32MZ_DMA_MODE_AUTOEN = 1 << 1U, /* Channel Auto-Enable mode */ + PIC32MZ_DMA_MODE_PMATCH = 1 << 2U, /* Pattern Match termination mode */ + PIC32MZ_DMA_MODE_CHCHAIN = 1 << 3U, /* Channel chaining mode */ + PIC32MZ_DMA_MODE_SFM = 1 << 4U /* Special Function Module mode */ +}; + +/* This structure holds the channel's configuration */ + +struct pic32mz_dma_chcfg_s +{ + uint8_t priority; /* Channel's priority (0..3) */ + uint8_t startirq; /* Start event */ + uint8_t abortirq; /* Abort event */ + uint8_t event; /* Interrupt event */ + enum pic32mz_dma_chmode_e mode; /* Channel's mode of operation */ +}; + +/* This structure holds a transfer's configuration */ + +struct pic32mz_dma_xfrcfg_s +{ + uint32_t srcaddr; /* Source address */ + uint32_t destaddr; /* Destination address */ + uint16_t srcsize; /* Source size */ + uint16_t destsize; /* Destination size */ + uint16_t cellsize; /* Cell size */ +}; + +/* The following is used for sampling DMA registers when CONFIG_DEBUG_DMA + * is selected + */ #ifdef CONFIG_DEBUG_DMA -struct pic32mx_dmaglobalregs_s -{ - /* Global Registers */ -#warning "Missing definitions" -}; - -struct pic32mx_dmachanregs_s -{ - /* Channel Registers */ -#warning "Missing definitions" -}; - -struct pic32mx_dmaregs_s +struct pic32mz_dmagblregs_s { /* Global Registers */ - struct pic32mx_dmaglobalregs_s gbl; + uint32_t con; + uint32_t stat; + uint32_t addr; +}; + +struct pic32mz_dmacrcregs_s +{ + /* CRC Registers */ + + uint32_t con; + uint32_t data; + uint32_t xor; +}; + +struct pic32mz_dmachanregs_s +{ + /* Channel Registers */ + + uint32_t con; + uint32_t econ; + uint32_t intcon; + uint32_t ssa; + uint32_t dsa; + uint32_t ssiz; + uint32_t dsiz; + uint32_t sptr; + uint32_t dptr; + uint32_t csiz; + uint32_t cptr; + uint32_t dat; +}; + +struct pic32mz_dmaregs_s +{ + /* Global Registers */ + + struct pic32mz_dmagblregs_s gbl; + + /* CRC Registers */ + + struct pic32mz_dmacrcregs_s crc; /* Channel Registers */ - struct pic32mx_dmachanregs_s ch; + struct pic32mz_dmachanregs_s ch; }; #endif -/************************************************************************************ +/******************************************************************************* * Public Data - ************************************************************************************/ + ******************************************************************************/ #undef EXTERN #if defined(__cplusplus) @@ -99,129 +213,102 @@ extern "C" #define EXTERN extern #endif -/************************************************************************************ +/******************************************************************************* * Public Function Prototypes - ************************************************************************************/ + ******************************************************************************/ -/************************************************************************************ - * Name: pic32mx_dmainitialize +/******************************************************************************* + * Name: pic32mz_dma_alloc * * Description: - * Initialize the GPDMA subsystem. + * Allocate a DMA channel. This function sets aside a DMA channel and gives + * the caller exclusive access to the DMA channel. + * + * Returned Value: + * On success, this function returns a non-NULL, void* DMA channel handle. + * NULL is returned on any failure. + * This function can fail only if no DMA channel is available. + * + ******************************************************************************/ + +DMA_HANDLE pic32mz_dma_alloc(const struct pic32mz_dma_chcfg_s *cfg); + +/******************************************************************************* + * Name: pic32mz_dma_free + * + * Description: + * Release a DMA channel. + * NOTE: The 'handle' used in this argument must NEVER be used again until + * pic32mz_dmachannel() is called again to re-gain a valid handle. * * Returned Value: * None * - ************************************************************************************/ + ******************************************************************************/ -#ifdef CONFIG_PIC32MX_DMA -void pic32mx_dmainitilaize(void); -#endif +void pic32mz_dma_free(DMA_HANDLE handle); -/************************************************************************************ - * Name: pic32mx_dmachannel - * - * Description: - * Allocate a DMA channel. This function sets aside a DMA channel and gives the - * caller exclusive access to the DMA channel. - * - * Returned Value: - * One success, this function returns a non-NULL, void* DMA channel handle. NULL - * is returned on any failure. This function can fail only if no DMA channel is - * available. - * - ************************************************************************************/ - -#ifdef CONFIG_PIC32MX_DMA -DMA_HANDLE pic32mx_dmachannel(void); -#endif - -/************************************************************************************ - * Name: pic32mx_dmafree - * - * Description: - * Release a DMA channel. NOTE: The 'handle' used in this argument must NEVER be - * used again until pic32mx_dmachannel() is called again to re-gain a valid handle. - * - * Returned Value: - * None - * - ************************************************************************************/ - -#ifdef CONFIG_PIC32MX_DMA -void pic32mx_dmafree(DMA_HANDLE handle); -#endif - -/************************************************************************************ - * Name: pic32mx_dmasetup +/******************************************************************************* + * Name: pic32mz_dma_xfrsetup * * Description: * Configure DMA for one transfer. * - ************************************************************************************/ + ******************************************************************************/ -#ifdef CONFIG_PIC32MX_DMA -int pic32mx_dmarxsetup(DMA_HANDLE handle, uint32_t control, uint32_t config, - uint32_t srcaddr, uint32_t destaddr, size_t nbytes); -#endif +int pic32mz_dma_xfrsetup(DMA_HANDLE handle, + FAR const struct pic32mz_dma_xfrcfg_s *cfg); -/************************************************************************************ - * Name: pic32mx_dmastart +/******************************************************************************* + * Name: pic32mz_dma_start * * Description: * Start the DMA transfer * - ************************************************************************************/ + ******************************************************************************/ -#ifdef CONFIG_PIC32MX_DMA -int pic32mx_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg); -#endif +int pic32mz_dma_start(DMA_HANDLE handle, dma_callback_t callback, void *arg); -/************************************************************************************ - * Name: pic32mx_dmastop +/******************************************************************************* + * Name: pic32mz_dma_stop * * Description: - * Cancel the DMA. After pic32mx_dmastop() is called, the DMA channel is reset - * and pic32mx_dmasetup() must be called before pic32mx_dmastart() can be called - * again + * Cancel the DMA. + * After pic32mz_dma_stop() is called, the DMA channel is reset + * and pic32mz_dma_xfrsetup() must be called before pic32mz_dma_start() + * can be called again. * - ************************************************************************************/ + ******************************************************************************/ -#ifdef CONFIG_PIC32MX_DMA -void pic32mx_dmastop(DMA_HANDLE handle); -#endif +void pic32mz_dma_stop(DMA_HANDLE handle); -/************************************************************************************ - * Name: pic32mx_dmasample +/******************************************************************************* + * Name: pic32mz_dma_sample * * Description: * Sample DMA register contents * - ************************************************************************************/ + ******************************************************************************/ -#ifdef CONFIG_PIC32MX_DMA #ifdef CONFIG_DEBUG_DMA -void pic32mx_dmasample(DMA_HANDLE handle, struct pic32mx_dmaregs_s *regs); +void pic32mz_dma_sample(DMA_HANDLE handle, struct pic32mz_dmaregs_s *regs); #else -# define pic32mx_dmasample(handle,regs) -#endif +# define pic32mz_dma_sample(handle,regs) #endif -/************************************************************************************ - * Name: pic32mx_dmadump +/******************************************************************************* + * Name: pic32mz_dma_dump * * Description: * Dump previously sampled DMA register contents * - ************************************************************************************/ + ******************************************************************************/ -#ifdef CONFIG_PIC32MX_DMA #ifdef CONFIG_DEBUG_DMA -void pic32mx_dmadump(DMA_HANDLE handle, const struct pic32mx_dmaregs_s *regs, +void pic32mz_dma_dump(DMA_HANDLE handle, const struct pic32mz_dmaregs_s *regs, const char *msg); #else -# define pic32mx_dmadump(handle,regs,msg) -#endif +# define pic32mz_dma_dump(handle,regs,msg) #endif #if defined(__cplusplus) @@ -231,3 +318,4 @@ void pic32mx_dmadump(DMA_HANDLE handle, const struct pic32mx_dmaregs_s *regs, #endif /* __ASSEMBLY__ */ #endif /* __ARCH_MIPS_SRC_PIC32MZ_PIC32MZ_DMA_H */ +