1e53470feSOleksandr Tymoshenko /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3af3dc4a7SPedro F. Giffuni *
4e53470feSOleksandr Tymoshenko * Copyright (c) 2011
5e53470feSOleksandr Tymoshenko * Ben Gray <ben.r.gray@gmail.com>.
6e53470feSOleksandr Tymoshenko * All rights reserved.
7e53470feSOleksandr Tymoshenko *
8e53470feSOleksandr Tymoshenko * Redistribution and use in source and binary forms, with or without
9e53470feSOleksandr Tymoshenko * modification, are permitted provided that the following conditions
10e53470feSOleksandr Tymoshenko * are met:
11e53470feSOleksandr Tymoshenko * 1. Redistributions of source code must retain the above copyright
12e53470feSOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer.
13e53470feSOleksandr Tymoshenko * 2. Redistributions in binary form must reproduce the above copyright
14e53470feSOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer in the
15e53470feSOleksandr Tymoshenko * documentation and/or other materials provided with the distribution.
16e53470feSOleksandr Tymoshenko *
17e53470feSOleksandr Tymoshenko * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18e53470feSOleksandr Tymoshenko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19e53470feSOleksandr Tymoshenko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20e53470feSOleksandr Tymoshenko * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21e53470feSOleksandr Tymoshenko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22e53470feSOleksandr Tymoshenko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23e53470feSOleksandr Tymoshenko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24e53470feSOleksandr Tymoshenko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25e53470feSOleksandr Tymoshenko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26e53470feSOleksandr Tymoshenko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27e53470feSOleksandr Tymoshenko * SUCH DAMAGE.
28e53470feSOleksandr Tymoshenko */
29e53470feSOleksandr Tymoshenko
30e53470feSOleksandr Tymoshenko #include <sys/param.h>
31e53470feSOleksandr Tymoshenko #include <sys/systm.h>
32e53470feSOleksandr Tymoshenko #include <sys/bus.h>
33e53470feSOleksandr Tymoshenko #include <sys/kernel.h>
34e53470feSOleksandr Tymoshenko #include <sys/lock.h>
35e53470feSOleksandr Tymoshenko #include <sys/interrupt.h>
36e53470feSOleksandr Tymoshenko #include <sys/module.h>
37e53470feSOleksandr Tymoshenko #include <sys/malloc.h>
38e53470feSOleksandr Tymoshenko #include <sys/mutex.h>
39e53470feSOleksandr Tymoshenko #include <sys/rman.h>
40e53470feSOleksandr Tymoshenko #include <sys/queue.h>
41e53470feSOleksandr Tymoshenko #include <sys/taskqueue.h>
42e53470feSOleksandr Tymoshenko #include <sys/timetc.h>
43e53470feSOleksandr Tymoshenko #include <machine/bus.h>
44e53470feSOleksandr Tymoshenko #include <machine/intr.h>
45e53470feSOleksandr Tymoshenko
46e53470feSOleksandr Tymoshenko #include <dev/ofw/openfirm.h>
47e53470feSOleksandr Tymoshenko #include <dev/ofw/ofw_bus.h>
48e53470feSOleksandr Tymoshenko #include <dev/ofw/ofw_bus_subr.h>
49e53470feSOleksandr Tymoshenko
50e53470feSOleksandr Tymoshenko #include <arm/ti/ti_cpuid.h>
510050ea24SMichal Meloun #include <arm/ti/ti_sysc.h>
52e53470feSOleksandr Tymoshenko #include <arm/ti/ti_sdma.h>
53e53470feSOleksandr Tymoshenko #include <arm/ti/ti_sdmareg.h>
54e53470feSOleksandr Tymoshenko
55e53470feSOleksandr Tymoshenko /**
56e53470feSOleksandr Tymoshenko * Kernel functions for using the DMA controller
57e53470feSOleksandr Tymoshenko *
58e53470feSOleksandr Tymoshenko *
59e53470feSOleksandr Tymoshenko * DMA TRANSFERS:
60e53470feSOleksandr Tymoshenko * A DMA transfer block consists of a number of frames (FN). Each frame
61e53470feSOleksandr Tymoshenko * consists of a number of elements, and each element can have a size of 8, 16,
62e53470feSOleksandr Tymoshenko * or 32 bits.
63e53470feSOleksandr Tymoshenko *
64e53470feSOleksandr Tymoshenko * OMAP44xx and newer chips support linked list (aka scatter gather) transfers,
65e53470feSOleksandr Tymoshenko * where a linked list of source/destination pairs can be placed in memory
66e53470feSOleksandr Tymoshenko * for the H/W to process. Earlier chips only allowed you to chain multiple
67e53470feSOleksandr Tymoshenko * channels together. However currently this linked list feature is not
68e53470feSOleksandr Tymoshenko * supported by the driver.
69e53470feSOleksandr Tymoshenko *
70e53470feSOleksandr Tymoshenko */
71e53470feSOleksandr Tymoshenko
72e53470feSOleksandr Tymoshenko /**
73e53470feSOleksandr Tymoshenko * Data structure per DMA channel.
74e53470feSOleksandr Tymoshenko *
75e53470feSOleksandr Tymoshenko *
76e53470feSOleksandr Tymoshenko */
77e53470feSOleksandr Tymoshenko struct ti_sdma_channel {
78e53470feSOleksandr Tymoshenko /*
79e53470feSOleksandr Tymoshenko * The configuration registers for the given channel, these are modified
80e53470feSOleksandr Tymoshenko * by the set functions and only written to the actual registers when a
81e53470feSOleksandr Tymoshenko * transaction is started.
82e53470feSOleksandr Tymoshenko */
83e53470feSOleksandr Tymoshenko uint32_t reg_csdp;
84e53470feSOleksandr Tymoshenko uint32_t reg_ccr;
85e53470feSOleksandr Tymoshenko uint32_t reg_cicr;
86e53470feSOleksandr Tymoshenko
87e53470feSOleksandr Tymoshenko /* Set when one of the configuration registers above change */
88e53470feSOleksandr Tymoshenko uint32_t need_reg_write;
89e53470feSOleksandr Tymoshenko
90e53470feSOleksandr Tymoshenko /* Callback function used when an interrupt is tripped on the given channel */
91e53470feSOleksandr Tymoshenko void (*callback)(unsigned int ch, uint32_t ch_status, void *data);
92e53470feSOleksandr Tymoshenko
93e53470feSOleksandr Tymoshenko /* Callback data passed in the callback ... duh */
94e53470feSOleksandr Tymoshenko void* callback_data;
95e53470feSOleksandr Tymoshenko
96e53470feSOleksandr Tymoshenko };
97e53470feSOleksandr Tymoshenko
98e53470feSOleksandr Tymoshenko /**
99e53470feSOleksandr Tymoshenko * DMA driver context, allocated and stored globally, this driver is not
100e53470feSOleksandr Tymoshenko * intetned to ever be unloaded (see ti_sdma_sc).
101e53470feSOleksandr Tymoshenko *
102e53470feSOleksandr Tymoshenko */
103e53470feSOleksandr Tymoshenko struct ti_sdma_softc {
104e53470feSOleksandr Tymoshenko device_t sc_dev;
105e53470feSOleksandr Tymoshenko struct resource* sc_irq_res;
106e53470feSOleksandr Tymoshenko struct resource* sc_mem_res;
107e53470feSOleksandr Tymoshenko
108e53470feSOleksandr Tymoshenko /*
109e53470feSOleksandr Tymoshenko * I guess in theory we should have a mutex per DMA channel for register
110e53470feSOleksandr Tymoshenko * modifications. But since we know we are never going to be run on a SMP
111e53470feSOleksandr Tymoshenko * system, we can use just the single lock for all channels.
112e53470feSOleksandr Tymoshenko */
113e53470feSOleksandr Tymoshenko struct mtx sc_mtx;
114e53470feSOleksandr Tymoshenko
115e53470feSOleksandr Tymoshenko /* Stores the H/W revision read from the registers */
116e53470feSOleksandr Tymoshenko uint32_t sc_hw_rev;
117e53470feSOleksandr Tymoshenko
118e53470feSOleksandr Tymoshenko /*
119e53470feSOleksandr Tymoshenko * Bits in the sc_active_channels data field indicate if the channel has
120e53470feSOleksandr Tymoshenko * been activated.
121e53470feSOleksandr Tymoshenko */
122e53470feSOleksandr Tymoshenko uint32_t sc_active_channels;
123e53470feSOleksandr Tymoshenko
124e53470feSOleksandr Tymoshenko struct ti_sdma_channel sc_channel[NUM_DMA_CHANNELS];
125e53470feSOleksandr Tymoshenko
126e53470feSOleksandr Tymoshenko };
127e53470feSOleksandr Tymoshenko
128e53470feSOleksandr Tymoshenko static struct ti_sdma_softc *ti_sdma_sc = NULL;
129e53470feSOleksandr Tymoshenko
130e53470feSOleksandr Tymoshenko /**
131e53470feSOleksandr Tymoshenko * Macros for driver mutex locking
132e53470feSOleksandr Tymoshenko */
133e53470feSOleksandr Tymoshenko #define TI_SDMA_LOCK(_sc) mtx_lock_spin(&(_sc)->sc_mtx)
134e53470feSOleksandr Tymoshenko #define TI_SDMA_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->sc_mtx)
135e53470feSOleksandr Tymoshenko #define TI_SDMA_LOCK_INIT(_sc) \
136e53470feSOleksandr Tymoshenko mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \
137e53470feSOleksandr Tymoshenko "ti_sdma", MTX_SPIN)
138e53470feSOleksandr Tymoshenko #define TI_SDMA_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
139e53470feSOleksandr Tymoshenko #define TI_SDMA_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED);
140e53470feSOleksandr Tymoshenko #define TI_SDMA_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
141e53470feSOleksandr Tymoshenko
142e53470feSOleksandr Tymoshenko /**
143e53470feSOleksandr Tymoshenko * Function prototypes
144e53470feSOleksandr Tymoshenko *
145e53470feSOleksandr Tymoshenko */
146e53470feSOleksandr Tymoshenko static void ti_sdma_intr(void *);
147e53470feSOleksandr Tymoshenko
148e53470feSOleksandr Tymoshenko /**
149e53470feSOleksandr Tymoshenko * ti_sdma_read_4 - reads a 32-bit value from one of the DMA registers
150e53470feSOleksandr Tymoshenko * @sc: DMA device context
151e53470feSOleksandr Tymoshenko * @off: The offset of a register from the DMA register address range
152e53470feSOleksandr Tymoshenko *
153e53470feSOleksandr Tymoshenko *
154e53470feSOleksandr Tymoshenko * RETURNS:
155e53470feSOleksandr Tymoshenko * 32-bit value read from the register.
156e53470feSOleksandr Tymoshenko */
157e53470feSOleksandr Tymoshenko static inline uint32_t
ti_sdma_read_4(struct ti_sdma_softc * sc,bus_size_t off)158e53470feSOleksandr Tymoshenko ti_sdma_read_4(struct ti_sdma_softc *sc, bus_size_t off)
159e53470feSOleksandr Tymoshenko {
160e53470feSOleksandr Tymoshenko return bus_read_4(sc->sc_mem_res, off);
161e53470feSOleksandr Tymoshenko }
162e53470feSOleksandr Tymoshenko
163e53470feSOleksandr Tymoshenko /**
164e53470feSOleksandr Tymoshenko * ti_sdma_write_4 - writes a 32-bit value to one of the DMA registers
165e53470feSOleksandr Tymoshenko * @sc: DMA device context
166e53470feSOleksandr Tymoshenko * @off: The offset of a register from the DMA register address range
167e53470feSOleksandr Tymoshenko *
168e53470feSOleksandr Tymoshenko *
169e53470feSOleksandr Tymoshenko * RETURNS:
170e53470feSOleksandr Tymoshenko * 32-bit value read from the register.
171e53470feSOleksandr Tymoshenko */
172e53470feSOleksandr Tymoshenko static inline void
ti_sdma_write_4(struct ti_sdma_softc * sc,bus_size_t off,uint32_t val)173e53470feSOleksandr Tymoshenko ti_sdma_write_4(struct ti_sdma_softc *sc, bus_size_t off, uint32_t val)
174e53470feSOleksandr Tymoshenko {
175e53470feSOleksandr Tymoshenko bus_write_4(sc->sc_mem_res, off, val);
176e53470feSOleksandr Tymoshenko }
177e53470feSOleksandr Tymoshenko
178e53470feSOleksandr Tymoshenko /**
179e53470feSOleksandr Tymoshenko * ti_sdma_is_omap3_rev - returns true if H/W is from OMAP3 series
180e53470feSOleksandr Tymoshenko * @sc: DMA device context
181e53470feSOleksandr Tymoshenko *
182e53470feSOleksandr Tymoshenko */
183e53470feSOleksandr Tymoshenko static inline int
ti_sdma_is_omap3_rev(struct ti_sdma_softc * sc)184e53470feSOleksandr Tymoshenko ti_sdma_is_omap3_rev(struct ti_sdma_softc *sc)
185e53470feSOleksandr Tymoshenko {
186e53470feSOleksandr Tymoshenko return (sc->sc_hw_rev == DMA4_OMAP3_REV);
187e53470feSOleksandr Tymoshenko }
188e53470feSOleksandr Tymoshenko
189e53470feSOleksandr Tymoshenko /**
190e53470feSOleksandr Tymoshenko * ti_sdma_is_omap4_rev - returns true if H/W is from OMAP4 series
191e53470feSOleksandr Tymoshenko * @sc: DMA device context
192e53470feSOleksandr Tymoshenko *
193e53470feSOleksandr Tymoshenko */
194e53470feSOleksandr Tymoshenko static inline int
ti_sdma_is_omap4_rev(struct ti_sdma_softc * sc)195e53470feSOleksandr Tymoshenko ti_sdma_is_omap4_rev(struct ti_sdma_softc *sc)
196e53470feSOleksandr Tymoshenko {
197e53470feSOleksandr Tymoshenko return (sc->sc_hw_rev == DMA4_OMAP4_REV);
198e53470feSOleksandr Tymoshenko }
199e53470feSOleksandr Tymoshenko
200e53470feSOleksandr Tymoshenko /**
201e53470feSOleksandr Tymoshenko * ti_sdma_intr - interrupt handler for all 4 DMA IRQs
202e53470feSOleksandr Tymoshenko * @arg: ignored
203e53470feSOleksandr Tymoshenko *
204e53470feSOleksandr Tymoshenko * Called when any of the four DMA IRQs are triggered.
205e53470feSOleksandr Tymoshenko *
206e53470feSOleksandr Tymoshenko * LOCKING:
207e53470feSOleksandr Tymoshenko * DMA registers protected by internal mutex
208e53470feSOleksandr Tymoshenko *
209e53470feSOleksandr Tymoshenko * RETURNS:
210e53470feSOleksandr Tymoshenko * nothing
211e53470feSOleksandr Tymoshenko */
212e53470feSOleksandr Tymoshenko static void
ti_sdma_intr(void * arg)213e53470feSOleksandr Tymoshenko ti_sdma_intr(void *arg)
214e53470feSOleksandr Tymoshenko {
215e53470feSOleksandr Tymoshenko struct ti_sdma_softc *sc = ti_sdma_sc;
216e53470feSOleksandr Tymoshenko uint32_t intr;
217e53470feSOleksandr Tymoshenko uint32_t csr;
218e53470feSOleksandr Tymoshenko unsigned int ch, j;
219e53470feSOleksandr Tymoshenko struct ti_sdma_channel* channel;
220e53470feSOleksandr Tymoshenko
221e53470feSOleksandr Tymoshenko TI_SDMA_LOCK(sc);
222e53470feSOleksandr Tymoshenko
223e53470feSOleksandr Tymoshenko for (j = 0; j < NUM_DMA_IRQS; j++) {
224e53470feSOleksandr Tymoshenko /* Get the flag interrupts (enabled) */
225e53470feSOleksandr Tymoshenko intr = ti_sdma_read_4(sc, DMA4_IRQSTATUS_L(j));
226e53470feSOleksandr Tymoshenko intr &= ti_sdma_read_4(sc, DMA4_IRQENABLE_L(j));
227e53470feSOleksandr Tymoshenko if (intr == 0x00000000)
228e53470feSOleksandr Tymoshenko continue;
229e53470feSOleksandr Tymoshenko
230e53470feSOleksandr Tymoshenko /* Loop through checking the status bits */
231e53470feSOleksandr Tymoshenko for (ch = 0; ch < NUM_DMA_CHANNELS; ch++) {
232e53470feSOleksandr Tymoshenko if (intr & (1 << ch)) {
233e53470feSOleksandr Tymoshenko channel = &sc->sc_channel[ch];
234e53470feSOleksandr Tymoshenko
235e53470feSOleksandr Tymoshenko /* Read the CSR regsiter and verify we don't have a spurious IRQ */
236e53470feSOleksandr Tymoshenko csr = ti_sdma_read_4(sc, DMA4_CSR(ch));
237e53470feSOleksandr Tymoshenko if (csr == 0) {
238e53470feSOleksandr Tymoshenko device_printf(sc->sc_dev, "Spurious DMA IRQ for channel "
239e53470feSOleksandr Tymoshenko "%d\n", ch);
240e53470feSOleksandr Tymoshenko continue;
241e53470feSOleksandr Tymoshenko }
242e53470feSOleksandr Tymoshenko
243e53470feSOleksandr Tymoshenko /* Sanity check this channel is active */
244e53470feSOleksandr Tymoshenko if ((sc->sc_active_channels & (1 << ch)) == 0) {
245e53470feSOleksandr Tymoshenko device_printf(sc->sc_dev, "IRQ %d for a non-activated "
246e53470feSOleksandr Tymoshenko "channel %d\n", j, ch);
247e53470feSOleksandr Tymoshenko continue;
248e53470feSOleksandr Tymoshenko }
249e53470feSOleksandr Tymoshenko
250e53470feSOleksandr Tymoshenko /* Check the status error codes */
251e53470feSOleksandr Tymoshenko if (csr & DMA4_CSR_DROP)
252e53470feSOleksandr Tymoshenko device_printf(sc->sc_dev, "Synchronization event drop "
253e53470feSOleksandr Tymoshenko "occurred during the transfer on channel %u\n",
254e53470feSOleksandr Tymoshenko ch);
255e53470feSOleksandr Tymoshenko if (csr & DMA4_CSR_SECURE_ERR)
256e53470feSOleksandr Tymoshenko device_printf(sc->sc_dev, "Secure transaction error event "
257e53470feSOleksandr Tymoshenko "on channel %u\n", ch);
258e53470feSOleksandr Tymoshenko if (csr & DMA4_CSR_MISALIGNED_ADRS_ERR)
259e53470feSOleksandr Tymoshenko device_printf(sc->sc_dev, "Misaligned address error event "
260e53470feSOleksandr Tymoshenko "on channel %u\n", ch);
261e53470feSOleksandr Tymoshenko if (csr & DMA4_CSR_TRANS_ERR) {
262e53470feSOleksandr Tymoshenko device_printf(sc->sc_dev, "Transaction error event on "
263e53470feSOleksandr Tymoshenko "channel %u\n", ch);
264e53470feSOleksandr Tymoshenko /*
265e53470feSOleksandr Tymoshenko * Apparently according to linux code, there is an errata
266e53470feSOleksandr Tymoshenko * that says the channel is not disabled upon this error.
267e53470feSOleksandr Tymoshenko * They explicitly disable the channel here .. since I
268e53470feSOleksandr Tymoshenko * haven't seen the errata, I'm going to ignore for now.
269e53470feSOleksandr Tymoshenko */
270e53470feSOleksandr Tymoshenko }
271e53470feSOleksandr Tymoshenko
272e53470feSOleksandr Tymoshenko /* Clear the status flags for the IRQ */
273e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CSR(ch), DMA4_CSR_CLEAR_MASK);
274e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_IRQSTATUS_L(j), (1 << ch));
275e53470feSOleksandr Tymoshenko
276e53470feSOleksandr Tymoshenko /* Call the callback for the given channel */
277e53470feSOleksandr Tymoshenko if (channel->callback)
278e53470feSOleksandr Tymoshenko channel->callback(ch, csr, channel->callback_data);
279e53470feSOleksandr Tymoshenko }
280e53470feSOleksandr Tymoshenko }
281e53470feSOleksandr Tymoshenko }
282e53470feSOleksandr Tymoshenko
283e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
284e53470feSOleksandr Tymoshenko
285e53470feSOleksandr Tymoshenko return;
286e53470feSOleksandr Tymoshenko }
287e53470feSOleksandr Tymoshenko
288e53470feSOleksandr Tymoshenko /**
289e53470feSOleksandr Tymoshenko * ti_sdma_activate_channel - activates a DMA channel
290e53470feSOleksandr Tymoshenko * @ch: upon return contains the channel allocated
291e53470feSOleksandr Tymoshenko * @callback: a callback function to associate with the channel
292e53470feSOleksandr Tymoshenko * @data: optional data supplied when the callback is called
293e53470feSOleksandr Tymoshenko *
294e53470feSOleksandr Tymoshenko * Simply activates a channel be enabling and writing default values to the
295e53470feSOleksandr Tymoshenko * channel's register set. It doesn't start a transaction, just populates the
296e53470feSOleksandr Tymoshenko * internal data structures and sets defaults.
297e53470feSOleksandr Tymoshenko *
298e53470feSOleksandr Tymoshenko * Note this function doesn't enable interrupts, for that you need to call
299e53470feSOleksandr Tymoshenko * ti_sdma_enable_channel_irq(). If not using IRQ to detect the end of the
300e53470feSOleksandr Tymoshenko * transfer, you can use ti_sdma_status_poll() to detect a change in the
301e53470feSOleksandr Tymoshenko * status.
302e53470feSOleksandr Tymoshenko *
303e53470feSOleksandr Tymoshenko * A channel must be activated before any of the other DMA functions can be
304e53470feSOleksandr Tymoshenko * called on it.
305e53470feSOleksandr Tymoshenko *
306e53470feSOleksandr Tymoshenko * LOCKING:
307e53470feSOleksandr Tymoshenko * DMA registers protected by internal mutex
308e53470feSOleksandr Tymoshenko *
309e53470feSOleksandr Tymoshenko * RETURNS:
310e53470feSOleksandr Tymoshenko * 0 on success, otherwise an error code
311e53470feSOleksandr Tymoshenko */
312e53470feSOleksandr Tymoshenko int
ti_sdma_activate_channel(unsigned int * ch,void (* callback)(unsigned int ch,uint32_t status,void * data),void * data)313e53470feSOleksandr Tymoshenko ti_sdma_activate_channel(unsigned int *ch,
314e53470feSOleksandr Tymoshenko void (*callback)(unsigned int ch, uint32_t status, void *data),
315e53470feSOleksandr Tymoshenko void *data)
316e53470feSOleksandr Tymoshenko {
317e53470feSOleksandr Tymoshenko struct ti_sdma_softc *sc = ti_sdma_sc;
318e53470feSOleksandr Tymoshenko struct ti_sdma_channel *channel = NULL;
319e53470feSOleksandr Tymoshenko uint32_t addr;
320e53470feSOleksandr Tymoshenko unsigned int i;
321e53470feSOleksandr Tymoshenko
322e53470feSOleksandr Tymoshenko /* Sanity check */
323e53470feSOleksandr Tymoshenko if (sc == NULL)
324e53470feSOleksandr Tymoshenko return (ENOMEM);
325e53470feSOleksandr Tymoshenko
326e53470feSOleksandr Tymoshenko if (ch == NULL)
327e53470feSOleksandr Tymoshenko return (EINVAL);
328e53470feSOleksandr Tymoshenko
329e53470feSOleksandr Tymoshenko TI_SDMA_LOCK(sc);
330e53470feSOleksandr Tymoshenko
331e53470feSOleksandr Tymoshenko /* Check to see if all channels are in use */
332e53470feSOleksandr Tymoshenko if (sc->sc_active_channels == 0xffffffff) {
333e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
334e53470feSOleksandr Tymoshenko return (ENOMEM);
335e53470feSOleksandr Tymoshenko }
336e53470feSOleksandr Tymoshenko
337e53470feSOleksandr Tymoshenko /* Find the first non-active channel */
338e53470feSOleksandr Tymoshenko for (i = 0; i < NUM_DMA_CHANNELS; i++) {
339e53470feSOleksandr Tymoshenko if (!(sc->sc_active_channels & (0x1 << i))) {
340e53470feSOleksandr Tymoshenko sc->sc_active_channels |= (0x1 << i);
341e53470feSOleksandr Tymoshenko *ch = i;
342e53470feSOleksandr Tymoshenko break;
343e53470feSOleksandr Tymoshenko }
344e53470feSOleksandr Tymoshenko }
345e53470feSOleksandr Tymoshenko
346e53470feSOleksandr Tymoshenko /* Get the channel struct and populate the fields */
347e53470feSOleksandr Tymoshenko channel = &sc->sc_channel[*ch];
348e53470feSOleksandr Tymoshenko
349e53470feSOleksandr Tymoshenko channel->callback = callback;
350e53470feSOleksandr Tymoshenko channel->callback_data = data;
351e53470feSOleksandr Tymoshenko
352e53470feSOleksandr Tymoshenko channel->need_reg_write = 1;
353e53470feSOleksandr Tymoshenko
354e53470feSOleksandr Tymoshenko /* Set the default configuration for the DMA channel */
355e53470feSOleksandr Tymoshenko channel->reg_csdp = DMA4_CSDP_DATA_TYPE(0x2)
356e53470feSOleksandr Tymoshenko | DMA4_CSDP_SRC_BURST_MODE(0)
357e53470feSOleksandr Tymoshenko | DMA4_CSDP_DST_BURST_MODE(0)
358e53470feSOleksandr Tymoshenko | DMA4_CSDP_SRC_ENDIANISM(0)
359e53470feSOleksandr Tymoshenko | DMA4_CSDP_DST_ENDIANISM(0)
360e53470feSOleksandr Tymoshenko | DMA4_CSDP_WRITE_MODE(0)
361e53470feSOleksandr Tymoshenko | DMA4_CSDP_SRC_PACKED(0)
362e53470feSOleksandr Tymoshenko | DMA4_CSDP_DST_PACKED(0);
363e53470feSOleksandr Tymoshenko
364e53470feSOleksandr Tymoshenko channel->reg_ccr = DMA4_CCR_DST_ADDRESS_MODE(1)
365e53470feSOleksandr Tymoshenko | DMA4_CCR_SRC_ADDRESS_MODE(1)
366e53470feSOleksandr Tymoshenko | DMA4_CCR_READ_PRIORITY(0)
367e53470feSOleksandr Tymoshenko | DMA4_CCR_WRITE_PRIORITY(0)
368e53470feSOleksandr Tymoshenko | DMA4_CCR_SYNC_TRIGGER(0)
369e53470feSOleksandr Tymoshenko | DMA4_CCR_FRAME_SYNC(0)
370e53470feSOleksandr Tymoshenko | DMA4_CCR_BLOCK_SYNC(0);
371e53470feSOleksandr Tymoshenko
372e53470feSOleksandr Tymoshenko channel->reg_cicr = DMA4_CICR_TRANS_ERR_IE
373e53470feSOleksandr Tymoshenko | DMA4_CICR_SECURE_ERR_IE
374e53470feSOleksandr Tymoshenko | DMA4_CICR_SUPERVISOR_ERR_IE
375e53470feSOleksandr Tymoshenko | DMA4_CICR_MISALIGNED_ADRS_ERR_IE;
376e53470feSOleksandr Tymoshenko
377e53470feSOleksandr Tymoshenko /* Clear all the channel registers, this should abort any transaction */
378e53470feSOleksandr Tymoshenko for (addr = DMA4_CCR(*ch); addr <= DMA4_COLOR(*ch); addr += 4)
379e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, addr, 0x00000000);
380e53470feSOleksandr Tymoshenko
381e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
382e53470feSOleksandr Tymoshenko
383e53470feSOleksandr Tymoshenko return 0;
384e53470feSOleksandr Tymoshenko }
385e53470feSOleksandr Tymoshenko
386e53470feSOleksandr Tymoshenko /**
387e53470feSOleksandr Tymoshenko * ti_sdma_deactivate_channel - deactivates a channel
388e53470feSOleksandr Tymoshenko * @ch: the channel to deactivate
389e53470feSOleksandr Tymoshenko *
390e53470feSOleksandr Tymoshenko *
391e53470feSOleksandr Tymoshenko *
392e53470feSOleksandr Tymoshenko * LOCKING:
393e53470feSOleksandr Tymoshenko * DMA registers protected by internal mutex
394e53470feSOleksandr Tymoshenko *
395e53470feSOleksandr Tymoshenko * RETURNS:
396e53470feSOleksandr Tymoshenko * EH_HANDLED or EH_NOT_HANDLED
397e53470feSOleksandr Tymoshenko */
398e53470feSOleksandr Tymoshenko int
ti_sdma_deactivate_channel(unsigned int ch)399e53470feSOleksandr Tymoshenko ti_sdma_deactivate_channel(unsigned int ch)
400e53470feSOleksandr Tymoshenko {
401e53470feSOleksandr Tymoshenko struct ti_sdma_softc *sc = ti_sdma_sc;
402e53470feSOleksandr Tymoshenko unsigned int j;
403e53470feSOleksandr Tymoshenko unsigned int addr;
404e53470feSOleksandr Tymoshenko
405e53470feSOleksandr Tymoshenko /* Sanity check */
406e53470feSOleksandr Tymoshenko if (sc == NULL)
407e53470feSOleksandr Tymoshenko return (ENOMEM);
408e53470feSOleksandr Tymoshenko
409e53470feSOleksandr Tymoshenko TI_SDMA_LOCK(sc);
410e53470feSOleksandr Tymoshenko
411e53470feSOleksandr Tymoshenko /* First check if the channel is currently active */
412e53470feSOleksandr Tymoshenko if ((sc->sc_active_channels & (1 << ch)) == 0) {
413e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
414e53470feSOleksandr Tymoshenko return (EBUSY);
415e53470feSOleksandr Tymoshenko }
416e53470feSOleksandr Tymoshenko
417e53470feSOleksandr Tymoshenko /* Mark the channel as inactive */
418e53470feSOleksandr Tymoshenko sc->sc_active_channels &= ~(1 << ch);
419e53470feSOleksandr Tymoshenko
420e53470feSOleksandr Tymoshenko /* Disable all DMA interrupts for the channel. */
421e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CICR(ch), 0);
422e53470feSOleksandr Tymoshenko
423e53470feSOleksandr Tymoshenko /* Make sure the DMA transfer is stopped. */
424e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CCR(ch), 0);
425e53470feSOleksandr Tymoshenko
426e53470feSOleksandr Tymoshenko /* Clear the CSR register and IRQ status register */
427e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CSR(ch), DMA4_CSR_CLEAR_MASK);
428e53470feSOleksandr Tymoshenko for (j = 0; j < NUM_DMA_IRQS; j++) {
429e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_IRQSTATUS_L(j), (1 << ch));
430e53470feSOleksandr Tymoshenko }
431e53470feSOleksandr Tymoshenko
432e53470feSOleksandr Tymoshenko /* Clear all the channel registers, this should abort any transaction */
433e53470feSOleksandr Tymoshenko for (addr = DMA4_CCR(ch); addr <= DMA4_COLOR(ch); addr += 4)
434e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, addr, 0x00000000);
435e53470feSOleksandr Tymoshenko
436e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
437e53470feSOleksandr Tymoshenko
438e53470feSOleksandr Tymoshenko return 0;
439e53470feSOleksandr Tymoshenko }
440e53470feSOleksandr Tymoshenko
441e53470feSOleksandr Tymoshenko /**
442e53470feSOleksandr Tymoshenko * ti_sdma_disable_channel_irq - disables IRQ's on the given channel
443e53470feSOleksandr Tymoshenko * @ch: the channel to disable IRQ's on
444e53470feSOleksandr Tymoshenko *
445255eff3bSPedro F. Giffuni * Disable interrupt generation for the given channel.
446e53470feSOleksandr Tymoshenko *
447e53470feSOleksandr Tymoshenko * LOCKING:
448e53470feSOleksandr Tymoshenko * DMA registers protected by internal mutex
449e53470feSOleksandr Tymoshenko *
450e53470feSOleksandr Tymoshenko * RETURNS:
451e53470feSOleksandr Tymoshenko * EH_HANDLED or EH_NOT_HANDLED
452e53470feSOleksandr Tymoshenko */
453e53470feSOleksandr Tymoshenko int
ti_sdma_disable_channel_irq(unsigned int ch)454e53470feSOleksandr Tymoshenko ti_sdma_disable_channel_irq(unsigned int ch)
455e53470feSOleksandr Tymoshenko {
456e53470feSOleksandr Tymoshenko struct ti_sdma_softc *sc = ti_sdma_sc;
457e53470feSOleksandr Tymoshenko uint32_t irq_enable;
458e53470feSOleksandr Tymoshenko unsigned int j;
459e53470feSOleksandr Tymoshenko
460e53470feSOleksandr Tymoshenko /* Sanity check */
461e53470feSOleksandr Tymoshenko if (sc == NULL)
462e53470feSOleksandr Tymoshenko return (ENOMEM);
463e53470feSOleksandr Tymoshenko
464e53470feSOleksandr Tymoshenko TI_SDMA_LOCK(sc);
465e53470feSOleksandr Tymoshenko
466e53470feSOleksandr Tymoshenko if ((sc->sc_active_channels & (1 << ch)) == 0) {
467e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
468e53470feSOleksandr Tymoshenko return (EINVAL);
469e53470feSOleksandr Tymoshenko }
470e53470feSOleksandr Tymoshenko
471e53470feSOleksandr Tymoshenko /* Disable all the individual error conditions */
472e53470feSOleksandr Tymoshenko sc->sc_channel[ch].reg_cicr = 0x0000;
473e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CICR(ch), 0x0000);
474e53470feSOleksandr Tymoshenko
475e53470feSOleksandr Tymoshenko /* Disable the channel interrupt enable */
476e53470feSOleksandr Tymoshenko for (j = 0; j < NUM_DMA_IRQS; j++) {
477e53470feSOleksandr Tymoshenko irq_enable = ti_sdma_read_4(sc, DMA4_IRQENABLE_L(j));
478e53470feSOleksandr Tymoshenko irq_enable &= ~(1 << ch);
479e53470feSOleksandr Tymoshenko
480e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_IRQENABLE_L(j), irq_enable);
481e53470feSOleksandr Tymoshenko }
482e53470feSOleksandr Tymoshenko
483e53470feSOleksandr Tymoshenko /* Indicate the registers need to be rewritten on the next transaction */
484e53470feSOleksandr Tymoshenko sc->sc_channel[ch].need_reg_write = 1;
485e53470feSOleksandr Tymoshenko
486e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
487e53470feSOleksandr Tymoshenko
488e53470feSOleksandr Tymoshenko return (0);
489e53470feSOleksandr Tymoshenko }
490e53470feSOleksandr Tymoshenko
491e53470feSOleksandr Tymoshenko /**
492e53470feSOleksandr Tymoshenko * ti_sdma_disable_channel_irq - enables IRQ's on the given channel
493e53470feSOleksandr Tymoshenko * @ch: the channel to enable IRQ's on
494e53470feSOleksandr Tymoshenko * @flags: bitmask of interrupt types to enable
495e53470feSOleksandr Tymoshenko *
496e53470feSOleksandr Tymoshenko * Flags can be a bitmask of the following options:
497e53470feSOleksandr Tymoshenko * DMA_IRQ_FLAG_DROP
498e53470feSOleksandr Tymoshenko * DMA_IRQ_FLAG_HALF_FRAME_COMPL
499e53470feSOleksandr Tymoshenko * DMA_IRQ_FLAG_FRAME_COMPL
500e53470feSOleksandr Tymoshenko * DMA_IRQ_FLAG_START_LAST_FRAME
501e53470feSOleksandr Tymoshenko * DMA_IRQ_FLAG_BLOCK_COMPL
502e53470feSOleksandr Tymoshenko * DMA_IRQ_FLAG_ENDOF_PKT
503e53470feSOleksandr Tymoshenko * DMA_IRQ_FLAG_DRAIN
504e53470feSOleksandr Tymoshenko *
505e53470feSOleksandr Tymoshenko *
506e53470feSOleksandr Tymoshenko * LOCKING:
507e53470feSOleksandr Tymoshenko * DMA registers protected by internal mutex
508e53470feSOleksandr Tymoshenko *
509e53470feSOleksandr Tymoshenko * RETURNS:
510e53470feSOleksandr Tymoshenko * EH_HANDLED or EH_NOT_HANDLED
511e53470feSOleksandr Tymoshenko */
512e53470feSOleksandr Tymoshenko int
ti_sdma_enable_channel_irq(unsigned int ch,uint32_t flags)513e53470feSOleksandr Tymoshenko ti_sdma_enable_channel_irq(unsigned int ch, uint32_t flags)
514e53470feSOleksandr Tymoshenko {
515e53470feSOleksandr Tymoshenko struct ti_sdma_softc *sc = ti_sdma_sc;
516e53470feSOleksandr Tymoshenko uint32_t irq_enable;
517e53470feSOleksandr Tymoshenko
518e53470feSOleksandr Tymoshenko /* Sanity check */
519e53470feSOleksandr Tymoshenko if (sc == NULL)
520e53470feSOleksandr Tymoshenko return (ENOMEM);
521e53470feSOleksandr Tymoshenko
522e53470feSOleksandr Tymoshenko TI_SDMA_LOCK(sc);
523e53470feSOleksandr Tymoshenko
524e53470feSOleksandr Tymoshenko if ((sc->sc_active_channels & (1 << ch)) == 0) {
525e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
526e53470feSOleksandr Tymoshenko return (EINVAL);
527e53470feSOleksandr Tymoshenko }
528e53470feSOleksandr Tymoshenko
529e53470feSOleksandr Tymoshenko /* Always enable the error interrupts if we have interrupts enabled */
530e53470feSOleksandr Tymoshenko flags |= DMA4_CICR_TRANS_ERR_IE | DMA4_CICR_SECURE_ERR_IE |
531e53470feSOleksandr Tymoshenko DMA4_CICR_SUPERVISOR_ERR_IE | DMA4_CICR_MISALIGNED_ADRS_ERR_IE;
532e53470feSOleksandr Tymoshenko
533e53470feSOleksandr Tymoshenko sc->sc_channel[ch].reg_cicr = flags;
534e53470feSOleksandr Tymoshenko
535e53470feSOleksandr Tymoshenko /* Write the values to the register */
536e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CICR(ch), flags);
537e53470feSOleksandr Tymoshenko
538e53470feSOleksandr Tymoshenko /* Enable the channel interrupt enable */
539e53470feSOleksandr Tymoshenko irq_enable = ti_sdma_read_4(sc, DMA4_IRQENABLE_L(0));
540e53470feSOleksandr Tymoshenko irq_enable |= (1 << ch);
541e53470feSOleksandr Tymoshenko
542e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_IRQENABLE_L(0), irq_enable);
543e53470feSOleksandr Tymoshenko
544e53470feSOleksandr Tymoshenko /* Indicate the registers need to be rewritten on the next transaction */
545e53470feSOleksandr Tymoshenko sc->sc_channel[ch].need_reg_write = 1;
546e53470feSOleksandr Tymoshenko
547e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
548e53470feSOleksandr Tymoshenko
549e53470feSOleksandr Tymoshenko return (0);
550e53470feSOleksandr Tymoshenko }
551e53470feSOleksandr Tymoshenko
552e53470feSOleksandr Tymoshenko /**
553e53470feSOleksandr Tymoshenko * ti_sdma_get_channel_status - returns the status of a given channel
554e53470feSOleksandr Tymoshenko * @ch: the channel number to get the status of
555e53470feSOleksandr Tymoshenko * @status: upon return will contain the status bitmask, see below for possible
556e53470feSOleksandr Tymoshenko * values.
557e53470feSOleksandr Tymoshenko *
558e53470feSOleksandr Tymoshenko * DMA_STATUS_DROP
559e53470feSOleksandr Tymoshenko * DMA_STATUS_HALF
560e53470feSOleksandr Tymoshenko * DMA_STATUS_FRAME
561e53470feSOleksandr Tymoshenko * DMA_STATUS_LAST
562e53470feSOleksandr Tymoshenko * DMA_STATUS_BLOCK
563e53470feSOleksandr Tymoshenko * DMA_STATUS_SYNC
564e53470feSOleksandr Tymoshenko * DMA_STATUS_PKT
565e53470feSOleksandr Tymoshenko * DMA_STATUS_TRANS_ERR
566e53470feSOleksandr Tymoshenko * DMA_STATUS_SECURE_ERR
567e53470feSOleksandr Tymoshenko * DMA_STATUS_SUPERVISOR_ERR
568e53470feSOleksandr Tymoshenko * DMA_STATUS_MISALIGNED_ADRS_ERR
569e53470feSOleksandr Tymoshenko * DMA_STATUS_DRAIN_END
570e53470feSOleksandr Tymoshenko *
571e53470feSOleksandr Tymoshenko *
572e53470feSOleksandr Tymoshenko * LOCKING:
573e53470feSOleksandr Tymoshenko * DMA registers protected by internal mutex
574e53470feSOleksandr Tymoshenko *
575e53470feSOleksandr Tymoshenko * RETURNS:
576e53470feSOleksandr Tymoshenko * EH_HANDLED or EH_NOT_HANDLED
577e53470feSOleksandr Tymoshenko */
578e53470feSOleksandr Tymoshenko int
ti_sdma_get_channel_status(unsigned int ch,uint32_t * status)579e53470feSOleksandr Tymoshenko ti_sdma_get_channel_status(unsigned int ch, uint32_t *status)
580e53470feSOleksandr Tymoshenko {
581e53470feSOleksandr Tymoshenko struct ti_sdma_softc *sc = ti_sdma_sc;
582e53470feSOleksandr Tymoshenko uint32_t csr;
583e53470feSOleksandr Tymoshenko
584e53470feSOleksandr Tymoshenko /* Sanity check */
585e53470feSOleksandr Tymoshenko if (sc == NULL)
586e53470feSOleksandr Tymoshenko return (ENOMEM);
587e53470feSOleksandr Tymoshenko
588e53470feSOleksandr Tymoshenko TI_SDMA_LOCK(sc);
589e53470feSOleksandr Tymoshenko
590e53470feSOleksandr Tymoshenko if ((sc->sc_active_channels & (1 << ch)) == 0) {
591e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
592e53470feSOleksandr Tymoshenko return (EINVAL);
593e53470feSOleksandr Tymoshenko }
594e53470feSOleksandr Tymoshenko
595e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
596e53470feSOleksandr Tymoshenko
597e53470feSOleksandr Tymoshenko csr = ti_sdma_read_4(sc, DMA4_CSR(ch));
598e53470feSOleksandr Tymoshenko
599e53470feSOleksandr Tymoshenko if (status != NULL)
600e53470feSOleksandr Tymoshenko *status = csr;
601e53470feSOleksandr Tymoshenko
602e53470feSOleksandr Tymoshenko return (0);
603e53470feSOleksandr Tymoshenko }
604e53470feSOleksandr Tymoshenko
605e53470feSOleksandr Tymoshenko /**
606e53470feSOleksandr Tymoshenko * ti_sdma_start_xfer - starts a DMA transfer
607255eff3bSPedro F. Giffuni * @ch: the channel number to set the endianness of
608e53470feSOleksandr Tymoshenko * @src_paddr: the source phsyical address
609e53470feSOleksandr Tymoshenko * @dst_paddr: the destination phsyical address
610e53470feSOleksandr Tymoshenko * @frmcnt: the number of frames per block
611e53470feSOleksandr Tymoshenko * @elmcnt: the number of elements in a frame, an element is either an 8, 16
612e53470feSOleksandr Tymoshenko * or 32-bit value as defined by ti_sdma_set_xfer_burst()
613e53470feSOleksandr Tymoshenko *
614e53470feSOleksandr Tymoshenko *
615e53470feSOleksandr Tymoshenko * LOCKING:
616e53470feSOleksandr Tymoshenko * DMA registers protected by internal mutex
617e53470feSOleksandr Tymoshenko *
618e53470feSOleksandr Tymoshenko * RETURNS:
619e53470feSOleksandr Tymoshenko * EH_HANDLED or EH_NOT_HANDLED
620e53470feSOleksandr Tymoshenko */
621e53470feSOleksandr Tymoshenko int
ti_sdma_start_xfer(unsigned int ch,unsigned int src_paddr,unsigned long dst_paddr,unsigned int frmcnt,unsigned int elmcnt)622e53470feSOleksandr Tymoshenko ti_sdma_start_xfer(unsigned int ch, unsigned int src_paddr,
623e53470feSOleksandr Tymoshenko unsigned long dst_paddr,
624e53470feSOleksandr Tymoshenko unsigned int frmcnt, unsigned int elmcnt)
625e53470feSOleksandr Tymoshenko {
626e53470feSOleksandr Tymoshenko struct ti_sdma_softc *sc = ti_sdma_sc;
627e53470feSOleksandr Tymoshenko struct ti_sdma_channel *channel;
628e53470feSOleksandr Tymoshenko uint32_t ccr;
629e53470feSOleksandr Tymoshenko
630e53470feSOleksandr Tymoshenko /* Sanity check */
631e53470feSOleksandr Tymoshenko if (sc == NULL)
632e53470feSOleksandr Tymoshenko return (ENOMEM);
633e53470feSOleksandr Tymoshenko
634e53470feSOleksandr Tymoshenko TI_SDMA_LOCK(sc);
635e53470feSOleksandr Tymoshenko
636e53470feSOleksandr Tymoshenko if ((sc->sc_active_channels & (1 << ch)) == 0) {
637e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
638e53470feSOleksandr Tymoshenko return (EINVAL);
639e53470feSOleksandr Tymoshenko }
640e53470feSOleksandr Tymoshenko
641e53470feSOleksandr Tymoshenko channel = &sc->sc_channel[ch];
642e53470feSOleksandr Tymoshenko
643e53470feSOleksandr Tymoshenko /* a) Write the CSDP register */
644e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CSDP(ch),
645e53470feSOleksandr Tymoshenko channel->reg_csdp | DMA4_CSDP_WRITE_MODE(1));
646e53470feSOleksandr Tymoshenko
647e53470feSOleksandr Tymoshenko /* b) Set the number of element per frame CEN[23:0] */
648e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CEN(ch), elmcnt);
649e53470feSOleksandr Tymoshenko
650e53470feSOleksandr Tymoshenko /* c) Set the number of frame per block CFN[15:0] */
651e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CFN(ch), frmcnt);
652e53470feSOleksandr Tymoshenko
653e53470feSOleksandr Tymoshenko /* d) Set the Source/dest start address index CSSA[31:0]/CDSA[31:0] */
654e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CSSA(ch), src_paddr);
655e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CDSA(ch), dst_paddr);
656e53470feSOleksandr Tymoshenko
657e53470feSOleksandr Tymoshenko /* e) Write the CCR register */
658e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CCR(ch), channel->reg_ccr);
659e53470feSOleksandr Tymoshenko
660e53470feSOleksandr Tymoshenko /* f) - Set the source element index increment CSEI[15:0] */
661e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CSE(ch), 0x0001);
662e53470feSOleksandr Tymoshenko
663e53470feSOleksandr Tymoshenko /* - Set the source frame index increment CSFI[15:0] */
664e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CSF(ch), 0x0001);
665e53470feSOleksandr Tymoshenko
666e53470feSOleksandr Tymoshenko /* - Set the destination element index increment CDEI[15:0]*/
667e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CDE(ch), 0x0001);
668e53470feSOleksandr Tymoshenko
669e53470feSOleksandr Tymoshenko /* - Set the destination frame index increment CDFI[31:0] */
670e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CDF(ch), 0x0001);
671e53470feSOleksandr Tymoshenko
672e53470feSOleksandr Tymoshenko /* Clear the status register */
673e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CSR(ch), 0x1FFE);
674e53470feSOleksandr Tymoshenko
675e53470feSOleksandr Tymoshenko /* Write the start-bit and away we go */
676e53470feSOleksandr Tymoshenko ccr = ti_sdma_read_4(sc, DMA4_CCR(ch));
677e53470feSOleksandr Tymoshenko ccr |= (1 << 7);
678e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CCR(ch), ccr);
679e53470feSOleksandr Tymoshenko
680e53470feSOleksandr Tymoshenko /* Clear the reg write flag */
681e53470feSOleksandr Tymoshenko channel->need_reg_write = 0;
682e53470feSOleksandr Tymoshenko
683e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
684e53470feSOleksandr Tymoshenko
685e53470feSOleksandr Tymoshenko return (0);
686e53470feSOleksandr Tymoshenko }
687e53470feSOleksandr Tymoshenko
688e53470feSOleksandr Tymoshenko /**
689e53470feSOleksandr Tymoshenko * ti_sdma_start_xfer_packet - starts a packet DMA transfer
690e53470feSOleksandr Tymoshenko * @ch: the channel number to use for the transfer
691e53470feSOleksandr Tymoshenko * @src_paddr: the source physical address
692e53470feSOleksandr Tymoshenko * @dst_paddr: the destination physical address
693e53470feSOleksandr Tymoshenko * @frmcnt: the number of frames to transfer
694e53470feSOleksandr Tymoshenko * @elmcnt: the number of elements in a frame, an element is either an 8, 16
695e53470feSOleksandr Tymoshenko * or 32-bit value as defined by ti_sdma_set_xfer_burst()
696e53470feSOleksandr Tymoshenko * @pktsize: the number of elements in each transfer packet
697e53470feSOleksandr Tymoshenko *
698e53470feSOleksandr Tymoshenko * The @frmcnt and @elmcnt define the overall number of bytes to transfer,
699e53470feSOleksandr Tymoshenko * typically @frmcnt is 1 and @elmcnt contains the total number of elements.
700e53470feSOleksandr Tymoshenko * @pktsize is the size of each individual packet, there might be multiple
701e53470feSOleksandr Tymoshenko * packets per transfer. i.e. for the following with element size of 32-bits
702e53470feSOleksandr Tymoshenko *
703e53470feSOleksandr Tymoshenko * frmcnt = 1, elmcnt = 512, pktsize = 128
704e53470feSOleksandr Tymoshenko *
705e53470feSOleksandr Tymoshenko * Total transfer bytes = 1 * 512 = 512 elements or 2048 bytes
706255eff3bSPedro F. Giffuni * Packets transferred = 128 / 512 = 4
707e53470feSOleksandr Tymoshenko *
708e53470feSOleksandr Tymoshenko *
709e53470feSOleksandr Tymoshenko * LOCKING:
710e53470feSOleksandr Tymoshenko * DMA registers protected by internal mutex
711e53470feSOleksandr Tymoshenko *
712e53470feSOleksandr Tymoshenko * RETURNS:
713e53470feSOleksandr Tymoshenko * EH_HANDLED or EH_NOT_HANDLED
714e53470feSOleksandr Tymoshenko */
715e53470feSOleksandr Tymoshenko int
ti_sdma_start_xfer_packet(unsigned int ch,unsigned int src_paddr,unsigned long dst_paddr,unsigned int frmcnt,unsigned int elmcnt,unsigned int pktsize)716e53470feSOleksandr Tymoshenko ti_sdma_start_xfer_packet(unsigned int ch, unsigned int src_paddr,
717e53470feSOleksandr Tymoshenko unsigned long dst_paddr, unsigned int frmcnt,
718e53470feSOleksandr Tymoshenko unsigned int elmcnt, unsigned int pktsize)
719e53470feSOleksandr Tymoshenko {
720e53470feSOleksandr Tymoshenko struct ti_sdma_softc *sc = ti_sdma_sc;
721e53470feSOleksandr Tymoshenko struct ti_sdma_channel *channel;
722e53470feSOleksandr Tymoshenko uint32_t ccr;
723e53470feSOleksandr Tymoshenko
724e53470feSOleksandr Tymoshenko /* Sanity check */
725e53470feSOleksandr Tymoshenko if (sc == NULL)
726e53470feSOleksandr Tymoshenko return (ENOMEM);
727e53470feSOleksandr Tymoshenko
728e53470feSOleksandr Tymoshenko TI_SDMA_LOCK(sc);
729e53470feSOleksandr Tymoshenko
730e53470feSOleksandr Tymoshenko if ((sc->sc_active_channels & (1 << ch)) == 0) {
731e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
732e53470feSOleksandr Tymoshenko return (EINVAL);
733e53470feSOleksandr Tymoshenko }
734e53470feSOleksandr Tymoshenko
735e53470feSOleksandr Tymoshenko channel = &sc->sc_channel[ch];
736e53470feSOleksandr Tymoshenko
737e53470feSOleksandr Tymoshenko /* a) Write the CSDP register */
738e53470feSOleksandr Tymoshenko if (channel->need_reg_write)
739e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CSDP(ch),
740e53470feSOleksandr Tymoshenko channel->reg_csdp | DMA4_CSDP_WRITE_MODE(1));
741e53470feSOleksandr Tymoshenko
742e53470feSOleksandr Tymoshenko /* b) Set the number of elements to transfer CEN[23:0] */
743e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CEN(ch), elmcnt);
744e53470feSOleksandr Tymoshenko
745e53470feSOleksandr Tymoshenko /* c) Set the number of frames to transfer CFN[15:0] */
746e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CFN(ch), frmcnt);
747e53470feSOleksandr Tymoshenko
748e53470feSOleksandr Tymoshenko /* d) Set the Source/dest start address index CSSA[31:0]/CDSA[31:0] */
749e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CSSA(ch), src_paddr);
750e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CDSA(ch), dst_paddr);
751e53470feSOleksandr Tymoshenko
752e53470feSOleksandr Tymoshenko /* e) Write the CCR register */
753e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CCR(ch),
754e53470feSOleksandr Tymoshenko channel->reg_ccr | DMA4_CCR_PACKET_TRANS);
755e53470feSOleksandr Tymoshenko
756e53470feSOleksandr Tymoshenko /* f) - Set the source element index increment CSEI[15:0] */
757e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CSE(ch), 0x0001);
758e53470feSOleksandr Tymoshenko
759e53470feSOleksandr Tymoshenko /* - Set the packet size, this is dependent on the sync source */
760e53470feSOleksandr Tymoshenko if (channel->reg_ccr & DMA4_CCR_SEL_SRC_DST_SYNC(1))
761e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CSF(ch), pktsize);
762e53470feSOleksandr Tymoshenko else
763e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CDF(ch), pktsize);
764e53470feSOleksandr Tymoshenko
765e53470feSOleksandr Tymoshenko /* - Set the destination frame index increment CDFI[31:0] */
766e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CDE(ch), 0x0001);
767e53470feSOleksandr Tymoshenko
768e53470feSOleksandr Tymoshenko /* Clear the status register */
769e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CSR(ch), 0x1FFE);
770e53470feSOleksandr Tymoshenko
771e53470feSOleksandr Tymoshenko /* Write the start-bit and away we go */
772e53470feSOleksandr Tymoshenko ccr = ti_sdma_read_4(sc, DMA4_CCR(ch));
773e53470feSOleksandr Tymoshenko ccr |= (1 << 7);
774e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CCR(ch), ccr);
775e53470feSOleksandr Tymoshenko
776e53470feSOleksandr Tymoshenko /* Clear the reg write flag */
777e53470feSOleksandr Tymoshenko channel->need_reg_write = 0;
778e53470feSOleksandr Tymoshenko
779e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
780e53470feSOleksandr Tymoshenko
781e53470feSOleksandr Tymoshenko return (0);
782e53470feSOleksandr Tymoshenko }
783e53470feSOleksandr Tymoshenko
784e53470feSOleksandr Tymoshenko /**
785e53470feSOleksandr Tymoshenko * ti_sdma_stop_xfer - stops any currently active transfers
786255eff3bSPedro F. Giffuni * @ch: the channel number to set the endianness of
787e53470feSOleksandr Tymoshenko *
788e53470feSOleksandr Tymoshenko * This function call is effectively a NOP if no transaction is in progress.
789e53470feSOleksandr Tymoshenko *
790e53470feSOleksandr Tymoshenko * LOCKING:
791e53470feSOleksandr Tymoshenko * DMA registers protected by internal mutex
792e53470feSOleksandr Tymoshenko *
793e53470feSOleksandr Tymoshenko * RETURNS:
794e53470feSOleksandr Tymoshenko * EH_HANDLED or EH_NOT_HANDLED
795e53470feSOleksandr Tymoshenko */
796e53470feSOleksandr Tymoshenko int
ti_sdma_stop_xfer(unsigned int ch)797e53470feSOleksandr Tymoshenko ti_sdma_stop_xfer(unsigned int ch)
798e53470feSOleksandr Tymoshenko {
799e53470feSOleksandr Tymoshenko struct ti_sdma_softc *sc = ti_sdma_sc;
800e53470feSOleksandr Tymoshenko unsigned int j;
801e53470feSOleksandr Tymoshenko
802e53470feSOleksandr Tymoshenko /* Sanity check */
803e53470feSOleksandr Tymoshenko if (sc == NULL)
804e53470feSOleksandr Tymoshenko return (ENOMEM);
805e53470feSOleksandr Tymoshenko
806e53470feSOleksandr Tymoshenko TI_SDMA_LOCK(sc);
807e53470feSOleksandr Tymoshenko
808e53470feSOleksandr Tymoshenko if ((sc->sc_active_channels & (1 << ch)) == 0) {
809e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
810e53470feSOleksandr Tymoshenko return (EINVAL);
811e53470feSOleksandr Tymoshenko }
812e53470feSOleksandr Tymoshenko
813e53470feSOleksandr Tymoshenko /* Disable all DMA interrupts for the channel. */
814e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CICR(ch), 0);
815e53470feSOleksandr Tymoshenko
816e53470feSOleksandr Tymoshenko /* Make sure the DMA transfer is stopped. */
817e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CCR(ch), 0);
818e53470feSOleksandr Tymoshenko
819e53470feSOleksandr Tymoshenko /* Clear the CSR register and IRQ status register */
820e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_CSR(ch), DMA4_CSR_CLEAR_MASK);
821e53470feSOleksandr Tymoshenko for (j = 0; j < NUM_DMA_IRQS; j++) {
822e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_IRQSTATUS_L(j), (1 << ch));
823e53470feSOleksandr Tymoshenko }
824e53470feSOleksandr Tymoshenko
825e53470feSOleksandr Tymoshenko /* Configuration registers need to be re-written on the next xfer */
826e53470feSOleksandr Tymoshenko sc->sc_channel[ch].need_reg_write = 1;
827e53470feSOleksandr Tymoshenko
828e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
829e53470feSOleksandr Tymoshenko
830e53470feSOleksandr Tymoshenko return (0);
831e53470feSOleksandr Tymoshenko }
832e53470feSOleksandr Tymoshenko
833e53470feSOleksandr Tymoshenko /**
834255eff3bSPedro F. Giffuni * ti_sdma_set_xfer_endianess - sets the endianness of subsequent transfers
835255eff3bSPedro F. Giffuni * @ch: the channel number to set the endianness of
836255eff3bSPedro F. Giffuni * @src: the source endianness (either DMA_ENDIAN_LITTLE or DMA_ENDIAN_BIG)
837255eff3bSPedro F. Giffuni * @dst: the destination endianness (either DMA_ENDIAN_LITTLE or DMA_ENDIAN_BIG)
838e53470feSOleksandr Tymoshenko *
839e53470feSOleksandr Tymoshenko *
840e53470feSOleksandr Tymoshenko * LOCKING:
841e53470feSOleksandr Tymoshenko * DMA registers protected by internal mutex
842e53470feSOleksandr Tymoshenko *
843e53470feSOleksandr Tymoshenko * RETURNS:
844e53470feSOleksandr Tymoshenko * EH_HANDLED or EH_NOT_HANDLED
845e53470feSOleksandr Tymoshenko */
846e53470feSOleksandr Tymoshenko int
ti_sdma_set_xfer_endianess(unsigned int ch,unsigned int src,unsigned int dst)847e53470feSOleksandr Tymoshenko ti_sdma_set_xfer_endianess(unsigned int ch, unsigned int src, unsigned int dst)
848e53470feSOleksandr Tymoshenko {
849e53470feSOleksandr Tymoshenko struct ti_sdma_softc *sc = ti_sdma_sc;
850e53470feSOleksandr Tymoshenko
851e53470feSOleksandr Tymoshenko /* Sanity check */
852e53470feSOleksandr Tymoshenko if (sc == NULL)
853e53470feSOleksandr Tymoshenko return (ENOMEM);
854e53470feSOleksandr Tymoshenko
855e53470feSOleksandr Tymoshenko TI_SDMA_LOCK(sc);
856e53470feSOleksandr Tymoshenko
857e53470feSOleksandr Tymoshenko if ((sc->sc_active_channels & (1 << ch)) == 0) {
858e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
859e53470feSOleksandr Tymoshenko return (EINVAL);
860e53470feSOleksandr Tymoshenko }
861e53470feSOleksandr Tymoshenko
862e53470feSOleksandr Tymoshenko sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_SRC_ENDIANISM(1);
863e53470feSOleksandr Tymoshenko sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_SRC_ENDIANISM(src);
864e53470feSOleksandr Tymoshenko
865e53470feSOleksandr Tymoshenko sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_DST_ENDIANISM(1);
866e53470feSOleksandr Tymoshenko sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_DST_ENDIANISM(dst);
867e53470feSOleksandr Tymoshenko
868e53470feSOleksandr Tymoshenko sc->sc_channel[ch].need_reg_write = 1;
869e53470feSOleksandr Tymoshenko
870e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
871e53470feSOleksandr Tymoshenko
872e53470feSOleksandr Tymoshenko return 0;
873e53470feSOleksandr Tymoshenko }
874e53470feSOleksandr Tymoshenko
875e53470feSOleksandr Tymoshenko /**
876e53470feSOleksandr Tymoshenko * ti_sdma_set_xfer_burst - sets the source and destination element size
877e53470feSOleksandr Tymoshenko * @ch: the channel number to set the burst settings of
878255eff3bSPedro F. Giffuni * @src: the source endianness (either DMA_BURST_NONE, DMA_BURST_16, DMA_BURST_32
879e53470feSOleksandr Tymoshenko * or DMA_BURST_64)
880255eff3bSPedro F. Giffuni * @dst: the destination endianness (either DMA_BURST_NONE, DMA_BURST_16,
881e53470feSOleksandr Tymoshenko * DMA_BURST_32 or DMA_BURST_64)
882e53470feSOleksandr Tymoshenko *
883e53470feSOleksandr Tymoshenko * This function sets the size of the elements for all subsequent transfers.
884e53470feSOleksandr Tymoshenko *
885e53470feSOleksandr Tymoshenko * LOCKING:
886e53470feSOleksandr Tymoshenko * DMA registers protected by internal mutex
887e53470feSOleksandr Tymoshenko *
888e53470feSOleksandr Tymoshenko * RETURNS:
889e53470feSOleksandr Tymoshenko * EH_HANDLED or EH_NOT_HANDLED
890e53470feSOleksandr Tymoshenko */
891e53470feSOleksandr Tymoshenko int
ti_sdma_set_xfer_burst(unsigned int ch,unsigned int src,unsigned int dst)892e53470feSOleksandr Tymoshenko ti_sdma_set_xfer_burst(unsigned int ch, unsigned int src, unsigned int dst)
893e53470feSOleksandr Tymoshenko {
894e53470feSOleksandr Tymoshenko struct ti_sdma_softc *sc = ti_sdma_sc;
895e53470feSOleksandr Tymoshenko
896e53470feSOleksandr Tymoshenko /* Sanity check */
897e53470feSOleksandr Tymoshenko if (sc == NULL)
898e53470feSOleksandr Tymoshenko return (ENOMEM);
899e53470feSOleksandr Tymoshenko
900e53470feSOleksandr Tymoshenko TI_SDMA_LOCK(sc);
901e53470feSOleksandr Tymoshenko
902e53470feSOleksandr Tymoshenko if ((sc->sc_active_channels & (1 << ch)) == 0) {
903e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
904e53470feSOleksandr Tymoshenko return (EINVAL);
905e53470feSOleksandr Tymoshenko }
906e53470feSOleksandr Tymoshenko
907e53470feSOleksandr Tymoshenko sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_SRC_BURST_MODE(0x3);
908e53470feSOleksandr Tymoshenko sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_SRC_BURST_MODE(src);
909e53470feSOleksandr Tymoshenko
910e53470feSOleksandr Tymoshenko sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_DST_BURST_MODE(0x3);
911e53470feSOleksandr Tymoshenko sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_DST_BURST_MODE(dst);
912e53470feSOleksandr Tymoshenko
913e53470feSOleksandr Tymoshenko sc->sc_channel[ch].need_reg_write = 1;
914e53470feSOleksandr Tymoshenko
915e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
916e53470feSOleksandr Tymoshenko
917e53470feSOleksandr Tymoshenko return 0;
918e53470feSOleksandr Tymoshenko }
919e53470feSOleksandr Tymoshenko
920e53470feSOleksandr Tymoshenko /**
921e53470feSOleksandr Tymoshenko * ti_sdma_set_xfer_data_type - driver attach function
922255eff3bSPedro F. Giffuni * @ch: the channel number to set the endianness of
923e53470feSOleksandr Tymoshenko * @type: the xfer data type (either DMA_DATA_8BITS_SCALAR, DMA_DATA_16BITS_SCALAR
924e53470feSOleksandr Tymoshenko * or DMA_DATA_32BITS_SCALAR)
925e53470feSOleksandr Tymoshenko *
926e53470feSOleksandr Tymoshenko *
927e53470feSOleksandr Tymoshenko * LOCKING:
928e53470feSOleksandr Tymoshenko * DMA registers protected by internal mutex
929e53470feSOleksandr Tymoshenko *
930e53470feSOleksandr Tymoshenko * RETURNS:
931e53470feSOleksandr Tymoshenko * EH_HANDLED or EH_NOT_HANDLED
932e53470feSOleksandr Tymoshenko */
933e53470feSOleksandr Tymoshenko int
ti_sdma_set_xfer_data_type(unsigned int ch,unsigned int type)934e53470feSOleksandr Tymoshenko ti_sdma_set_xfer_data_type(unsigned int ch, unsigned int type)
935e53470feSOleksandr Tymoshenko {
936e53470feSOleksandr Tymoshenko struct ti_sdma_softc *sc = ti_sdma_sc;
937e53470feSOleksandr Tymoshenko
938e53470feSOleksandr Tymoshenko /* Sanity check */
939e53470feSOleksandr Tymoshenko if (sc == NULL)
940e53470feSOleksandr Tymoshenko return (ENOMEM);
941e53470feSOleksandr Tymoshenko
942e53470feSOleksandr Tymoshenko TI_SDMA_LOCK(sc);
943e53470feSOleksandr Tymoshenko
944e53470feSOleksandr Tymoshenko if ((sc->sc_active_channels & (1 << ch)) == 0) {
945e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
946e53470feSOleksandr Tymoshenko return (EINVAL);
947e53470feSOleksandr Tymoshenko }
948e53470feSOleksandr Tymoshenko
949e53470feSOleksandr Tymoshenko sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_DATA_TYPE(0x3);
950e53470feSOleksandr Tymoshenko sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_DATA_TYPE(type);
951e53470feSOleksandr Tymoshenko
952e53470feSOleksandr Tymoshenko sc->sc_channel[ch].need_reg_write = 1;
953e53470feSOleksandr Tymoshenko
954e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
955e53470feSOleksandr Tymoshenko
956e53470feSOleksandr Tymoshenko return 0;
957e53470feSOleksandr Tymoshenko }
958e53470feSOleksandr Tymoshenko
959e53470feSOleksandr Tymoshenko /**
960e53470feSOleksandr Tymoshenko * ti_sdma_set_callback - driver attach function
961e53470feSOleksandr Tymoshenko * @dev: dma device handle
962e53470feSOleksandr Tymoshenko *
963e53470feSOleksandr Tymoshenko *
964e53470feSOleksandr Tymoshenko *
965e53470feSOleksandr Tymoshenko * LOCKING:
966e53470feSOleksandr Tymoshenko * DMA registers protected by internal mutex
967e53470feSOleksandr Tymoshenko *
968e53470feSOleksandr Tymoshenko * RETURNS:
969e53470feSOleksandr Tymoshenko * EH_HANDLED or EH_NOT_HANDLED
970e53470feSOleksandr Tymoshenko */
971e53470feSOleksandr Tymoshenko int
ti_sdma_set_callback(unsigned int ch,void (* callback)(unsigned int ch,uint32_t status,void * data),void * data)972e53470feSOleksandr Tymoshenko ti_sdma_set_callback(unsigned int ch,
973e53470feSOleksandr Tymoshenko void (*callback)(unsigned int ch, uint32_t status, void *data),
974e53470feSOleksandr Tymoshenko void *data)
975e53470feSOleksandr Tymoshenko {
976e53470feSOleksandr Tymoshenko struct ti_sdma_softc *sc = ti_sdma_sc;
977e53470feSOleksandr Tymoshenko
978e53470feSOleksandr Tymoshenko /* Sanity check */
979e53470feSOleksandr Tymoshenko if (sc == NULL)
980e53470feSOleksandr Tymoshenko return (ENOMEM);
981e53470feSOleksandr Tymoshenko
982e53470feSOleksandr Tymoshenko TI_SDMA_LOCK(sc);
983e53470feSOleksandr Tymoshenko
984e53470feSOleksandr Tymoshenko if ((sc->sc_active_channels & (1 << ch)) == 0) {
985e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
986e53470feSOleksandr Tymoshenko return (EINVAL);
987e53470feSOleksandr Tymoshenko }
988e53470feSOleksandr Tymoshenko
989e53470feSOleksandr Tymoshenko sc->sc_channel[ch].callback = callback;
990e53470feSOleksandr Tymoshenko sc->sc_channel[ch].callback_data = data;
991e53470feSOleksandr Tymoshenko
992e53470feSOleksandr Tymoshenko sc->sc_channel[ch].need_reg_write = 1;
993e53470feSOleksandr Tymoshenko
994e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
995e53470feSOleksandr Tymoshenko
996e53470feSOleksandr Tymoshenko return 0;
997e53470feSOleksandr Tymoshenko }
998e53470feSOleksandr Tymoshenko
999e53470feSOleksandr Tymoshenko /**
1000e53470feSOleksandr Tymoshenko * ti_sdma_sync_params - sets channel sync settings
1001e53470feSOleksandr Tymoshenko * @ch: the channel number to set the sync on
1002e53470feSOleksandr Tymoshenko * @trigger: the number of the sync trigger, this depends on what other H/W
1003e53470feSOleksandr Tymoshenko * module is triggering/receiving the DMA transactions
1004e53470feSOleksandr Tymoshenko * @mode: flags describing the sync mode to use, it may have one or more of
1005e53470feSOleksandr Tymoshenko * the following bits set; TI_SDMA_SYNC_FRAME,
1006e53470feSOleksandr Tymoshenko * TI_SDMA_SYNC_BLOCK, TI_SDMA_SYNC_TRIG_ON_SRC.
1007e53470feSOleksandr Tymoshenko *
1008e53470feSOleksandr Tymoshenko *
1009e53470feSOleksandr Tymoshenko *
1010e53470feSOleksandr Tymoshenko * LOCKING:
1011e53470feSOleksandr Tymoshenko * DMA registers protected by internal mutex
1012e53470feSOleksandr Tymoshenko *
1013e53470feSOleksandr Tymoshenko * RETURNS:
1014e53470feSOleksandr Tymoshenko * EH_HANDLED or EH_NOT_HANDLED
1015e53470feSOleksandr Tymoshenko */
1016e53470feSOleksandr Tymoshenko int
ti_sdma_sync_params(unsigned int ch,unsigned int trigger,unsigned int mode)1017e53470feSOleksandr Tymoshenko ti_sdma_sync_params(unsigned int ch, unsigned int trigger, unsigned int mode)
1018e53470feSOleksandr Tymoshenko {
1019e53470feSOleksandr Tymoshenko struct ti_sdma_softc *sc = ti_sdma_sc;
1020e53470feSOleksandr Tymoshenko uint32_t ccr;
1021e53470feSOleksandr Tymoshenko
1022e53470feSOleksandr Tymoshenko /* Sanity check */
1023e53470feSOleksandr Tymoshenko if (sc == NULL)
1024e53470feSOleksandr Tymoshenko return (ENOMEM);
1025e53470feSOleksandr Tymoshenko
1026e53470feSOleksandr Tymoshenko TI_SDMA_LOCK(sc);
1027e53470feSOleksandr Tymoshenko
1028e53470feSOleksandr Tymoshenko if ((sc->sc_active_channels & (1 << ch)) == 0) {
1029e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
1030e53470feSOleksandr Tymoshenko return (EINVAL);
1031e53470feSOleksandr Tymoshenko }
1032e53470feSOleksandr Tymoshenko
1033e53470feSOleksandr Tymoshenko ccr = sc->sc_channel[ch].reg_ccr;
1034e53470feSOleksandr Tymoshenko
1035e53470feSOleksandr Tymoshenko ccr &= ~DMA4_CCR_SYNC_TRIGGER(0x7F);
1036e53470feSOleksandr Tymoshenko ccr |= DMA4_CCR_SYNC_TRIGGER(trigger + 1);
1037e53470feSOleksandr Tymoshenko
1038e53470feSOleksandr Tymoshenko if (mode & TI_SDMA_SYNC_FRAME)
1039e53470feSOleksandr Tymoshenko ccr |= DMA4_CCR_FRAME_SYNC(1);
1040e53470feSOleksandr Tymoshenko else
1041e53470feSOleksandr Tymoshenko ccr &= ~DMA4_CCR_FRAME_SYNC(1);
1042e53470feSOleksandr Tymoshenko
1043e53470feSOleksandr Tymoshenko if (mode & TI_SDMA_SYNC_BLOCK)
1044e53470feSOleksandr Tymoshenko ccr |= DMA4_CCR_BLOCK_SYNC(1);
1045e53470feSOleksandr Tymoshenko else
1046e53470feSOleksandr Tymoshenko ccr &= ~DMA4_CCR_BLOCK_SYNC(1);
1047e53470feSOleksandr Tymoshenko
1048e53470feSOleksandr Tymoshenko if (mode & TI_SDMA_SYNC_TRIG_ON_SRC)
1049e53470feSOleksandr Tymoshenko ccr |= DMA4_CCR_SEL_SRC_DST_SYNC(1);
1050e53470feSOleksandr Tymoshenko else
1051e53470feSOleksandr Tymoshenko ccr &= ~DMA4_CCR_SEL_SRC_DST_SYNC(1);
1052e53470feSOleksandr Tymoshenko
1053e53470feSOleksandr Tymoshenko sc->sc_channel[ch].reg_ccr = ccr;
1054e53470feSOleksandr Tymoshenko
1055e53470feSOleksandr Tymoshenko sc->sc_channel[ch].need_reg_write = 1;
1056e53470feSOleksandr Tymoshenko
1057e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
1058e53470feSOleksandr Tymoshenko
1059e53470feSOleksandr Tymoshenko return 0;
1060e53470feSOleksandr Tymoshenko }
1061e53470feSOleksandr Tymoshenko
1062e53470feSOleksandr Tymoshenko /**
1063e53470feSOleksandr Tymoshenko * ti_sdma_set_addr_mode - driver attach function
1064255eff3bSPedro F. Giffuni * @ch: the channel number to set the endianness of
1065e53470feSOleksandr Tymoshenko * @rd_mode: the xfer source addressing mode (either DMA_ADDR_CONSTANT,
1066e53470feSOleksandr Tymoshenko * DMA_ADDR_POST_INCREMENT, DMA_ADDR_SINGLE_INDEX or
1067e53470feSOleksandr Tymoshenko * DMA_ADDR_DOUBLE_INDEX)
1068e53470feSOleksandr Tymoshenko * @wr_mode: the xfer destination addressing mode (either DMA_ADDR_CONSTANT,
1069e53470feSOleksandr Tymoshenko * DMA_ADDR_POST_INCREMENT, DMA_ADDR_SINGLE_INDEX or
1070e53470feSOleksandr Tymoshenko * DMA_ADDR_DOUBLE_INDEX)
1071e53470feSOleksandr Tymoshenko *
1072e53470feSOleksandr Tymoshenko *
1073e53470feSOleksandr Tymoshenko * LOCKING:
1074e53470feSOleksandr Tymoshenko * DMA registers protected by internal mutex
1075e53470feSOleksandr Tymoshenko *
1076e53470feSOleksandr Tymoshenko * RETURNS:
1077e53470feSOleksandr Tymoshenko * EH_HANDLED or EH_NOT_HANDLED
1078e53470feSOleksandr Tymoshenko */
1079e53470feSOleksandr Tymoshenko int
ti_sdma_set_addr_mode(unsigned int ch,unsigned int src_mode,unsigned int dst_mode)1080e53470feSOleksandr Tymoshenko ti_sdma_set_addr_mode(unsigned int ch, unsigned int src_mode,
1081e53470feSOleksandr Tymoshenko unsigned int dst_mode)
1082e53470feSOleksandr Tymoshenko {
1083e53470feSOleksandr Tymoshenko struct ti_sdma_softc *sc = ti_sdma_sc;
1084e53470feSOleksandr Tymoshenko uint32_t ccr;
1085e53470feSOleksandr Tymoshenko
1086e53470feSOleksandr Tymoshenko /* Sanity check */
1087e53470feSOleksandr Tymoshenko if (sc == NULL)
1088e53470feSOleksandr Tymoshenko return (ENOMEM);
1089e53470feSOleksandr Tymoshenko
1090e53470feSOleksandr Tymoshenko TI_SDMA_LOCK(sc);
1091e53470feSOleksandr Tymoshenko
1092e53470feSOleksandr Tymoshenko if ((sc->sc_active_channels & (1 << ch)) == 0) {
1093e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
1094e53470feSOleksandr Tymoshenko return (EINVAL);
1095e53470feSOleksandr Tymoshenko }
1096e53470feSOleksandr Tymoshenko
1097e53470feSOleksandr Tymoshenko ccr = sc->sc_channel[ch].reg_ccr;
1098e53470feSOleksandr Tymoshenko
1099e53470feSOleksandr Tymoshenko ccr &= ~DMA4_CCR_SRC_ADDRESS_MODE(0x3);
1100e53470feSOleksandr Tymoshenko ccr |= DMA4_CCR_SRC_ADDRESS_MODE(src_mode);
1101e53470feSOleksandr Tymoshenko
1102e53470feSOleksandr Tymoshenko ccr &= ~DMA4_CCR_DST_ADDRESS_MODE(0x3);
1103e53470feSOleksandr Tymoshenko ccr |= DMA4_CCR_DST_ADDRESS_MODE(dst_mode);
1104e53470feSOleksandr Tymoshenko
1105e53470feSOleksandr Tymoshenko sc->sc_channel[ch].reg_ccr = ccr;
1106e53470feSOleksandr Tymoshenko
1107e53470feSOleksandr Tymoshenko sc->sc_channel[ch].need_reg_write = 1;
1108e53470feSOleksandr Tymoshenko
1109e53470feSOleksandr Tymoshenko TI_SDMA_UNLOCK(sc);
1110e53470feSOleksandr Tymoshenko
1111e53470feSOleksandr Tymoshenko return 0;
1112e53470feSOleksandr Tymoshenko }
1113e53470feSOleksandr Tymoshenko
1114e53470feSOleksandr Tymoshenko /**
1115e53470feSOleksandr Tymoshenko * ti_sdma_probe - driver probe function
1116e53470feSOleksandr Tymoshenko * @dev: dma device handle
1117e53470feSOleksandr Tymoshenko *
1118e53470feSOleksandr Tymoshenko *
1119e53470feSOleksandr Tymoshenko *
1120e53470feSOleksandr Tymoshenko * RETURNS:
1121e53470feSOleksandr Tymoshenko * Always returns 0.
1122e53470feSOleksandr Tymoshenko */
1123e53470feSOleksandr Tymoshenko static int
ti_sdma_probe(device_t dev)1124e53470feSOleksandr Tymoshenko ti_sdma_probe(device_t dev)
1125e53470feSOleksandr Tymoshenko {
1126add35ed5SIan Lepore
1127add35ed5SIan Lepore if (!ofw_bus_status_okay(dev))
1128add35ed5SIan Lepore return (ENXIO);
1129add35ed5SIan Lepore
11305b03aba6SOleksandr Tymoshenko if (!ofw_bus_is_compatible(dev, "ti,omap4430-sdma"))
1131e53470feSOleksandr Tymoshenko return (ENXIO);
1132e53470feSOleksandr Tymoshenko
1133e53470feSOleksandr Tymoshenko device_set_desc(dev, "TI sDMA Controller");
1134e53470feSOleksandr Tymoshenko return (0);
1135e53470feSOleksandr Tymoshenko }
1136e53470feSOleksandr Tymoshenko
1137e53470feSOleksandr Tymoshenko /**
1138e53470feSOleksandr Tymoshenko * ti_sdma_attach - driver attach function
1139e53470feSOleksandr Tymoshenko * @dev: dma device handle
1140e53470feSOleksandr Tymoshenko *
1141e53470feSOleksandr Tymoshenko * Initialises memory mapping/pointers to the DMA register set and requests
1142e53470feSOleksandr Tymoshenko * IRQs. This is effectively the setup function for the driver.
1143e53470feSOleksandr Tymoshenko *
1144e53470feSOleksandr Tymoshenko * RETURNS:
1145e53470feSOleksandr Tymoshenko * 0 on success or a negative error code failure.
1146e53470feSOleksandr Tymoshenko */
1147e53470feSOleksandr Tymoshenko static int
ti_sdma_attach(device_t dev)1148e53470feSOleksandr Tymoshenko ti_sdma_attach(device_t dev)
1149e53470feSOleksandr Tymoshenko {
1150e53470feSOleksandr Tymoshenko struct ti_sdma_softc *sc = device_get_softc(dev);
1151e53470feSOleksandr Tymoshenko unsigned int timeout;
1152e53470feSOleksandr Tymoshenko unsigned int i;
1153e53470feSOleksandr Tymoshenko int rid;
1154e53470feSOleksandr Tymoshenko void *ihl;
1155e53470feSOleksandr Tymoshenko int err;
1156e53470feSOleksandr Tymoshenko
1157e53470feSOleksandr Tymoshenko /* Setup the basics */
1158e53470feSOleksandr Tymoshenko sc->sc_dev = dev;
1159e53470feSOleksandr Tymoshenko
1160e53470feSOleksandr Tymoshenko /* No channels active at the moment */
1161e53470feSOleksandr Tymoshenko sc->sc_active_channels = 0x00000000;
1162e53470feSOleksandr Tymoshenko
1163e53470feSOleksandr Tymoshenko /* Mutex to protect the shared data structures */
1164e53470feSOleksandr Tymoshenko TI_SDMA_LOCK_INIT(sc);
1165e53470feSOleksandr Tymoshenko
1166e53470feSOleksandr Tymoshenko /* Get the memory resource for the register mapping */
1167e53470feSOleksandr Tymoshenko rid = 0;
1168e53470feSOleksandr Tymoshenko sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
1169e53470feSOleksandr Tymoshenko if (sc->sc_mem_res == NULL)
1170e53470feSOleksandr Tymoshenko panic("%s: Cannot map registers", device_get_name(dev));
1171e53470feSOleksandr Tymoshenko
1172e53470feSOleksandr Tymoshenko /* Enable the interface and functional clocks */
11730050ea24SMichal Meloun ti_sysc_clock_enable(device_get_parent(dev));
1174e53470feSOleksandr Tymoshenko
1175e53470feSOleksandr Tymoshenko /* Read the sDMA revision register and sanity check it's known */
11760050ea24SMichal Meloun sc->sc_hw_rev = ti_sdma_read_4(sc,
11770050ea24SMichal Meloun ti_sysc_get_rev_address_offset_host(device_get_parent(dev)));
1178e53470feSOleksandr Tymoshenko device_printf(dev, "sDMA revision %08x\n", sc->sc_hw_rev);
1179e53470feSOleksandr Tymoshenko
1180e53470feSOleksandr Tymoshenko if (!ti_sdma_is_omap4_rev(sc) && !ti_sdma_is_omap3_rev(sc)) {
1181e53470feSOleksandr Tymoshenko device_printf(sc->sc_dev, "error - unknown sDMA H/W revision\n");
1182e53470feSOleksandr Tymoshenko return (EINVAL);
1183e53470feSOleksandr Tymoshenko }
1184e53470feSOleksandr Tymoshenko
1185e53470feSOleksandr Tymoshenko /* Disable all interrupts */
1186e53470feSOleksandr Tymoshenko for (i = 0; i < NUM_DMA_IRQS; i++) {
1187e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_IRQENABLE_L(i), 0x00000000);
1188e53470feSOleksandr Tymoshenko }
1189e53470feSOleksandr Tymoshenko
1190e53470feSOleksandr Tymoshenko /* Soft-reset is only supported on pre-OMAP44xx devices */
1191e53470feSOleksandr Tymoshenko if (ti_sdma_is_omap3_rev(sc)) {
1192e53470feSOleksandr Tymoshenko /* Soft-reset */
1193e53470feSOleksandr Tymoshenko ti_sdma_write_4(sc, DMA4_OCP_SYSCONFIG, 0x0002);
1194e53470feSOleksandr Tymoshenko
1195e53470feSOleksandr Tymoshenko /* Set the timeout to 100ms*/
1196e53470feSOleksandr Tymoshenko timeout = (hz < 10) ? 1 : ((100 * hz) / 1000);
1197e53470feSOleksandr Tymoshenko
1198e53470feSOleksandr Tymoshenko /* Wait for DMA reset to complete */
1199e53470feSOleksandr Tymoshenko while ((ti_sdma_read_4(sc, DMA4_SYSSTATUS) & 0x1) == 0x0) {
1200e53470feSOleksandr Tymoshenko /* Sleep for a tick */
1201e53470feSOleksandr Tymoshenko pause("DMARESET", 1);
1202e53470feSOleksandr Tymoshenko
1203e53470feSOleksandr Tymoshenko if (timeout-- == 0) {
1204e53470feSOleksandr Tymoshenko device_printf(sc->sc_dev, "sDMA reset operation timed out\n");
1205e53470feSOleksandr Tymoshenko return (EINVAL);
1206e53470feSOleksandr Tymoshenko }
1207e53470feSOleksandr Tymoshenko }
1208e53470feSOleksandr Tymoshenko }
1209e53470feSOleksandr Tymoshenko
1210e53470feSOleksandr Tymoshenko /*
1211e53470feSOleksandr Tymoshenko * Install interrupt handlers for the for possible interrupts. Any channel
1212e53470feSOleksandr Tymoshenko * can trip one of the four IRQs
1213e53470feSOleksandr Tymoshenko */
1214e53470feSOleksandr Tymoshenko rid = 0;
1215e53470feSOleksandr Tymoshenko sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
1216e53470feSOleksandr Tymoshenko RF_ACTIVE | RF_SHAREABLE);
1217e53470feSOleksandr Tymoshenko if (sc->sc_irq_res == NULL)
1218e53470feSOleksandr Tymoshenko panic("Unable to setup the dma irq handler.\n");
1219e53470feSOleksandr Tymoshenko
1220e53470feSOleksandr Tymoshenko err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
1221e53470feSOleksandr Tymoshenko NULL, ti_sdma_intr, NULL, &ihl);
1222e53470feSOleksandr Tymoshenko if (err)
1223e53470feSOleksandr Tymoshenko panic("%s: Cannot register IRQ", device_get_name(dev));
1224e53470feSOleksandr Tymoshenko
1225e53470feSOleksandr Tymoshenko /* Store the DMA structure globally ... this driver should never be unloaded */
1226e53470feSOleksandr Tymoshenko ti_sdma_sc = sc;
1227e53470feSOleksandr Tymoshenko
1228e53470feSOleksandr Tymoshenko return (0);
1229e53470feSOleksandr Tymoshenko }
1230e53470feSOleksandr Tymoshenko
1231e53470feSOleksandr Tymoshenko static device_method_t ti_sdma_methods[] = {
1232e53470feSOleksandr Tymoshenko DEVMETHOD(device_probe, ti_sdma_probe),
1233e53470feSOleksandr Tymoshenko DEVMETHOD(device_attach, ti_sdma_attach),
1234e53470feSOleksandr Tymoshenko {0, 0},
1235e53470feSOleksandr Tymoshenko };
1236e53470feSOleksandr Tymoshenko
1237e53470feSOleksandr Tymoshenko static driver_t ti_sdma_driver = {
1238e53470feSOleksandr Tymoshenko "ti_sdma",
1239e53470feSOleksandr Tymoshenko ti_sdma_methods,
1240e53470feSOleksandr Tymoshenko sizeof(struct ti_sdma_softc),
1241e53470feSOleksandr Tymoshenko };
1242e53470feSOleksandr Tymoshenko
12438537e671SJohn Baldwin DRIVER_MODULE(ti_sdma, simplebus, ti_sdma_driver, 0, 0);
12440050ea24SMichal Meloun MODULE_DEPEND(ti_sdma, ti_sysc, 1, 1, 1);
1245