1 /* $OpenBSD: edma.c,v 1.5 2015/01/22 14:33:01 krw Exp $ */
3 * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 #include <sys/param.h>
19 #include <sys/types.h>
20 #include <sys/systm.h>
22 #include <machine/bus.h>
24 #include <armv7/armv7/armv7var.h>
25 #include <armv7/omap/prcmvar.h>
26 #include <armv7/omap/edmavar.h>
28 #define DEVNAME(s) ((s)->sc_dev.dv_xname)
33 bus_space_tag_t sc_iot
;
34 bus_space_handle_t sc_tpcc
;
37 edma_intr_cb_t sc_intr_cb
[64];
38 void *sc_intr_dat
[64];
41 #define EDMA_NUM_DMA_CHANS 64
42 #define EDMA_NUM_QDMA_CHANS 8
43 #define EDMA_TPCC_DHCM(x) (0x100 + (x * 4))
44 #define EDMA_REG_X(x) (0x1000 + (0x200 * x))
45 #define EDMA_TPCC_PID 0x0
46 #define EDMA_TPCC_EMCR 0x308
47 #define EDMA_TPCC_EMCRH 0x30c
48 #define EDMA_TPCC_CCERRCLR 0x31c
49 #define EDMA_TPCC_DRAE0 0x340
50 #define EDMA_TPCC_DRAEH0 0x344
51 #define EDMA_TPCC_ESR 0x1010
52 #define EDMA_TPCC_ESRH 0x1014
53 #define EDMA_TPCC_EESR 0x1030
54 #define EDMA_TPCC_EESRH 0x1034
55 #define EDMA_TPCC_SECR 0x1040
56 #define EDMA_TPCC_SECRH 0x1044
57 #define EDMA_TPCC_IER 0x1050
58 #define EDMA_TPCC_IERH 0x1054
59 #define EDMA_TPCC_IECR 0x1058
60 #define EDMA_TPCC_IECRH 0x105c
61 #define EDMA_TPCC_IESR 0x1060
62 #define EDMA_TPCC_IESRH 0x1064
63 #define EDMA_TPCC_IPR 0x1068
64 #define EDMA_TPCC_IPRH 0x106c
65 #define EDMA_TPCC_ICR 0x1070
66 #define EDMA_TPCC_ICRH 0x1074
67 #define EDMA_TPCC_IEVAL 0x1078
68 #define EDMA_TPCC_OPT(x) (0x4000 + (x * 0x20))
70 #define TPCC_READ_4(sc, reg) \
71 (bus_space_read_4((sc)->sc_iot, (sc)->sc_tpcc, (reg)))
72 #define TPCC_WRITE_4(sc, reg, val) \
73 (bus_space_write_4((sc)->sc_iot, (sc)->sc_tpcc, (reg), (val)))
74 #define TPCC_SET(sc, reg, val) \
75 (TPCC_WRITE_4((sc), (reg), (TPCC_READ_4(sc, reg) | (val))))
76 #define TPCC_FILTSET(sc, reg, val, filt) \
77 (TPCC_WRITE_4((sc), (reg), (TPCC_READ_4(sc, reg) & (filt)) | (val)))
79 struct edma_softc
*edma_sc
;
81 void edma_attach(struct device
*, struct device
*, void *);
82 int edma_comp_intr(void *);
84 struct cfattach edma_ca
= {
85 sizeof(struct edma_softc
), NULL
, edma_attach
88 struct cfdriver edma_cd
= {
93 edma_attach(struct device
*parent
, struct device
*self
, void *aux
)
95 struct armv7_attach_args
*aa
= aux
;
96 struct edma_softc
*sc
= (struct edma_softc
*)self
;
100 sc
->sc_iot
= aa
->aa_iot
;
102 /* Map Base address for TPCC and TPCTX */
103 if (bus_space_map(sc
->sc_iot
, aa
->aa_dev
->mem
[0].addr
,
104 aa
->aa_dev
->mem
[0].size
, 0, &sc
->sc_tpcc
)) {
105 printf("%s: bus_space_map failed for TPCC\n", DEVNAME(sc
));
109 /* Enable TPCC and TPTC0 in PRCM */
110 prcm_enablemodule(PRCM_TPCC
);
111 prcm_enablemodule(PRCM_TPTC0
);
113 rev
= TPCC_READ_4(sc
, EDMA_TPCC_PID
);
114 printf(" rev %d.%d\n", rev
>> 4 & 0xf, rev
& 0xf);
117 /* Enable interrupts line */
118 sc
->sc_ih_comp
= arm_intr_establish(aa
->aa_dev
->irq
[0], IPL_VM
,
119 edma_comp_intr
, sc
, DEVNAME(sc
));
120 if (sc
->sc_ih_comp
== NULL
) {
121 printf("%s: unable to establish interrupt comp\n", DEVNAME(sc
));
122 bus_space_unmap(sc
->sc_iot
, sc
->sc_tpcc
,
123 aa
->aa_dev
->mem
[0].size
);
127 /* Set global softc */
130 /* Clear Event Missed Events */
131 TPCC_WRITE_4(sc
, EDMA_TPCC_EMCR
, 0xffffffff);
132 TPCC_WRITE_4(sc
, EDMA_TPCC_EMCRH
, 0xffffffff);
133 TPCC_WRITE_4(sc
, EDMA_TPCC_CCERRCLR
, 0xffffffff);
135 /* Identity Map Channels PaRAM */
136 for (i
= 0; i
< EDMA_NUM_DMA_CHANS
; i
++)
137 TPCC_WRITE_4(sc
, EDMA_TPCC_DHCM(i
), i
<< 5);
140 * Enable SHADOW Region 0 and only use this region
141 * This is needed to have working intr...
143 TPCC_WRITE_4(sc
, EDMA_TPCC_DRAE0
, 0xffffffff);
144 TPCC_WRITE_4(sc
, EDMA_TPCC_DRAEH0
, 0xffffffff);
150 edma_comp_intr(void *arg
)
152 struct edma_softc
*sc
= arg
;
156 ipr
= TPCC_READ_4(sc
, EDMA_TPCC_IPR
);
157 iprh
= TPCC_READ_4(sc
, EDMA_TPCC_IPRH
);
159 /* Lookup to intr in the first 32 chans */
160 for (i
= 0; i
< (EDMA_NUM_DMA_CHANS
/2); i
++) {
161 if (ISSET(ipr
, (1<<i
))) {
162 TPCC_WRITE_4(sc
, EDMA_TPCC_ICR
, (1<<i
));
163 if (sc
->sc_intr_cb
[i
])
164 sc
->sc_intr_cb
[i
](sc
->sc_intr_dat
[i
]);
168 for (i
= 0; i
< (EDMA_NUM_DMA_CHANS
/2); i
++) {
169 if (ISSET(iprh
, (1<<i
))) {
170 TPCC_WRITE_4(sc
, EDMA_TPCC_ICRH
, (1<<i
));
171 if (sc
->sc_intr_cb
[i
+ 32])
172 sc
->sc_intr_cb
[i
+ 32](sc
->sc_intr_dat
[i
+ 32]);
176 /* Trig pending intr */
177 TPCC_WRITE_4(sc
, EDMA_TPCC_IEVAL
, 1);
183 edma_intr_dma_en(uint32_t ch
, edma_intr_cb_t cb
, void *dat
)
185 if (edma_sc
== NULL
|| ch
>= EDMA_NUM_DMA_CHANS
)
188 edma_sc
->sc_intr_cb
[ch
] = cb
;
189 edma_sc
->sc_intr_dat
[ch
] = dat
;
192 TPCC_WRITE_4(edma_sc
, EDMA_TPCC_IESR
, 1 << ch
);
193 TPCC_WRITE_4(edma_sc
, EDMA_TPCC_IESR
+ EDMA_REG_X(0), 1 << ch
);
195 TPCC_WRITE_4(edma_sc
, EDMA_TPCC_IESRH
, 1 << (ch
- 32));
196 TPCC_WRITE_4(edma_sc
, EDMA_TPCC_IESRH
+ EDMA_REG_X(0),
204 edma_intr_dma_dis(uint32_t ch
)
206 if (edma_sc
== NULL
|| ch
>= EDMA_NUM_DMA_CHANS
)
210 TPCC_WRITE_4(edma_sc
, EDMA_TPCC_IECR
, 1 << ch
);
212 TPCC_WRITE_4(edma_sc
, EDMA_TPCC_IECRH
, 1 << (ch
- 32));
213 edma_sc
->sc_intr_cb
[ch
] = NULL
;
214 edma_sc
->sc_intr_dat
[ch
] = NULL
;
220 edma_trig_xfer_man(uint32_t ch
)
222 if (edma_sc
== NULL
|| ch
>= EDMA_NUM_DMA_CHANS
)
227 * enable IEVAL only if there is an intr associated
230 if (ISSET(TPCC_READ_4(edma_sc
, EDMA_TPCC_IER
), 1 << ch
))
231 TPCC_WRITE_4(edma_sc
, EDMA_TPCC_IEVAL
, 1);
232 TPCC_WRITE_4(edma_sc
, EDMA_TPCC_ICR
, 1 << ch
);
233 TPCC_WRITE_4(edma_sc
, EDMA_TPCC_EMCR
, 1 << ch
);
234 TPCC_WRITE_4(edma_sc
, EDMA_TPCC_ESR
, 1 << ch
);
236 if (ISSET(TPCC_READ_4(edma_sc
, EDMA_TPCC_IERH
), 1 << (ch
- 32)))
237 TPCC_WRITE_4(edma_sc
, EDMA_TPCC_IEVAL
, 1);
238 TPCC_WRITE_4(edma_sc
, EDMA_TPCC_ICRH
, 1 << (ch
- 32));
239 TPCC_WRITE_4(edma_sc
, EDMA_TPCC_EMCRH
, 1 << (ch
- 32));
240 TPCC_WRITE_4(edma_sc
, EDMA_TPCC_ESRH
, 1 << (ch
- 32));
247 edma_trig_xfer_by_dev(uint32_t ch
)
249 if (edma_sc
== NULL
|| ch
>= EDMA_NUM_DMA_CHANS
)
253 if (ISSET(TPCC_READ_4(edma_sc
, EDMA_TPCC_IER
), 1 << ch
))
254 TPCC_WRITE_4(edma_sc
, EDMA_TPCC_IEVAL
, 1);
255 TPCC_WRITE_4(edma_sc
, EDMA_TPCC_ICR
, 1 << ch
);
256 TPCC_WRITE_4(edma_sc
, EDMA_TPCC_SECR
, 1 << ch
);
257 TPCC_WRITE_4(edma_sc
, EDMA_TPCC_EMCR
, 1 << ch
);
258 TPCC_WRITE_4(edma_sc
, EDMA_TPCC_EESR
, 1 << ch
);
260 if (ISSET(TPCC_READ_4(edma_sc
, EDMA_TPCC_IERH
), 1 << (ch
- 32)))
261 TPCC_WRITE_4(edma_sc
, EDMA_TPCC_IEVAL
, 1);
262 TPCC_WRITE_4(edma_sc
, EDMA_TPCC_ICRH
, 1 << (ch
- 32));
263 TPCC_WRITE_4(edma_sc
, EDMA_TPCC_SECRH
, 1 << (ch
- 32));
264 TPCC_WRITE_4(edma_sc
, EDMA_TPCC_EMCRH
, 1 << (ch
- 32));
265 TPCC_WRITE_4(edma_sc
, EDMA_TPCC_EESRH
, 1 << (ch
- 32));
271 edma_param_write(uint32_t ch
, struct edma_param
*params
)
273 bus_space_write_region_4(edma_sc
->sc_iot
, edma_sc
->sc_tpcc
,
274 EDMA_TPCC_OPT(ch
), (uint32_t *)params
, 8);
278 edma_param_read(uint32_t ch
, struct edma_param
*params
)
280 bus_space_read_region_4(edma_sc
->sc_iot
, edma_sc
->sc_tpcc
,
281 EDMA_TPCC_OPT(ch
), (uint32_t *)params
, 8);