ti_edma.c revision 1.2 1 1.2 jmcneill /* $NetBSD: ti_edma.c,v 1.2 2021/01/15 22:59:50 jmcneill Exp $ */
2 1.1 jmcneill
3 1.1 jmcneill /*-
4 1.1 jmcneill * Copyright (c) 2014 Jared D. McNeill <jmcneill (at) invisible.ca>
5 1.1 jmcneill * All rights reserved.
6 1.1 jmcneill *
7 1.1 jmcneill * Redistribution and use in source and binary forms, with or without
8 1.1 jmcneill * modification, are permitted provided that the following conditions
9 1.1 jmcneill * are met:
10 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright
11 1.1 jmcneill * notice, this list of conditions and the following disclaimer.
12 1.1 jmcneill * 2. The name of the author may not be used to endorse or promote products
13 1.1 jmcneill * derived from this software without specific prior written permission.
14 1.1 jmcneill *
15 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 1.1 jmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 1.1 jmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 1.1 jmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 1.1 jmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 1.1 jmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 1.1 jmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22 1.1 jmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 1.1 jmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 1.1 jmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 1.1 jmcneill * SUCH DAMAGE.
26 1.1 jmcneill */
27 1.1 jmcneill
28 1.1 jmcneill #include <sys/cdefs.h>
29 1.2 jmcneill __KERNEL_RCSID(0, "$NetBSD: ti_edma.c,v 1.2 2021/01/15 22:59:50 jmcneill Exp $");
30 1.1 jmcneill
31 1.1 jmcneill #include <sys/param.h>
32 1.1 jmcneill #include <sys/systm.h>
33 1.1 jmcneill #include <sys/device.h>
34 1.1 jmcneill #include <sys/conf.h>
35 1.1 jmcneill #include <sys/intr.h>
36 1.1 jmcneill #include <sys/mutex.h>
37 1.1 jmcneill #include <sys/bus.h>
38 1.1 jmcneill #include <sys/bitops.h>
39 1.1 jmcneill
40 1.1 jmcneill #include <dev/fdt/fdtvar.h>
41 1.1 jmcneill
42 1.1 jmcneill #include <arm/ti/ti_prcm.h>
43 1.1 jmcneill #include <arm/ti/ti_edma.h>
44 1.1 jmcneill
45 1.1 jmcneill #define NUM_DMA_CHANNELS 64
46 1.1 jmcneill #define NUM_PARAM_SETS 256
47 1.1 jmcneill #define MAX_PARAM_PER_CHANNEL 32
48 1.1 jmcneill
49 1.1 jmcneill #ifdef EDMA_DEBUG
50 1.1 jmcneill int edmadebug = 1;
51 1.1 jmcneill #define DPRINTF(n,s) do { if ((n) <= edmadebug) device_printf s; } while (0)
52 1.1 jmcneill #else
53 1.1 jmcneill #define DPRINTF(n,s) do {} while (0)
54 1.1 jmcneill #endif
55 1.1 jmcneill
56 1.1 jmcneill struct edma_softc;
57 1.1 jmcneill
58 1.1 jmcneill struct edma_channel {
59 1.1 jmcneill struct edma_softc *ch_sc;
60 1.1 jmcneill enum edma_type ch_type;
61 1.1 jmcneill uint8_t ch_index;
62 1.1 jmcneill void (*ch_callback)(void *);
63 1.1 jmcneill void *ch_callbackarg;
64 1.1 jmcneill unsigned int ch_nparams;
65 1.1 jmcneill };
66 1.1 jmcneill
67 1.1 jmcneill struct edma_softc {
68 1.1 jmcneill device_t sc_dev;
69 1.1 jmcneill bus_space_tag_t sc_iot;
70 1.1 jmcneill bus_space_handle_t sc_ioh;
71 1.1 jmcneill kmutex_t sc_lock;
72 1.1 jmcneill struct edma_channel sc_dma[NUM_DMA_CHANNELS];
73 1.1 jmcneill
74 1.1 jmcneill void *sc_ih;
75 1.1 jmcneill
76 1.1 jmcneill uint32_t sc_dmamask[NUM_DMA_CHANNELS / 32];
77 1.1 jmcneill uint32_t sc_parammask[NUM_PARAM_SETS / 32];
78 1.1 jmcneill };
79 1.1 jmcneill
80 1.1 jmcneill static int edma_match(device_t, cfdata_t, void *);
81 1.1 jmcneill static void edma_attach(device_t, device_t, void *);
82 1.1 jmcneill
83 1.1 jmcneill static void edma_init(struct edma_softc *);
84 1.1 jmcneill static int edma_intr(void *);
85 1.1 jmcneill static void edma_write_param(struct edma_softc *,
86 1.1 jmcneill unsigned int, const struct edma_param *);
87 1.1 jmcneill static bool edma_bit_isset(uint32_t *, unsigned int);
88 1.1 jmcneill static void edma_bit_set(uint32_t *, unsigned int);
89 1.1 jmcneill static void edma_bit_clr(uint32_t *, unsigned int);
90 1.1 jmcneill
91 1.1 jmcneill CFATTACH_DECL_NEW(ti_edma, sizeof(struct edma_softc),
92 1.1 jmcneill edma_match, edma_attach, NULL, NULL);
93 1.1 jmcneill
94 1.1 jmcneill #define EDMA_READ(sc, reg) \
95 1.1 jmcneill bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))
96 1.1 jmcneill #define EDMA_WRITE(sc, reg, val) \
97 1.1 jmcneill bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
98 1.1 jmcneill
99 1.1 jmcneill static const char * compatible[] = {
100 1.1 jmcneill "ti,edma3-tpcc",
101 1.1 jmcneill NULL
102 1.1 jmcneill };
103 1.1 jmcneill
104 1.1 jmcneill static int
105 1.1 jmcneill edma_match(device_t parent, cfdata_t match, void *aux)
106 1.1 jmcneill {
107 1.1 jmcneill struct fdt_attach_args * const faa = aux;
108 1.1 jmcneill
109 1.1 jmcneill return of_match_compatible(faa->faa_phandle, compatible);
110 1.1 jmcneill }
111 1.1 jmcneill
112 1.1 jmcneill static void
113 1.1 jmcneill edma_attach(device_t parent, device_t self, void *aux)
114 1.1 jmcneill {
115 1.1 jmcneill struct edma_softc *sc = device_private(self);
116 1.1 jmcneill struct fdt_attach_args * const faa = aux;
117 1.1 jmcneill const int phandle = faa->faa_phandle;
118 1.1 jmcneill char intrstr[128];
119 1.1 jmcneill bus_addr_t addr;
120 1.1 jmcneill bus_size_t size;
121 1.1 jmcneill int idx;
122 1.1 jmcneill
123 1.1 jmcneill if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
124 1.1 jmcneill aprint_error(": couldn't get registers\n");
125 1.1 jmcneill return;
126 1.1 jmcneill }
127 1.1 jmcneill
128 1.1 jmcneill if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
129 1.1 jmcneill aprint_error(": failed to decode interrupt\n");
130 1.1 jmcneill return;
131 1.1 jmcneill }
132 1.1 jmcneill
133 1.1 jmcneill sc->sc_dev = self;
134 1.1 jmcneill sc->sc_iot = faa->faa_bst;
135 1.1 jmcneill mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
136 1.1 jmcneill if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh) != 0) {
137 1.1 jmcneill aprint_error(": couldn't map registers\n");
138 1.1 jmcneill return;
139 1.1 jmcneill }
140 1.1 jmcneill
141 1.1 jmcneill aprint_naive("\n");
142 1.1 jmcneill aprint_normal(": EDMA Channel Controller\n");
143 1.1 jmcneill
144 1.1 jmcneill for (idx = 0; idx < NUM_DMA_CHANNELS; idx++) {
145 1.1 jmcneill struct edma_channel *ch = &sc->sc_dma[idx];
146 1.1 jmcneill ch->ch_sc = sc;
147 1.1 jmcneill ch->ch_type = EDMA_TYPE_DMA;
148 1.1 jmcneill ch->ch_index = idx;
149 1.1 jmcneill ch->ch_callback = NULL;
150 1.1 jmcneill ch->ch_callbackarg = NULL;
151 1.1 jmcneill ch->ch_nparams = 0;
152 1.1 jmcneill }
153 1.1 jmcneill
154 1.1 jmcneill if (ti_prcm_enable_hwmod(phandle, 0) != 0) {
155 1.1 jmcneill aprint_error_dev(self, "couldn't enable module\n");
156 1.1 jmcneill return;
157 1.1 jmcneill }
158 1.1 jmcneill
159 1.1 jmcneill edma_init(sc);
160 1.1 jmcneill
161 1.1 jmcneill sc->sc_ih = fdtbus_intr_establish_byname(phandle, "edma3_ccint",
162 1.2 jmcneill IPL_VM, FDT_INTR_MPSAFE, edma_intr, sc, device_xname(self));
163 1.1 jmcneill if (sc->sc_ih == NULL) {
164 1.1 jmcneill aprint_error_dev(self, "failed to establish interrupt\n");
165 1.1 jmcneill return;
166 1.1 jmcneill }
167 1.1 jmcneill aprint_normal_dev(self, "interrupting on %s\n", intrstr);
168 1.1 jmcneill }
169 1.1 jmcneill
170 1.1 jmcneill /*
171 1.1 jmcneill * Hardware initialization
172 1.1 jmcneill */
173 1.1 jmcneill static void
174 1.1 jmcneill edma_init(struct edma_softc *sc)
175 1.1 jmcneill {
176 1.1 jmcneill struct edma_param param;
177 1.1 jmcneill uint32_t val;
178 1.1 jmcneill int idx;
179 1.1 jmcneill
180 1.1 jmcneill val = EDMA_READ(sc, EDMA_CCCFG_REG);
181 1.1 jmcneill if (val & EDMA_CCCFG_CHMAP_EXIST) {
182 1.1 jmcneill for (idx = 0; idx < NUM_DMA_CHANNELS; idx++) {
183 1.1 jmcneill EDMA_WRITE(sc, EDMA_DCHMAP_REG(idx),
184 1.1 jmcneill __SHIFTIN(0, EDMA_DCHMAP_PAENTRY));
185 1.1 jmcneill }
186 1.1 jmcneill }
187 1.1 jmcneill
188 1.1 jmcneill memset(¶m, 0, sizeof(param));
189 1.1 jmcneill param.ep_bcnt = 1;
190 1.1 jmcneill for (idx = 0; idx < NUM_PARAM_SETS; idx++) {
191 1.1 jmcneill edma_write_param(sc, idx, ¶m);
192 1.1 jmcneill }
193 1.1 jmcneill
194 1.1 jmcneill /* reserve PaRAM entry 0 for dummy slot */
195 1.1 jmcneill edma_bit_set(sc->sc_parammask, 0);
196 1.1 jmcneill for (idx = 1; idx <= 32; idx++) {
197 1.1 jmcneill edma_bit_set(sc->sc_parammask, idx);
198 1.1 jmcneill }
199 1.1 jmcneill }
200 1.1 jmcneill
201 1.1 jmcneill /*
202 1.1 jmcneill * Write a PaRAM entry
203 1.1 jmcneill */
204 1.1 jmcneill static void
205 1.1 jmcneill edma_write_param(struct edma_softc *sc,
206 1.1 jmcneill unsigned int idx, const struct edma_param *ep)
207 1.1 jmcneill {
208 1.1 jmcneill EDMA_WRITE(sc, EDMA_PARAM_OPT_REG(idx), ep->ep_opt);
209 1.1 jmcneill EDMA_WRITE(sc, EDMA_PARAM_SRC_REG(idx), ep->ep_src);
210 1.1 jmcneill EDMA_WRITE(sc, EDMA_PARAM_CNT_REG(idx),
211 1.1 jmcneill __SHIFTIN(ep->ep_bcnt, EDMA_PARAM_CNT_BCNT) |
212 1.1 jmcneill __SHIFTIN(ep->ep_acnt, EDMA_PARAM_CNT_ACNT));
213 1.1 jmcneill EDMA_WRITE(sc, EDMA_PARAM_DST_REG(idx), ep->ep_dst);
214 1.1 jmcneill EDMA_WRITE(sc, EDMA_PARAM_BIDX_REG(idx),
215 1.1 jmcneill __SHIFTIN(ep->ep_dstbidx, EDMA_PARAM_BIDX_DSTBIDX) |
216 1.1 jmcneill __SHIFTIN(ep->ep_srcbidx, EDMA_PARAM_BIDX_SRCBIDX));
217 1.1 jmcneill EDMA_WRITE(sc, EDMA_PARAM_LNK_REG(idx),
218 1.1 jmcneill __SHIFTIN(ep->ep_bcntrld, EDMA_PARAM_LNK_BCNTRLD) |
219 1.1 jmcneill __SHIFTIN(ep->ep_link, EDMA_PARAM_LNK_LINK));
220 1.1 jmcneill EDMA_WRITE(sc, EDMA_PARAM_CIDX_REG(idx),
221 1.1 jmcneill __SHIFTIN(ep->ep_dstcidx, EDMA_PARAM_CIDX_DSTCIDX) |
222 1.1 jmcneill __SHIFTIN(ep->ep_srccidx, EDMA_PARAM_CIDX_SRCCIDX));
223 1.1 jmcneill EDMA_WRITE(sc, EDMA_PARAM_CCNT_REG(idx),
224 1.1 jmcneill __SHIFTIN(ep->ep_ccnt, EDMA_PARAM_CCNT_CCNT));
225 1.1 jmcneill }
226 1.1 jmcneill
227 1.1 jmcneill static bool
228 1.1 jmcneill edma_bit_isset(uint32_t *bits, unsigned int bit)
229 1.1 jmcneill {
230 1.1 jmcneill return !!(bits[bit >> 5] & (1 << (bit & 0x1f)));
231 1.1 jmcneill }
232 1.1 jmcneill
233 1.1 jmcneill static void
234 1.1 jmcneill edma_bit_set(uint32_t *bits, unsigned int bit)
235 1.1 jmcneill {
236 1.1 jmcneill bits[bit >> 5] |= (1 << (bit & 0x1f));
237 1.1 jmcneill }
238 1.1 jmcneill
239 1.1 jmcneill static void
240 1.1 jmcneill edma_bit_clr(uint32_t *bits, unsigned int bit)
241 1.1 jmcneill {
242 1.1 jmcneill bits[bit >> 5] &= ~(1 << (bit & 0x1f));
243 1.1 jmcneill }
244 1.1 jmcneill
245 1.1 jmcneill static int
246 1.1 jmcneill edma_intr(void *priv)
247 1.1 jmcneill {
248 1.1 jmcneill struct edma_softc *sc = priv;
249 1.1 jmcneill uint64_t ipr, ier;
250 1.1 jmcneill int bit, idx;
251 1.1 jmcneill
252 1.1 jmcneill ipr = EDMA_READ(sc, EDMA_IPR_REG);
253 1.1 jmcneill ipr |= (uint64_t)EDMA_READ(sc, EDMA_IPRH_REG) << 32;
254 1.1 jmcneill if (ipr == 0)
255 1.1 jmcneill return 0;
256 1.1 jmcneill
257 1.1 jmcneill ier = EDMA_READ(sc, EDMA_IER_REG);
258 1.1 jmcneill ier |= (uint64_t)EDMA_READ(sc, EDMA_IERH_REG) << 32;
259 1.1 jmcneill
260 1.1 jmcneill DPRINTF(2, (sc->sc_dev, "ipr = 0x%016llx ier 0x%016llx\n", ipr, ier));
261 1.1 jmcneill
262 1.1 jmcneill EDMA_WRITE(sc, EDMA_ICR_REG, ipr & 0xffffffff);
263 1.1 jmcneill EDMA_WRITE(sc, EDMA_ICRH_REG, ipr >> 32);
264 1.1 jmcneill
265 1.1 jmcneill while ((bit = ffs64(ipr)) != 0) {
266 1.1 jmcneill idx = bit - 1;
267 1.1 jmcneill ipr &= ~__BIT(idx);
268 1.1 jmcneill if (!(ier & __BIT(idx)))
269 1.1 jmcneill continue;
270 1.1 jmcneill if (!edma_bit_isset(sc->sc_dmamask, idx))
271 1.1 jmcneill continue;
272 1.1 jmcneill
273 1.1 jmcneill sc->sc_dma[idx].ch_callback(sc->sc_dma[idx].ch_callbackarg);
274 1.1 jmcneill }
275 1.1 jmcneill
276 1.1 jmcneill EDMA_WRITE(sc, EDMA_IEVAL_REG, EDMA_IEVAL_EVAL);
277 1.1 jmcneill
278 1.1 jmcneill return 1;
279 1.1 jmcneill }
280 1.1 jmcneill
281 1.1 jmcneill /*
282 1.1 jmcneill * Allocate a DMA channel. Currently only DMA types are supported, not QDMA.
283 1.1 jmcneill * Returns NULL on failure.
284 1.1 jmcneill */
285 1.1 jmcneill struct edma_channel *
286 1.1 jmcneill edma_channel_alloc(enum edma_type type, unsigned int drq,
287 1.1 jmcneill void (*cb)(void *), void *cbarg)
288 1.1 jmcneill {
289 1.1 jmcneill struct edma_softc *sc;
290 1.1 jmcneill device_t dev;
291 1.1 jmcneill struct edma_channel *ch = NULL;
292 1.1 jmcneill
293 1.1 jmcneill KASSERT(drq < __arraycount(sc->sc_dma));
294 1.1 jmcneill KASSERT(type == EDMA_TYPE_DMA); /* QDMA not implemented */
295 1.1 jmcneill KASSERT(cb != NULL);
296 1.1 jmcneill KASSERT(cbarg != NULL);
297 1.1 jmcneill
298 1.1 jmcneill dev = device_find_by_driver_unit("tiedma", 0);
299 1.1 jmcneill if (dev == NULL)
300 1.1 jmcneill return NULL;
301 1.1 jmcneill sc = device_private(dev);
302 1.1 jmcneill
303 1.1 jmcneill mutex_enter(&sc->sc_lock);
304 1.1 jmcneill if (!edma_bit_isset(sc->sc_dmamask, drq)) {
305 1.1 jmcneill ch = &sc->sc_dma[drq];
306 1.1 jmcneill KASSERT(ch->ch_callback == NULL);
307 1.1 jmcneill KASSERT(ch->ch_index == drq);
308 1.1 jmcneill ch->ch_callback = cb;
309 1.1 jmcneill ch->ch_callbackarg = cbarg;
310 1.1 jmcneill edma_bit_set(sc->sc_dmamask, drq);
311 1.1 jmcneill }
312 1.1 jmcneill
313 1.1 jmcneill if (ch == NULL)
314 1.1 jmcneill goto done;
315 1.1 jmcneill
316 1.1 jmcneill EDMA_WRITE(sc, EDMA_DRAE_REG(0), sc->sc_dmamask[0]);
317 1.1 jmcneill EDMA_WRITE(sc, EDMA_DRAEH_REG(0), sc->sc_dmamask[1]);
318 1.1 jmcneill
319 1.1 jmcneill if (ch->ch_index < 32) {
320 1.1 jmcneill EDMA_WRITE(sc, EDMA_ICR_REG, __BIT(ch->ch_index));
321 1.1 jmcneill EDMA_WRITE(sc, EDMA_IESR_REG, __BIT(ch->ch_index));
322 1.1 jmcneill } else {
323 1.1 jmcneill EDMA_WRITE(sc, EDMA_ICRH_REG, __BIT(ch->ch_index - 32));
324 1.1 jmcneill EDMA_WRITE(sc, EDMA_IESRH_REG, __BIT(ch->ch_index - 32));
325 1.1 jmcneill }
326 1.1 jmcneill
327 1.1 jmcneill done:
328 1.1 jmcneill mutex_exit(&sc->sc_lock);
329 1.1 jmcneill
330 1.1 jmcneill return ch;
331 1.1 jmcneill }
332 1.1 jmcneill
333 1.1 jmcneill /*
334 1.1 jmcneill * Free a DMA channel allocated with edma_channel_alloc
335 1.1 jmcneill */
336 1.1 jmcneill void
337 1.1 jmcneill edma_channel_free(struct edma_channel *ch)
338 1.1 jmcneill {
339 1.1 jmcneill struct edma_softc *sc = ch->ch_sc;
340 1.1 jmcneill
341 1.1 jmcneill KASSERT(ch->ch_nparams == 0);
342 1.1 jmcneill
343 1.1 jmcneill mutex_enter(&sc->sc_lock);
344 1.1 jmcneill if (ch->ch_index < 32) {
345 1.1 jmcneill EDMA_WRITE(sc, EDMA_IECR_REG, __BIT(ch->ch_index));
346 1.1 jmcneill } else {
347 1.1 jmcneill EDMA_WRITE(sc, EDMA_IECRH_REG, __BIT(ch->ch_index - 32));
348 1.1 jmcneill }
349 1.1 jmcneill ch->ch_callback = NULL;
350 1.1 jmcneill ch->ch_callbackarg = NULL;
351 1.1 jmcneill edma_bit_clr(sc->sc_dmamask, ch->ch_index);
352 1.1 jmcneill mutex_exit(&sc->sc_lock);
353 1.1 jmcneill }
354 1.1 jmcneill
355 1.1 jmcneill /*
356 1.1 jmcneill * Allocate a PaRAM entry. The driver artifically restricts the number
357 1.1 jmcneill * of PaRAM entries available for each channel to MAX_PARAM_PER_CHANNEL.
358 1.1 jmcneill * If the number of entries for the channel has been exceeded, or there
359 1.1 jmcneill * are no entries available, 0xffff is returned.
360 1.1 jmcneill */
361 1.1 jmcneill uint16_t
362 1.1 jmcneill edma_param_alloc(struct edma_channel *ch)
363 1.1 jmcneill {
364 1.1 jmcneill struct edma_softc *sc = ch->ch_sc;
365 1.1 jmcneill uint16_t param_entry = 0xffff;
366 1.1 jmcneill int idx;
367 1.1 jmcneill
368 1.1 jmcneill if (ch->ch_nparams == MAX_PARAM_PER_CHANNEL)
369 1.1 jmcneill return param_entry;
370 1.1 jmcneill
371 1.1 jmcneill mutex_enter(&sc->sc_lock);
372 1.1 jmcneill for (idx = 0; idx < NUM_PARAM_SETS; idx++) {
373 1.1 jmcneill if (!edma_bit_isset(sc->sc_parammask, idx)) {
374 1.1 jmcneill param_entry = idx;
375 1.1 jmcneill edma_bit_set(sc->sc_parammask, idx);
376 1.1 jmcneill ch->ch_nparams++;
377 1.1 jmcneill break;
378 1.1 jmcneill }
379 1.1 jmcneill }
380 1.1 jmcneill mutex_exit(&sc->sc_lock);
381 1.1 jmcneill
382 1.1 jmcneill return param_entry;
383 1.1 jmcneill }
384 1.1 jmcneill
385 1.1 jmcneill /*
386 1.1 jmcneill * Free a PaRAM entry allocated with edma_param_alloc
387 1.1 jmcneill */
388 1.1 jmcneill void
389 1.1 jmcneill edma_param_free(struct edma_channel *ch, uint16_t param_entry)
390 1.1 jmcneill {
391 1.1 jmcneill struct edma_softc *sc = ch->ch_sc;
392 1.1 jmcneill
393 1.1 jmcneill KASSERT(param_entry < NUM_PARAM_SETS);
394 1.1 jmcneill KASSERT(ch->ch_nparams > 0);
395 1.1 jmcneill KASSERT(edma_bit_isset(sc->sc_parammask, param_entry));
396 1.1 jmcneill
397 1.1 jmcneill mutex_enter(&sc->sc_lock);
398 1.1 jmcneill edma_bit_clr(sc->sc_parammask, param_entry);
399 1.1 jmcneill ch->ch_nparams--;
400 1.1 jmcneill mutex_exit(&sc->sc_lock);
401 1.1 jmcneill }
402 1.1 jmcneill
403 1.1 jmcneill /*
404 1.1 jmcneill * Update a PaRAM entry register set with caller-provided values
405 1.1 jmcneill */
406 1.1 jmcneill void
407 1.1 jmcneill edma_set_param(struct edma_channel *ch, uint16_t param_entry,
408 1.1 jmcneill struct edma_param *ep)
409 1.1 jmcneill {
410 1.1 jmcneill struct edma_softc *sc = ch->ch_sc;
411 1.1 jmcneill
412 1.1 jmcneill KASSERT(param_entry < NUM_PARAM_SETS);
413 1.1 jmcneill KASSERT(ch->ch_nparams > 0);
414 1.1 jmcneill KASSERT(edma_bit_isset(sc->sc_parammask, param_entry));
415 1.1 jmcneill
416 1.1 jmcneill DPRINTF(1, (sc->sc_dev, "write param entry ch# %d pe %d: 0x%08x -> 0x%08x (%u, %u, %u)\n", ch->ch_index, param_entry, ep->ep_src, ep->ep_dst, ep->ep_acnt, ep->ep_bcnt, ep->ep_ccnt));
417 1.1 jmcneill edma_write_param(sc, param_entry, ep);
418 1.1 jmcneill }
419 1.1 jmcneill
420 1.1 jmcneill /*
421 1.1 jmcneill * Enable a DMA channel: Point channel to the PaRam entry,
422 1.1 jmcneill * clear error if any, and only set the Event Enable bit.
423 1.1 jmcneill * The Even will either be generated by hardware, or with
424 1.1 jmcneill * edma_transfer_start()
425 1.1 jmcneill */
426 1.1 jmcneill int
427 1.1 jmcneill edma_transfer_enable(struct edma_channel *ch, uint16_t param_entry)
428 1.1 jmcneill {
429 1.1 jmcneill struct edma_softc *sc = ch->ch_sc;
430 1.1 jmcneill bus_size_t off = (ch->ch_index < 32 ? 0 : 4);
431 1.1 jmcneill uint32_t bit = __BIT(ch->ch_index < 32 ?
432 1.1 jmcneill ch->ch_index : ch->ch_index - 32);
433 1.1 jmcneill
434 1.1 jmcneill DPRINTF(1, (sc->sc_dev, "enable transfer ch# %d off %d bit %x pe %d\n", ch->ch_index, (int)off, bit, param_entry));
435 1.1 jmcneill
436 1.1 jmcneill EDMA_WRITE(sc, EDMA_DCHMAP_REG(ch->ch_index),
437 1.1 jmcneill __SHIFTIN(param_entry, EDMA_DCHMAP_PAENTRY));
438 1.1 jmcneill
439 1.1 jmcneill uint32_t ccerr = EDMA_READ(sc, EDMA_CCERR_REG);
440 1.1 jmcneill if (ccerr) {
441 1.1 jmcneill device_printf(sc->sc_dev, " !!! CCER %08x\n", ccerr);
442 1.1 jmcneill EDMA_WRITE(sc, EDMA_CCERRCLR_REG, ccerr);
443 1.1 jmcneill }
444 1.1 jmcneill
445 1.1 jmcneill EDMA_WRITE(sc, EDMA_EESR_REG + off, bit);
446 1.1 jmcneill return 0;
447 1.1 jmcneill }
448 1.1 jmcneill
449 1.1 jmcneill /*
450 1.1 jmcneill * Software-start a DMA channel: Set the Event bit.
451 1.1 jmcneill */
452 1.1 jmcneill int
453 1.1 jmcneill edma_transfer_start(struct edma_channel *ch)
454 1.1 jmcneill {
455 1.1 jmcneill struct edma_softc *sc = ch->ch_sc;
456 1.1 jmcneill bus_size_t off = (ch->ch_index < 32 ? 0 : 4);
457 1.1 jmcneill uint32_t bit = __BIT(ch->ch_index < 32 ?
458 1.1 jmcneill ch->ch_index : ch->ch_index - 32);
459 1.1 jmcneill
460 1.1 jmcneill DPRINTF(1, (sc->sc_dev, "start transfer ch# %d off %d bit %x pe %d\n", ch->ch_index, (int)off, bit));
461 1.1 jmcneill
462 1.1 jmcneill EDMA_WRITE(sc, EDMA_ESR_REG + off, bit);
463 1.1 jmcneill return 0;
464 1.1 jmcneill }
465 1.1 jmcneill
466 1.1 jmcneill /*
467 1.1 jmcneill * Halt a DMA transfer. Called after successfull transfer, or to abort
468 1.1 jmcneill * a transfer.
469 1.1 jmcneill */
470 1.1 jmcneill void
471 1.1 jmcneill edma_halt(struct edma_channel *ch)
472 1.1 jmcneill {
473 1.1 jmcneill struct edma_softc *sc = ch->ch_sc;
474 1.1 jmcneill bus_size_t off = (ch->ch_index < 32 ? 0 : 4);
475 1.1 jmcneill uint32_t bit = __BIT(ch->ch_index < 32 ?
476 1.1 jmcneill ch->ch_index : ch->ch_index - 32);
477 1.1 jmcneill
478 1.1 jmcneill EDMA_WRITE(sc, EDMA_EECR_REG + off, bit);
479 1.1 jmcneill EDMA_WRITE(sc, EDMA_ECR_REG + off, bit);
480 1.1 jmcneill EDMA_WRITE(sc, EDMA_SECR_REG + off, bit);
481 1.1 jmcneill EDMA_WRITE(sc, EDMA_EMCR_REG + off, bit);
482 1.1 jmcneill
483 1.1 jmcneill EDMA_WRITE(sc, EDMA_DCHMAP_REG(ch->ch_index),
484 1.1 jmcneill __SHIFTIN(0, EDMA_DCHMAP_PAENTRY));
485 1.1 jmcneill }
486 1.1 jmcneill
487 1.1 jmcneill uint8_t
488 1.1 jmcneill edma_channel_index(struct edma_channel *ch)
489 1.1 jmcneill {
490 1.1 jmcneill return ch->ch_index;
491 1.1 jmcneill }
492 1.1 jmcneill
493 1.1 jmcneill void
494 1.1 jmcneill edma_dump(struct edma_channel *ch)
495 1.1 jmcneill {
496 1.1 jmcneill static const struct {
497 1.1 jmcneill const char *name;
498 1.1 jmcneill uint16_t off;
499 1.1 jmcneill } regs[] = {
500 1.1 jmcneill { "ER", EDMA_ER_REG },
501 1.1 jmcneill { "ERH", EDMA_ERH_REG },
502 1.1 jmcneill { "EER", EDMA_EER_REG },
503 1.1 jmcneill { "EERH", EDMA_EERH_REG },
504 1.1 jmcneill { "SER", EDMA_SER_REG },
505 1.1 jmcneill { "SERH", EDMA_SERH_REG },
506 1.1 jmcneill { "IER", EDMA_IER_REG },
507 1.1 jmcneill { "IERH", EDMA_IERH_REG },
508 1.1 jmcneill { "IPR", EDMA_IPR_REG },
509 1.1 jmcneill { "IPRH", EDMA_IPRH_REG },
510 1.1 jmcneill { "CCERR", EDMA_CCERR_REG },
511 1.1 jmcneill { "CCSTAT", EDMA_CCSTAT_REG },
512 1.1 jmcneill { "DRAE0", EDMA_DRAE_REG(0) },
513 1.1 jmcneill { "DRAEH0", EDMA_DRAEH_REG(0) },
514 1.1 jmcneill { NULL, 0 }
515 1.1 jmcneill };
516 1.1 jmcneill struct edma_softc *sc = ch->ch_sc;
517 1.1 jmcneill int i;
518 1.1 jmcneill
519 1.1 jmcneill for (i = 0; regs[i].name; i++) {
520 1.1 jmcneill device_printf(sc->sc_dev, "%s: %08x\n",
521 1.1 jmcneill regs[i].name, EDMA_READ(sc, regs[i].off));
522 1.1 jmcneill }
523 1.1 jmcneill device_printf(sc->sc_dev, "DCHMAP%d: %08x\n", ch->ch_index,
524 1.1 jmcneill EDMA_READ(sc, EDMA_DCHMAP_REG(ch->ch_index)));
525 1.1 jmcneill }
526 1.1 jmcneill
527 1.1 jmcneill void
528 1.1 jmcneill edma_dump_param(struct edma_channel *ch, uint16_t param_entry)
529 1.1 jmcneill {
530 1.1 jmcneill struct {
531 1.1 jmcneill const char *name;
532 1.1 jmcneill uint16_t off;
533 1.1 jmcneill } regs[] = {
534 1.1 jmcneill { "OPT", EDMA_PARAM_OPT_REG(param_entry) },
535 1.1 jmcneill { "CNT", EDMA_PARAM_CNT_REG(param_entry) },
536 1.1 jmcneill { "DST", EDMA_PARAM_DST_REG(param_entry) },
537 1.1 jmcneill { "BIDX", EDMA_PARAM_BIDX_REG(param_entry) },
538 1.1 jmcneill { "LNK", EDMA_PARAM_LNK_REG(param_entry) },
539 1.1 jmcneill { "CIDX", EDMA_PARAM_CIDX_REG(param_entry) },
540 1.1 jmcneill { "CCNT", EDMA_PARAM_CCNT_REG(param_entry) },
541 1.1 jmcneill { NULL, 0 }
542 1.1 jmcneill };
543 1.1 jmcneill struct edma_softc *sc = ch->ch_sc;
544 1.1 jmcneill int i;
545 1.1 jmcneill
546 1.1 jmcneill for (i = 0; regs[i].name; i++) {
547 1.1 jmcneill device_printf(sc->sc_dev, "%s%d: %08x\n",
548 1.1 jmcneill regs[i].name, param_entry, EDMA_READ(sc, regs[i].off));
549 1.1 jmcneill }
550 1.1 jmcneill }
551