rockbox/firmware/export/pl080.h

271 lines
9.8 KiB
C

/***************************************************************************
* __________ __ ___.
* 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 <stdint.h>
#include <stddef.h>
#include <stdbool.h>
/* 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 */