Path: blob/master/arch/xtensa/variants/s6000/include/variant/dmac.h
10821 views
/*1* include/asm-xtensa/variant-s6000/dmac.h2*3* This file is subject to the terms and conditions of the GNU General Public4* License. See the file "COPYING" in the main directory of this archive5* for more details.6*7* Copyright (C) 2006 Tensilica Inc.8* Copyright (C) 2008 Emlix GmbH <[email protected]>9* Authors: Fabian Godehardt <[email protected]>10* Oskar Schirmer <[email protected]>11* Daniel Gloeckner <[email protected]>12*/1314#ifndef __ASM_XTENSA_S6000_DMAC_H15#define __ASM_XTENSA_S6000_DMAC_H16#include <linux/io.h>17#include <variant/hardware.h>1819/* DMA global */2021#define S6_DMA_INTSTAT0 0x00022#define S6_DMA_INTSTAT1 0x00423#define S6_DMA_INTENABLE0 0x00824#define S6_DMA_INTENABLE1 0x00C25#define S6_DMA_INTRAW0 0x01026#define S6_DMA_INTRAW1 0x01427#define S6_DMA_INTCLEAR0 0x01828#define S6_DMA_INTCLEAR1 0x01C29#define S6_DMA_INTSET0 0x02030#define S6_DMA_INTSET1 0x02431#define S6_DMA_INT0_UNDER 032#define S6_DMA_INT0_OVER 1633#define S6_DMA_INT1_CHANNEL 034#define S6_DMA_INT1_MASTER 1635#define S6_DMA_INT1_MASTER_MASK 736#define S6_DMA_TERMCNTIRQSTAT 0x02837#define S6_DMA_TERMCNTIRQCLR 0x02C38#define S6_DMA_TERMCNTIRQSET 0x03039#define S6_DMA_PENDCNTIRQSTAT 0x03440#define S6_DMA_PENDCNTIRQCLR 0x03841#define S6_DMA_PENDCNTIRQSET 0x03C42#define S6_DMA_LOWWMRKIRQSTAT 0x04043#define S6_DMA_LOWWMRKIRQCLR 0x04444#define S6_DMA_LOWWMRKIRQSET 0x04845#define S6_DMA_MASTERERRINFO 0x04C46#define S6_DMA_MASTERERR_CHAN(n) (4*(n))47#define S6_DMA_MASTERERR_CHAN_MASK 0xF48#define S6_DMA_DESCRFIFO0 0x05049#define S6_DMA_DESCRFIFO1 0x05450#define S6_DMA_DESCRFIFO2 0x05851#define S6_DMA_DESCRFIFO2_AUTODISABLE 2452#define S6_DMA_DESCRFIFO3 0x05C53#define S6_DMA_MASTER0START 0x06054#define S6_DMA_MASTER0END 0x06455#define S6_DMA_MASTER1START 0x06856#define S6_DMA_MASTER1END 0x06C57#define S6_DMA_NEXTFREE 0x07058#define S6_DMA_NEXTFREE_CHAN 059#define S6_DMA_NEXTFREE_CHAN_MASK 0x1F60#define S6_DMA_NEXTFREE_ENA 1661#define S6_DMA_NEXTFREE_ENA_MASK ((1 << 16) - 1)62#define S6_DMA_DPORTCTRLGRP(p) ((p) * 4 + 0x074)63#define S6_DMA_DPORTCTRLGRP_FRAMEREP 064#define S6_DMA_DPORTCTRLGRP_NRCHANS 165#define S6_DMA_DPORTCTRLGRP_NRCHANS_1 066#define S6_DMA_DPORTCTRLGRP_NRCHANS_3 167#define S6_DMA_DPORTCTRLGRP_NRCHANS_4 268#define S6_DMA_DPORTCTRLGRP_NRCHANS_2 369#define S6_DMA_DPORTCTRLGRP_ENA 31707172/* DMA per channel */7374#define DMA_CHNL(dmac, n) ((dmac) + 0x1000 + (n) * 0x100)75#define DMA_INDEX_CHNL(addr) (((addr) >> 8) & 0xF)76#define DMA_MASK_DMAC(addr) ((addr) & 0xFFFF0000)77#define S6_DMA_CHNCTRL 0x00078#define S6_DMA_CHNCTRL_ENABLE 079#define S6_DMA_CHNCTRL_PAUSE 180#define S6_DMA_CHNCTRL_PRIO 281#define S6_DMA_CHNCTRL_PRIO_MASK 382#define S6_DMA_CHNCTRL_PERIPHXFER 483#define S6_DMA_CHNCTRL_PERIPHENA 584#define S6_DMA_CHNCTRL_SRCINC 685#define S6_DMA_CHNCTRL_DSTINC 786#define S6_DMA_CHNCTRL_BURSTLOG 887#define S6_DMA_CHNCTRL_BURSTLOG_MASK 788#define S6_DMA_CHNCTRL_DESCFIFODEPTH 1289#define S6_DMA_CHNCTRL_DESCFIFODEPTH_MASK 0x1F90#define S6_DMA_CHNCTRL_DESCFIFOFULL 1791#define S6_DMA_CHNCTRL_BWCONSEL 1892#define S6_DMA_CHNCTRL_BWCONENA 1993#define S6_DMA_CHNCTRL_PENDGCNTSTAT 2094#define S6_DMA_CHNCTRL_PENDGCNTSTAT_MASK 0x3F95#define S6_DMA_CHNCTRL_LOWWMARK 2696#define S6_DMA_CHNCTRL_LOWWMARK_MASK 0xF97#define S6_DMA_CHNCTRL_TSTAMP 3098#define S6_DMA_TERMCNTNB 0x00499#define S6_DMA_TERMCNTNB_MASK 0xFFFF100#define S6_DMA_TERMCNTTMO 0x008101#define S6_DMA_TERMCNTSTAT 0x00C102#define S6_DMA_TERMCNTSTAT_MASK 0xFF103#define S6_DMA_CMONCHUNK 0x010104#define S6_DMA_SRCSKIP 0x014105#define S6_DMA_DSTSKIP 0x018106#define S6_DMA_CUR_SRC 0x024107#define S6_DMA_CUR_DST 0x028108#define S6_DMA_TIMESTAMP 0x030109110/* DMA channel lists */111112#define S6_DPDMA_CHAN(stream, channel) (4 * (stream) + (channel))113#define S6_DPDMA_NB 16114115#define S6_HIFDMA_GMACTX 0116#define S6_HIFDMA_GMACRX 1117#define S6_HIFDMA_I2S0 2118#define S6_HIFDMA_I2S1 3119#define S6_HIFDMA_EGIB 4120#define S6_HIFDMA_PCITX 5121#define S6_HIFDMA_PCIRX 6122#define S6_HIFDMA_NB 7123124#define S6_NIDMA_NB 4125126#define S6_LMSDMA_NB 12127128/* controller access */129130#define S6_DMAC_NB 4131#define S6_DMAC_INDEX(dmac) (((unsigned)(dmac) >> 18) % S6_DMAC_NB)132133struct s6dmac_ctrl {134u32 dmac;135spinlock_t lock;136u8 chan_nb;137};138139extern struct s6dmac_ctrl s6dmac_ctrl[S6_DMAC_NB];140141142/* DMA control, per channel */143144static inline int s6dmac_fifo_full(u32 dmac, int chan)145{146return (readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL)147& (1 << S6_DMA_CHNCTRL_DESCFIFOFULL)) && 1;148}149150static inline int s6dmac_termcnt_irq(u32 dmac, int chan)151{152u32 m = 1 << chan;153int r = (readl(dmac + S6_DMA_TERMCNTIRQSTAT) & m) && 1;154if (r)155writel(m, dmac + S6_DMA_TERMCNTIRQCLR);156return r;157}158159static inline int s6dmac_pendcnt_irq(u32 dmac, int chan)160{161u32 m = 1 << chan;162int r = (readl(dmac + S6_DMA_PENDCNTIRQSTAT) & m) && 1;163if (r)164writel(m, dmac + S6_DMA_PENDCNTIRQCLR);165return r;166}167168static inline int s6dmac_lowwmark_irq(u32 dmac, int chan)169{170int r = (readl(dmac + S6_DMA_LOWWMRKIRQSTAT) & (1 << chan)) ? 1 : 0;171if (r)172writel(1 << chan, dmac + S6_DMA_LOWWMRKIRQCLR);173return r;174}175176static inline u32 s6dmac_pending_count(u32 dmac, int chan)177{178return (readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL)179>> S6_DMA_CHNCTRL_PENDGCNTSTAT)180& S6_DMA_CHNCTRL_PENDGCNTSTAT_MASK;181}182183static inline void s6dmac_set_terminal_count(u32 dmac, int chan, u32 n)184{185n &= S6_DMA_TERMCNTNB_MASK;186n |= readl(DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB)187& ~S6_DMA_TERMCNTNB_MASK;188writel(n, DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB);189}190191static inline u32 s6dmac_get_terminal_count(u32 dmac, int chan)192{193return (readl(DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB))194& S6_DMA_TERMCNTNB_MASK;195}196197static inline u32 s6dmac_timestamp(u32 dmac, int chan)198{199return readl(DMA_CHNL(dmac, chan) + S6_DMA_TIMESTAMP);200}201202static inline u32 s6dmac_cur_src(u32 dmac, int chan)203{204return readl(DMA_CHNL(dmac, chan) + S6_DMA_CUR_SRC);205}206207static inline u32 s6dmac_cur_dst(u32 dmac, int chan)208{209return readl(DMA_CHNL(dmac, chan) + S6_DMA_CUR_DST);210}211212static inline void s6dmac_disable_chan(u32 dmac, int chan)213{214u32 ctrl;215writel(readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL)216& ~(1 << S6_DMA_CHNCTRL_ENABLE),217DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL);218do219ctrl = readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL);220while (ctrl & (1 << S6_DMA_CHNCTRL_ENABLE));221}222223static inline void s6dmac_set_stride_skip(u32 dmac, int chan,224int comchunk, /* 0: disable scatter/gather */225int srcskip, int dstskip)226{227writel(comchunk, DMA_CHNL(dmac, chan) + S6_DMA_CMONCHUNK);228writel(srcskip, DMA_CHNL(dmac, chan) + S6_DMA_SRCSKIP);229writel(dstskip, DMA_CHNL(dmac, chan) + S6_DMA_DSTSKIP);230}231232static inline void s6dmac_enable_chan(u32 dmac, int chan,233int prio, /* 0 (highest) .. 3 (lowest) */234int periphxfer, /* <0: disable p.req.line, 0..1: mode */235int srcinc, int dstinc, /* 0: dont increment src/dst address */236int comchunk, /* 0: disable scatter/gather */237int srcskip, int dstskip,238int burstsize, /* 4 for I2S, 7 for everything else */239int bandwidthconserve, /* <0: disable, 0..1: select */240int lowwmark, /* 0..15 */241int timestamp, /* 0: disable timestamp */242int enable) /* 0: disable for now */243{244writel(1, DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB);245writel(0, DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTTMO);246writel(lowwmark << S6_DMA_CHNCTRL_LOWWMARK,247DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL);248s6dmac_set_stride_skip(dmac, chan, comchunk, srcskip, dstskip);249writel(((enable ? 1 : 0) << S6_DMA_CHNCTRL_ENABLE) |250(prio << S6_DMA_CHNCTRL_PRIO) |251(((periphxfer > 0) ? 1 : 0) << S6_DMA_CHNCTRL_PERIPHXFER) |252(((periphxfer < 0) ? 0 : 1) << S6_DMA_CHNCTRL_PERIPHENA) |253((srcinc ? 1 : 0) << S6_DMA_CHNCTRL_SRCINC) |254((dstinc ? 1 : 0) << S6_DMA_CHNCTRL_DSTINC) |255(burstsize << S6_DMA_CHNCTRL_BURSTLOG) |256(((bandwidthconserve > 0) ? 1 : 0) << S6_DMA_CHNCTRL_BWCONSEL) |257(((bandwidthconserve < 0) ? 0 : 1) << S6_DMA_CHNCTRL_BWCONENA) |258(lowwmark << S6_DMA_CHNCTRL_LOWWMARK) |259((timestamp ? 1 : 0) << S6_DMA_CHNCTRL_TSTAMP),260DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL);261}262263264/* DMA control, per engine */265266static inline unsigned _dmac_addr_index(u32 dmac)267{268unsigned i = S6_DMAC_INDEX(dmac);269if (s6dmac_ctrl[i].dmac != dmac)270BUG();271return i;272}273274static inline void _s6dmac_disable_error_irqs(u32 dmac, u32 mask)275{276writel(mask, dmac + S6_DMA_TERMCNTIRQCLR);277writel(mask, dmac + S6_DMA_PENDCNTIRQCLR);278writel(mask, dmac + S6_DMA_LOWWMRKIRQCLR);279writel(readl(dmac + S6_DMA_INTENABLE0)280& ~((mask << S6_DMA_INT0_UNDER) | (mask << S6_DMA_INT0_OVER)),281dmac + S6_DMA_INTENABLE0);282writel(readl(dmac + S6_DMA_INTENABLE1) & ~(mask << S6_DMA_INT1_CHANNEL),283dmac + S6_DMA_INTENABLE1);284writel((mask << S6_DMA_INT0_UNDER) | (mask << S6_DMA_INT0_OVER),285dmac + S6_DMA_INTCLEAR0);286writel(mask << S6_DMA_INT1_CHANNEL, dmac + S6_DMA_INTCLEAR1);287}288289/*290* request channel from specified engine291* with chan<0, accept any channel292* further parameters see s6dmac_enable_chan293* returns < 0 upon error, channel nb otherwise294*/295static inline int s6dmac_request_chan(u32 dmac, int chan,296int prio,297int periphxfer,298int srcinc, int dstinc,299int comchunk,300int srcskip, int dstskip,301int burstsize,302int bandwidthconserve,303int lowwmark,304int timestamp,305int enable)306{307int r = chan;308unsigned long flags;309spinlock_t *spinl = &s6dmac_ctrl[_dmac_addr_index(dmac)].lock;310spin_lock_irqsave(spinl, flags);311if (r < 0) {312r = (readl(dmac + S6_DMA_NEXTFREE) >> S6_DMA_NEXTFREE_CHAN)313& S6_DMA_NEXTFREE_CHAN_MASK;314}315if (r >= s6dmac_ctrl[_dmac_addr_index(dmac)].chan_nb) {316if (chan < 0)317r = -EBUSY;318else319r = -ENXIO;320} else if (((readl(dmac + S6_DMA_NEXTFREE) >> S6_DMA_NEXTFREE_ENA)321>> r) & 1) {322r = -EBUSY;323} else {324s6dmac_enable_chan(dmac, r, prio, periphxfer,325srcinc, dstinc, comchunk, srcskip, dstskip, burstsize,326bandwidthconserve, lowwmark, timestamp, enable);327}328spin_unlock_irqrestore(spinl, flags);329return r;330}331332static inline void s6dmac_put_fifo(u32 dmac, int chan,333u32 src, u32 dst, u32 size)334{335unsigned long flags;336spinlock_t *spinl = &s6dmac_ctrl[_dmac_addr_index(dmac)].lock;337spin_lock_irqsave(spinl, flags);338writel(src, dmac + S6_DMA_DESCRFIFO0);339writel(dst, dmac + S6_DMA_DESCRFIFO1);340writel(size, dmac + S6_DMA_DESCRFIFO2);341writel(chan, dmac + S6_DMA_DESCRFIFO3);342spin_unlock_irqrestore(spinl, flags);343}344345static inline u32 s6dmac_channel_enabled(u32 dmac, int chan)346{347return readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL) &348(1 << S6_DMA_CHNCTRL_ENABLE);349}350351/*352* group 1-4 data port channels353* with port=0..3, nrch=1-4 channels,354* frrep=0/1 (dis- or enable frame repeat)355*/356static inline void s6dmac_dp_setup_group(u32 dmac, int port,357int nrch, int frrep)358{359const static u8 mask[4] = {0, 3, 1, 2};360BUG_ON(dmac != S6_REG_DPDMA);361if ((port < 0) || (port > 3) || (nrch < 1) || (nrch > 4))362return;363writel((mask[nrch - 1] << S6_DMA_DPORTCTRLGRP_NRCHANS)364| ((frrep ? 1 : 0) << S6_DMA_DPORTCTRLGRP_FRAMEREP),365dmac + S6_DMA_DPORTCTRLGRP(port));366}367368static inline void s6dmac_dp_switch_group(u32 dmac, int port, int enable)369{370u32 tmp;371BUG_ON(dmac != S6_REG_DPDMA);372tmp = readl(dmac + S6_DMA_DPORTCTRLGRP(port));373if (enable)374tmp |= (1 << S6_DMA_DPORTCTRLGRP_ENA);375else376tmp &= ~(1 << S6_DMA_DPORTCTRLGRP_ENA);377writel(tmp, dmac + S6_DMA_DPORTCTRLGRP(port));378}379380extern void s6dmac_put_fifo_cache(u32 dmac, int chan,381u32 src, u32 dst, u32 size);382extern void s6dmac_disable_error_irqs(u32 dmac, u32 mask);383extern u32 s6dmac_int_sources(u32 dmac, u32 channel);384extern void s6dmac_release_chan(u32 dmac, int chan);385386#endif /* __ASM_XTENSA_S6000_DMAC_H */387388389