dbdma.c 28.3 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/*
 *
 * BRIEF MODULE DESCRIPTION
 *      The Descriptor Based DMA channel manager that first appeared
 *	on the Au1550.  I started with dma.c, but I think all that is
 *	left is this initial comment :-)
 *
 * Copyright 2004 Embedded Edge, LLC
 *	dan@embeddededge.com
 *
 *  This program is free software; you can redistribute  it and/or modify it
 *  under  the terms of  the GNU General  Public License as published by the
 *  Free Software Foundation;  either version 2 of the  License, or (at your
 *  option) any later version.
 *
 *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
 *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
 *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
 *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *  You should have received a copy of the  GNU General Public License along
 *  with this program; if not, write  to the Free Software Foundation, Inc.,
 *  675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */
P
Pete Popov 已提交
32

L
Linus Torvalds 已提交
33 34 35 36
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
37
#include <linux/module.h>
L
Linus Torvalds 已提交
38 39
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1xxx_dbdma.h>
P
Pete Popov 已提交
40

L
Linus Torvalds 已提交
41 42 43 44 45 46 47 48 49 50 51 52 53
#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200)

/*
 * The Descriptor Based DMA supports up to 16 channels.
 *
 * There are 32 devices defined. We keep an internal structure
 * of devices using these channels, along with additional
 * information.
 *
 * We allocate the descriptors and allow access to them through various
 * functions.  The drivers allocate the data buffers and assign them
 * to the descriptors.
 */
54
static DEFINE_SPINLOCK(au1xxx_dbdma_spin_lock);
L
Linus Torvalds 已提交
55

56
/* I couldn't find a macro that did this... */
L
Linus Torvalds 已提交
57 58
#define ALIGN_ADDR(x, a)	((((u32)(x)) + (a-1)) & ~(a-1))

P
Pete Popov 已提交
59
static dbdma_global_t *dbdma_gptr = (dbdma_global_t *)DDMA_GLOBAL_BASE;
60
static int dbdma_initialized;
L
Linus Torvalds 已提交
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
static void au1xxx_dbdma_init(void);

static dbdev_tab_t dbdev_tab[] = {
#ifdef CONFIG_SOC_AU1550
	/* UARTS */
	{ DSCR_CMD0_UART0_TX, DEV_FLAGS_OUT, 0, 8, 0x11100004, 0, 0 },
	{ DSCR_CMD0_UART0_RX, DEV_FLAGS_IN, 0, 8, 0x11100000, 0, 0 },
	{ DSCR_CMD0_UART3_TX, DEV_FLAGS_OUT, 0, 8, 0x11400004, 0, 0 },
	{ DSCR_CMD0_UART3_RX, DEV_FLAGS_IN, 0, 8, 0x11400000, 0, 0 },

	/* EXT DMA */
	{ DSCR_CMD0_DMA_REQ0, 0, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_DMA_REQ1, 0, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_DMA_REQ2, 0, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_DMA_REQ3, 0, 0, 0, 0x00000000, 0, 0 },

	/* USB DEV */
	{ DSCR_CMD0_USBDEV_RX0, DEV_FLAGS_IN, 4, 8, 0x10200000, 0, 0 },
	{ DSCR_CMD0_USBDEV_TX0, DEV_FLAGS_OUT, 4, 8, 0x10200004, 0, 0 },
	{ DSCR_CMD0_USBDEV_TX1, DEV_FLAGS_OUT, 4, 8, 0x10200008, 0, 0 },
	{ DSCR_CMD0_USBDEV_TX2, DEV_FLAGS_OUT, 4, 8, 0x1020000c, 0, 0 },
	{ DSCR_CMD0_USBDEV_RX3, DEV_FLAGS_IN, 4, 8, 0x10200010, 0, 0 },
	{ DSCR_CMD0_USBDEV_RX4, DEV_FLAGS_IN, 4, 8, 0x10200014, 0, 0 },

	/* PSC 0 */
	{ DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT, 0, 0, 0x11a0001c, 0, 0 },
	{ DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN, 0, 0, 0x11a0001c, 0, 0 },

	/* PSC 1 */
	{ DSCR_CMD0_PSC1_TX, DEV_FLAGS_OUT, 0, 0, 0x11b0001c, 0, 0 },
	{ DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN, 0, 0, 0x11b0001c, 0, 0 },

	/* PSC 2 */
	{ DSCR_CMD0_PSC2_TX, DEV_FLAGS_OUT, 0, 0, 0x10a0001c, 0, 0 },
	{ DSCR_CMD0_PSC2_RX, DEV_FLAGS_IN, 0, 0, 0x10a0001c, 0, 0 },

	/* PSC 3 */
	{ DSCR_CMD0_PSC3_TX, DEV_FLAGS_OUT, 0, 0, 0x10b0001c, 0, 0 },
	{ DSCR_CMD0_PSC3_RX, DEV_FLAGS_IN, 0, 0, 0x10b0001c, 0, 0 },

	{ DSCR_CMD0_PCI_WRITE, 0, 0, 0, 0x00000000, 0, 0 },	/* PCI */
	{ DSCR_CMD0_NAND_FLASH, 0, 0, 0, 0x00000000, 0, 0 },	/* NAND */

	/* MAC 0 */
	{ DSCR_CMD0_MAC0_RX, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_MAC0_TX, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 },

	/* MAC 1 */
	{ DSCR_CMD0_MAC1_RX, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_MAC1_TX, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 },

#endif /* CONFIG_SOC_AU1550 */

#ifdef CONFIG_SOC_AU1200
	{ DSCR_CMD0_UART0_TX, DEV_FLAGS_OUT, 0, 8, 0x11100004, 0, 0 },
	{ DSCR_CMD0_UART0_RX, DEV_FLAGS_IN, 0, 8, 0x11100000, 0, 0 },
	{ DSCR_CMD0_UART1_TX, DEV_FLAGS_OUT, 0, 8, 0x11200004, 0, 0 },
	{ DSCR_CMD0_UART1_RX, DEV_FLAGS_IN, 0, 8, 0x11200000, 0, 0 },

	{ DSCR_CMD0_DMA_REQ0, 0, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_DMA_REQ1, 0, 0, 0, 0x00000000, 0, 0 },

	{ DSCR_CMD0_MAE_BE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_MAE_FE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_MAE_BOTH, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_LCD, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },

P
Pete Popov 已提交
128 129 130 131
	{ DSCR_CMD0_SDMS_TX0, DEV_FLAGS_OUT, 4, 8, 0x10600000, 0, 0 },
	{ DSCR_CMD0_SDMS_RX0, DEV_FLAGS_IN, 4, 8, 0x10600004, 0, 0 },
	{ DSCR_CMD0_SDMS_TX1, DEV_FLAGS_OUT, 4, 8, 0x10680000, 0, 0 },
	{ DSCR_CMD0_SDMS_RX1, DEV_FLAGS_IN, 4, 8, 0x10680004, 0, 0 },
L
Linus Torvalds 已提交
132

P
Pete Popov 已提交
133 134
	{ DSCR_CMD0_AES_RX, DEV_FLAGS_IN , 4, 32, 0x10300008, 0, 0 },
	{ DSCR_CMD0_AES_TX, DEV_FLAGS_OUT, 4, 32, 0x10300004, 0, 0 },
L
Linus Torvalds 已提交
135

P
Pete Popov 已提交
136 137
	{ DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT, 0, 16, 0x11a0001c, 0, 0 },
	{ DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN, 0, 16, 0x11a0001c, 0, 0 },
L
Linus Torvalds 已提交
138 139
	{ DSCR_CMD0_PSC0_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },

P
Pete Popov 已提交
140 141
	{ DSCR_CMD0_PSC1_TX, DEV_FLAGS_OUT, 0, 16, 0x11b0001c, 0, 0 },
	{ DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN, 0, 16, 0x11b0001c, 0, 0 },
L
Linus Torvalds 已提交
142 143
	{ DSCR_CMD0_PSC1_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },

P
Pete Popov 已提交
144 145 146
	{ DSCR_CMD0_CIM_RXA, DEV_FLAGS_IN, 0, 32, 0x14004020, 0, 0 },
	{ DSCR_CMD0_CIM_RXB, DEV_FLAGS_IN, 0, 32, 0x14004040, 0, 0 },
	{ DSCR_CMD0_CIM_RXC, DEV_FLAGS_IN, 0, 32, 0x14004060, 0, 0 },
L
Linus Torvalds 已提交
147 148 149 150
	{ DSCR_CMD0_CIM_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },

	{ DSCR_CMD0_NAND_FLASH, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },

151
#endif /* CONFIG_SOC_AU1200 */
L
Linus Torvalds 已提交
152 153 154

	{ DSCR_CMD0_THROTTLE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
	{ DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
P
Pete Popov 已提交
155 156

	/* Provide 16 user definable device types */
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
	{ ~0, 0, 0, 0, 0, 0, 0 },
	{ ~0, 0, 0, 0, 0, 0, 0 },
	{ ~0, 0, 0, 0, 0, 0, 0 },
	{ ~0, 0, 0, 0, 0, 0, 0 },
	{ ~0, 0, 0, 0, 0, 0, 0 },
	{ ~0, 0, 0, 0, 0, 0, 0 },
	{ ~0, 0, 0, 0, 0, 0, 0 },
	{ ~0, 0, 0, 0, 0, 0, 0 },
	{ ~0, 0, 0, 0, 0, 0, 0 },
	{ ~0, 0, 0, 0, 0, 0, 0 },
	{ ~0, 0, 0, 0, 0, 0, 0 },
	{ ~0, 0, 0, 0, 0, 0, 0 },
	{ ~0, 0, 0, 0, 0, 0, 0 },
	{ ~0, 0, 0, 0, 0, 0, 0 },
	{ ~0, 0, 0, 0, 0, 0, 0 },
	{ ~0, 0, 0, 0, 0, 0, 0 },
L
Linus Torvalds 已提交
173 174
};

175
#define DBDEV_TAB_SIZE	ARRAY_SIZE(dbdev_tab)
L
Linus Torvalds 已提交
176

177
#ifdef CONFIG_PM
178
static u32 au1xxx_dbdma_pm_regs[NUM_DBDMA_CHANS + 1][6];
179 180 181
#endif


L
Linus Torvalds 已提交
182 183
static chan_tab_t *chan_tab_ptr[NUM_DBDMA_CHANS];

184
static dbdev_tab_t *find_dbdev_id(u32 id)
L
Linus Torvalds 已提交
185 186 187 188 189 190 191 192 193 194 195
{
	int i;
	dbdev_tab_t *p;
	for (i = 0; i < DBDEV_TAB_SIZE; ++i) {
		p = &dbdev_tab[i];
		if (p->dev_id == id)
			return p;
	}
	return NULL;
}

196
void *au1xxx_ddma_get_nextptr_virt(au1x_ddma_desc_t *dp)
P
Pete Popov 已提交
197
{
198
	return phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
P
Pete Popov 已提交
199 200 201
}
EXPORT_SYMBOL(au1xxx_ddma_get_nextptr_virt);

202
u32 au1xxx_ddma_add_device(dbdev_tab_t *dev)
P
Pete Popov 已提交
203 204
{
	u32 ret = 0;
205 206
	dbdev_tab_t *p;
	static u16 new_id = 0x1000;
P
Pete Popov 已提交
207

208
	p = find_dbdev_id(~0);
209
	if (NULL != p) {
P
Pete Popov 已提交
210
		memcpy(p, dev, sizeof(dbdev_tab_t));
211
		p->dev_id = DSCR_DEV2CUSTOM_ID(new_id, dev->dev_id);
P
Pete Popov 已提交
212 213 214
		ret = p->dev_id;
		new_id++;
#if 0
215 216
		printk(KERN_DEBUG "add_device: id:%x flags:%x padd:%x\n",
				  p->dev_id, p->dev_flags, p->dev_physaddr);
P
Pete Popov 已提交
217 218 219 220 221 222 223
#endif
	}

	return ret;
}
EXPORT_SYMBOL(au1xxx_ddma_add_device);

224 225 226 227 228 229 230 231 232 233 234
void au1xxx_ddma_del_device(u32 devid)
{
	dbdev_tab_t *p = find_dbdev_id(devid);

	if (p != NULL) {
		memset(p, 0, sizeof(dbdev_tab_t));
		p->dev_id = ~0;
	}
}
EXPORT_SYMBOL(au1xxx_ddma_del_device);

235 236
/* Allocate a channel and return a non-zero descriptor if successful. */
u32 au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,
237
       void (*callback)(int, void *), void *callparam)
L
Linus Torvalds 已提交
238 239 240 241 242 243 244
{
	unsigned long   flags;
	u32		used, chan, rv;
	u32		dcp;
	int		i;
	dbdev_tab_t	*stp, *dtp;
	chan_tab_t	*ctp;
P
Pete Popov 已提交
245
	au1x_dma_chan_t *cp;
L
Linus Torvalds 已提交
246

247 248
	/*
	 * We do the intialization on the first channel allocation.
L
Linus Torvalds 已提交
249 250 251 252 253 254 255
	 * We have to wait because of the interrupt handler initialization
	 * which can't be done successfully during board set up.
	 */
	if (!dbdma_initialized)
		au1xxx_dbdma_init();
	dbdma_initialized = 1;

256 257
	stp = find_dbdev_id(srcid);
	if (stp == NULL)
258
		return 0;
259 260
	dtp = find_dbdev_id(destid);
	if (dtp == NULL)
261
		return 0;
L
Linus Torvalds 已提交
262 263 264 265

	used = 0;
	rv = 0;

266
	/* Check to see if we can get both channels. */
L
Linus Torvalds 已提交
267 268 269
	spin_lock_irqsave(&au1xxx_dbdma_spin_lock, flags);
	if (!(stp->dev_flags & DEV_FLAGS_INUSE) ||
	     (stp->dev_flags & DEV_FLAGS_ANYUSE)) {
270
		/* Got source */
L
Linus Torvalds 已提交
271 272 273 274 275
		stp->dev_flags |= DEV_FLAGS_INUSE;
		if (!(dtp->dev_flags & DEV_FLAGS_INUSE) ||
		     (dtp->dev_flags & DEV_FLAGS_ANYUSE)) {
			/* Got destination */
			dtp->dev_flags |= DEV_FLAGS_INUSE;
276 277
		} else {
			/* Can't get dest.  Release src. */
L
Linus Torvalds 已提交
278 279 280
			stp->dev_flags &= ~DEV_FLAGS_INUSE;
			used++;
		}
281
	} else
L
Linus Torvalds 已提交
282 283 284 285
		used++;
	spin_unlock_irqrestore(&au1xxx_dbdma_spin_lock, flags);

	if (!used) {
286
		/* Let's see if we can allocate a channel for it. */
L
Linus Torvalds 已提交
287 288 289
		ctp = NULL;
		chan = 0;
		spin_lock_irqsave(&au1xxx_dbdma_spin_lock, flags);
290
		for (i = 0; i < NUM_DBDMA_CHANS; i++)
L
Linus Torvalds 已提交
291
			if (chan_tab_ptr[i] == NULL) {
292 293
				/*
				 * If kmalloc fails, it is caught below same
L
Linus Torvalds 已提交
294 295
				 * as a channel not available.
				 */
296
				ctp = kmalloc(sizeof(chan_tab_t), GFP_ATOMIC);
L
Linus Torvalds 已提交
297 298 299 300 301 302 303
				chan_tab_ptr[i] = ctp;
				break;
			}
		spin_unlock_irqrestore(&au1xxx_dbdma_spin_lock, flags);

		if (ctp != NULL) {
			memset(ctp, 0, sizeof(chan_tab_t));
P
Pete Popov 已提交
304
			ctp->chan_index = chan = i;
L
Linus Torvalds 已提交
305 306 307
			dcp = DDMA_CHANNEL_BASE;
			dcp += (0x0100 * chan);
			ctp->chan_ptr = (au1x_dma_chan_t *)dcp;
P
Pete Popov 已提交
308
			cp = (au1x_dma_chan_t *)dcp;
L
Linus Torvalds 已提交
309 310 311 312 313
			ctp->chan_src = stp;
			ctp->chan_dest = dtp;
			ctp->chan_callback = callback;
			ctp->chan_callparam = callparam;

314
			/* Initialize channel configuration. */
L
Linus Torvalds 已提交
315 316 317 318 319 320 321 322 323
			i = 0;
			if (stp->dev_intlevel)
				i |= DDMA_CFG_SED;
			if (stp->dev_intpolarity)
				i |= DDMA_CFG_SP;
			if (dtp->dev_intlevel)
				i |= DDMA_CFG_DED;
			if (dtp->dev_intpolarity)
				i |= DDMA_CFG_DP;
P
Pete Popov 已提交
324 325 326
			if ((stp->dev_flags & DEV_FLAGS_SYNC) ||
				(dtp->dev_flags & DEV_FLAGS_SYNC))
					i |= DDMA_CFG_SYNC;
L
Linus Torvalds 已提交
327 328 329 330 331 332 333 334
			cp->ddma_cfg = i;
			au_sync();

			/* Return a non-zero value that can be used to
			 * find the channel information in subsequent
			 * operations.
			 */
			rv = (u32)(&chan_tab_ptr[chan]);
335
		} else {
P
Pete Popov 已提交
336
			/* Release devices */
L
Linus Torvalds 已提交
337 338 339 340 341 342
			stp->dev_flags &= ~DEV_FLAGS_INUSE;
			dtp->dev_flags &= ~DEV_FLAGS_INUSE;
		}
	}
	return rv;
}
P
Pete Popov 已提交
343
EXPORT_SYMBOL(au1xxx_dbdma_chan_alloc);
L
Linus Torvalds 已提交
344

345 346
/*
 * Set the device width if source or destination is a FIFO.
L
Linus Torvalds 已提交
347 348
 * Should be 8, 16, or 32 bits.
 */
349
u32 au1xxx_dbdma_set_devwidth(u32 chanid, int bits)
L
Linus Torvalds 已提交
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
{
	u32		rv;
	chan_tab_t	*ctp;
	dbdev_tab_t	*stp, *dtp;

	ctp = *((chan_tab_t **)chanid);
	stp = ctp->chan_src;
	dtp = ctp->chan_dest;
	rv = 0;

	if (stp->dev_flags & DEV_FLAGS_IN) {	/* Source in fifo */
		rv = stp->dev_devwidth;
		stp->dev_devwidth = bits;
	}
	if (dtp->dev_flags & DEV_FLAGS_OUT) {	/* Destination out fifo */
		rv = dtp->dev_devwidth;
		dtp->dev_devwidth = bits;
	}

	return rv;
}
P
Pete Popov 已提交
371
EXPORT_SYMBOL(au1xxx_dbdma_set_devwidth);
L
Linus Torvalds 已提交
372

373 374
/* Allocate a descriptor ring, initializing as much as possible. */
u32 au1xxx_dbdma_ring_alloc(u32 chanid, int entries)
L
Linus Torvalds 已提交
375 376 377 378 379 380 381 382 383
{
	int			i;
	u32			desc_base, srcid, destid;
	u32			cmd0, cmd1, src1, dest1;
	u32			src0, dest0;
	chan_tab_t		*ctp;
	dbdev_tab_t		*stp, *dtp;
	au1x_ddma_desc_t	*dp;

384 385
	/*
	 * I guess we could check this to be within the
L
Linus Torvalds 已提交
386 387 388 389 390 391
	 * range of the table......
	 */
	ctp = *((chan_tab_t **)chanid);
	stp = ctp->chan_src;
	dtp = ctp->chan_dest;

392 393
	/*
	 * The descriptors must be 32-byte aligned.  There is a
L
Linus Torvalds 已提交
394 395 396 397
	 * possibility the allocation will give us such an address,
	 * and if we try that first we are likely to not waste larger
	 * slabs of memory.
	 */
P
Pete Popov 已提交
398
	desc_base = (u32)kmalloc(entries * sizeof(au1x_ddma_desc_t),
399
				 GFP_KERNEL|GFP_DMA);
L
Linus Torvalds 已提交
400 401 402 403
	if (desc_base == 0)
		return 0;

	if (desc_base & 0x1f) {
404 405
		/*
		 * Lost....do it again, allocate extra, and round
L
Linus Torvalds 已提交
406 407 408 409 410
		 * the address base.
		 */
		kfree((const void *)desc_base);
		i = entries * sizeof(au1x_ddma_desc_t);
		i += (sizeof(au1x_ddma_desc_t) - 1);
411 412
		desc_base = (u32)kmalloc(i, GFP_KERNEL|GFP_DMA);
		if (desc_base == 0)
L
Linus Torvalds 已提交
413 414 415 416 417 418
			return 0;

		desc_base = ALIGN_ADDR(desc_base, sizeof(au1x_ddma_desc_t));
	}
	dp = (au1x_ddma_desc_t *)desc_base;

419
	/* Keep track of the base descriptor. */
L
Linus Torvalds 已提交
420 421
	ctp->chan_desc_base = dp;

422
	/* Initialize the rings with as much information as we know. */
L
Linus Torvalds 已提交
423 424 425 426 427 428 429 430 431
	srcid = stp->dev_id;
	destid = dtp->dev_id;

	cmd0 = cmd1 = src1 = dest1 = 0;
	src0 = dest0 = 0;

	cmd0 |= DSCR_CMD0_SID(srcid);
	cmd0 |= DSCR_CMD0_DID(destid);
	cmd0 |= DSCR_CMD0_IE | DSCR_CMD0_CV;
P
Pete Popov 已提交
432 433
	cmd0 |= DSCR_CMD0_ST(DSCR_CMD0_ST_NOCHANGE);

434 435 436 437 438 439
	/* Is it mem to mem transfer? */
	if (((DSCR_CUSTOM2DEV_ID(srcid) == DSCR_CMD0_THROTTLE) ||
	     (DSCR_CUSTOM2DEV_ID(srcid) == DSCR_CMD0_ALWAYS)) &&
	    ((DSCR_CUSTOM2DEV_ID(destid) == DSCR_CMD0_THROTTLE) ||
	     (DSCR_CUSTOM2DEV_ID(destid) == DSCR_CMD0_ALWAYS)))
		cmd0 |= DSCR_CMD0_MEM;
L
Linus Torvalds 已提交
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466

	switch (stp->dev_devwidth) {
	case 8:
		cmd0 |= DSCR_CMD0_SW(DSCR_CMD0_BYTE);
		break;
	case 16:
		cmd0 |= DSCR_CMD0_SW(DSCR_CMD0_HALFWORD);
		break;
	case 32:
	default:
		cmd0 |= DSCR_CMD0_SW(DSCR_CMD0_WORD);
		break;
	}

	switch (dtp->dev_devwidth) {
	case 8:
		cmd0 |= DSCR_CMD0_DW(DSCR_CMD0_BYTE);
		break;
	case 16:
		cmd0 |= DSCR_CMD0_DW(DSCR_CMD0_HALFWORD);
		break;
	case 32:
	default:
		cmd0 |= DSCR_CMD0_DW(DSCR_CMD0_WORD);
		break;
	}

467 468
	/*
	 * If the device is marked as an in/out FIFO, ensure it is
L
Linus Torvalds 已提交
469 470 471
	 * set non-coherent.
	 */
	if (stp->dev_flags & DEV_FLAGS_IN)
472
		cmd0 |= DSCR_CMD0_SN;		/* Source in FIFO */
L
Linus Torvalds 已提交
473
	if (dtp->dev_flags & DEV_FLAGS_OUT)
474
		cmd0 |= DSCR_CMD0_DN;		/* Destination out FIFO */
L
Linus Torvalds 已提交
475

476 477
	/*
	 * Set up source1.  For now, assume no stride and increment.
L
Linus Torvalds 已提交
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
	 * A channel attribute update can change this later.
	 */
	switch (stp->dev_tsize) {
	case 1:
		src1 |= DSCR_SRC1_STS(DSCR_xTS_SIZE1);
		break;
	case 2:
		src1 |= DSCR_SRC1_STS(DSCR_xTS_SIZE2);
		break;
	case 4:
		src1 |= DSCR_SRC1_STS(DSCR_xTS_SIZE4);
		break;
	case 8:
	default:
		src1 |= DSCR_SRC1_STS(DSCR_xTS_SIZE8);
		break;
	}

496
	/* If source input is FIFO, set static address.	*/
L
Linus Torvalds 已提交
497
	if (stp->dev_flags & DEV_FLAGS_IN) {
498
		if (stp->dev_flags & DEV_FLAGS_BURSTABLE)
P
Pete Popov 已提交
499 500
			src1 |= DSCR_SRC1_SAM(DSCR_xAM_BURST);
		else
501
			src1 |= DSCR_SRC1_SAM(DSCR_xAM_STATIC);
L
Linus Torvalds 已提交
502
	}
503

P
Pete Popov 已提交
504 505
	if (stp->dev_physaddr)
		src0 = stp->dev_physaddr;
L
Linus Torvalds 已提交
506

507 508
	/*
	 * Set up dest1.  For now, assume no stride and increment.
L
Linus Torvalds 已提交
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526
	 * A channel attribute update can change this later.
	 */
	switch (dtp->dev_tsize) {
	case 1:
		dest1 |= DSCR_DEST1_DTS(DSCR_xTS_SIZE1);
		break;
	case 2:
		dest1 |= DSCR_DEST1_DTS(DSCR_xTS_SIZE2);
		break;
	case 4:
		dest1 |= DSCR_DEST1_DTS(DSCR_xTS_SIZE4);
		break;
	case 8:
	default:
		dest1 |= DSCR_DEST1_DTS(DSCR_xTS_SIZE8);
		break;
	}

527
	/* If destination output is FIFO, set static address. */
L
Linus Torvalds 已提交
528
	if (dtp->dev_flags & DEV_FLAGS_OUT) {
529 530 531 532
		if (dtp->dev_flags & DEV_FLAGS_BURSTABLE)
			dest1 |= DSCR_DEST1_DAM(DSCR_xAM_BURST);
		else
			dest1 |= DSCR_DEST1_DAM(DSCR_xAM_STATIC);
L
Linus Torvalds 已提交
533
	}
534

P
Pete Popov 已提交
535 536
	if (dtp->dev_physaddr)
		dest0 = dtp->dev_physaddr;
L
Linus Torvalds 已提交
537

P
Pete Popov 已提交
538
#if 0
539 540 541 542
		printk(KERN_DEBUG "did:%x sid:%x cmd0:%x cmd1:%x source0:%x "
				  "source1:%x dest0:%x dest1:%x\n",
				  dtp->dev_id, stp->dev_id, cmd0, cmd1, src0,
				  src1, dest0, dest1);
P
Pete Popov 已提交
543
#endif
544
	for (i = 0; i < entries; i++) {
L
Linus Torvalds 已提交
545 546 547 548 549 550 551
		dp->dscr_cmd0 = cmd0;
		dp->dscr_cmd1 = cmd1;
		dp->dscr_source0 = src0;
		dp->dscr_source1 = src1;
		dp->dscr_dest0 = dest0;
		dp->dscr_dest1 = dest1;
		dp->dscr_stat = 0;
P
Pete Popov 已提交
552 553
		dp->sw_context = 0;
		dp->sw_status = 0;
L
Linus Torvalds 已提交
554 555 556 557
		dp->dscr_nxtptr = DSCR_NXTPTR(virt_to_phys(dp + 1));
		dp++;
	}

558
	/* Make last descrptor point to the first. */
L
Linus Torvalds 已提交
559 560 561 562
	dp--;
	dp->dscr_nxtptr = DSCR_NXTPTR(virt_to_phys(ctp->chan_desc_base));
	ctp->get_ptr = ctp->put_ptr = ctp->cur_ptr = ctp->chan_desc_base;

563
	return (u32)ctp->chan_desc_base;
L
Linus Torvalds 已提交
564
}
P
Pete Popov 已提交
565
EXPORT_SYMBOL(au1xxx_dbdma_ring_alloc);
L
Linus Torvalds 已提交
566

567 568
/*
 * Put a source buffer into the DMA ring.
L
Linus Torvalds 已提交
569 570 571
 * This updates the source pointer and byte count.  Normally used
 * for memory to fifo transfers.
 */
572
u32 _au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes, u32 flags)
L
Linus Torvalds 已提交
573 574 575 576
{
	chan_tab_t		*ctp;
	au1x_ddma_desc_t	*dp;

577 578
	/*
	 * I guess we could check this to be within the
L
Linus Torvalds 已提交
579 580
	 * range of the table......
	 */
581
	ctp = *(chan_tab_t **)chanid;
L
Linus Torvalds 已提交
582

583 584
	/*
	 * We should have multiple callers for a particular channel,
L
Linus Torvalds 已提交
585 586 587 588 589
	 * an interrupt doesn't affect this pointer nor the descriptor,
	 * so no locking should be needed.
	 */
	dp = ctp->put_ptr;

590 591
	/*
	 * If the descriptor is valid, we are way ahead of the DMA
L
Linus Torvalds 已提交
592 593
	 * engine, so just return an error condition.
	 */
594
	if (dp->dscr_cmd0 & DSCR_CMD0_V)
L
Linus Torvalds 已提交
595 596
		return 0;

597
	/* Load up buffer address and byte count. */
L
Linus Torvalds 已提交
598 599
	dp->dscr_source0 = virt_to_phys(buf);
	dp->dscr_cmd1 = nbytes;
600
	/* Check flags */
P
Pete Popov 已提交
601 602 603 604
	if (flags & DDMA_FLAGS_IE)
		dp->dscr_cmd0 |= DSCR_CMD0_IE;
	if (flags & DDMA_FLAGS_NOIE)
		dp->dscr_cmd0 &= ~DSCR_CMD0_IE;
L
Linus Torvalds 已提交
605

P
Pete Popov 已提交
606 607
	/*
	 * There is an errata on the Au1200/Au1550 parts that could result
608 609 610
	 * in "stale" data being DMA'ed. It has to do with the snoop logic on
	 * the cache eviction buffer.  DMA_NONCOHERENT is on by default for
	 * these parts. If it is fixed in the future, these dma_cache_inv will
P
Pete Popov 已提交
611
	 * just be nothing more than empty macros. See io.h.
612
	 */
613
	dma_cache_wback_inv((unsigned long)buf, nbytes);
614
	dp->dscr_cmd0 |= DSCR_CMD0_V;	/* Let it rip */
P
Pete Popov 已提交
615
	au_sync();
616
	dma_cache_wback_inv((unsigned long)dp, sizeof(*dp));
617
	ctp->chan_ptr->ddma_dbell = 0;
P
Pete Popov 已提交
618

619
	/* Get next descriptor pointer.	*/
P
Pete Popov 已提交
620 621
	ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));

622
	/* Return something non-zero. */
L
Linus Torvalds 已提交
623 624
	return nbytes;
}
P
Pete Popov 已提交
625
EXPORT_SYMBOL(_au1xxx_dbdma_put_source);
L
Linus Torvalds 已提交
626 627 628 629 630 631

/* Put a destination buffer into the DMA ring.
 * This updates the destination pointer and byte count.  Normally used
 * to place an empty buffer into the ring for fifo to memory transfers.
 */
u32
P
Pete Popov 已提交
632
_au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes, u32 flags)
L
Linus Torvalds 已提交
633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
{
	chan_tab_t		*ctp;
	au1x_ddma_desc_t	*dp;

	/* I guess we could check this to be within the
	 * range of the table......
	 */
	ctp = *((chan_tab_t **)chanid);

	/* We should have multiple callers for a particular channel,
	 * an interrupt doesn't affect this pointer nor the descriptor,
	 * so no locking should be needed.
	 */
	dp = ctp->put_ptr;

	/* If the descriptor is valid, we are way ahead of the DMA
	 * engine, so just return an error condition.
	 */
	if (dp->dscr_cmd0 & DSCR_CMD0_V)
		return 0;

P
Pete Popov 已提交
654 655 656 657 658 659 660 661
	/* Load up buffer address and byte count */

	/* Check flags  */
	if (flags & DDMA_FLAGS_IE)
		dp->dscr_cmd0 |= DSCR_CMD0_IE;
	if (flags & DDMA_FLAGS_NOIE)
		dp->dscr_cmd0 &= ~DSCR_CMD0_IE;

L
Linus Torvalds 已提交
662 663
	dp->dscr_dest0 = virt_to_phys(buf);
	dp->dscr_cmd1 = nbytes;
P
Pete Popov 已提交
664
#if 0
665 666 667
	printk(KERN_DEBUG "cmd0:%x cmd1:%x source0:%x source1:%x dest0:%x dest1:%x\n",
			  dp->dscr_cmd0, dp->dscr_cmd1, dp->dscr_source0,
			  dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1);
P
Pete Popov 已提交
668 669 670
#endif
	/*
	 * There is an errata on the Au1200/Au1550 parts that could result in
671 672 673
	 * "stale" data being DMA'ed. It has to do with the snoop logic on the
	 * cache eviction buffer.  DMA_NONCOHERENT is on by default for these
	 * parts. If it is fixed in the future, these dma_cache_inv will just
P
Pete Popov 已提交
674
	 * be nothing more than empty macros. See io.h.
675
	 */
676
	dma_cache_inv((unsigned long)buf, nbytes);
L
Linus Torvalds 已提交
677
	dp->dscr_cmd0 |= DSCR_CMD0_V;	/* Let it rip */
P
Pete Popov 已提交
678
	au_sync();
679
	dma_cache_wback_inv((unsigned long)dp, sizeof(*dp));
680
	ctp->chan_ptr->ddma_dbell = 0;
L
Linus Torvalds 已提交
681

682
	/* Get next descriptor pointer.	*/
L
Linus Torvalds 已提交
683 684
	ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));

685
	/* Return something non-zero. */
L
Linus Torvalds 已提交
686 687
	return nbytes;
}
P
Pete Popov 已提交
688
EXPORT_SYMBOL(_au1xxx_dbdma_put_dest);
L
Linus Torvalds 已提交
689

690 691
/*
 * Get a destination buffer into the DMA ring.
L
Linus Torvalds 已提交
692 693 694 695
 * Normally used to get a full buffer from the ring during fifo
 * to memory transfers.  This does not set the valid bit, you will
 * have to put another destination buffer to keep the DMA going.
 */
696
u32 au1xxx_dbdma_get_dest(u32 chanid, void **buf, int *nbytes)
L
Linus Torvalds 已提交
697 698 699 700 701
{
	chan_tab_t		*ctp;
	au1x_ddma_desc_t	*dp;
	u32			rv;

702 703
	/*
	 * I guess we could check this to be within the
L
Linus Torvalds 已提交
704 705 706 707
	 * range of the table......
	 */
	ctp = *((chan_tab_t **)chanid);

708 709
	/*
	 * We should have multiple callers for a particular channel,
L
Linus Torvalds 已提交
710 711 712 713 714
	 * an interrupt doesn't affect this pointer nor the descriptor,
	 * so no locking should be needed.
	 */
	dp = ctp->get_ptr;

715 716
	/*
	 * If the descriptor is valid, we are way ahead of the DMA
L
Linus Torvalds 已提交
717 718 719 720 721
	 * engine, so just return an error condition.
	 */
	if (dp->dscr_cmd0 & DSCR_CMD0_V)
		return 0;

722
	/* Return buffer address and byte count. */
L
Linus Torvalds 已提交
723 724 725 726
	*buf = (void *)(phys_to_virt(dp->dscr_dest0));
	*nbytes = dp->dscr_cmd1;
	rv = dp->dscr_stat;

727
	/* Get next descriptor pointer.	*/
L
Linus Torvalds 已提交
728 729
	ctp->get_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));

730
	/* Return something non-zero. */
L
Linus Torvalds 已提交
731 732
	return rv;
}
733 734
EXPORT_SYMBOL_GPL(au1xxx_dbdma_get_dest);

735
void au1xxx_dbdma_stop(u32 chanid)
L
Linus Torvalds 已提交
736 737
{
	chan_tab_t	*ctp;
P
Pete Popov 已提交
738
	au1x_dma_chan_t *cp;
L
Linus Torvalds 已提交
739 740 741 742 743 744 745 746 747 748 749
	int halt_timeout = 0;

	ctp = *((chan_tab_t **)chanid);

	cp = ctp->chan_ptr;
	cp->ddma_cfg &= ~DDMA_CFG_EN;	/* Disable channel */
	au_sync();
	while (!(cp->ddma_stat & DDMA_STAT_H)) {
		udelay(1);
		halt_timeout++;
		if (halt_timeout > 100) {
750
			printk(KERN_WARNING "warning: DMA channel won't halt\n");
L
Linus Torvalds 已提交
751 752 753 754 755 756 757
			break;
		}
	}
	/* clear current desc valid and doorbell */
	cp->ddma_stat |= (DDMA_STAT_DB | DDMA_STAT_V);
	au_sync();
}
P
Pete Popov 已提交
758
EXPORT_SYMBOL(au1xxx_dbdma_stop);
L
Linus Torvalds 已提交
759

760 761 762
/*
 * Start using the current descriptor pointer.  If the DBDMA encounters
 * a non-valid descriptor, it will stop.  In this case, we can just
L
Linus Torvalds 已提交
763 764
 * continue by adding a buffer to the list and starting again.
 */
765
void au1xxx_dbdma_start(u32 chanid)
L
Linus Torvalds 已提交
766 767
{
	chan_tab_t	*ctp;
P
Pete Popov 已提交
768
	au1x_dma_chan_t *cp;
L
Linus Torvalds 已提交
769 770 771 772 773 774

	ctp = *((chan_tab_t **)chanid);
	cp = ctp->chan_ptr;
	cp->ddma_desptr = virt_to_phys(ctp->cur_ptr);
	cp->ddma_cfg |= DDMA_CFG_EN;	/* Enable channel */
	au_sync();
P
Pete Popov 已提交
775
	cp->ddma_dbell = 0;
L
Linus Torvalds 已提交
776 777
	au_sync();
}
P
Pete Popov 已提交
778
EXPORT_SYMBOL(au1xxx_dbdma_start);
L
Linus Torvalds 已提交
779

780
void au1xxx_dbdma_reset(u32 chanid)
L
Linus Torvalds 已提交
781 782 783 784 785 786 787 788 789
{
	chan_tab_t		*ctp;
	au1x_ddma_desc_t	*dp;

	au1xxx_dbdma_stop(chanid);

	ctp = *((chan_tab_t **)chanid);
	ctp->get_ptr = ctp->put_ptr = ctp->cur_ptr = ctp->chan_desc_base;

790
	/* Run through the descriptors and reset the valid indicator. */
L
Linus Torvalds 已提交
791 792 793 794
	dp = ctp->chan_desc_base;

	do {
		dp->dscr_cmd0 &= ~DSCR_CMD0_V;
795 796 797
		/*
		 * Reset our software status -- this is used to determine
		 * if a descriptor is in use by upper level software. Since
P
Pete Popov 已提交
798 799 800
		 * posting can reset 'V' bit.
		 */
		dp->sw_status = 0;
L
Linus Torvalds 已提交
801 802 803
		dp = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
	} while (dp != ctp->chan_desc_base);
}
P
Pete Popov 已提交
804
EXPORT_SYMBOL(au1xxx_dbdma_reset);
L
Linus Torvalds 已提交
805

806
u32 au1xxx_get_dma_residue(u32 chanid)
L
Linus Torvalds 已提交
807 808
{
	chan_tab_t	*ctp;
P
Pete Popov 已提交
809
	au1x_dma_chan_t *cp;
L
Linus Torvalds 已提交
810 811 812 813 814
	u32		rv;

	ctp = *((chan_tab_t **)chanid);
	cp = ctp->chan_ptr;

815
	/* This is only valid if the channel is stopped. */
L
Linus Torvalds 已提交
816 817 818 819 820
	rv = cp->ddma_bytecnt;
	au_sync();

	return rv;
}
821 822
EXPORT_SYMBOL_GPL(au1xxx_get_dma_residue);

823
void au1xxx_dbdma_chan_free(u32 chanid)
L
Linus Torvalds 已提交
824 825 826 827 828 829 830 831 832 833
{
	chan_tab_t	*ctp;
	dbdev_tab_t	*stp, *dtp;

	ctp = *((chan_tab_t **)chanid);
	stp = ctp->chan_src;
	dtp = ctp->chan_dest;

	au1xxx_dbdma_stop(chanid);

834
	kfree((void *)ctp->chan_desc_base);
L
Linus Torvalds 已提交
835 836 837 838 839 840 841

	stp->dev_flags &= ~DEV_FLAGS_INUSE;
	dtp->dev_flags &= ~DEV_FLAGS_INUSE;
	chan_tab_ptr[ctp->chan_index] = NULL;

	kfree(ctp);
}
P
Pete Popov 已提交
842
EXPORT_SYMBOL(au1xxx_dbdma_chan_free);
L
Linus Torvalds 已提交
843

844
static irqreturn_t dbdma_interrupt(int irq, void *dev_id)
L
Linus Torvalds 已提交
845
{
846 847
	u32 intstat;
	u32 chan_index;
L
Linus Torvalds 已提交
848 849
	chan_tab_t		*ctp;
	au1x_ddma_desc_t	*dp;
P
Pete Popov 已提交
850
	au1x_dma_chan_t *cp;
L
Linus Torvalds 已提交
851 852 853

	intstat = dbdma_gptr->ddma_intstat;
	au_sync();
854
	chan_index = __ffs(intstat);
L
Linus Torvalds 已提交
855 856 857 858 859

	ctp = chan_tab_ptr[chan_index];
	cp = ctp->chan_ptr;
	dp = ctp->cur_ptr;

860
	/* Reset interrupt. */
L
Linus Torvalds 已提交
861 862 863 864
	cp->ddma_irq = 0;
	au_sync();

	if (ctp->chan_callback)
865
		ctp->chan_callback(irq, ctp->chan_callparam);
L
Linus Torvalds 已提交
866 867

	ctp->cur_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
868
	return IRQ_RETVAL(1);
L
Linus Torvalds 已提交
869 870
}

P
Pete Popov 已提交
871
static void au1xxx_dbdma_init(void)
L
Linus Torvalds 已提交
872
{
P
Pete Popov 已提交
873 874
	int irq_nr;

L
Linus Torvalds 已提交
875 876 877 878 879
	dbdma_gptr->ddma_config = 0;
	dbdma_gptr->ddma_throttle = 0;
	dbdma_gptr->ddma_inten = 0xffff;
	au_sync();

P
Pete Popov 已提交
880 881 882 883 884 885 886 887
#if defined(CONFIG_SOC_AU1550)
	irq_nr = AU1550_DDMA_INT;
#elif defined(CONFIG_SOC_AU1200)
	irq_nr = AU1200_DDMA_INT;
#else
	#error Unknown Au1x00 SOC
#endif

888
	if (request_irq(irq_nr, dbdma_interrupt, IRQF_DISABLED,
L
Linus Torvalds 已提交
889
			"Au1xxx dbdma", (void *)dbdma_gptr))
890
		printk(KERN_ERR "Can't get 1550 dbdma irq");
L
Linus Torvalds 已提交
891 892
}

893
void au1xxx_dbdma_dump(u32 chanid)
L
Linus Torvalds 已提交
894
{
895 896 897 898 899
	chan_tab_t	 *ctp;
	au1x_ddma_desc_t *dp;
	dbdev_tab_t	 *stp, *dtp;
	au1x_dma_chan_t  *cp;
	u32 i		 = 0;
L
Linus Torvalds 已提交
900 901 902 903 904 905

	ctp = *((chan_tab_t **)chanid);
	stp = ctp->chan_src;
	dtp = ctp->chan_dest;
	cp = ctp->chan_ptr;

906 907 908 909 910 911 912 913 914 915 916 917 918 919 920
	printk(KERN_DEBUG "Chan %x, stp %x (dev %d)  dtp %x (dev %d) \n",
			  (u32)ctp, (u32)stp, stp - dbdev_tab, (u32)dtp,
			  dtp - dbdev_tab);
	printk(KERN_DEBUG "desc base %x, get %x, put %x, cur %x\n",
			  (u32)(ctp->chan_desc_base), (u32)(ctp->get_ptr),
			  (u32)(ctp->put_ptr), (u32)(ctp->cur_ptr));

	printk(KERN_DEBUG "dbdma chan %x\n", (u32)cp);
	printk(KERN_DEBUG "cfg %08x, desptr %08x, statptr %08x\n",
			  cp->ddma_cfg, cp->ddma_desptr, cp->ddma_statptr);
	printk(KERN_DEBUG "dbell %08x, irq %08x, stat %08x, bytecnt %08x\n",
			  cp->ddma_dbell, cp->ddma_irq, cp->ddma_stat,
			  cp->ddma_bytecnt);

	/* Run through the descriptors */
L
Linus Torvalds 已提交
921 922 923
	dp = ctp->chan_desc_base;

	do {
924 925 926 927 928 929 930
		printk(KERN_DEBUG "Dp[%d]= %08x, cmd0 %08x, cmd1 %08x\n",
				  i++, (u32)dp, dp->dscr_cmd0, dp->dscr_cmd1);
		printk(KERN_DEBUG "src0 %08x, src1 %08x, dest0 %08x, dest1 %08x\n",
				  dp->dscr_source0, dp->dscr_source1,
				  dp->dscr_dest0, dp->dscr_dest1);
		printk(KERN_DEBUG "stat %08x, nxtptr %08x\n",
				  dp->dscr_stat, dp->dscr_nxtptr);
L
Linus Torvalds 已提交
931 932 933 934
		dp = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
	} while (dp != ctp->chan_desc_base);
}

P
Pete Popov 已提交
935 936 937
/* Put a descriptor into the DMA ring.
 * This updates the source/destination pointers and byte count.
 */
938
u32 au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr)
P
Pete Popov 已提交
939 940 941
{
	chan_tab_t *ctp;
	au1x_ddma_desc_t *dp;
942
	u32 nbytes = 0;
P
Pete Popov 已提交
943

944 945 946 947
	/*
	 * I guess we could check this to be within the
	 * range of the table......
	 */
P
Pete Popov 已提交
948 949
	ctp = *((chan_tab_t **)chanid);

950 951 952 953 954
	/*
	 * We should have multiple callers for a particular channel,
	 * an interrupt doesn't affect this pointer nor the descriptor,
	 * so no locking should be needed.
	 */
P
Pete Popov 已提交
955 956
	dp = ctp->put_ptr;

957 958 959 960
	/*
	 * If the descriptor is valid, we are way ahead of the DMA
	 * engine, so just return an error condition.
	 */
P
Pete Popov 已提交
961 962 963
	if (dp->dscr_cmd0 & DSCR_CMD0_V)
		return 0;

964
	/* Load up buffer addresses and byte count. */
P
Pete Popov 已提交
965 966 967 968 969 970 971 972 973 974 975
	dp->dscr_dest0 = dscr->dscr_dest0;
	dp->dscr_source0 = dscr->dscr_source0;
	dp->dscr_dest1 = dscr->dscr_dest1;
	dp->dscr_source1 = dscr->dscr_source1;
	dp->dscr_cmd1 = dscr->dscr_cmd1;
	nbytes = dscr->dscr_cmd1;
	/* Allow the caller to specifiy if an interrupt is generated */
	dp->dscr_cmd0 &= ~DSCR_CMD0_IE;
	dp->dscr_cmd0 |= dscr->dscr_cmd0 | DSCR_CMD0_V;
	ctp->chan_ptr->ddma_dbell = 0;

976
	/* Get next descriptor pointer.	*/
P
Pete Popov 已提交
977 978
	ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));

979
	/* Return something non-zero. */
P
Pete Popov 已提交
980 981 982
	return nbytes;
}

983 984 985 986 987 988 989 990 991 992 993 994 995
#ifdef CONFIG_PM
void au1xxx_dbdma_suspend(void)
{
	int i;
	u32 addr;

	addr = DDMA_GLOBAL_BASE;
	au1xxx_dbdma_pm_regs[0][0] = au_readl(addr + 0x00);
	au1xxx_dbdma_pm_regs[0][1] = au_readl(addr + 0x04);
	au1xxx_dbdma_pm_regs[0][2] = au_readl(addr + 0x08);
	au1xxx_dbdma_pm_regs[0][3] = au_readl(addr + 0x0c);

	/* save channel configurations */
996
	for (i = 1, addr = DDMA_CHANNEL_BASE; i <= NUM_DBDMA_CHANS; i++) {
997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028
		au1xxx_dbdma_pm_regs[i][0] = au_readl(addr + 0x00);
		au1xxx_dbdma_pm_regs[i][1] = au_readl(addr + 0x04);
		au1xxx_dbdma_pm_regs[i][2] = au_readl(addr + 0x08);
		au1xxx_dbdma_pm_regs[i][3] = au_readl(addr + 0x0c);
		au1xxx_dbdma_pm_regs[i][4] = au_readl(addr + 0x10);
		au1xxx_dbdma_pm_regs[i][5] = au_readl(addr + 0x14);

		/* halt channel */
		au_writel(au1xxx_dbdma_pm_regs[i][0] & ~1, addr + 0x00);
		au_sync();
		while (!(au_readl(addr + 0x14) & 1))
			au_sync();

		addr += 0x100;	/* next channel base */
	}
	/* disable channel interrupts */
	au_writel(0, DDMA_GLOBAL_BASE + 0x0c);
	au_sync();
}

void au1xxx_dbdma_resume(void)
{
	int i;
	u32 addr;

	addr = DDMA_GLOBAL_BASE;
	au_writel(au1xxx_dbdma_pm_regs[0][0], addr + 0x00);
	au_writel(au1xxx_dbdma_pm_regs[0][1], addr + 0x04);
	au_writel(au1xxx_dbdma_pm_regs[0][2], addr + 0x08);
	au_writel(au1xxx_dbdma_pm_regs[0][3], addr + 0x0c);

	/* restore channel configurations */
1029
	for (i = 1, addr = DDMA_CHANNEL_BASE; i <= NUM_DBDMA_CHANS; i++) {
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
		au_writel(au1xxx_dbdma_pm_regs[i][0], addr + 0x00);
		au_writel(au1xxx_dbdma_pm_regs[i][1], addr + 0x04);
		au_writel(au1xxx_dbdma_pm_regs[i][2], addr + 0x08);
		au_writel(au1xxx_dbdma_pm_regs[i][3], addr + 0x0c);
		au_writel(au1xxx_dbdma_pm_regs[i][4], addr + 0x10);
		au_writel(au1xxx_dbdma_pm_regs[i][5], addr + 0x14);
		au_sync();
		addr += 0x100;	/* next channel base */
	}
}
#endif	/* CONFIG_PM */
L
Linus Torvalds 已提交
1041
#endif /* defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) */