2 * Authors: Oskar Schirmer <os@emlix.com>
3 * Daniel Gloeckner <dg@emlix.com>
4 * (c) 2008 emlix GmbH http://www.emlix.com
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
12 #include <linux/kernel.h>
14 #include <linux/types.h>
15 #include <linux/errno.h>
16 #include <linux/spinlock.h>
17 #include <asm/cacheflush.h>
18 #include <variant/dmac.h>
20 /* DMA engine lookup */
22 struct s6dmac_ctrl s6dmac_ctrl
[S6_DMAC_NB
];
25 /* DMA control, per engine */
27 void s6dmac_put_fifo_cache(u32 dmac
, int chan
, u32 src
, u32 dst
, u32 size
)
29 if (xtensa_need_flush_dma_source(src
)) {
32 u32 chunk
= readl(DMA_CHNL(dmac
, chan
) + S6_DMA_CMONCHUNK
);
33 if (chunk
&& (size
> chunk
)) {
35 readl(DMA_CHNL(dmac
, chan
) + S6_DMA_SRCSKIP
);
36 u32 gaps
= (size
+chunk
-1)/chunk
- 1;
39 } else if (-skip
> chunk
) {
40 s32 decr
= gaps
* (chunk
+ skip
);
44 span
= max(span
+ gaps
* skip
,
45 (chunk
+ skip
) * gaps
- skip
);
48 flush_dcache_unaligned(base
, span
);
50 if (xtensa_need_invalidate_dma_destination(dst
)) {
53 u32 chunk
= readl(DMA_CHNL(dmac
, chan
) + S6_DMA_CMONCHUNK
);
54 if (chunk
&& (size
> chunk
)) {
56 readl(DMA_CHNL(dmac
, chan
) + S6_DMA_DSTSKIP
);
57 u32 gaps
= (size
+chunk
-1)/chunk
- 1;
60 } else if (-skip
> chunk
) {
61 s32 decr
= gaps
* (chunk
+ skip
);
65 span
= max(span
+ gaps
* skip
,
66 (chunk
+ skip
) * gaps
- skip
);
69 invalidate_dcache_unaligned(base
, span
);
71 s6dmac_put_fifo(dmac
, chan
, src
, dst
, size
);
74 void s6dmac_disable_error_irqs(u32 dmac
, u32 mask
)
77 spinlock_t
*spinl
= &s6dmac_ctrl
[_dmac_addr_index(dmac
)].lock
;
78 spin_lock_irqsave(spinl
, flags
);
79 _s6dmac_disable_error_irqs(dmac
, mask
);
80 spin_unlock_irqrestore(spinl
, flags
);
83 u32
s6dmac_int_sources(u32 dmac
, u32 channel
)
88 tmp
= readl(dmac
+ S6_DMA_TERMCNTIRQSTAT
);
90 writel(tmp
, dmac
+ S6_DMA_TERMCNTIRQCLR
);
93 tmp
= readl(dmac
+ S6_DMA_PENDCNTIRQSTAT
);
95 writel(tmp
, dmac
+ S6_DMA_PENDCNTIRQCLR
);
96 ret
|= (tmp
>> channel
) << 1;
98 tmp
= readl(dmac
+ S6_DMA_LOWWMRKIRQSTAT
);
100 writel(tmp
, dmac
+ S6_DMA_LOWWMRKIRQCLR
);
101 ret
|= (tmp
>> channel
) << 2;
103 tmp
= readl(dmac
+ S6_DMA_INTRAW0
);
104 tmp
&= (mask
<< S6_DMA_INT0_OVER
) | (mask
<< S6_DMA_INT0_UNDER
);
105 writel(tmp
, dmac
+ S6_DMA_INTCLEAR0
);
107 if (tmp
& (mask
<< S6_DMA_INT0_UNDER
))
109 if (tmp
& (mask
<< S6_DMA_INT0_OVER
))
112 tmp
= readl(dmac
+ S6_DMA_MASTERERRINFO
);
113 mask
<<= S6_DMA_INT1_CHANNEL
;
114 if (((tmp
>> S6_DMA_MASTERERR_CHAN(0)) & S6_DMA_MASTERERR_CHAN_MASK
)
116 mask
|= 1 << S6_DMA_INT1_MASTER
;
117 if (((tmp
>> S6_DMA_MASTERERR_CHAN(1)) & S6_DMA_MASTERERR_CHAN_MASK
)
119 mask
|= 1 << (S6_DMA_INT1_MASTER
+ 1);
120 if (((tmp
>> S6_DMA_MASTERERR_CHAN(2)) & S6_DMA_MASTERERR_CHAN_MASK
)
122 mask
|= 1 << (S6_DMA_INT1_MASTER
+ 2);
124 tmp
= readl(dmac
+ S6_DMA_INTRAW1
) & mask
;
125 writel(tmp
, dmac
+ S6_DMA_INTCLEAR1
);
126 ret
|= ((tmp
>> channel
) & 1) << 5;
127 ret
|= ((tmp
>> S6_DMA_INT1_MASTER
) & S6_DMA_INT1_MASTER_MASK
) << 6;
132 void s6dmac_release_chan(u32 dmac
, int chan
)
135 s6dmac_disable_chan(dmac
, chan
);
141 static inline void __init
dmac_init(u32 dmac
, u8 chan_nb
)
143 s6dmac_ctrl
[S6_DMAC_INDEX(dmac
)].dmac
= dmac
;
144 spin_lock_init(&s6dmac_ctrl
[S6_DMAC_INDEX(dmac
)].lock
);
145 s6dmac_ctrl
[S6_DMAC_INDEX(dmac
)].chan_nb
= chan_nb
;
146 writel(S6_DMA_INT1_MASTER_MASK
<< S6_DMA_INT1_MASTER
,
147 dmac
+ S6_DMA_INTCLEAR1
);
150 static inline void __init
dmac_master(u32 dmac
,
151 u32 m0start
, u32 m0end
, u32 m1start
, u32 m1end
)
153 writel(m0start
, dmac
+ S6_DMA_MASTER0START
);
154 writel(m0end
- 1, dmac
+ S6_DMA_MASTER0END
);
155 writel(m1start
, dmac
+ S6_DMA_MASTER1START
);
156 writel(m1end
- 1, dmac
+ S6_DMA_MASTER1END
);
159 static void __init
s6_dmac_init(void)
161 dmac_init(S6_REG_LMSDMA
, S6_LMSDMA_NB
);
162 dmac_master(S6_REG_LMSDMA
,
163 S6_MEM_DDR
, S6_MEM_PCIE_APER
, S6_MEM_EFI
, S6_MEM_GMAC
);
164 dmac_init(S6_REG_NIDMA
, S6_NIDMA_NB
);
165 dmac_init(S6_REG_DPDMA
, S6_DPDMA_NB
);
166 dmac_master(S6_REG_DPDMA
,
167 S6_MEM_DDR
, S6_MEM_PCIE_APER
, S6_REG_DP
, S6_REG_DPDMA
);
168 dmac_init(S6_REG_HIFDMA
, S6_HIFDMA_NB
);
169 dmac_master(S6_REG_HIFDMA
,
170 S6_MEM_GMAC
, S6_MEM_PCIE_CFG
, S6_MEM_PCIE_APER
, S6_MEM_AUX
);
173 arch_initcall(s6_dmac_init
);