Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/xtensa/variants/s6000/include/variant/dmac.h
10821 views
1
/*
2
* include/asm-xtensa/variant-s6000/dmac.h
3
*
4
* This file is subject to the terms and conditions of the GNU General Public
5
* License. See the file "COPYING" in the main directory of this archive
6
* for more details.
7
*
8
* Copyright (C) 2006 Tensilica Inc.
9
* Copyright (C) 2008 Emlix GmbH <[email protected]>
10
* Authors: Fabian Godehardt <[email protected]>
11
* Oskar Schirmer <[email protected]>
12
* Daniel Gloeckner <[email protected]>
13
*/
14
15
#ifndef __ASM_XTENSA_S6000_DMAC_H
16
#define __ASM_XTENSA_S6000_DMAC_H
17
#include <linux/io.h>
18
#include <variant/hardware.h>
19
20
/* DMA global */
21
22
#define S6_DMA_INTSTAT0 0x000
23
#define S6_DMA_INTSTAT1 0x004
24
#define S6_DMA_INTENABLE0 0x008
25
#define S6_DMA_INTENABLE1 0x00C
26
#define S6_DMA_INTRAW0 0x010
27
#define S6_DMA_INTRAW1 0x014
28
#define S6_DMA_INTCLEAR0 0x018
29
#define S6_DMA_INTCLEAR1 0x01C
30
#define S6_DMA_INTSET0 0x020
31
#define S6_DMA_INTSET1 0x024
32
#define S6_DMA_INT0_UNDER 0
33
#define S6_DMA_INT0_OVER 16
34
#define S6_DMA_INT1_CHANNEL 0
35
#define S6_DMA_INT1_MASTER 16
36
#define S6_DMA_INT1_MASTER_MASK 7
37
#define S6_DMA_TERMCNTIRQSTAT 0x028
38
#define S6_DMA_TERMCNTIRQCLR 0x02C
39
#define S6_DMA_TERMCNTIRQSET 0x030
40
#define S6_DMA_PENDCNTIRQSTAT 0x034
41
#define S6_DMA_PENDCNTIRQCLR 0x038
42
#define S6_DMA_PENDCNTIRQSET 0x03C
43
#define S6_DMA_LOWWMRKIRQSTAT 0x040
44
#define S6_DMA_LOWWMRKIRQCLR 0x044
45
#define S6_DMA_LOWWMRKIRQSET 0x048
46
#define S6_DMA_MASTERERRINFO 0x04C
47
#define S6_DMA_MASTERERR_CHAN(n) (4*(n))
48
#define S6_DMA_MASTERERR_CHAN_MASK 0xF
49
#define S6_DMA_DESCRFIFO0 0x050
50
#define S6_DMA_DESCRFIFO1 0x054
51
#define S6_DMA_DESCRFIFO2 0x058
52
#define S6_DMA_DESCRFIFO2_AUTODISABLE 24
53
#define S6_DMA_DESCRFIFO3 0x05C
54
#define S6_DMA_MASTER0START 0x060
55
#define S6_DMA_MASTER0END 0x064
56
#define S6_DMA_MASTER1START 0x068
57
#define S6_DMA_MASTER1END 0x06C
58
#define S6_DMA_NEXTFREE 0x070
59
#define S6_DMA_NEXTFREE_CHAN 0
60
#define S6_DMA_NEXTFREE_CHAN_MASK 0x1F
61
#define S6_DMA_NEXTFREE_ENA 16
62
#define S6_DMA_NEXTFREE_ENA_MASK ((1 << 16) - 1)
63
#define S6_DMA_DPORTCTRLGRP(p) ((p) * 4 + 0x074)
64
#define S6_DMA_DPORTCTRLGRP_FRAMEREP 0
65
#define S6_DMA_DPORTCTRLGRP_NRCHANS 1
66
#define S6_DMA_DPORTCTRLGRP_NRCHANS_1 0
67
#define S6_DMA_DPORTCTRLGRP_NRCHANS_3 1
68
#define S6_DMA_DPORTCTRLGRP_NRCHANS_4 2
69
#define S6_DMA_DPORTCTRLGRP_NRCHANS_2 3
70
#define S6_DMA_DPORTCTRLGRP_ENA 31
71
72
73
/* DMA per channel */
74
75
#define DMA_CHNL(dmac, n) ((dmac) + 0x1000 + (n) * 0x100)
76
#define DMA_INDEX_CHNL(addr) (((addr) >> 8) & 0xF)
77
#define DMA_MASK_DMAC(addr) ((addr) & 0xFFFF0000)
78
#define S6_DMA_CHNCTRL 0x000
79
#define S6_DMA_CHNCTRL_ENABLE 0
80
#define S6_DMA_CHNCTRL_PAUSE 1
81
#define S6_DMA_CHNCTRL_PRIO 2
82
#define S6_DMA_CHNCTRL_PRIO_MASK 3
83
#define S6_DMA_CHNCTRL_PERIPHXFER 4
84
#define S6_DMA_CHNCTRL_PERIPHENA 5
85
#define S6_DMA_CHNCTRL_SRCINC 6
86
#define S6_DMA_CHNCTRL_DSTINC 7
87
#define S6_DMA_CHNCTRL_BURSTLOG 8
88
#define S6_DMA_CHNCTRL_BURSTLOG_MASK 7
89
#define S6_DMA_CHNCTRL_DESCFIFODEPTH 12
90
#define S6_DMA_CHNCTRL_DESCFIFODEPTH_MASK 0x1F
91
#define S6_DMA_CHNCTRL_DESCFIFOFULL 17
92
#define S6_DMA_CHNCTRL_BWCONSEL 18
93
#define S6_DMA_CHNCTRL_BWCONENA 19
94
#define S6_DMA_CHNCTRL_PENDGCNTSTAT 20
95
#define S6_DMA_CHNCTRL_PENDGCNTSTAT_MASK 0x3F
96
#define S6_DMA_CHNCTRL_LOWWMARK 26
97
#define S6_DMA_CHNCTRL_LOWWMARK_MASK 0xF
98
#define S6_DMA_CHNCTRL_TSTAMP 30
99
#define S6_DMA_TERMCNTNB 0x004
100
#define S6_DMA_TERMCNTNB_MASK 0xFFFF
101
#define S6_DMA_TERMCNTTMO 0x008
102
#define S6_DMA_TERMCNTSTAT 0x00C
103
#define S6_DMA_TERMCNTSTAT_MASK 0xFF
104
#define S6_DMA_CMONCHUNK 0x010
105
#define S6_DMA_SRCSKIP 0x014
106
#define S6_DMA_DSTSKIP 0x018
107
#define S6_DMA_CUR_SRC 0x024
108
#define S6_DMA_CUR_DST 0x028
109
#define S6_DMA_TIMESTAMP 0x030
110
111
/* DMA channel lists */
112
113
#define S6_DPDMA_CHAN(stream, channel) (4 * (stream) + (channel))
114
#define S6_DPDMA_NB 16
115
116
#define S6_HIFDMA_GMACTX 0
117
#define S6_HIFDMA_GMACRX 1
118
#define S6_HIFDMA_I2S0 2
119
#define S6_HIFDMA_I2S1 3
120
#define S6_HIFDMA_EGIB 4
121
#define S6_HIFDMA_PCITX 5
122
#define S6_HIFDMA_PCIRX 6
123
#define S6_HIFDMA_NB 7
124
125
#define S6_NIDMA_NB 4
126
127
#define S6_LMSDMA_NB 12
128
129
/* controller access */
130
131
#define S6_DMAC_NB 4
132
#define S6_DMAC_INDEX(dmac) (((unsigned)(dmac) >> 18) % S6_DMAC_NB)
133
134
struct s6dmac_ctrl {
135
u32 dmac;
136
spinlock_t lock;
137
u8 chan_nb;
138
};
139
140
extern struct s6dmac_ctrl s6dmac_ctrl[S6_DMAC_NB];
141
142
143
/* DMA control, per channel */
144
145
static inline int s6dmac_fifo_full(u32 dmac, int chan)
146
{
147
return (readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL)
148
& (1 << S6_DMA_CHNCTRL_DESCFIFOFULL)) && 1;
149
}
150
151
static inline int s6dmac_termcnt_irq(u32 dmac, int chan)
152
{
153
u32 m = 1 << chan;
154
int r = (readl(dmac + S6_DMA_TERMCNTIRQSTAT) & m) && 1;
155
if (r)
156
writel(m, dmac + S6_DMA_TERMCNTIRQCLR);
157
return r;
158
}
159
160
static inline int s6dmac_pendcnt_irq(u32 dmac, int chan)
161
{
162
u32 m = 1 << chan;
163
int r = (readl(dmac + S6_DMA_PENDCNTIRQSTAT) & m) && 1;
164
if (r)
165
writel(m, dmac + S6_DMA_PENDCNTIRQCLR);
166
return r;
167
}
168
169
static inline int s6dmac_lowwmark_irq(u32 dmac, int chan)
170
{
171
int r = (readl(dmac + S6_DMA_LOWWMRKIRQSTAT) & (1 << chan)) ? 1 : 0;
172
if (r)
173
writel(1 << chan, dmac + S6_DMA_LOWWMRKIRQCLR);
174
return r;
175
}
176
177
static inline u32 s6dmac_pending_count(u32 dmac, int chan)
178
{
179
return (readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL)
180
>> S6_DMA_CHNCTRL_PENDGCNTSTAT)
181
& S6_DMA_CHNCTRL_PENDGCNTSTAT_MASK;
182
}
183
184
static inline void s6dmac_set_terminal_count(u32 dmac, int chan, u32 n)
185
{
186
n &= S6_DMA_TERMCNTNB_MASK;
187
n |= readl(DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB)
188
& ~S6_DMA_TERMCNTNB_MASK;
189
writel(n, DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB);
190
}
191
192
static inline u32 s6dmac_get_terminal_count(u32 dmac, int chan)
193
{
194
return (readl(DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB))
195
& S6_DMA_TERMCNTNB_MASK;
196
}
197
198
static inline u32 s6dmac_timestamp(u32 dmac, int chan)
199
{
200
return readl(DMA_CHNL(dmac, chan) + S6_DMA_TIMESTAMP);
201
}
202
203
static inline u32 s6dmac_cur_src(u32 dmac, int chan)
204
{
205
return readl(DMA_CHNL(dmac, chan) + S6_DMA_CUR_SRC);
206
}
207
208
static inline u32 s6dmac_cur_dst(u32 dmac, int chan)
209
{
210
return readl(DMA_CHNL(dmac, chan) + S6_DMA_CUR_DST);
211
}
212
213
static inline void s6dmac_disable_chan(u32 dmac, int chan)
214
{
215
u32 ctrl;
216
writel(readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL)
217
& ~(1 << S6_DMA_CHNCTRL_ENABLE),
218
DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL);
219
do
220
ctrl = readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL);
221
while (ctrl & (1 << S6_DMA_CHNCTRL_ENABLE));
222
}
223
224
static inline void s6dmac_set_stride_skip(u32 dmac, int chan,
225
int comchunk, /* 0: disable scatter/gather */
226
int srcskip, int dstskip)
227
{
228
writel(comchunk, DMA_CHNL(dmac, chan) + S6_DMA_CMONCHUNK);
229
writel(srcskip, DMA_CHNL(dmac, chan) + S6_DMA_SRCSKIP);
230
writel(dstskip, DMA_CHNL(dmac, chan) + S6_DMA_DSTSKIP);
231
}
232
233
static inline void s6dmac_enable_chan(u32 dmac, int chan,
234
int prio, /* 0 (highest) .. 3 (lowest) */
235
int periphxfer, /* <0: disable p.req.line, 0..1: mode */
236
int srcinc, int dstinc, /* 0: dont increment src/dst address */
237
int comchunk, /* 0: disable scatter/gather */
238
int srcskip, int dstskip,
239
int burstsize, /* 4 for I2S, 7 for everything else */
240
int bandwidthconserve, /* <0: disable, 0..1: select */
241
int lowwmark, /* 0..15 */
242
int timestamp, /* 0: disable timestamp */
243
int enable) /* 0: disable for now */
244
{
245
writel(1, DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB);
246
writel(0, DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTTMO);
247
writel(lowwmark << S6_DMA_CHNCTRL_LOWWMARK,
248
DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL);
249
s6dmac_set_stride_skip(dmac, chan, comchunk, srcskip, dstskip);
250
writel(((enable ? 1 : 0) << S6_DMA_CHNCTRL_ENABLE) |
251
(prio << S6_DMA_CHNCTRL_PRIO) |
252
(((periphxfer > 0) ? 1 : 0) << S6_DMA_CHNCTRL_PERIPHXFER) |
253
(((periphxfer < 0) ? 0 : 1) << S6_DMA_CHNCTRL_PERIPHENA) |
254
((srcinc ? 1 : 0) << S6_DMA_CHNCTRL_SRCINC) |
255
((dstinc ? 1 : 0) << S6_DMA_CHNCTRL_DSTINC) |
256
(burstsize << S6_DMA_CHNCTRL_BURSTLOG) |
257
(((bandwidthconserve > 0) ? 1 : 0) << S6_DMA_CHNCTRL_BWCONSEL) |
258
(((bandwidthconserve < 0) ? 0 : 1) << S6_DMA_CHNCTRL_BWCONENA) |
259
(lowwmark << S6_DMA_CHNCTRL_LOWWMARK) |
260
((timestamp ? 1 : 0) << S6_DMA_CHNCTRL_TSTAMP),
261
DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL);
262
}
263
264
265
/* DMA control, per engine */
266
267
static inline unsigned _dmac_addr_index(u32 dmac)
268
{
269
unsigned i = S6_DMAC_INDEX(dmac);
270
if (s6dmac_ctrl[i].dmac != dmac)
271
BUG();
272
return i;
273
}
274
275
static inline void _s6dmac_disable_error_irqs(u32 dmac, u32 mask)
276
{
277
writel(mask, dmac + S6_DMA_TERMCNTIRQCLR);
278
writel(mask, dmac + S6_DMA_PENDCNTIRQCLR);
279
writel(mask, dmac + S6_DMA_LOWWMRKIRQCLR);
280
writel(readl(dmac + S6_DMA_INTENABLE0)
281
& ~((mask << S6_DMA_INT0_UNDER) | (mask << S6_DMA_INT0_OVER)),
282
dmac + S6_DMA_INTENABLE0);
283
writel(readl(dmac + S6_DMA_INTENABLE1) & ~(mask << S6_DMA_INT1_CHANNEL),
284
dmac + S6_DMA_INTENABLE1);
285
writel((mask << S6_DMA_INT0_UNDER) | (mask << S6_DMA_INT0_OVER),
286
dmac + S6_DMA_INTCLEAR0);
287
writel(mask << S6_DMA_INT1_CHANNEL, dmac + S6_DMA_INTCLEAR1);
288
}
289
290
/*
291
* request channel from specified engine
292
* with chan<0, accept any channel
293
* further parameters see s6dmac_enable_chan
294
* returns < 0 upon error, channel nb otherwise
295
*/
296
static inline int s6dmac_request_chan(u32 dmac, int chan,
297
int prio,
298
int periphxfer,
299
int srcinc, int dstinc,
300
int comchunk,
301
int srcskip, int dstskip,
302
int burstsize,
303
int bandwidthconserve,
304
int lowwmark,
305
int timestamp,
306
int enable)
307
{
308
int r = chan;
309
unsigned long flags;
310
spinlock_t *spinl = &s6dmac_ctrl[_dmac_addr_index(dmac)].lock;
311
spin_lock_irqsave(spinl, flags);
312
if (r < 0) {
313
r = (readl(dmac + S6_DMA_NEXTFREE) >> S6_DMA_NEXTFREE_CHAN)
314
& S6_DMA_NEXTFREE_CHAN_MASK;
315
}
316
if (r >= s6dmac_ctrl[_dmac_addr_index(dmac)].chan_nb) {
317
if (chan < 0)
318
r = -EBUSY;
319
else
320
r = -ENXIO;
321
} else if (((readl(dmac + S6_DMA_NEXTFREE) >> S6_DMA_NEXTFREE_ENA)
322
>> r) & 1) {
323
r = -EBUSY;
324
} else {
325
s6dmac_enable_chan(dmac, r, prio, periphxfer,
326
srcinc, dstinc, comchunk, srcskip, dstskip, burstsize,
327
bandwidthconserve, lowwmark, timestamp, enable);
328
}
329
spin_unlock_irqrestore(spinl, flags);
330
return r;
331
}
332
333
static inline void s6dmac_put_fifo(u32 dmac, int chan,
334
u32 src, u32 dst, u32 size)
335
{
336
unsigned long flags;
337
spinlock_t *spinl = &s6dmac_ctrl[_dmac_addr_index(dmac)].lock;
338
spin_lock_irqsave(spinl, flags);
339
writel(src, dmac + S6_DMA_DESCRFIFO0);
340
writel(dst, dmac + S6_DMA_DESCRFIFO1);
341
writel(size, dmac + S6_DMA_DESCRFIFO2);
342
writel(chan, dmac + S6_DMA_DESCRFIFO3);
343
spin_unlock_irqrestore(spinl, flags);
344
}
345
346
static inline u32 s6dmac_channel_enabled(u32 dmac, int chan)
347
{
348
return readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL) &
349
(1 << S6_DMA_CHNCTRL_ENABLE);
350
}
351
352
/*
353
* group 1-4 data port channels
354
* with port=0..3, nrch=1-4 channels,
355
* frrep=0/1 (dis- or enable frame repeat)
356
*/
357
static inline void s6dmac_dp_setup_group(u32 dmac, int port,
358
int nrch, int frrep)
359
{
360
const static u8 mask[4] = {0, 3, 1, 2};
361
BUG_ON(dmac != S6_REG_DPDMA);
362
if ((port < 0) || (port > 3) || (nrch < 1) || (nrch > 4))
363
return;
364
writel((mask[nrch - 1] << S6_DMA_DPORTCTRLGRP_NRCHANS)
365
| ((frrep ? 1 : 0) << S6_DMA_DPORTCTRLGRP_FRAMEREP),
366
dmac + S6_DMA_DPORTCTRLGRP(port));
367
}
368
369
static inline void s6dmac_dp_switch_group(u32 dmac, int port, int enable)
370
{
371
u32 tmp;
372
BUG_ON(dmac != S6_REG_DPDMA);
373
tmp = readl(dmac + S6_DMA_DPORTCTRLGRP(port));
374
if (enable)
375
tmp |= (1 << S6_DMA_DPORTCTRLGRP_ENA);
376
else
377
tmp &= ~(1 << S6_DMA_DPORTCTRLGRP_ENA);
378
writel(tmp, dmac + S6_DMA_DPORTCTRLGRP(port));
379
}
380
381
extern void s6dmac_put_fifo_cache(u32 dmac, int chan,
382
u32 src, u32 dst, u32 size);
383
extern void s6dmac_disable_error_irqs(u32 dmac, u32 mask);
384
extern u32 s6dmac_int_sources(u32 dmac, u32 channel);
385
extern void s6dmac_release_chan(u32 dmac, int chan);
386
387
#endif /* __ASM_XTENSA_S6000_DMAC_H */
388
389