Path: blob/master/arch/xtensa/variants/s6000/dmac.c
10819 views
/*1* Authors: Oskar Schirmer <[email protected]>2* Daniel Gloeckner <[email protected]>3* (c) 2008 emlix GmbH http://www.emlix.com4*5* This program is free software; you can redistribute it and/or modify it6* under the terms of the GNU General Public License as published by the7* Free Software Foundation; either version 2 of the License, or (at your8* option) any later version.9*/1011#include <linux/kernel.h>12#include <linux/io.h>13#include <linux/types.h>14#include <linux/errno.h>15#include <linux/spinlock.h>16#include <asm/cacheflush.h>17#include <variant/dmac.h>1819/* DMA engine lookup */2021struct s6dmac_ctrl s6dmac_ctrl[S6_DMAC_NB];222324/* DMA control, per engine */2526void s6dmac_put_fifo_cache(u32 dmac, int chan, u32 src, u32 dst, u32 size)27{28if (xtensa_need_flush_dma_source(src)) {29u32 base = src;30u32 span = size;31u32 chunk = readl(DMA_CHNL(dmac, chan) + S6_DMA_CMONCHUNK);32if (chunk && (size > chunk)) {33s32 skip =34readl(DMA_CHNL(dmac, chan) + S6_DMA_SRCSKIP);35u32 gaps = (size+chunk-1)/chunk - 1;36if (skip >= 0) {37span += gaps * skip;38} else if (-skip > chunk) {39s32 decr = gaps * (chunk + skip);40base += decr;41span = chunk - decr;42} else {43span = max(span + gaps * skip,44(chunk + skip) * gaps - skip);45}46}47flush_dcache_unaligned(base, span);48}49if (xtensa_need_invalidate_dma_destination(dst)) {50u32 base = dst;51u32 span = size;52u32 chunk = readl(DMA_CHNL(dmac, chan) + S6_DMA_CMONCHUNK);53if (chunk && (size > chunk)) {54s32 skip =55readl(DMA_CHNL(dmac, chan) + S6_DMA_DSTSKIP);56u32 gaps = (size+chunk-1)/chunk - 1;57if (skip >= 0) {58span += gaps * skip;59} else if (-skip > chunk) {60s32 decr = gaps * (chunk + skip);61base += decr;62span = chunk - decr;63} else {64span = max(span + gaps * skip,65(chunk + skip) * gaps - skip);66}67}68invalidate_dcache_unaligned(base, span);69}70s6dmac_put_fifo(dmac, chan, src, dst, size);71}7273void s6dmac_disable_error_irqs(u32 dmac, u32 mask)74{75unsigned long flags;76spinlock_t *spinl = &s6dmac_ctrl[_dmac_addr_index(dmac)].lock;77spin_lock_irqsave(spinl, flags);78_s6dmac_disable_error_irqs(dmac, mask);79spin_unlock_irqrestore(spinl, flags);80}8182u32 s6dmac_int_sources(u32 dmac, u32 channel)83{84u32 mask, ret, tmp;85mask = 1 << channel;8687tmp = readl(dmac + S6_DMA_TERMCNTIRQSTAT);88tmp &= mask;89writel(tmp, dmac + S6_DMA_TERMCNTIRQCLR);90ret = tmp >> channel;9192tmp = readl(dmac + S6_DMA_PENDCNTIRQSTAT);93tmp &= mask;94writel(tmp, dmac + S6_DMA_PENDCNTIRQCLR);95ret |= (tmp >> channel) << 1;9697tmp = readl(dmac + S6_DMA_LOWWMRKIRQSTAT);98tmp &= mask;99writel(tmp, dmac + S6_DMA_LOWWMRKIRQCLR);100ret |= (tmp >> channel) << 2;101102tmp = readl(dmac + S6_DMA_INTRAW0);103tmp &= (mask << S6_DMA_INT0_OVER) | (mask << S6_DMA_INT0_UNDER);104writel(tmp, dmac + S6_DMA_INTCLEAR0);105106if (tmp & (mask << S6_DMA_INT0_UNDER))107ret |= 1 << 3;108if (tmp & (mask << S6_DMA_INT0_OVER))109ret |= 1 << 4;110111tmp = readl(dmac + S6_DMA_MASTERERRINFO);112mask <<= S6_DMA_INT1_CHANNEL;113if (((tmp >> S6_DMA_MASTERERR_CHAN(0)) & S6_DMA_MASTERERR_CHAN_MASK)114== channel)115mask |= 1 << S6_DMA_INT1_MASTER;116if (((tmp >> S6_DMA_MASTERERR_CHAN(1)) & S6_DMA_MASTERERR_CHAN_MASK)117== channel)118mask |= 1 << (S6_DMA_INT1_MASTER + 1);119if (((tmp >> S6_DMA_MASTERERR_CHAN(2)) & S6_DMA_MASTERERR_CHAN_MASK)120== channel)121mask |= 1 << (S6_DMA_INT1_MASTER + 2);122123tmp = readl(dmac + S6_DMA_INTRAW1) & mask;124writel(tmp, dmac + S6_DMA_INTCLEAR1);125ret |= ((tmp >> channel) & 1) << 5;126ret |= ((tmp >> S6_DMA_INT1_MASTER) & S6_DMA_INT1_MASTER_MASK) << 6;127128return ret;129}130131void s6dmac_release_chan(u32 dmac, int chan)132{133if (chan >= 0)134s6dmac_disable_chan(dmac, chan);135}136137138/* global init */139140static inline void __init dmac_init(u32 dmac, u8 chan_nb)141{142s6dmac_ctrl[S6_DMAC_INDEX(dmac)].dmac = dmac;143spin_lock_init(&s6dmac_ctrl[S6_DMAC_INDEX(dmac)].lock);144s6dmac_ctrl[S6_DMAC_INDEX(dmac)].chan_nb = chan_nb;145writel(S6_DMA_INT1_MASTER_MASK << S6_DMA_INT1_MASTER,146dmac + S6_DMA_INTCLEAR1);147}148149static inline void __init dmac_master(u32 dmac,150u32 m0start, u32 m0end, u32 m1start, u32 m1end)151{152writel(m0start, dmac + S6_DMA_MASTER0START);153writel(m0end - 1, dmac + S6_DMA_MASTER0END);154writel(m1start, dmac + S6_DMA_MASTER1START);155writel(m1end - 1, dmac + S6_DMA_MASTER1END);156}157158static void __init s6_dmac_init(void)159{160dmac_init(S6_REG_LMSDMA, S6_LMSDMA_NB);161dmac_master(S6_REG_LMSDMA,162S6_MEM_DDR, S6_MEM_PCIE_APER, S6_MEM_EFI, S6_MEM_GMAC);163dmac_init(S6_REG_NIDMA, S6_NIDMA_NB);164dmac_init(S6_REG_DPDMA, S6_DPDMA_NB);165dmac_master(S6_REG_DPDMA,166S6_MEM_DDR, S6_MEM_PCIE_APER, S6_REG_DP, S6_REG_DPDMA);167dmac_init(S6_REG_HIFDMA, S6_HIFDMA_NB);168dmac_master(S6_REG_HIFDMA,169S6_MEM_GMAC, S6_MEM_PCIE_CFG, S6_MEM_PCIE_APER, S6_MEM_AUX);170}171172arch_initcall(s6_dmac_init);173174175