Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/xtensa/variants/s6000/dmac.c
10819 views
1
/*
2
* Authors: Oskar Schirmer <[email protected]>
3
* Daniel Gloeckner <[email protected]>
4
* (c) 2008 emlix GmbH http://www.emlix.com
5
*
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.
10
*/
11
12
#include <linux/kernel.h>
13
#include <linux/io.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>
19
20
/* DMA engine lookup */
21
22
struct s6dmac_ctrl s6dmac_ctrl[S6_DMAC_NB];
23
24
25
/* DMA control, per engine */
26
27
void s6dmac_put_fifo_cache(u32 dmac, int chan, u32 src, u32 dst, u32 size)
28
{
29
if (xtensa_need_flush_dma_source(src)) {
30
u32 base = src;
31
u32 span = size;
32
u32 chunk = readl(DMA_CHNL(dmac, chan) + S6_DMA_CMONCHUNK);
33
if (chunk && (size > chunk)) {
34
s32 skip =
35
readl(DMA_CHNL(dmac, chan) + S6_DMA_SRCSKIP);
36
u32 gaps = (size+chunk-1)/chunk - 1;
37
if (skip >= 0) {
38
span += gaps * skip;
39
} else if (-skip > chunk) {
40
s32 decr = gaps * (chunk + skip);
41
base += decr;
42
span = chunk - decr;
43
} else {
44
span = max(span + gaps * skip,
45
(chunk + skip) * gaps - skip);
46
}
47
}
48
flush_dcache_unaligned(base, span);
49
}
50
if (xtensa_need_invalidate_dma_destination(dst)) {
51
u32 base = dst;
52
u32 span = size;
53
u32 chunk = readl(DMA_CHNL(dmac, chan) + S6_DMA_CMONCHUNK);
54
if (chunk && (size > chunk)) {
55
s32 skip =
56
readl(DMA_CHNL(dmac, chan) + S6_DMA_DSTSKIP);
57
u32 gaps = (size+chunk-1)/chunk - 1;
58
if (skip >= 0) {
59
span += gaps * skip;
60
} else if (-skip > chunk) {
61
s32 decr = gaps * (chunk + skip);
62
base += decr;
63
span = chunk - decr;
64
} else {
65
span = max(span + gaps * skip,
66
(chunk + skip) * gaps - skip);
67
}
68
}
69
invalidate_dcache_unaligned(base, span);
70
}
71
s6dmac_put_fifo(dmac, chan, src, dst, size);
72
}
73
74
void s6dmac_disable_error_irqs(u32 dmac, u32 mask)
75
{
76
unsigned long flags;
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);
81
}
82
83
u32 s6dmac_int_sources(u32 dmac, u32 channel)
84
{
85
u32 mask, ret, tmp;
86
mask = 1 << channel;
87
88
tmp = readl(dmac + S6_DMA_TERMCNTIRQSTAT);
89
tmp &= mask;
90
writel(tmp, dmac + S6_DMA_TERMCNTIRQCLR);
91
ret = tmp >> channel;
92
93
tmp = readl(dmac + S6_DMA_PENDCNTIRQSTAT);
94
tmp &= mask;
95
writel(tmp, dmac + S6_DMA_PENDCNTIRQCLR);
96
ret |= (tmp >> channel) << 1;
97
98
tmp = readl(dmac + S6_DMA_LOWWMRKIRQSTAT);
99
tmp &= mask;
100
writel(tmp, dmac + S6_DMA_LOWWMRKIRQCLR);
101
ret |= (tmp >> channel) << 2;
102
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);
106
107
if (tmp & (mask << S6_DMA_INT0_UNDER))
108
ret |= 1 << 3;
109
if (tmp & (mask << S6_DMA_INT0_OVER))
110
ret |= 1 << 4;
111
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)
115
== channel)
116
mask |= 1 << S6_DMA_INT1_MASTER;
117
if (((tmp >> S6_DMA_MASTERERR_CHAN(1)) & S6_DMA_MASTERERR_CHAN_MASK)
118
== channel)
119
mask |= 1 << (S6_DMA_INT1_MASTER + 1);
120
if (((tmp >> S6_DMA_MASTERERR_CHAN(2)) & S6_DMA_MASTERERR_CHAN_MASK)
121
== channel)
122
mask |= 1 << (S6_DMA_INT1_MASTER + 2);
123
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;
128
129
return ret;
130
}
131
132
void s6dmac_release_chan(u32 dmac, int chan)
133
{
134
if (chan >= 0)
135
s6dmac_disable_chan(dmac, chan);
136
}
137
138
139
/* global init */
140
141
static inline void __init dmac_init(u32 dmac, u8 chan_nb)
142
{
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);
148
}
149
150
static inline void __init dmac_master(u32 dmac,
151
u32 m0start, u32 m0end, u32 m1start, u32 m1end)
152
{
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);
157
}
158
159
static void __init s6_dmac_init(void)
160
{
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);
171
}
172
173
arch_initcall(s6_dmac_init);
174
175