/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2014 Cástor Muñoz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #ifndef _PL080_H #define _PL080_H /* * ARM PrimeCell PL080 Multiple Master DMA controller */ #include #include /* general defines */ #define DMAC_CH_COUNT 8 #define DMAC_LLI_MAX_COUNT 0xfff #define DMAC_CH_PRIO(x) (x) #define DMAC_CH_BASE(dmac_ba,ch_n) ((dmac_ba) + 0x100 + ((ch_n) << 5)) /* PL080 controller registers */ #define DMACINTSTS(base) (*((uint32_t volatile*)((base) + 0x00))) #define DMACINTTCSTS(base) (*((uint32_t volatile*)((base) + 0x04))) #define DMACINTTCCLR(base) (*((uint32_t volatile*)((base) + 0x08))) #define DMACINTERRSTS(base) (*((uint32_t volatile*)((base) + 0x0c))) #define DMACINTERRCLR(base) (*((uint32_t volatile*)((base) + 0x10))) #define DMACRAWINTTCSTS(base) (*((uint32_t volatile*)((base) + 0x14))) #define DMACRAWINTERRSTS(base) (*((uint32_t volatile*)((base) + 0x18))) #define DMACENABLEDCHANS(base) (*((uint32_t volatile*)((base) + 0x1c))) #define DMACSOFTBREQ(base) (*((uint32_t volatile*)((base) + 0x20))) #define DMACSOFTSREQ(base) (*((uint32_t volatile*)((base) + 0x24))) #define DMACSOFTLBREQ(base) (*((uint32_t volatile*)((base) + 0x28))) #define DMACSOFTLSREQ(base) (*((uint32_t volatile*)((base) + 0x2c))) #define DMACCONFIG(base) (*((uint32_t volatile*)((base) + 0x30))) #define DMACSYNC(base) (*((uint32_t volatile*)((base) + 0x34))) /* PL080 controller channel registers */ #define DMACCxSRCADDR(base) (*((void* volatile*)((base) + 0x00))) #define DMACCxDESTADDR(base) (*((void* volatile*)((base) + 0x04))) #define DMACCxLINK(base) (*((uint32_t volatile*)((base) + 0x08))) #define DMACCxCONTROL(base) (*((uint32_t volatile*)((base) + 0x0c))) #define DMACCxCONFIG(base) (*((uint32_t volatile*)((base) + 0x10))) /* PL080 controller channel LLI */ #define DMACCxLLI(base) ((struct dmac_lli volatile*)(base)) /* PL080 DMA controller configuration register */ #define DMACCONFIG_E_POS 0 /* DMAC enable */ #define DMACCONFIG_E_MSK 0x1 #define DMACCONFIG_M1_POS 1 /* AHB Master 1 endianness */ #define DMACCONFIG_M1_MSK 0x1 #define DMACCONFIG_M2_POS 2 /* AHB Master 2 endianness */ #define DMACCONFIG_M2_MSK 0x1 #define DMACCONFIG_E_BIT (1 << DMACCONFIG_E_POS) #define DMACCONFIG_M1_BIT (1 << DMACCCONFI_M1_POS) #define DMACCONFIG_M2_BIT (1 << DMACCCONFI_M2_POS) #define DMACCONFIG_M_LITTLE_ENDIAN 0 #define DMACCONFIG_M_BIG_ENDIAN 1 /* PL080 DMA controller channel LLI register */ #define DMACCxLINK_LM_POS 0 #define DMACCxLINK_LM_MSK 0x1 #define DMACCxLINK_NEXTLLI_POS 2 #define DMACCxLINK_NEXTLLI_MSK 0x3fffffff /* PL080 channel control register */ #define DMACCxCONTROL_I_POS 31 /* terminal count interrupt */ #define DMACCxCONTROL_I_MSK 0x1 #define DMACCxCONTROL_PROT_POS 28 /* protection bits */ #define DMACCxCONTROL_PROT_MSK 0x7 #define DMACCxCONTROL_DI_POS 27 /* destination addr increment */ #define DMACCxCONTROL_DI_MSK 0x1 #define DMACCxCONTROL_SI_POS 26 /* source addr increment */ #define DMACCxCONTROL_SI_MSK 0x1 #define DMACCxCONTROL_D_POS 25 /* destinantion AHB master */ #define DMACCxCONTROL_D_MSK 0x1 #define DMACCxCONTROL_S_POS 24 /* source AHB master */ #define DMACCxCONTROL_S_MSK 0x1 #define DMACCxCONTROL_DWIDTH_POS 21 /* destinantion transfer width */ #define DMACCxCONTROL_DWIDTH_MSK 0x7 #define DMACCxCONTROL_SWIDTH_POS 18 /* source transfer width */ #define DMACCxCONTROL_SWIDTH_MSK 0x7 #define DMACCxCONTROL_DBSIZE_POS 15 /* destinantion burst size */ #define DMACCxCONTROL_DBSIZE_MSK 0x7 #define DMACCxCONTROL_SBSIZE_POS 12 /* source burst size */ #define DMACCxCONTROL_SBSIZE_MSK 0x7 #define DMACCxCONTROL_COUNT_POS 0 /* n SWIDTH size transfers */ #define DMACCxCONTROL_COUNT_MSK 0xfff #define DMACCxCONTROL_WIDTH_8 0 #define DMACCxCONTROL_WIDTH_16 1 #define DMACCxCONTROL_WIDTH_32 2 #define DMACCxCONTROL_BSIZE_1 0 #define DMACCxCONTROL_BSIZE_4 1 #define DMACCxCONTROL_BSIZE_8 2 #define DMACCxCONTROL_BSIZE_16 3 #define DMACCxCONTROL_BSIZE_32 4 #define DMACCxCONTROL_BSIZE_64 5 #define DMACCxCONTROL_BSIZE_128 6 #define DMACCxCONTROL_BSIZE_256 7 #define DMACCxCONTROL_INC_DISABLE 0 #define DMACCxCONTROL_INC_ENABLE 1 #define DMACCxCONTROL_I_BIT (1 << DMACCxCONTROL_I_POS) /* protection bits */ #define DMAC_PROT_PRIV (1 << 0) #define DMAC_PROT_BUFF (1 << 1) #define DMAC_PROT_CACH (1 << 2) /* bus */ #define DMAC_MASTER_AHB1 0 #define DMAC_MASTER_AHB2 1 /* PL080 channel configuration register */ #define DMACCxCONFIG_E_POS 0 /* enable */ #define DMACCxCONFIG_E_MSK 0x1 #define DMACCxCONFIG_SRCPERI_POS 1 /* source peripheral */ #define DMACCxCONFIG_SRCPERI_MSK 0xf #define DMACCxCONFIG_DESTPERI_POS 6 /* destination peripheral */ #define DMACCxCONFIG_DESTPERI_MSK 0xf #define DMACCxCONFIG_FLOWCNTRL_POS 11 /* DMA transfer type */ #define DMACCxCONFIG_FLOWCNTRL_MSK 0x7 #define DMACCxCONFIG_IE_POS 14 /* interrupt error mask */ #define DMACCxCONFIG_IE_MSK 0x1 #define DMACCxCONFIG_ITC_POS 15 /* interrupt terminal count mask */ #define DMACCxCONFIG_ITC_MSK 0x1 #define DMACCxCONFIG_L_POS 16 /* lock */ #define DMACCxCONFIG_L_MSK 0x1 #define DMACCxCONFIG_A_POS 17 /* active */ #define DMACCxCONFIG_A_MSK 0x1 #define DMACCxCONFIG_H_POS 18 /* halt */ #define DMACCxCONFIG_H_MSK 0x1 #define DMACCxCONFIG_E_BIT (1 << DMACCxCONFIG_E_POS) #define DMACCxCONFIG_IE_BIT (1 << DMACCxCONFIG_IE_POS) #define DMACCxCONFIG_ITC_BIT (1 << DMACCxCONFIG_ITC_POS) #define DMACCxCONFIG_L_BIT (1 << DMACCxCONFIG_L_POS) #define DMACCxCONFIG_A_BIT (1 << DMACCxCONFIG_A_POS) #define DMACCxCONFIG_H_BIT (1 << DMACCxCONFIG_H_POS) #define DMACCxCONFIG_FLOWCNTRL_MEMMEM_DMA 0 #define DMACCxCONFIG_FLOWCNTRL_MEMPERI_DMA 1 #define DMACCxCONFIG_FLOWCNTRL_PERIMEM_DMA 2 #define DMACCxCONFIG_FLOWCNTRL_PERIPERI_DMA 3 #define DMACCxCONFIG_FLOWCNTRL_PERIPERI_DSTPERI 4 #define DMACCxCONFIG_FLOWCNTRL_MEMPERI_PERI 5 #define DMACCxCONFIG_FLOWCNTRL_PERIMEM_PERI 6 #define DMACCxCONFIG_FLOWCNTRL_PERIPERI_SRCPERI 7 /* * types */ struct dmac_lli { void* srcaddr; void* dstaddr; uint32_t link; uint32_t control; } __attribute__((aligned(16))); struct dmac_tsk { struct dmac_lli volatile *start_lli; struct dmac_lli volatile *end_lli; uint32_t size; void *cb_data; }; /* used when src/dst peri is memory */ #define DMAC_PERI_NONE 0x80 struct dmac_ch_cfg { uint8_t srcperi; uint8_t dstperi; uint8_t sbsize; uint8_t dbsize; uint8_t swidth; uint8_t dwidth; uint8_t sbus; uint8_t dbus; uint8_t sinc; uint8_t dinc; uint8_t prot; uint16_t lli_xfer_max_count; }; struct dmac_ch { /** user configurable data **/ struct dmac *dmac; unsigned int prio; void (*cb_fn)(void *cb_data); /* tsk circular buffer */ struct dmac_tsk *tskbuf; uint32_t tskbuf_mask; uint32_t queue_mode; /* lli circular buffer */ struct dmac_lli volatile *llibuf; uint32_t llibuf_mask; uint32_t llibuf_bus; /** private driver data **/ uint32_t baddr; struct dmac_lli volatile *llibuf_top; uint32_t tasks_queued; /* roll-over counter */ uint32_t tasks_done; /* roll-over counter */ uint32_t control; struct dmac_ch_cfg *cfg; }; struct dmac { /* user configurable data */ const uint32_t baddr; const uint8_t m1; const uint8_t m2; /* driver private data */ struct dmac_ch *ch_l[DMAC_CH_COUNT]; uint32_t ch_run_status; /* channel running status mask */ }; /* dmac_ch->queue_mode */ enum { QUEUE_NORMAL, QUEUE_LINK, }; /* * prototypes */ void dmac_callback(struct dmac *dmac); void dmac_open(struct dmac *dmac); void dmac_ch_init(struct dmac_ch *ch, struct dmac_ch_cfg *cfg); void dmac_ch_lock_int(struct dmac_ch *ch); void dmac_ch_unlock_int(struct dmac_ch *ch); void dmac_ch_queue_2d(struct dmac_ch *ch, void *srcaddr, void *dstaddr, size_t size, size_t width, size_t stride, void *cb_data); #define dmac_ch_queue(ch, srcaddr, dstaddr, size, cb_data) \ dmac_ch_queue_2d(ch, srcaddr, dstaddr, size, 0, 0, cb_data) void dmac_ch_stop(struct dmac_ch* ch); bool dmac_ch_running(struct dmac_ch *ch); void *dmac_ch_get_info(struct dmac_ch *ch, size_t *bytes, size_t *t_bytes); #endif /* _PL080_H */