au1000_dma.h 10.9 KB
Newer Older
L
Linus Torvalds 已提交
1 2
/*
 * BRIEF MODULE DESCRIPTION
3 4
 *	Defines for using and allocating DMA channels on the Alchemy
 *      Au1x00 MIPS processors.
L
Linus Torvalds 已提交
5
 *
6 7
 * Copyright 2000, 2008 MontaVista Software Inc.
 * Author: MontaVista Software, Inc. <source@mvista.com>
L
Linus Torvalds 已提交
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
 *
 *  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.
 *
 */
#ifndef __ASM_AU1000_DMA_H
#define __ASM_AU1000_DMA_H

33
#include <linux/io.h>		/* need byte IO */
L
Linus Torvalds 已提交
34 35 36
#include <linux/spinlock.h>	/* And spinlocks */
#include <linux/delay.h>

R
Ralf Baechle 已提交
37
#define NUM_AU1000_DMA_CHANNELS 8
L
Linus Torvalds 已提交
38 39 40 41 42 43 44 45 46

/* DMA Channel Register Offsets */
#define DMA_MODE_SET		0x00000000
#define DMA_MODE_READ		DMA_MODE_SET
#define DMA_MODE_CLEAR		0x00000004
/* DMA Mode register bits follow */
#define DMA_DAH_MASK		(0x0f << 20)
#define DMA_DID_BIT		16
#define DMA_DID_MASK		(0x0f << DMA_DID_BIT)
47 48 49
#define DMA_DS			(1 << 15)
#define DMA_BE			(1 << 13)
#define DMA_DR			(1 << 12)
R
Ralf Baechle 已提交
50
#define DMA_TS8			(1 << 11)
L
Linus Torvalds 已提交
51 52 53 54 55
#define DMA_DW_BIT		9
#define DMA_DW_MASK		(0x03 << DMA_DW_BIT)
#define DMA_DW8			(0 << DMA_DW_BIT)
#define DMA_DW16		(1 << DMA_DW_BIT)
#define DMA_DW32		(2 << DMA_DW_BIT)
56 57 58 59 60 61
#define DMA_NC			(1 << 8)
#define DMA_IE			(1 << 7)
#define DMA_HALT		(1 << 6)
#define DMA_GO			(1 << 5)
#define DMA_AB			(1 << 4)
#define DMA_D1			(1 << 3)
R
Ralf Baechle 已提交
62
#define DMA_BE1			(1 << 2)
63
#define DMA_D0			(1 << 1)
R
Ralf Baechle 已提交
64
#define DMA_BE0			(1 << 0)
65 66 67 68 69 70 71 72 73 74 75 76

#define DMA_PERIPHERAL_ADDR	0x00000008
#define DMA_BUFFER0_START	0x0000000C
#define DMA_BUFFER1_START	0x00000014
#define DMA_BUFFER0_COUNT	0x00000010
#define DMA_BUFFER1_COUNT	0x00000018
#define DMA_BAH_BIT	16
#define DMA_BAH_MASK	(0x0f << DMA_BAH_BIT)
#define DMA_COUNT_BIT	0
#define DMA_COUNT_MASK	(0xffff << DMA_COUNT_BIT)

/* DMA Device IDs follow */
L
Linus Torvalds 已提交
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
enum {
	DMA_ID_UART0_TX = 0,
	DMA_ID_UART0_RX,
	DMA_ID_GP04,
	DMA_ID_GP05,
	DMA_ID_AC97C_TX,
	DMA_ID_AC97C_RX,
	DMA_ID_UART3_TX,
	DMA_ID_UART3_RX,
	DMA_ID_USBDEV_EP0_RX,
	DMA_ID_USBDEV_EP0_TX,
	DMA_ID_USBDEV_EP2_TX,
	DMA_ID_USBDEV_EP3_TX,
	DMA_ID_USBDEV_EP4_RX,
	DMA_ID_USBDEV_EP5_RX,
	DMA_ID_I2S_TX,
	DMA_ID_I2S_RX,
	DMA_NUM_DEV
};

/* DMA Device ID's for 2nd bank (AU1100) follow */
enum {
	DMA_ID_SD0_TX = 0,
	DMA_ID_SD0_RX,
	DMA_ID_SD1_TX,
	DMA_ID_SD1_RX,
	DMA_NUM_DEV_BANK2
};

struct dma_chan {
107 108
	int dev_id;		/* this channel is allocated if >= 0, */
				/* free otherwise */
109
	void __iomem *io;
L
Linus Torvalds 已提交
110 111 112 113 114 115 116 117 118 119 120
	const char *dev_str;
	int irq;
	void *irq_dev;
	unsigned int fifo_addr;
	unsigned int mode;
};

/* These are in arch/mips/au1000/common/dma.c */
extern struct dma_chan au1000_dma_table[];
extern int request_au1000_dma(int dev_id,
			      const char *dev_str,
121
			      irq_handler_t irqhandler,
L
Linus Torvalds 已提交
122 123 124 125 126 127 128 129
			      unsigned long irqflags,
			      void *irq_dev_id);
extern void free_au1000_dma(unsigned int dmanr);
extern int au1000_dma_read_proc(char *buf, char **start, off_t fpos,
				int length, int *eof, void *data);
extern void dump_au1000_dma_channel(unsigned int dmanr);
extern spinlock_t au1000_dma_spin_lock;

130
static inline struct dma_chan *get_dma_chan(unsigned int dmanr)
L
Linus Torvalds 已提交
131
{
132 133
	if (dmanr >= NUM_AU1000_DMA_CHANNELS ||
	    au1000_dma_table[dmanr].dev_id < 0)
L
Linus Torvalds 已提交
134 135 136 137
		return NULL;
	return &au1000_dma_table[dmanr];
}

138
static inline unsigned long claim_dma_lock(void)
L
Linus Torvalds 已提交
139 140
{
	unsigned long flags;
141

L
Linus Torvalds 已提交
142 143 144 145
	spin_lock_irqsave(&au1000_dma_spin_lock, flags);
	return flags;
}

146
static inline void release_dma_lock(unsigned long flags)
L
Linus Torvalds 已提交
147 148 149 150 151 152 153
{
	spin_unlock_irqrestore(&au1000_dma_spin_lock, flags);
}

/*
 * Set the DMA buffer enable bits in the mode register.
 */
154
static inline void enable_dma_buffer0(unsigned int dmanr)
L
Linus Torvalds 已提交
155 156
{
	struct dma_chan *chan = get_dma_chan(dmanr);
157

L
Linus Torvalds 已提交
158 159
	if (!chan)
		return;
160
	__raw_writel(DMA_BE0, chan->io + DMA_MODE_SET);
L
Linus Torvalds 已提交
161
}
162 163

static inline void enable_dma_buffer1(unsigned int dmanr)
L
Linus Torvalds 已提交
164 165
{
	struct dma_chan *chan = get_dma_chan(dmanr);
166

L
Linus Torvalds 已提交
167 168
	if (!chan)
		return;
169
	__raw_writel(DMA_BE1, chan->io + DMA_MODE_SET);
L
Linus Torvalds 已提交
170
}
171
static inline void enable_dma_buffers(unsigned int dmanr)
L
Linus Torvalds 已提交
172 173
{
	struct dma_chan *chan = get_dma_chan(dmanr);
174

L
Linus Torvalds 已提交
175 176
	if (!chan)
		return;
177
	__raw_writel(DMA_BE0 | DMA_BE1, chan->io + DMA_MODE_SET);
L
Linus Torvalds 已提交
178 179
}

180
static inline void start_dma(unsigned int dmanr)
L
Linus Torvalds 已提交
181 182
{
	struct dma_chan *chan = get_dma_chan(dmanr);
183

L
Linus Torvalds 已提交
184 185
	if (!chan)
		return;
186
	__raw_writel(DMA_GO, chan->io + DMA_MODE_SET);
L
Linus Torvalds 已提交
187 188 189 190
}

#define DMA_HALT_POLL 0x5000

191
static inline void halt_dma(unsigned int dmanr)
L
Linus Torvalds 已提交
192 193 194
{
	struct dma_chan *chan = get_dma_chan(dmanr);
	int i;
195

L
Linus Torvalds 已提交
196 197
	if (!chan)
		return;
198
	__raw_writel(DMA_GO, chan->io + DMA_MODE_CLEAR);
199 200

	/* Poll the halt bit */
L
Linus Torvalds 已提交
201
	for (i = 0; i < DMA_HALT_POLL; i++)
202
		if (__raw_readl(chan->io + DMA_MODE_READ) & DMA_HALT)
L
Linus Torvalds 已提交
203 204 205 206 207
			break;
	if (i == DMA_HALT_POLL)
		printk(KERN_INFO "halt_dma: HALT poll expired!\n");
}

208
static inline void disable_dma(unsigned int dmanr)
L
Linus Torvalds 已提交
209 210
{
	struct dma_chan *chan = get_dma_chan(dmanr);
211

L
Linus Torvalds 已提交
212 213 214 215 216
	if (!chan)
		return;

	halt_dma(dmanr);

217
	/* Now we can disable the buffers */
218
	__raw_writel(~DMA_GO, chan->io + DMA_MODE_CLEAR);
L
Linus Torvalds 已提交
219 220
}

221
static inline int dma_halted(unsigned int dmanr)
L
Linus Torvalds 已提交
222 223
{
	struct dma_chan *chan = get_dma_chan(dmanr);
224

L
Linus Torvalds 已提交
225 226
	if (!chan)
		return 1;
227
	return (__raw_readl(chan->io + DMA_MODE_READ) & DMA_HALT) ? 1 : 0;
L
Linus Torvalds 已提交
228 229
}

230 231
/* Initialize a DMA channel. */
static inline void init_dma(unsigned int dmanr)
L
Linus Torvalds 已提交
232 233 234
{
	struct dma_chan *chan = get_dma_chan(dmanr);
	u32 mode;
235

L
Linus Torvalds 已提交
236 237 238 239 240
	if (!chan)
		return;

	disable_dma(dmanr);

241
	/* Set device FIFO address */
242
	__raw_writel(CPHYSADDR(chan->fifo_addr), chan->io + DMA_PERIPHERAL_ADDR);
L
Linus Torvalds 已提交
243 244 245 246 247

	mode = chan->mode | (chan->dev_id << DMA_DID_BIT);
	if (chan->irq)
		mode |= DMA_IE;

248 249
	__raw_writel(~mode, chan->io + DMA_MODE_CLEAR);
	__raw_writel(mode,	 chan->io + DMA_MODE_SET);
L
Linus Torvalds 已提交
250 251 252
}

/*
253
 * Set mode for a specific DMA channel
L
Linus Torvalds 已提交
254
 */
255
static inline void set_dma_mode(unsigned int dmanr, unsigned int mode)
L
Linus Torvalds 已提交
256 257
{
	struct dma_chan *chan = get_dma_chan(dmanr);
258

L
Linus Torvalds 已提交
259 260 261 262 263 264 265 266 267 268 269 270
	if (!chan)
		return;
	/*
	 * set_dma_mode is only allowed to change endianess, direction,
	 * transfer size, device FIFO width, and coherency settings.
	 * Make sure anything else is masked off.
	 */
	mode &= (DMA_BE | DMA_DR | DMA_TS8 | DMA_DW_MASK | DMA_NC);
	chan->mode &= ~(DMA_BE | DMA_DR | DMA_TS8 | DMA_DW_MASK | DMA_NC);
	chan->mode |= mode;
}

271
static inline unsigned int get_dma_mode(unsigned int dmanr)
L
Linus Torvalds 已提交
272 273
{
	struct dma_chan *chan = get_dma_chan(dmanr);
274

L
Linus Torvalds 已提交
275 276 277 278 279
	if (!chan)
		return 0;
	return chan->mode;
}

280
static inline int get_dma_active_buffer(unsigned int dmanr)
L
Linus Torvalds 已提交
281 282
{
	struct dma_chan *chan = get_dma_chan(dmanr);
283

L
Linus Torvalds 已提交
284 285
	if (!chan)
		return -1;
286
	return (__raw_readl(chan->io + DMA_MODE_READ) & DMA_AB) ? 1 : 0;
L
Linus Torvalds 已提交
287 288 289
}

/*
290
 * Set the device FIFO address for a specific DMA channel - only
L
Linus Torvalds 已提交
291 292 293
 * applicable to GPO4 and GPO5. All the other devices have fixed
 * FIFO addresses.
 */
294
static inline void set_dma_fifo_addr(unsigned int dmanr, unsigned int a)
L
Linus Torvalds 已提交
295 296
{
	struct dma_chan *chan = get_dma_chan(dmanr);
297

L
Linus Torvalds 已提交
298 299 300
	if (!chan)
		return;

301
	if (chan->mode & DMA_DS)	/* second bank of device IDs */
L
Linus Torvalds 已提交
302 303 304 305 306
		return;

	if (chan->dev_id != DMA_ID_GP04 && chan->dev_id != DMA_ID_GP05)
		return;

307
	__raw_writel(CPHYSADDR(a), chan->io + DMA_PERIPHERAL_ADDR);
L
Linus Torvalds 已提交
308 309 310 311 312
}

/*
 * Clear the DMA buffer done bits in the mode register.
 */
313
static inline void clear_dma_done0(unsigned int dmanr)
L
Linus Torvalds 已提交
314 315
{
	struct dma_chan *chan = get_dma_chan(dmanr);
316

L
Linus Torvalds 已提交
317 318
	if (!chan)
		return;
319
	__raw_writel(DMA_D0, chan->io + DMA_MODE_CLEAR);
L
Linus Torvalds 已提交
320
}
321 322

static inline void clear_dma_done1(unsigned int dmanr)
L
Linus Torvalds 已提交
323 324
{
	struct dma_chan *chan = get_dma_chan(dmanr);
325

L
Linus Torvalds 已提交
326 327
	if (!chan)
		return;
328
	__raw_writel(DMA_D1, chan->io + DMA_MODE_CLEAR);
L
Linus Torvalds 已提交
329 330 331 332 333
}

/*
 * This does nothing - not applicable to Au1000 DMA.
 */
334
static inline void set_dma_page(unsigned int dmanr, char pagenr)
L
Linus Torvalds 已提交
335 336 337 338 339 340
{
}

/*
 * Set Buffer 0 transfer address for specific DMA channel.
 */
341
static inline void set_dma_addr0(unsigned int dmanr, unsigned int a)
L
Linus Torvalds 已提交
342 343
{
	struct dma_chan *chan = get_dma_chan(dmanr);
344

L
Linus Torvalds 已提交
345 346
	if (!chan)
		return;
347
	__raw_writel(a, chan->io + DMA_BUFFER0_START);
L
Linus Torvalds 已提交
348 349 350 351 352
}

/*
 * Set Buffer 1 transfer address for specific DMA channel.
 */
353
static inline void set_dma_addr1(unsigned int dmanr, unsigned int a)
L
Linus Torvalds 已提交
354 355
{
	struct dma_chan *chan = get_dma_chan(dmanr);
356

L
Linus Torvalds 已提交
357 358
	if (!chan)
		return;
359
	__raw_writel(a, chan->io + DMA_BUFFER1_START);
L
Linus Torvalds 已提交
360 361 362 363 364 365
}


/*
 * Set Buffer 0 transfer size (max 64k) for a specific DMA channel.
 */
366
static inline void set_dma_count0(unsigned int dmanr, unsigned int count)
L
Linus Torvalds 已提交
367 368
{
	struct dma_chan *chan = get_dma_chan(dmanr);
369

L
Linus Torvalds 已提交
370 371 372
	if (!chan)
		return;
	count &= DMA_COUNT_MASK;
373
	__raw_writel(count, chan->io + DMA_BUFFER0_COUNT);
L
Linus Torvalds 已提交
374 375 376 377 378
}

/*
 * Set Buffer 1 transfer size (max 64k) for a specific DMA channel.
 */
379
static inline void set_dma_count1(unsigned int dmanr, unsigned int count)
L
Linus Torvalds 已提交
380 381
{
	struct dma_chan *chan = get_dma_chan(dmanr);
382

L
Linus Torvalds 已提交
383 384 385
	if (!chan)
		return;
	count &= DMA_COUNT_MASK;
386
	__raw_writel(count, chan->io + DMA_BUFFER1_COUNT);
L
Linus Torvalds 已提交
387 388 389 390 391
}

/*
 * Set both buffer transfer sizes (max 64k) for a specific DMA channel.
 */
392
static inline void set_dma_count(unsigned int dmanr, unsigned int count)
L
Linus Torvalds 已提交
393 394
{
	struct dma_chan *chan = get_dma_chan(dmanr);
395

L
Linus Torvalds 已提交
396 397 398
	if (!chan)
		return;
	count &= DMA_COUNT_MASK;
399 400
	__raw_writel(count, chan->io + DMA_BUFFER0_COUNT);
	__raw_writel(count, chan->io + DMA_BUFFER1_COUNT);
L
Linus Torvalds 已提交
401 402 403 404 405 406
}

/*
 * Returns which buffer has its done bit set in the mode register.
 * Returns -1 if neither or both done bits set.
 */
407
static inline unsigned int get_dma_buffer_done(unsigned int dmanr)
L
Linus Torvalds 已提交
408 409
{
	struct dma_chan *chan = get_dma_chan(dmanr);
410

L
Linus Torvalds 已提交
411 412
	if (!chan)
		return 0;
413
	return __raw_readl(chan->io + DMA_MODE_READ) & (DMA_D0 | DMA_D1);
L
Linus Torvalds 已提交
414 415 416 417 418 419
}


/*
 * Returns the DMA channel's Buffer Done IRQ number.
 */
420
static inline int get_dma_done_irq(unsigned int dmanr)
L
Linus Torvalds 已提交
421 422
{
	struct dma_chan *chan = get_dma_chan(dmanr);
423

L
Linus Torvalds 已提交
424 425 426 427 428 429 430 431
	if (!chan)
		return -1;
	return chan->irq;
}

/*
 * Get DMA residue count. Returns the number of _bytes_ left to transfer.
 */
432
static inline int get_dma_residue(unsigned int dmanr)
L
Linus Torvalds 已提交
433 434 435
{
	int curBufCntReg, count;
	struct dma_chan *chan = get_dma_chan(dmanr);
436

L
Linus Torvalds 已提交
437 438 439
	if (!chan)
		return 0;

440
	curBufCntReg = (__raw_readl(chan->io + DMA_MODE_READ) & DMA_AB) ?
L
Linus Torvalds 已提交
441 442
	    DMA_BUFFER1_COUNT : DMA_BUFFER0_COUNT;

443
	count = __raw_readl(chan->io + curBufCntReg) & DMA_COUNT_MASK;
L
Linus Torvalds 已提交
444 445 446 447 448 449 450 451 452 453

	if ((chan->mode & DMA_DW_MASK) == DMA_DW16)
		count <<= 1;
	else if ((chan->mode & DMA_DW_MASK) == DMA_DW32)
		count <<= 2;

	return count;
}

#endif /* __ASM_AU1000_DMA_H */