1239281Sgonzo/*-
2239281Sgonzo * Copyright (c) 2011
3239281Sgonzo *	Ben Gray <ben.r.gray@gmail.com>.
4239281Sgonzo * All rights reserved.
5239281Sgonzo *
6239281Sgonzo * Redistribution and use in source and binary forms, with or without
7239281Sgonzo * modification, are permitted provided that the following conditions
8239281Sgonzo * are met:
9239281Sgonzo * 1. Redistributions of source code must retain the above copyright
10239281Sgonzo *    notice, this list of conditions and the following disclaimer.
11239281Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
12239281Sgonzo *    notice, this list of conditions and the following disclaimer in the
13239281Sgonzo *    documentation and/or other materials provided with the distribution.
14239281Sgonzo *
15239281Sgonzo * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16239281Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17239281Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18239281Sgonzo * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
19239281Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20239281Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21239281Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22239281Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23239281Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24239281Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25239281Sgonzo * SUCH DAMAGE.
26239281Sgonzo */
27239281Sgonzo
28239281Sgonzo#include <sys/cdefs.h>
29239281Sgonzo__FBSDID("$FreeBSD: releng/10.3/sys/arm/ti/ti_sdma.c 266152 2014-05-15 16:11:06Z ian $");
30239281Sgonzo
31239281Sgonzo#include <sys/param.h>
32239281Sgonzo#include <sys/systm.h>
33239281Sgonzo#include <sys/bus.h>
34239281Sgonzo#include <sys/kernel.h>
35239281Sgonzo#include <sys/lock.h>
36239281Sgonzo#include <sys/interrupt.h>
37239281Sgonzo#include <sys/module.h>
38239281Sgonzo#include <sys/malloc.h>
39239281Sgonzo#include <sys/mutex.h>
40239281Sgonzo#include <sys/rman.h>
41239281Sgonzo#include <sys/queue.h>
42239281Sgonzo#include <sys/taskqueue.h>
43239281Sgonzo#include <sys/timetc.h>
44239281Sgonzo#include <machine/bus.h>
45239281Sgonzo#include <machine/intr.h>
46239281Sgonzo
47239281Sgonzo#include <dev/fdt/fdt_common.h>
48239281Sgonzo#include <dev/ofw/openfirm.h>
49239281Sgonzo#include <dev/ofw/ofw_bus.h>
50239281Sgonzo#include <dev/ofw/ofw_bus_subr.h>
51239281Sgonzo
52239281Sgonzo#include <arm/ti/ti_cpuid.h>
53239281Sgonzo#include <arm/ti/ti_prcm.h>
54239281Sgonzo#include <arm/ti/ti_sdma.h>
55239281Sgonzo#include <arm/ti/ti_sdmareg.h>
56239281Sgonzo
57239281Sgonzo/**
58239281Sgonzo *	Kernel functions for using the DMA controller
59239281Sgonzo *
60239281Sgonzo *
61239281Sgonzo *	DMA TRANSFERS:
62239281Sgonzo *	A DMA transfer block consists of a number of frames (FN). Each frame
63239281Sgonzo *	consists of a number of elements, and each element can have a size of 8, 16,
64239281Sgonzo *	or 32 bits.
65239281Sgonzo *
66239281Sgonzo *	OMAP44xx and newer chips support linked list (aka scatter gather) transfers,
67239281Sgonzo *	where a linked list of source/destination pairs can be placed in memory
68239281Sgonzo *	for the H/W to process.  Earlier chips only allowed you to chain multiple
69239281Sgonzo *	channels together.  However currently this linked list feature is not
70239281Sgonzo *	supported by the driver.
71239281Sgonzo *
72239281Sgonzo */
73239281Sgonzo
74239281Sgonzo/**
75239281Sgonzo *	Data structure per DMA channel.
76239281Sgonzo *
77239281Sgonzo *
78239281Sgonzo */
79239281Sgonzostruct ti_sdma_channel {
80239281Sgonzo
81239281Sgonzo	/*
82239281Sgonzo	 * The configuration registers for the given channel, these are modified
83239281Sgonzo	 * by the set functions and only written to the actual registers when a
84239281Sgonzo	 * transaction is started.
85239281Sgonzo	 */
86239281Sgonzo	uint32_t		reg_csdp;
87239281Sgonzo	uint32_t		reg_ccr;
88239281Sgonzo	uint32_t		reg_cicr;
89239281Sgonzo
90239281Sgonzo	/* Set when one of the configuration registers above change */
91239281Sgonzo	uint32_t		need_reg_write;
92239281Sgonzo
93239281Sgonzo	/* Callback function used when an interrupt is tripped on the given channel */
94239281Sgonzo	void (*callback)(unsigned int ch, uint32_t ch_status, void *data);
95239281Sgonzo
96239281Sgonzo	/* Callback data passed in the callback ... duh */
97239281Sgonzo	void*			callback_data;
98239281Sgonzo
99239281Sgonzo};
100239281Sgonzo
101239281Sgonzo/**
102239281Sgonzo *	DMA driver context, allocated and stored globally, this driver is not
103239281Sgonzo *	intetned to ever be unloaded (see ti_sdma_sc).
104239281Sgonzo *
105239281Sgonzo */
106239281Sgonzostruct ti_sdma_softc {
107239281Sgonzo	device_t		sc_dev;
108239281Sgonzo	struct resource*	sc_irq_res;
109239281Sgonzo	struct resource*	sc_mem_res;
110239281Sgonzo
111239281Sgonzo	/*
112239281Sgonzo	 * I guess in theory we should have a mutex per DMA channel for register
113239281Sgonzo	 * modifications. But since we know we are never going to be run on a SMP
114239281Sgonzo	 * system, we can use just the single lock for all channels.
115239281Sgonzo	 */
116239281Sgonzo	struct mtx		sc_mtx;
117239281Sgonzo
118239281Sgonzo	/* Stores the H/W revision read from the registers */
119239281Sgonzo	uint32_t		sc_hw_rev;
120239281Sgonzo
121239281Sgonzo	/*
122239281Sgonzo	 * Bits in the sc_active_channels data field indicate if the channel has
123239281Sgonzo	 * been activated.
124239281Sgonzo	 */
125239281Sgonzo	uint32_t		sc_active_channels;
126239281Sgonzo
127239281Sgonzo	struct ti_sdma_channel sc_channel[NUM_DMA_CHANNELS];
128239281Sgonzo
129239281Sgonzo};
130239281Sgonzo
131239281Sgonzostatic struct ti_sdma_softc *ti_sdma_sc = NULL;
132239281Sgonzo
133239281Sgonzo/**
134239281Sgonzo *	Macros for driver mutex locking
135239281Sgonzo */
136239281Sgonzo#define TI_SDMA_LOCK(_sc)             mtx_lock_spin(&(_sc)->sc_mtx)
137239281Sgonzo#define TI_SDMA_UNLOCK(_sc)           mtx_unlock_spin(&(_sc)->sc_mtx)
138239281Sgonzo#define TI_SDMA_LOCK_INIT(_sc) \
139239281Sgonzo	mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \
140239281Sgonzo	         "ti_sdma", MTX_SPIN)
141239281Sgonzo#define TI_SDMA_LOCK_DESTROY(_sc)     mtx_destroy(&_sc->sc_mtx);
142239281Sgonzo#define TI_SDMA_ASSERT_LOCKED(_sc)    mtx_assert(&_sc->sc_mtx, MA_OWNED);
143239281Sgonzo#define TI_SDMA_ASSERT_UNLOCKED(_sc)  mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
144239281Sgonzo
145239281Sgonzo/**
146239281Sgonzo *	Function prototypes
147239281Sgonzo *
148239281Sgonzo */
149239281Sgonzostatic void ti_sdma_intr(void *);
150239281Sgonzo
151239281Sgonzo/**
152239281Sgonzo *	ti_sdma_read_4 - reads a 32-bit value from one of the DMA registers
153239281Sgonzo *	@sc: DMA device context
154239281Sgonzo *	@off: The offset of a register from the DMA register address range
155239281Sgonzo *
156239281Sgonzo *
157239281Sgonzo *	RETURNS:
158239281Sgonzo *	32-bit value read from the register.
159239281Sgonzo */
160239281Sgonzostatic inline uint32_t
161239281Sgonzoti_sdma_read_4(struct ti_sdma_softc *sc, bus_size_t off)
162239281Sgonzo{
163239281Sgonzo	return bus_read_4(sc->sc_mem_res, off);
164239281Sgonzo}
165239281Sgonzo
166239281Sgonzo/**
167239281Sgonzo *	ti_sdma_write_4 - writes a 32-bit value to one of the DMA registers
168239281Sgonzo *	@sc: DMA device context
169239281Sgonzo *	@off: The offset of a register from the DMA register address range
170239281Sgonzo *
171239281Sgonzo *
172239281Sgonzo *	RETURNS:
173239281Sgonzo *	32-bit value read from the register.
174239281Sgonzo */
175239281Sgonzostatic inline void
176239281Sgonzoti_sdma_write_4(struct ti_sdma_softc *sc, bus_size_t off, uint32_t val)
177239281Sgonzo{
178239281Sgonzo	bus_write_4(sc->sc_mem_res, off, val);
179239281Sgonzo}
180239281Sgonzo
181239281Sgonzo/**
182239281Sgonzo *	ti_sdma_is_omap3_rev - returns true if H/W is from OMAP3 series
183239281Sgonzo *	@sc: DMA device context
184239281Sgonzo *
185239281Sgonzo */
186239281Sgonzostatic inline int
187239281Sgonzoti_sdma_is_omap3_rev(struct ti_sdma_softc *sc)
188239281Sgonzo{
189239281Sgonzo	return (sc->sc_hw_rev == DMA4_OMAP3_REV);
190239281Sgonzo}
191239281Sgonzo
192239281Sgonzo/**
193239281Sgonzo *	ti_sdma_is_omap4_rev - returns true if H/W is from OMAP4 series
194239281Sgonzo *	@sc: DMA device context
195239281Sgonzo *
196239281Sgonzo */
197239281Sgonzostatic inline int
198239281Sgonzoti_sdma_is_omap4_rev(struct ti_sdma_softc *sc)
199239281Sgonzo{
200239281Sgonzo	return (sc->sc_hw_rev == DMA4_OMAP4_REV);
201239281Sgonzo}
202239281Sgonzo
203239281Sgonzo/**
204239281Sgonzo *	ti_sdma_intr - interrupt handler for all 4 DMA IRQs
205239281Sgonzo *	@arg: ignored
206239281Sgonzo *
207239281Sgonzo *	Called when any of the four DMA IRQs are triggered.
208239281Sgonzo *
209239281Sgonzo *	LOCKING:
210239281Sgonzo *	DMA registers protected by internal mutex
211239281Sgonzo *
212239281Sgonzo *	RETURNS:
213239281Sgonzo *	nothing
214239281Sgonzo */
215239281Sgonzostatic void
216239281Sgonzoti_sdma_intr(void *arg)
217239281Sgonzo{
218239281Sgonzo	struct ti_sdma_softc *sc = ti_sdma_sc;
219239281Sgonzo	uint32_t intr;
220239281Sgonzo	uint32_t csr;
221239281Sgonzo	unsigned int ch, j;
222239281Sgonzo	struct ti_sdma_channel* channel;
223239281Sgonzo
224239281Sgonzo	TI_SDMA_LOCK(sc);
225239281Sgonzo
226239281Sgonzo	for (j = 0; j < NUM_DMA_IRQS; j++) {
227239281Sgonzo
228239281Sgonzo		/* Get the flag interrupts (enabled) */
229239281Sgonzo		intr = ti_sdma_read_4(sc, DMA4_IRQSTATUS_L(j));
230239281Sgonzo		intr &= ti_sdma_read_4(sc, DMA4_IRQENABLE_L(j));
231239281Sgonzo		if (intr == 0x00000000)
232239281Sgonzo			continue;
233239281Sgonzo
234239281Sgonzo		/* Loop through checking the status bits */
235239281Sgonzo		for (ch = 0; ch < NUM_DMA_CHANNELS; ch++) {
236239281Sgonzo			if (intr & (1 << ch)) {
237239281Sgonzo				channel = &sc->sc_channel[ch];
238239281Sgonzo
239239281Sgonzo				/* Read the CSR regsiter and verify we don't have a spurious IRQ */
240239281Sgonzo				csr = ti_sdma_read_4(sc, DMA4_CSR(ch));
241239281Sgonzo				if (csr == 0) {
242239281Sgonzo					device_printf(sc->sc_dev, "Spurious DMA IRQ for channel "
243239281Sgonzo					              "%d\n", ch);
244239281Sgonzo					continue;
245239281Sgonzo				}
246239281Sgonzo
247239281Sgonzo				/* Sanity check this channel is active */
248239281Sgonzo				if ((sc->sc_active_channels & (1 << ch)) == 0) {
249239281Sgonzo					device_printf(sc->sc_dev, "IRQ %d for a non-activated "
250239281Sgonzo					              "channel %d\n", j, ch);
251239281Sgonzo					continue;
252239281Sgonzo				}
253239281Sgonzo
254239281Sgonzo				/* Check the status error codes */
255239281Sgonzo				if (csr & DMA4_CSR_DROP)
256239281Sgonzo					device_printf(sc->sc_dev, "Synchronization event drop "
257239281Sgonzo					              "occurred during the transfer on channel %u\n",
258239281Sgonzo								  ch);
259239281Sgonzo				if (csr & DMA4_CSR_SECURE_ERR)
260239281Sgonzo					device_printf(sc->sc_dev, "Secure transaction error event "
261239281Sgonzo					              "on channel %u\n", ch);
262239281Sgonzo				if (csr & DMA4_CSR_MISALIGNED_ADRS_ERR)
263239281Sgonzo					device_printf(sc->sc_dev, "Misaligned address error event "
264239281Sgonzo					              "on channel %u\n", ch);
265239281Sgonzo				if (csr & DMA4_CSR_TRANS_ERR) {
266239281Sgonzo					device_printf(sc->sc_dev, "Transaction error event on "
267239281Sgonzo					              "channel %u\n", ch);
268239281Sgonzo					/*
269239281Sgonzo					 * Apparently according to linux code, there is an errata
270239281Sgonzo					 * that says the channel is not disabled upon this error.
271239281Sgonzo					 * They explicitly disable the channel here .. since I
272239281Sgonzo					 * haven't seen the errata, I'm going to ignore for now.
273239281Sgonzo					 */
274239281Sgonzo				}
275239281Sgonzo
276239281Sgonzo				/* Clear the status flags for the IRQ */
277239281Sgonzo				ti_sdma_write_4(sc, DMA4_CSR(ch), DMA4_CSR_CLEAR_MASK);
278239281Sgonzo				ti_sdma_write_4(sc, DMA4_IRQSTATUS_L(j), (1 << ch));
279239281Sgonzo
280239281Sgonzo				/* Call the callback for the given channel */
281239281Sgonzo				if (channel->callback)
282239281Sgonzo					channel->callback(ch, csr, channel->callback_data);
283239281Sgonzo			}
284239281Sgonzo		}
285239281Sgonzo	}
286239281Sgonzo
287239281Sgonzo	TI_SDMA_UNLOCK(sc);
288239281Sgonzo
289239281Sgonzo	return;
290239281Sgonzo}
291239281Sgonzo
292239281Sgonzo/**
293239281Sgonzo *	ti_sdma_activate_channel - activates a DMA channel
294239281Sgonzo *	@ch: upon return contains the channel allocated
295239281Sgonzo *	@callback: a callback function to associate with the channel
296239281Sgonzo *	@data: optional data supplied when the callback is called
297239281Sgonzo *
298239281Sgonzo *	Simply activates a channel be enabling and writing default values to the
299239281Sgonzo *	channel's register set.  It doesn't start a transaction, just populates the
300239281Sgonzo *	internal data structures and sets defaults.
301239281Sgonzo *
302239281Sgonzo *	Note this function doesn't enable interrupts, for that you need to call
303239281Sgonzo *	ti_sdma_enable_channel_irq(). If not using IRQ to detect the end of the
304239281Sgonzo *	transfer, you can use ti_sdma_status_poll() to detect a change in the
305239281Sgonzo *	status.
306239281Sgonzo *
307239281Sgonzo *	A channel must be activated before any of the other DMA functions can be
308239281Sgonzo *	called on it.
309239281Sgonzo *
310239281Sgonzo *	LOCKING:
311239281Sgonzo *	DMA registers protected by internal mutex
312239281Sgonzo *
313239281Sgonzo *	RETURNS:
314239281Sgonzo *	0 on success, otherwise an error code
315239281Sgonzo */
316239281Sgonzoint
317239281Sgonzoti_sdma_activate_channel(unsigned int *ch,
318239281Sgonzo                          void (*callback)(unsigned int ch, uint32_t status, void *data),
319239281Sgonzo                          void *data)
320239281Sgonzo{
321239281Sgonzo	struct ti_sdma_softc *sc = ti_sdma_sc;
322239281Sgonzo	struct ti_sdma_channel *channel = NULL;
323239281Sgonzo	uint32_t addr;
324239281Sgonzo	unsigned int i;
325239281Sgonzo
326239281Sgonzo	/* Sanity check */
327239281Sgonzo	if (sc == NULL)
328239281Sgonzo		return (ENOMEM);
329239281Sgonzo
330239281Sgonzo	if (ch == NULL)
331239281Sgonzo		return (EINVAL);
332239281Sgonzo
333239281Sgonzo	TI_SDMA_LOCK(sc);
334239281Sgonzo
335239281Sgonzo	/* Check to see if all channels are in use */
336239281Sgonzo	if (sc->sc_active_channels == 0xffffffff) {
337239281Sgonzo		TI_SDMA_UNLOCK(sc);
338239281Sgonzo		return (ENOMEM);
339239281Sgonzo	}
340239281Sgonzo
341239281Sgonzo	/* Find the first non-active channel */
342239281Sgonzo	for (i = 0; i < NUM_DMA_CHANNELS; i++) {
343239281Sgonzo		if (!(sc->sc_active_channels & (0x1 << i))) {
344239281Sgonzo			sc->sc_active_channels |= (0x1 << i);
345239281Sgonzo			*ch = i;
346239281Sgonzo			break;
347239281Sgonzo		}
348239281Sgonzo	}
349239281Sgonzo
350239281Sgonzo	/* Get the channel struct and populate the fields */
351239281Sgonzo	channel = &sc->sc_channel[*ch];
352239281Sgonzo
353239281Sgonzo	channel->callback = callback;
354239281Sgonzo	channel->callback_data = data;
355239281Sgonzo
356239281Sgonzo	channel->need_reg_write = 1;
357239281Sgonzo
358239281Sgonzo	/* Set the default configuration for the DMA channel */
359239281Sgonzo	channel->reg_csdp = DMA4_CSDP_DATA_TYPE(0x2)
360239281Sgonzo		| DMA4_CSDP_SRC_BURST_MODE(0)
361239281Sgonzo		| DMA4_CSDP_DST_BURST_MODE(0)
362239281Sgonzo		| DMA4_CSDP_SRC_ENDIANISM(0)
363239281Sgonzo		| DMA4_CSDP_DST_ENDIANISM(0)
364239281Sgonzo		| DMA4_CSDP_WRITE_MODE(0)
365239281Sgonzo		| DMA4_CSDP_SRC_PACKED(0)
366239281Sgonzo		| DMA4_CSDP_DST_PACKED(0);
367239281Sgonzo
368239281Sgonzo	channel->reg_ccr = DMA4_CCR_DST_ADDRESS_MODE(1)
369239281Sgonzo		| DMA4_CCR_SRC_ADDRESS_MODE(1)
370239281Sgonzo		| DMA4_CCR_READ_PRIORITY(0)
371239281Sgonzo		| DMA4_CCR_WRITE_PRIORITY(0)
372239281Sgonzo		| DMA4_CCR_SYNC_TRIGGER(0)
373239281Sgonzo		| DMA4_CCR_FRAME_SYNC(0)
374239281Sgonzo		| DMA4_CCR_BLOCK_SYNC(0);
375239281Sgonzo
376239281Sgonzo	channel->reg_cicr = DMA4_CICR_TRANS_ERR_IE
377239281Sgonzo		| DMA4_CICR_SECURE_ERR_IE
378239281Sgonzo		| DMA4_CICR_SUPERVISOR_ERR_IE
379239281Sgonzo		| DMA4_CICR_MISALIGNED_ADRS_ERR_IE;
380239281Sgonzo
381239281Sgonzo	/* Clear all the channel registers, this should abort any transaction */
382239281Sgonzo	for (addr = DMA4_CCR(*ch); addr <= DMA4_COLOR(*ch); addr += 4)
383239281Sgonzo		ti_sdma_write_4(sc, addr, 0x00000000);
384239281Sgonzo
385239281Sgonzo	TI_SDMA_UNLOCK(sc);
386239281Sgonzo
387239281Sgonzo	return 0;
388239281Sgonzo}
389239281Sgonzo
390239281Sgonzo/**
391239281Sgonzo *	ti_sdma_deactivate_channel - deactivates a channel
392239281Sgonzo *	@ch: the channel to deactivate
393239281Sgonzo *
394239281Sgonzo *
395239281Sgonzo *
396239281Sgonzo *	LOCKING:
397239281Sgonzo *	DMA registers protected by internal mutex
398239281Sgonzo *
399239281Sgonzo *	RETURNS:
400239281Sgonzo *	EH_HANDLED or EH_NOT_HANDLED
401239281Sgonzo */
402239281Sgonzoint
403239281Sgonzoti_sdma_deactivate_channel(unsigned int ch)
404239281Sgonzo{
405239281Sgonzo	struct ti_sdma_softc *sc = ti_sdma_sc;
406239281Sgonzo	unsigned int j;
407239281Sgonzo	unsigned int addr;
408239281Sgonzo
409239281Sgonzo	/* Sanity check */
410239281Sgonzo	if (sc == NULL)
411239281Sgonzo		return (ENOMEM);
412239281Sgonzo
413239281Sgonzo	TI_SDMA_LOCK(sc);
414239281Sgonzo
415239281Sgonzo	/* First check if the channel is currently active */
416239281Sgonzo	if ((sc->sc_active_channels & (1 << ch)) == 0) {
417239281Sgonzo		TI_SDMA_UNLOCK(sc);
418239281Sgonzo		return (EBUSY);
419239281Sgonzo	}
420239281Sgonzo
421239281Sgonzo	/* Mark the channel as inactive */
422239281Sgonzo	sc->sc_active_channels &= ~(1 << ch);
423239281Sgonzo
424239281Sgonzo	/* Disable all DMA interrupts for the channel. */
425239281Sgonzo	ti_sdma_write_4(sc, DMA4_CICR(ch), 0);
426239281Sgonzo
427239281Sgonzo	/* Make sure the DMA transfer is stopped. */
428239281Sgonzo	ti_sdma_write_4(sc, DMA4_CCR(ch), 0);
429239281Sgonzo
430239281Sgonzo	/* Clear the CSR register and IRQ status register */
431239281Sgonzo	ti_sdma_write_4(sc, DMA4_CSR(ch), DMA4_CSR_CLEAR_MASK);
432239281Sgonzo	for (j = 0; j < NUM_DMA_IRQS; j++) {
433239281Sgonzo		ti_sdma_write_4(sc, DMA4_IRQSTATUS_L(j), (1 << ch));
434239281Sgonzo	}
435239281Sgonzo
436239281Sgonzo	/* Clear all the channel registers, this should abort any transaction */
437239281Sgonzo	for (addr = DMA4_CCR(ch); addr <= DMA4_COLOR(ch); addr += 4)
438239281Sgonzo		ti_sdma_write_4(sc, addr, 0x00000000);
439239281Sgonzo
440239281Sgonzo	TI_SDMA_UNLOCK(sc);
441239281Sgonzo
442239281Sgonzo	return 0;
443239281Sgonzo}
444239281Sgonzo
445239281Sgonzo/**
446239281Sgonzo *	ti_sdma_disable_channel_irq - disables IRQ's on the given channel
447239281Sgonzo *	@ch: the channel to disable IRQ's on
448239281Sgonzo *
449239281Sgonzo *	Disable interupt generation for the given channel.
450239281Sgonzo *
451239281Sgonzo *	LOCKING:
452239281Sgonzo *	DMA registers protected by internal mutex
453239281Sgonzo *
454239281Sgonzo *	RETURNS:
455239281Sgonzo *	EH_HANDLED or EH_NOT_HANDLED
456239281Sgonzo */
457239281Sgonzoint
458239281Sgonzoti_sdma_disable_channel_irq(unsigned int ch)
459239281Sgonzo{
460239281Sgonzo	struct ti_sdma_softc *sc = ti_sdma_sc;
461239281Sgonzo	uint32_t irq_enable;
462239281Sgonzo	unsigned int j;
463239281Sgonzo
464239281Sgonzo	/* Sanity check */
465239281Sgonzo	if (sc == NULL)
466239281Sgonzo		return (ENOMEM);
467239281Sgonzo
468239281Sgonzo	TI_SDMA_LOCK(sc);
469239281Sgonzo
470239281Sgonzo	if ((sc->sc_active_channels & (1 << ch)) == 0) {
471239281Sgonzo		TI_SDMA_UNLOCK(sc);
472239281Sgonzo		return (EINVAL);
473239281Sgonzo	}
474239281Sgonzo
475239281Sgonzo	/* Disable all the individual error conditions */
476239281Sgonzo	sc->sc_channel[ch].reg_cicr = 0x0000;
477239281Sgonzo	ti_sdma_write_4(sc, DMA4_CICR(ch), 0x0000);
478239281Sgonzo
479239281Sgonzo	/* Disable the channel interrupt enable */
480239281Sgonzo	for (j = 0; j < NUM_DMA_IRQS; j++) {
481239281Sgonzo		irq_enable = ti_sdma_read_4(sc, DMA4_IRQENABLE_L(j));
482239281Sgonzo		irq_enable &= ~(1 << ch);
483239281Sgonzo
484239281Sgonzo		ti_sdma_write_4(sc, DMA4_IRQENABLE_L(j), irq_enable);
485239281Sgonzo	}
486239281Sgonzo
487239281Sgonzo	/* Indicate the registers need to be rewritten on the next transaction */
488239281Sgonzo	sc->sc_channel[ch].need_reg_write = 1;
489239281Sgonzo
490239281Sgonzo	TI_SDMA_UNLOCK(sc);
491239281Sgonzo
492239281Sgonzo	return (0);
493239281Sgonzo}
494239281Sgonzo
495239281Sgonzo/**
496239281Sgonzo *	ti_sdma_disable_channel_irq - enables IRQ's on the given channel
497239281Sgonzo *	@ch: the channel to enable IRQ's on
498239281Sgonzo *	@flags: bitmask of interrupt types to enable
499239281Sgonzo *
500239281Sgonzo *	Flags can be a bitmask of the following options:
501239281Sgonzo *		DMA_IRQ_FLAG_DROP
502239281Sgonzo *		DMA_IRQ_FLAG_HALF_FRAME_COMPL
503239281Sgonzo *		DMA_IRQ_FLAG_FRAME_COMPL
504239281Sgonzo *		DMA_IRQ_FLAG_START_LAST_FRAME
505239281Sgonzo *		DMA_IRQ_FLAG_BLOCK_COMPL
506239281Sgonzo *		DMA_IRQ_FLAG_ENDOF_PKT
507239281Sgonzo *		DMA_IRQ_FLAG_DRAIN
508239281Sgonzo *
509239281Sgonzo *
510239281Sgonzo *	LOCKING:
511239281Sgonzo *	DMA registers protected by internal mutex
512239281Sgonzo *
513239281Sgonzo *	RETURNS:
514239281Sgonzo *	EH_HANDLED or EH_NOT_HANDLED
515239281Sgonzo */
516239281Sgonzoint
517239281Sgonzoti_sdma_enable_channel_irq(unsigned int ch, uint32_t flags)
518239281Sgonzo{
519239281Sgonzo	struct ti_sdma_softc *sc = ti_sdma_sc;
520239281Sgonzo	uint32_t irq_enable;
521239281Sgonzo
522239281Sgonzo	/* Sanity check */
523239281Sgonzo	if (sc == NULL)
524239281Sgonzo		return (ENOMEM);
525239281Sgonzo
526239281Sgonzo	TI_SDMA_LOCK(sc);
527239281Sgonzo
528239281Sgonzo	if ((sc->sc_active_channels & (1 << ch)) == 0) {
529239281Sgonzo		TI_SDMA_UNLOCK(sc);
530239281Sgonzo		return (EINVAL);
531239281Sgonzo	}
532239281Sgonzo
533239281Sgonzo	/* Always enable the error interrupts if we have interrupts enabled */
534239281Sgonzo	flags |= DMA4_CICR_TRANS_ERR_IE | DMA4_CICR_SECURE_ERR_IE |
535239281Sgonzo	         DMA4_CICR_SUPERVISOR_ERR_IE | DMA4_CICR_MISALIGNED_ADRS_ERR_IE;
536239281Sgonzo
537239281Sgonzo	sc->sc_channel[ch].reg_cicr = flags;
538239281Sgonzo
539239281Sgonzo	/* Write the values to the register */
540239281Sgonzo	ti_sdma_write_4(sc, DMA4_CICR(ch), flags);
541239281Sgonzo
542239281Sgonzo	/* Enable the channel interrupt enable */
543239281Sgonzo	irq_enable = ti_sdma_read_4(sc, DMA4_IRQENABLE_L(0));
544239281Sgonzo	irq_enable |= (1 << ch);
545239281Sgonzo
546239281Sgonzo	ti_sdma_write_4(sc, DMA4_IRQENABLE_L(0), irq_enable);
547239281Sgonzo
548239281Sgonzo	/* Indicate the registers need to be rewritten on the next transaction */
549239281Sgonzo	sc->sc_channel[ch].need_reg_write = 1;
550239281Sgonzo
551239281Sgonzo	TI_SDMA_UNLOCK(sc);
552239281Sgonzo
553239281Sgonzo	return (0);
554239281Sgonzo}
555239281Sgonzo
556239281Sgonzo/**
557239281Sgonzo *	ti_sdma_get_channel_status - returns the status of a given channel
558239281Sgonzo *	@ch: the channel number to get the status of
559239281Sgonzo *	@status: upon return will contain the status bitmask, see below for possible
560239281Sgonzo *	         values.
561239281Sgonzo *
562239281Sgonzo *	      DMA_STATUS_DROP
563239281Sgonzo *	      DMA_STATUS_HALF
564239281Sgonzo *	      DMA_STATUS_FRAME
565239281Sgonzo *	      DMA_STATUS_LAST
566239281Sgonzo *	      DMA_STATUS_BLOCK
567239281Sgonzo *	      DMA_STATUS_SYNC
568239281Sgonzo *	      DMA_STATUS_PKT
569239281Sgonzo *	      DMA_STATUS_TRANS_ERR
570239281Sgonzo *	      DMA_STATUS_SECURE_ERR
571239281Sgonzo *	      DMA_STATUS_SUPERVISOR_ERR
572239281Sgonzo *	      DMA_STATUS_MISALIGNED_ADRS_ERR
573239281Sgonzo *	      DMA_STATUS_DRAIN_END
574239281Sgonzo *
575239281Sgonzo *
576239281Sgonzo *	LOCKING:
577239281Sgonzo *	DMA registers protected by internal mutex
578239281Sgonzo *
579239281Sgonzo *	RETURNS:
580239281Sgonzo *	EH_HANDLED or EH_NOT_HANDLED
581239281Sgonzo */
582239281Sgonzoint
583239281Sgonzoti_sdma_get_channel_status(unsigned int ch, uint32_t *status)
584239281Sgonzo{
585239281Sgonzo	struct ti_sdma_softc *sc = ti_sdma_sc;
586239281Sgonzo	uint32_t csr;
587239281Sgonzo
588239281Sgonzo	/* Sanity check */
589239281Sgonzo	if (sc == NULL)
590239281Sgonzo		return (ENOMEM);
591239281Sgonzo
592239281Sgonzo	TI_SDMA_LOCK(sc);
593239281Sgonzo
594239281Sgonzo	if ((sc->sc_active_channels & (1 << ch)) == 0) {
595239281Sgonzo		TI_SDMA_UNLOCK(sc);
596239281Sgonzo		return (EINVAL);
597239281Sgonzo	}
598239281Sgonzo
599239281Sgonzo	TI_SDMA_UNLOCK(sc);
600239281Sgonzo
601239281Sgonzo	csr = ti_sdma_read_4(sc, DMA4_CSR(ch));
602239281Sgonzo
603239281Sgonzo	if (status != NULL)
604239281Sgonzo		*status = csr;
605239281Sgonzo
606239281Sgonzo	return (0);
607239281Sgonzo}
608239281Sgonzo
609239281Sgonzo/**
610239281Sgonzo *	ti_sdma_start_xfer - starts a DMA transfer
611239281Sgonzo *	@ch: the channel number to set the endianess of
612239281Sgonzo *	@src_paddr: the source phsyical address
613239281Sgonzo *	@dst_paddr: the destination phsyical address
614239281Sgonzo *	@frmcnt: the number of frames per block
615239281Sgonzo *	@elmcnt: the number of elements in a frame, an element is either an 8, 16
616239281Sgonzo *           or 32-bit value as defined by ti_sdma_set_xfer_burst()
617239281Sgonzo *
618239281Sgonzo *
619239281Sgonzo *	LOCKING:
620239281Sgonzo *	DMA registers protected by internal mutex
621239281Sgonzo *
622239281Sgonzo *	RETURNS:
623239281Sgonzo *	EH_HANDLED or EH_NOT_HANDLED
624239281Sgonzo */
625239281Sgonzoint
626239281Sgonzoti_sdma_start_xfer(unsigned int ch, unsigned int src_paddr,
627239281Sgonzo                    unsigned long dst_paddr,
628239281Sgonzo                    unsigned int frmcnt, unsigned int elmcnt)
629239281Sgonzo{
630239281Sgonzo	struct ti_sdma_softc *sc = ti_sdma_sc;
631239281Sgonzo	struct ti_sdma_channel *channel;
632239281Sgonzo	uint32_t ccr;
633239281Sgonzo
634239281Sgonzo	/* Sanity check */
635239281Sgonzo	if (sc == NULL)
636239281Sgonzo		return (ENOMEM);
637239281Sgonzo
638239281Sgonzo	TI_SDMA_LOCK(sc);
639239281Sgonzo
640239281Sgonzo	if ((sc->sc_active_channels & (1 << ch)) == 0) {
641239281Sgonzo		TI_SDMA_UNLOCK(sc);
642239281Sgonzo		return (EINVAL);
643239281Sgonzo	}
644239281Sgonzo
645239281Sgonzo	channel = &sc->sc_channel[ch];
646239281Sgonzo
647239281Sgonzo	/* a) Write the CSDP register */
648239281Sgonzo	ti_sdma_write_4(sc, DMA4_CSDP(ch),
649239281Sgonzo	    channel->reg_csdp | DMA4_CSDP_WRITE_MODE(1));
650239281Sgonzo
651239281Sgonzo	/* b) Set the number of element per frame CEN[23:0] */
652239281Sgonzo	ti_sdma_write_4(sc, DMA4_CEN(ch), elmcnt);
653239281Sgonzo
654239281Sgonzo	/* c) Set the number of frame per block CFN[15:0] */
655239281Sgonzo	ti_sdma_write_4(sc, DMA4_CFN(ch), frmcnt);
656239281Sgonzo
657239281Sgonzo	/* d) Set the Source/dest start address index CSSA[31:0]/CDSA[31:0] */
658239281Sgonzo	ti_sdma_write_4(sc, DMA4_CSSA(ch), src_paddr);
659239281Sgonzo	ti_sdma_write_4(sc, DMA4_CDSA(ch), dst_paddr);
660239281Sgonzo
661239281Sgonzo	/* e) Write the CCR register */
662239281Sgonzo	ti_sdma_write_4(sc, DMA4_CCR(ch), channel->reg_ccr);
663239281Sgonzo
664239281Sgonzo	/* f)  - Set the source element index increment CSEI[15:0] */
665239281Sgonzo	ti_sdma_write_4(sc, DMA4_CSE(ch), 0x0001);
666239281Sgonzo
667239281Sgonzo	/*     - Set the source frame index increment CSFI[15:0] */
668239281Sgonzo	ti_sdma_write_4(sc, DMA4_CSF(ch), 0x0001);
669239281Sgonzo
670239281Sgonzo	/*     - Set the destination element index increment CDEI[15:0]*/
671239281Sgonzo	ti_sdma_write_4(sc, DMA4_CDE(ch), 0x0001);
672239281Sgonzo
673239281Sgonzo	/* - Set the destination frame index increment CDFI[31:0] */
674239281Sgonzo	ti_sdma_write_4(sc, DMA4_CDF(ch), 0x0001);
675239281Sgonzo
676239281Sgonzo	/* Clear the status register */
677239281Sgonzo	ti_sdma_write_4(sc, DMA4_CSR(ch), 0x1FFE);
678239281Sgonzo
679239281Sgonzo	/* Write the start-bit and away we go */
680239281Sgonzo	ccr = ti_sdma_read_4(sc, DMA4_CCR(ch));
681239281Sgonzo	ccr |= (1 << 7);
682239281Sgonzo	ti_sdma_write_4(sc, DMA4_CCR(ch), ccr);
683239281Sgonzo
684239281Sgonzo	/* Clear the reg write flag */
685239281Sgonzo	channel->need_reg_write = 0;
686239281Sgonzo
687239281Sgonzo	TI_SDMA_UNLOCK(sc);
688239281Sgonzo
689239281Sgonzo	return (0);
690239281Sgonzo}
691239281Sgonzo
692239281Sgonzo/**
693239281Sgonzo *	ti_sdma_start_xfer_packet - starts a packet DMA transfer
694239281Sgonzo *	@ch: the channel number to use for the transfer
695239281Sgonzo *	@src_paddr: the source physical address
696239281Sgonzo *	@dst_paddr: the destination physical address
697239281Sgonzo *	@frmcnt: the number of frames to transfer
698239281Sgonzo *	@elmcnt: the number of elements in a frame, an element is either an 8, 16
699239281Sgonzo *           or 32-bit value as defined by ti_sdma_set_xfer_burst()
700239281Sgonzo *	@pktsize: the number of elements in each transfer packet
701239281Sgonzo *
702239281Sgonzo *	The @frmcnt and @elmcnt define the overall number of bytes to transfer,
703239281Sgonzo *	typically @frmcnt is 1 and @elmcnt contains the total number of elements.
704239281Sgonzo *	@pktsize is the size of each individual packet, there might be multiple
705239281Sgonzo *	packets per transfer.  i.e. for the following with element size of 32-bits
706239281Sgonzo *
707239281Sgonzo *		frmcnt = 1, elmcnt = 512, pktsize = 128
708239281Sgonzo *
709239281Sgonzo *	       Total transfer bytes = 1 * 512 = 512 elements or 2048 bytes
710239281Sgonzo *	       Packets transfered   = 128 / 512 = 4
711239281Sgonzo *
712239281Sgonzo *
713239281Sgonzo *	LOCKING:
714239281Sgonzo *	DMA registers protected by internal mutex
715239281Sgonzo *
716239281Sgonzo *	RETURNS:
717239281Sgonzo *	EH_HANDLED or EH_NOT_HANDLED
718239281Sgonzo */
719239281Sgonzoint
720239281Sgonzoti_sdma_start_xfer_packet(unsigned int ch, unsigned int src_paddr,
721239281Sgonzo                           unsigned long dst_paddr, unsigned int frmcnt,
722239281Sgonzo                           unsigned int elmcnt, unsigned int pktsize)
723239281Sgonzo{
724239281Sgonzo	struct ti_sdma_softc *sc = ti_sdma_sc;
725239281Sgonzo	struct ti_sdma_channel *channel;
726239281Sgonzo	uint32_t ccr;
727239281Sgonzo
728239281Sgonzo	/* Sanity check */
729239281Sgonzo	if (sc == NULL)
730239281Sgonzo		return (ENOMEM);
731239281Sgonzo
732239281Sgonzo	TI_SDMA_LOCK(sc);
733239281Sgonzo
734239281Sgonzo	if ((sc->sc_active_channels & (1 << ch)) == 0) {
735239281Sgonzo		TI_SDMA_UNLOCK(sc);
736239281Sgonzo		return (EINVAL);
737239281Sgonzo	}
738239281Sgonzo
739239281Sgonzo	channel = &sc->sc_channel[ch];
740239281Sgonzo
741239281Sgonzo	/* a) Write the CSDP register */
742239281Sgonzo	if (channel->need_reg_write)
743239281Sgonzo		ti_sdma_write_4(sc, DMA4_CSDP(ch),
744239281Sgonzo		    channel->reg_csdp | DMA4_CSDP_WRITE_MODE(1));
745239281Sgonzo
746239281Sgonzo	/* b) Set the number of elements to transfer CEN[23:0] */
747239281Sgonzo	ti_sdma_write_4(sc, DMA4_CEN(ch), elmcnt);
748239281Sgonzo
749239281Sgonzo	/* c) Set the number of frames to transfer CFN[15:0] */
750239281Sgonzo	ti_sdma_write_4(sc, DMA4_CFN(ch), frmcnt);
751239281Sgonzo
752239281Sgonzo	/* d) Set the Source/dest start address index CSSA[31:0]/CDSA[31:0] */
753239281Sgonzo	ti_sdma_write_4(sc, DMA4_CSSA(ch), src_paddr);
754239281Sgonzo	ti_sdma_write_4(sc, DMA4_CDSA(ch), dst_paddr);
755239281Sgonzo
756239281Sgonzo	/* e) Write the CCR register */
757239281Sgonzo	ti_sdma_write_4(sc, DMA4_CCR(ch),
758239281Sgonzo	    channel->reg_ccr | DMA4_CCR_PACKET_TRANS);
759239281Sgonzo
760239281Sgonzo	/* f)  - Set the source element index increment CSEI[15:0] */
761239281Sgonzo	ti_sdma_write_4(sc, DMA4_CSE(ch), 0x0001);
762239281Sgonzo
763239281Sgonzo	/*     - Set the packet size, this is dependent on the sync source */
764239281Sgonzo	if (channel->reg_ccr & DMA4_CCR_SEL_SRC_DST_SYNC(1))
765239281Sgonzo		ti_sdma_write_4(sc, DMA4_CSF(ch), pktsize);
766239281Sgonzo	else
767239281Sgonzo		ti_sdma_write_4(sc, DMA4_CDF(ch), pktsize);
768239281Sgonzo
769239281Sgonzo	/* - Set the destination frame index increment CDFI[31:0] */
770239281Sgonzo	ti_sdma_write_4(sc, DMA4_CDE(ch), 0x0001);
771239281Sgonzo
772239281Sgonzo	/* Clear the status register */
773239281Sgonzo	ti_sdma_write_4(sc, DMA4_CSR(ch), 0x1FFE);
774239281Sgonzo
775239281Sgonzo	/* Write the start-bit and away we go */
776239281Sgonzo	ccr = ti_sdma_read_4(sc, DMA4_CCR(ch));
777239281Sgonzo	ccr |= (1 << 7);
778239281Sgonzo	ti_sdma_write_4(sc, DMA4_CCR(ch), ccr);
779239281Sgonzo
780239281Sgonzo	/* Clear the reg write flag */
781239281Sgonzo	channel->need_reg_write = 0;
782239281Sgonzo
783239281Sgonzo	TI_SDMA_UNLOCK(sc);
784239281Sgonzo
785239281Sgonzo	return (0);
786239281Sgonzo}
787239281Sgonzo
788239281Sgonzo/**
789239281Sgonzo *	ti_sdma_stop_xfer - stops any currently active transfers
790239281Sgonzo *	@ch: the channel number to set the endianess of
791239281Sgonzo *
792239281Sgonzo *	This function call is effectively a NOP if no transaction is in progress.
793239281Sgonzo *
794239281Sgonzo *	LOCKING:
795239281Sgonzo *	DMA registers protected by internal mutex
796239281Sgonzo *
797239281Sgonzo *	RETURNS:
798239281Sgonzo *	EH_HANDLED or EH_NOT_HANDLED
799239281Sgonzo */
800239281Sgonzoint
801239281Sgonzoti_sdma_stop_xfer(unsigned int ch)
802239281Sgonzo{
803239281Sgonzo	struct ti_sdma_softc *sc = ti_sdma_sc;
804239281Sgonzo	unsigned int j;
805239281Sgonzo
806239281Sgonzo	/* Sanity check */
807239281Sgonzo	if (sc == NULL)
808239281Sgonzo		return (ENOMEM);
809239281Sgonzo
810239281Sgonzo	TI_SDMA_LOCK(sc);
811239281Sgonzo
812239281Sgonzo	if ((sc->sc_active_channels & (1 << ch)) == 0) {
813239281Sgonzo		TI_SDMA_UNLOCK(sc);
814239281Sgonzo		return (EINVAL);
815239281Sgonzo	}
816239281Sgonzo
817239281Sgonzo	/* Disable all DMA interrupts for the channel. */
818239281Sgonzo	ti_sdma_write_4(sc, DMA4_CICR(ch), 0);
819239281Sgonzo
820239281Sgonzo	/* Make sure the DMA transfer is stopped. */
821239281Sgonzo	ti_sdma_write_4(sc, DMA4_CCR(ch), 0);
822239281Sgonzo
823239281Sgonzo	/* Clear the CSR register and IRQ status register */
824239281Sgonzo	ti_sdma_write_4(sc, DMA4_CSR(ch), DMA4_CSR_CLEAR_MASK);
825239281Sgonzo	for (j = 0; j < NUM_DMA_IRQS; j++) {
826239281Sgonzo		ti_sdma_write_4(sc, DMA4_IRQSTATUS_L(j), (1 << ch));
827239281Sgonzo	}
828239281Sgonzo
829239281Sgonzo	/* Configuration registers need to be re-written on the next xfer */
830239281Sgonzo	sc->sc_channel[ch].need_reg_write = 1;
831239281Sgonzo
832239281Sgonzo	TI_SDMA_UNLOCK(sc);
833239281Sgonzo
834239281Sgonzo	return (0);
835239281Sgonzo}
836239281Sgonzo
837239281Sgonzo/**
838239281Sgonzo *	ti_sdma_set_xfer_endianess - sets the endianess of subsequent transfers
839239281Sgonzo *	@ch: the channel number to set the endianess of
840239281Sgonzo *	@src: the source endianess (either DMA_ENDIAN_LITTLE or DMA_ENDIAN_BIG)
841239281Sgonzo *	@dst: the destination endianess (either DMA_ENDIAN_LITTLE or DMA_ENDIAN_BIG)
842239281Sgonzo *
843239281Sgonzo *
844239281Sgonzo *	LOCKING:
845239281Sgonzo *	DMA registers protected by internal mutex
846239281Sgonzo *
847239281Sgonzo *	RETURNS:
848239281Sgonzo *	EH_HANDLED or EH_NOT_HANDLED
849239281Sgonzo */
850239281Sgonzoint
851239281Sgonzoti_sdma_set_xfer_endianess(unsigned int ch, unsigned int src, unsigned int dst)
852239281Sgonzo{
853239281Sgonzo	struct ti_sdma_softc *sc = ti_sdma_sc;
854239281Sgonzo
855239281Sgonzo	/* Sanity check */
856239281Sgonzo	if (sc == NULL)
857239281Sgonzo		return (ENOMEM);
858239281Sgonzo
859239281Sgonzo	TI_SDMA_LOCK(sc);
860239281Sgonzo
861239281Sgonzo	if ((sc->sc_active_channels & (1 << ch)) == 0) {
862239281Sgonzo		TI_SDMA_UNLOCK(sc);
863239281Sgonzo		return (EINVAL);
864239281Sgonzo	}
865239281Sgonzo
866239281Sgonzo	sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_SRC_ENDIANISM(1);
867239281Sgonzo	sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_SRC_ENDIANISM(src);
868239281Sgonzo
869239281Sgonzo	sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_DST_ENDIANISM(1);
870239281Sgonzo	sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_DST_ENDIANISM(dst);
871239281Sgonzo
872239281Sgonzo	sc->sc_channel[ch].need_reg_write = 1;
873239281Sgonzo
874239281Sgonzo	TI_SDMA_UNLOCK(sc);
875239281Sgonzo
876239281Sgonzo	return 0;
877239281Sgonzo}
878239281Sgonzo
879239281Sgonzo/**
880239281Sgonzo *	ti_sdma_set_xfer_burst - sets the source and destination element size
881239281Sgonzo *	@ch: the channel number to set the burst settings of
882239281Sgonzo *	@src: the source endianess (either DMA_BURST_NONE, DMA_BURST_16, DMA_BURST_32
883239281Sgonzo *	      or DMA_BURST_64)
884239281Sgonzo *	@dst: the destination endianess (either DMA_BURST_NONE, DMA_BURST_16,
885239281Sgonzo *	      DMA_BURST_32 or DMA_BURST_64)
886239281Sgonzo *
887239281Sgonzo *	This function sets the size of the elements for all subsequent transfers.
888239281Sgonzo *
889239281Sgonzo *	LOCKING:
890239281Sgonzo *	DMA registers protected by internal mutex
891239281Sgonzo *
892239281Sgonzo *	RETURNS:
893239281Sgonzo *	EH_HANDLED or EH_NOT_HANDLED
894239281Sgonzo */
895239281Sgonzoint
896239281Sgonzoti_sdma_set_xfer_burst(unsigned int ch, unsigned int src, unsigned int dst)
897239281Sgonzo{
898239281Sgonzo	struct ti_sdma_softc *sc = ti_sdma_sc;
899239281Sgonzo
900239281Sgonzo	/* Sanity check */
901239281Sgonzo	if (sc == NULL)
902239281Sgonzo		return (ENOMEM);
903239281Sgonzo
904239281Sgonzo	TI_SDMA_LOCK(sc);
905239281Sgonzo
906239281Sgonzo	if ((sc->sc_active_channels & (1 << ch)) == 0) {
907239281Sgonzo		TI_SDMA_UNLOCK(sc);
908239281Sgonzo		return (EINVAL);
909239281Sgonzo	}
910239281Sgonzo
911239281Sgonzo	sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_SRC_BURST_MODE(0x3);
912239281Sgonzo	sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_SRC_BURST_MODE(src);
913239281Sgonzo
914239281Sgonzo	sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_DST_BURST_MODE(0x3);
915239281Sgonzo	sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_DST_BURST_MODE(dst);
916239281Sgonzo
917239281Sgonzo	sc->sc_channel[ch].need_reg_write = 1;
918239281Sgonzo
919239281Sgonzo	TI_SDMA_UNLOCK(sc);
920239281Sgonzo
921239281Sgonzo	return 0;
922239281Sgonzo}
923239281Sgonzo
924239281Sgonzo/**
925239281Sgonzo *	ti_sdma_set_xfer_data_type - driver attach function
926239281Sgonzo *	@ch: the channel number to set the endianess of
927239281Sgonzo *	@type: the xfer data type (either DMA_DATA_8BITS_SCALAR, DMA_DATA_16BITS_SCALAR
928239281Sgonzo *	       or DMA_DATA_32BITS_SCALAR)
929239281Sgonzo *
930239281Sgonzo *
931239281Sgonzo *	LOCKING:
932239281Sgonzo *	DMA registers protected by internal mutex
933239281Sgonzo *
934239281Sgonzo *	RETURNS:
935239281Sgonzo *	EH_HANDLED or EH_NOT_HANDLED
936239281Sgonzo */
937239281Sgonzoint
938239281Sgonzoti_sdma_set_xfer_data_type(unsigned int ch, unsigned int type)
939239281Sgonzo{
940239281Sgonzo	struct ti_sdma_softc *sc = ti_sdma_sc;
941239281Sgonzo
942239281Sgonzo	/* Sanity check */
943239281Sgonzo	if (sc == NULL)
944239281Sgonzo		return (ENOMEM);
945239281Sgonzo
946239281Sgonzo	TI_SDMA_LOCK(sc);
947239281Sgonzo
948239281Sgonzo	if ((sc->sc_active_channels & (1 << ch)) == 0) {
949239281Sgonzo		TI_SDMA_UNLOCK(sc);
950239281Sgonzo		return (EINVAL);
951239281Sgonzo	}
952239281Sgonzo
953239281Sgonzo	sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_DATA_TYPE(0x3);
954239281Sgonzo	sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_DATA_TYPE(type);
955239281Sgonzo
956239281Sgonzo	sc->sc_channel[ch].need_reg_write = 1;
957239281Sgonzo
958239281Sgonzo	TI_SDMA_UNLOCK(sc);
959239281Sgonzo
960239281Sgonzo	return 0;
961239281Sgonzo}
962239281Sgonzo
963239281Sgonzo/**
964239281Sgonzo *	ti_sdma_set_callback - driver attach function
965239281Sgonzo *	@dev: dma device handle
966239281Sgonzo *
967239281Sgonzo *
968239281Sgonzo *
969239281Sgonzo *	LOCKING:
970239281Sgonzo *	DMA registers protected by internal mutex
971239281Sgonzo *
972239281Sgonzo *	RETURNS:
973239281Sgonzo *	EH_HANDLED or EH_NOT_HANDLED
974239281Sgonzo */
975239281Sgonzoint
976239281Sgonzoti_sdma_set_callback(unsigned int ch,
977239281Sgonzo                      void (*callback)(unsigned int ch, uint32_t status, void *data),
978239281Sgonzo                      void *data)
979239281Sgonzo{
980239281Sgonzo	struct ti_sdma_softc *sc = ti_sdma_sc;
981239281Sgonzo
982239281Sgonzo	/* Sanity check */
983239281Sgonzo	if (sc == NULL)
984239281Sgonzo		return (ENOMEM);
985239281Sgonzo
986239281Sgonzo	TI_SDMA_LOCK(sc);
987239281Sgonzo
988239281Sgonzo	if ((sc->sc_active_channels & (1 << ch)) == 0) {
989239281Sgonzo		TI_SDMA_UNLOCK(sc);
990239281Sgonzo		return (EINVAL);
991239281Sgonzo	}
992239281Sgonzo
993239281Sgonzo	sc->sc_channel[ch].callback = callback;
994239281Sgonzo	sc->sc_channel[ch].callback_data = data;
995239281Sgonzo
996239281Sgonzo	sc->sc_channel[ch].need_reg_write = 1;
997239281Sgonzo
998239281Sgonzo	TI_SDMA_UNLOCK(sc);
999239281Sgonzo
1000239281Sgonzo	return 0;
1001239281Sgonzo}
1002239281Sgonzo
1003239281Sgonzo/**
1004239281Sgonzo *	ti_sdma_sync_params - sets channel sync settings
1005239281Sgonzo *	@ch: the channel number to set the sync on
1006239281Sgonzo *	@trigger: the number of the sync trigger, this depends on what other H/W
1007239281Sgonzo *	          module is triggering/receiving the DMA transactions
1008239281Sgonzo *	@mode: flags describing the sync mode to use, it may have one or more of
1009239281Sgonzo *	          the following bits set; TI_SDMA_SYNC_FRAME,
1010239281Sgonzo *	          TI_SDMA_SYNC_BLOCK, TI_SDMA_SYNC_TRIG_ON_SRC.
1011239281Sgonzo *
1012239281Sgonzo *
1013239281Sgonzo *
1014239281Sgonzo *	LOCKING:
1015239281Sgonzo *	DMA registers protected by internal mutex
1016239281Sgonzo *
1017239281Sgonzo *	RETURNS:
1018239281Sgonzo *	EH_HANDLED or EH_NOT_HANDLED
1019239281Sgonzo */
1020239281Sgonzoint
1021239281Sgonzoti_sdma_sync_params(unsigned int ch, unsigned int trigger, unsigned int mode)
1022239281Sgonzo{
1023239281Sgonzo	struct ti_sdma_softc *sc = ti_sdma_sc;
1024239281Sgonzo	uint32_t ccr;
1025239281Sgonzo
1026239281Sgonzo	/* Sanity check */
1027239281Sgonzo	if (sc == NULL)
1028239281Sgonzo		return (ENOMEM);
1029239281Sgonzo
1030239281Sgonzo	TI_SDMA_LOCK(sc);
1031239281Sgonzo
1032239281Sgonzo	if ((sc->sc_active_channels & (1 << ch)) == 0) {
1033239281Sgonzo		TI_SDMA_UNLOCK(sc);
1034239281Sgonzo		return (EINVAL);
1035239281Sgonzo	}
1036239281Sgonzo
1037239281Sgonzo	ccr = sc->sc_channel[ch].reg_ccr;
1038239281Sgonzo
1039239281Sgonzo	ccr &= ~DMA4_CCR_SYNC_TRIGGER(0x7F);
1040239281Sgonzo	ccr |= DMA4_CCR_SYNC_TRIGGER(trigger + 1);
1041239281Sgonzo
1042239281Sgonzo	if (mode & TI_SDMA_SYNC_FRAME)
1043239281Sgonzo		ccr |= DMA4_CCR_FRAME_SYNC(1);
1044239281Sgonzo	else
1045239281Sgonzo		ccr &= ~DMA4_CCR_FRAME_SYNC(1);
1046239281Sgonzo
1047239281Sgonzo	if (mode & TI_SDMA_SYNC_BLOCK)
1048239281Sgonzo		ccr |= DMA4_CCR_BLOCK_SYNC(1);
1049239281Sgonzo	else
1050239281Sgonzo		ccr &= ~DMA4_CCR_BLOCK_SYNC(1);
1051239281Sgonzo
1052239281Sgonzo	if (mode & TI_SDMA_SYNC_TRIG_ON_SRC)
1053239281Sgonzo		ccr |= DMA4_CCR_SEL_SRC_DST_SYNC(1);
1054239281Sgonzo	else
1055239281Sgonzo		ccr &= ~DMA4_CCR_SEL_SRC_DST_SYNC(1);
1056239281Sgonzo
1057239281Sgonzo	sc->sc_channel[ch].reg_ccr = ccr;
1058239281Sgonzo
1059239281Sgonzo	sc->sc_channel[ch].need_reg_write = 1;
1060239281Sgonzo
1061239281Sgonzo	TI_SDMA_UNLOCK(sc);
1062239281Sgonzo
1063239281Sgonzo	return 0;
1064239281Sgonzo}
1065239281Sgonzo
1066239281Sgonzo/**
1067239281Sgonzo *	ti_sdma_set_addr_mode - driver attach function
1068239281Sgonzo *	@ch: the channel number to set the endianess of
1069239281Sgonzo *	@rd_mode: the xfer source addressing mode (either DMA_ADDR_CONSTANT,
1070239281Sgonzo *	          DMA_ADDR_POST_INCREMENT, DMA_ADDR_SINGLE_INDEX or
1071239281Sgonzo *	          DMA_ADDR_DOUBLE_INDEX)
1072239281Sgonzo *	@wr_mode: the xfer destination addressing mode (either DMA_ADDR_CONSTANT,
1073239281Sgonzo *	          DMA_ADDR_POST_INCREMENT, DMA_ADDR_SINGLE_INDEX or
1074239281Sgonzo *	          DMA_ADDR_DOUBLE_INDEX)
1075239281Sgonzo *
1076239281Sgonzo *
1077239281Sgonzo *	LOCKING:
1078239281Sgonzo *	DMA registers protected by internal mutex
1079239281Sgonzo *
1080239281Sgonzo *	RETURNS:
1081239281Sgonzo *	EH_HANDLED or EH_NOT_HANDLED
1082239281Sgonzo */
1083239281Sgonzoint
1084239281Sgonzoti_sdma_set_addr_mode(unsigned int ch, unsigned int src_mode,
1085239281Sgonzo                       unsigned int dst_mode)
1086239281Sgonzo{
1087239281Sgonzo	struct ti_sdma_softc *sc = ti_sdma_sc;
1088239281Sgonzo	uint32_t ccr;
1089239281Sgonzo
1090239281Sgonzo	/* Sanity check */
1091239281Sgonzo	if (sc == NULL)
1092239281Sgonzo		return (ENOMEM);
1093239281Sgonzo
1094239281Sgonzo	TI_SDMA_LOCK(sc);
1095239281Sgonzo
1096239281Sgonzo	if ((sc->sc_active_channels & (1 << ch)) == 0) {
1097239281Sgonzo		TI_SDMA_UNLOCK(sc);
1098239281Sgonzo		return (EINVAL);
1099239281Sgonzo	}
1100239281Sgonzo
1101239281Sgonzo	ccr = sc->sc_channel[ch].reg_ccr;
1102239281Sgonzo
1103239281Sgonzo	ccr &= ~DMA4_CCR_SRC_ADDRESS_MODE(0x3);
1104239281Sgonzo	ccr |= DMA4_CCR_SRC_ADDRESS_MODE(src_mode);
1105239281Sgonzo
1106239281Sgonzo	ccr &= ~DMA4_CCR_DST_ADDRESS_MODE(0x3);
1107239281Sgonzo	ccr |= DMA4_CCR_DST_ADDRESS_MODE(dst_mode);
1108239281Sgonzo
1109239281Sgonzo	sc->sc_channel[ch].reg_ccr = ccr;
1110239281Sgonzo
1111239281Sgonzo	sc->sc_channel[ch].need_reg_write = 1;
1112239281Sgonzo
1113239281Sgonzo	TI_SDMA_UNLOCK(sc);
1114239281Sgonzo
1115239281Sgonzo	return 0;
1116239281Sgonzo}
1117239281Sgonzo
1118239281Sgonzo/**
1119239281Sgonzo *	ti_sdma_probe - driver probe function
1120239281Sgonzo *	@dev: dma device handle
1121239281Sgonzo *
1122239281Sgonzo *
1123239281Sgonzo *
1124239281Sgonzo *	RETURNS:
1125239281Sgonzo *	Always returns 0.
1126239281Sgonzo */
1127239281Sgonzostatic int
1128239281Sgonzoti_sdma_probe(device_t dev)
1129239281Sgonzo{
1130266152Sian
1131266152Sian	if (!ofw_bus_status_okay(dev))
1132266152Sian		return (ENXIO);
1133266152Sian
1134239281Sgonzo	if (!ofw_bus_is_compatible(dev, "ti,sdma"))
1135239281Sgonzo		return (ENXIO);
1136239281Sgonzo
1137239281Sgonzo	device_set_desc(dev, "TI sDMA Controller");
1138239281Sgonzo	return (0);
1139239281Sgonzo}
1140239281Sgonzo
1141239281Sgonzo/**
1142239281Sgonzo *	ti_sdma_attach - driver attach function
1143239281Sgonzo *	@dev: dma device handle
1144239281Sgonzo *
1145239281Sgonzo *	Initialises memory mapping/pointers to the DMA register set and requests
1146239281Sgonzo *	IRQs. This is effectively the setup function for the driver.
1147239281Sgonzo *
1148239281Sgonzo *	RETURNS:
1149239281Sgonzo *	0 on success or a negative error code failure.
1150239281Sgonzo */
1151239281Sgonzostatic int
1152239281Sgonzoti_sdma_attach(device_t dev)
1153239281Sgonzo{
1154239281Sgonzo	struct ti_sdma_softc *sc = device_get_softc(dev);
1155239281Sgonzo	unsigned int timeout;
1156239281Sgonzo	unsigned int i;
1157239281Sgonzo	int      rid;
1158239281Sgonzo	void    *ihl;
1159239281Sgonzo	int      err;
1160239281Sgonzo
1161239281Sgonzo	/* Setup the basics */
1162239281Sgonzo	sc->sc_dev = dev;
1163239281Sgonzo
1164239281Sgonzo	/* No channels active at the moment */
1165239281Sgonzo	sc->sc_active_channels = 0x00000000;
1166239281Sgonzo
1167239281Sgonzo	/* Mutex to protect the shared data structures */
1168239281Sgonzo	TI_SDMA_LOCK_INIT(sc);
1169239281Sgonzo
1170239281Sgonzo	/* Get the memory resource for the register mapping */
1171239281Sgonzo	rid = 0;
1172239281Sgonzo	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
1173239281Sgonzo	if (sc->sc_mem_res == NULL)
1174239281Sgonzo		panic("%s: Cannot map registers", device_get_name(dev));
1175239281Sgonzo
1176239281Sgonzo	/* Enable the interface and functional clocks */
1177239281Sgonzo	ti_prcm_clk_enable(SDMA_CLK);
1178239281Sgonzo
1179239281Sgonzo	/* Read the sDMA revision register and sanity check it's known */
1180239281Sgonzo	sc->sc_hw_rev = ti_sdma_read_4(sc, DMA4_REVISION);
1181239281Sgonzo	device_printf(dev, "sDMA revision %08x\n", sc->sc_hw_rev);
1182239281Sgonzo
1183239281Sgonzo	if (!ti_sdma_is_omap4_rev(sc) && !ti_sdma_is_omap3_rev(sc)) {
1184239281Sgonzo		device_printf(sc->sc_dev, "error - unknown sDMA H/W revision\n");
1185239281Sgonzo		return (EINVAL);
1186239281Sgonzo	}
1187239281Sgonzo
1188239281Sgonzo	/* Disable all interrupts */
1189239281Sgonzo	for (i = 0; i < NUM_DMA_IRQS; i++) {
1190239281Sgonzo		ti_sdma_write_4(sc, DMA4_IRQENABLE_L(i), 0x00000000);
1191239281Sgonzo	}
1192239281Sgonzo
1193239281Sgonzo	/* Soft-reset is only supported on pre-OMAP44xx devices */
1194239281Sgonzo	if (ti_sdma_is_omap3_rev(sc)) {
1195239281Sgonzo
1196239281Sgonzo		/* Soft-reset */
1197239281Sgonzo		ti_sdma_write_4(sc, DMA4_OCP_SYSCONFIG, 0x0002);
1198239281Sgonzo
1199239281Sgonzo		/* Set the timeout to 100ms*/
1200239281Sgonzo		timeout = (hz < 10) ? 1 : ((100 * hz) / 1000);
1201239281Sgonzo
1202239281Sgonzo		/* Wait for DMA reset to complete */
1203239281Sgonzo		while ((ti_sdma_read_4(sc, DMA4_SYSSTATUS) & 0x1) == 0x0) {
1204239281Sgonzo
1205239281Sgonzo			/* Sleep for a tick */
1206239281Sgonzo			pause("DMARESET", 1);
1207239281Sgonzo
1208239281Sgonzo			if (timeout-- == 0) {
1209239281Sgonzo				device_printf(sc->sc_dev, "sDMA reset operation timed out\n");
1210239281Sgonzo				return (EINVAL);
1211239281Sgonzo			}
1212239281Sgonzo		}
1213239281Sgonzo	}
1214239281Sgonzo
1215239281Sgonzo	/*
1216239281Sgonzo	 * Install interrupt handlers for the for possible interrupts. Any channel
1217239281Sgonzo	 * can trip one of the four IRQs
1218239281Sgonzo	 */
1219239281Sgonzo	rid = 0;
1220239281Sgonzo	sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
1221239281Sgonzo	    RF_ACTIVE | RF_SHAREABLE);
1222239281Sgonzo	if (sc->sc_irq_res == NULL)
1223239281Sgonzo		panic("Unable to setup the dma irq handler.\n");
1224239281Sgonzo
1225239281Sgonzo	err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
1226239281Sgonzo	    NULL, ti_sdma_intr, NULL, &ihl);
1227239281Sgonzo	if (err)
1228239281Sgonzo		panic("%s: Cannot register IRQ", device_get_name(dev));
1229239281Sgonzo
1230239281Sgonzo	/* Store the DMA structure globally ... this driver should never be unloaded */
1231239281Sgonzo	ti_sdma_sc = sc;
1232239281Sgonzo
1233239281Sgonzo	return (0);
1234239281Sgonzo}
1235239281Sgonzo
1236239281Sgonzostatic device_method_t ti_sdma_methods[] = {
1237239281Sgonzo	DEVMETHOD(device_probe, ti_sdma_probe),
1238239281Sgonzo	DEVMETHOD(device_attach, ti_sdma_attach),
1239239281Sgonzo	{0, 0},
1240239281Sgonzo};
1241239281Sgonzo
1242239281Sgonzostatic driver_t ti_sdma_driver = {
1243239281Sgonzo	"ti_sdma",
1244239281Sgonzo	ti_sdma_methods,
1245239281Sgonzo	sizeof(struct ti_sdma_softc),
1246239281Sgonzo};
1247239281Sgonzostatic devclass_t ti_sdma_devclass;
1248239281Sgonzo
1249239281SgonzoDRIVER_MODULE(ti_sdma, simplebus, ti_sdma_driver, ti_sdma_devclass, 0, 0);
1250239281SgonzoMODULE_DEPEND(ti_sdma, ti_prcm, 1, 1, 1);
1251