dma.h 9.2 KB
Newer Older
Bryan Wu's avatar
Bryan Wu committed
1
/*
2
 * dma.h - Blackfin DMA defines/structures/etc...
Bryan Wu's avatar
Bryan Wu committed
3
 *
4 5
 * Copyright 2004-2008 Analog Devices Inc.
 * Licensed under the GPL-2 or later.
Bryan Wu's avatar
Bryan Wu committed
6 7 8 9 10 11
 */

#ifndef _BLACKFIN_DMA_H_
#define _BLACKFIN_DMA_H_

#include <linux/interrupt.h>
12
#include <mach/dma.h>
Arun Sharma's avatar
Arun Sharma committed
13
#include <linux/atomic.h>
Bryan Wu's avatar
Bryan Wu committed
14
#include <asm/blackfin.h>
15
#include <asm/page.h>
16
#include <asm-generic/dma.h>
17
#include <asm/bfin_dma.h>
Bryan Wu's avatar
Bryan Wu committed
18 19 20 21

/*-------------------------
 * config reg bits value
 *-------------------------*/
Mike Frysinger's avatar
Mike Frysinger committed
22 23 24
#define DATA_SIZE_8			0
#define DATA_SIZE_16		1
#define DATA_SIZE_32		2
25 26 27
#ifdef CONFIG_BF60x
#define DATA_SIZE_64		3
#endif
Bryan Wu's avatar
Bryan Wu committed
28

Mike Frysinger's avatar
Mike Frysinger committed
29 30
#define DMA_FLOW_STOP		0
#define DMA_FLOW_AUTO		1
31 32 33 34 35 36
#ifdef CONFIG_BF60x
#define DMA_FLOW_LIST		4
#define DMA_FLOW_ARRAY		5
#define DMA_FLOW_LIST_DEMAND	6
#define DMA_FLOW_ARRAY_DEMAND	7
#else
Mike Frysinger's avatar
Mike Frysinger committed
37 38 39
#define DMA_FLOW_ARRAY		4
#define DMA_FLOW_SMALL		6
#define DMA_FLOW_LARGE		7
40
#endif
Bryan Wu's avatar
Bryan Wu committed
41

Mike Frysinger's avatar
Mike Frysinger committed
42 43
#define DIMENSION_LINEAR	0
#define DIMENSION_2D		1
Bryan Wu's avatar
Bryan Wu committed
44

Mike Frysinger's avatar
Mike Frysinger committed
45 46
#define DIR_READ			0
#define DIR_WRITE			1
Bryan Wu's avatar
Bryan Wu committed
47

Mike Frysinger's avatar
Mike Frysinger committed
48
#define INTR_DISABLE		0
49 50 51
#ifdef CONFIG_BF60x
#define INTR_ON_PERI			1
#endif
Mike Frysinger's avatar
Mike Frysinger committed
52 53
#define INTR_ON_BUF			2
#define INTR_ON_ROW			3
Bryan Wu's avatar
Bryan Wu committed
54

55
#define DMA_NOSYNC_KEEP_DMA_BUF	0
Mike Frysinger's avatar
Mike Frysinger committed
56
#define DMA_SYNC_RESTART		1
57

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
#ifdef DMA_MMR_SIZE_32
#define DMA_MMR_SIZE_TYPE long
#define DMA_MMR_READ bfin_read32
#define DMA_MMR_WRITE bfin_write32
#else
#define DMA_MMR_SIZE_TYPE short
#define DMA_MMR_READ bfin_read16
#define DMA_MMR_WRITE bfin_write16
#endif

struct dma_desc_array {
	unsigned long start_addr;
	unsigned DMA_MMR_SIZE_TYPE cfg;
	unsigned DMA_MMR_SIZE_TYPE x_count;
	DMA_MMR_SIZE_TYPE x_modify;
} __attribute__((packed));

Bryan Wu's avatar
Bryan Wu committed
75
struct dmasg {
76
	void *next_desc_addr;
Bryan Wu's avatar
Bryan Wu committed
77
	unsigned long start_addr;
78 79 80 81 82
	unsigned DMA_MMR_SIZE_TYPE cfg;
	unsigned DMA_MMR_SIZE_TYPE x_count;
	DMA_MMR_SIZE_TYPE x_modify;
	unsigned DMA_MMR_SIZE_TYPE y_count;
	DMA_MMR_SIZE_TYPE y_modify;
Bryan Wu's avatar
Bryan Wu committed
83 84 85
} __attribute__((packed));

struct dma_register {
86
	void *next_desc_ptr;	/* DMA Next Descriptor Pointer register */
Bryan Wu's avatar
Bryan Wu committed
87
	unsigned long start_addr;	/* DMA Start address  register */
88 89
#ifdef CONFIG_BF60x
	unsigned long cfg;	/* DMA Configuration register */
Bryan Wu's avatar
Bryan Wu committed
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
	unsigned long x_count;	/* DMA x_count register */

	long x_modify;	/* DMA x_modify register */

	unsigned long y_count;	/* DMA y_count register */

	long y_modify;	/* DMA y_modify register */

	unsigned long reserved;
	unsigned long reserved2;

	void *curr_desc_ptr;	/* DMA Current Descriptor Pointer
					   register */
	void *prev_desc_ptr;	/* DMA previous initial Descriptor Pointer
					   register */
	unsigned long curr_addr_ptr;	/* DMA Current Address Pointer
						   register */
	unsigned long irq_status;	/* DMA irq status register */

	unsigned long curr_x_count;	/* DMA Current x-count register */

	unsigned long curr_y_count;	/* DMA Current y-count register */

	unsigned long reserved3;

	unsigned long bw_limit_count;	/* DMA band width limit count register */
	unsigned long curr_bw_limit_count;	/* DMA Current band width limit
							count register */
	unsigned long bw_monitor_count;	/* DMA band width limit count register */
	unsigned long curr_bw_monitor_count;	/* DMA Current band width limit
							count register */
#else
Bryan Wu's avatar
Bryan Wu committed
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
	unsigned short cfg;	/* DMA Configuration register */
	unsigned short dummy1;	/* DMA Configuration register */

	unsigned long reserved;

	unsigned short x_count;	/* DMA x_count register */
	unsigned short dummy2;

	short x_modify;	/* DMA x_modify register */
	unsigned short dummy3;

	unsigned short y_count;	/* DMA y_count register */
	unsigned short dummy4;

	short y_modify;	/* DMA y_modify register */
	unsigned short dummy5;

140
	void *curr_desc_ptr;	/* DMA Current Descriptor Pointer
Bryan Wu's avatar
Bryan Wu committed
141
					   register */
142
	unsigned long curr_addr_ptr;	/* DMA Current Address Pointer
Bryan Wu's avatar
Bryan Wu committed
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
						   register */
	unsigned short irq_status;	/* DMA irq status register */
	unsigned short dummy6;

	unsigned short peripheral_map;	/* DMA peripheral map register */
	unsigned short dummy7;

	unsigned short curr_x_count;	/* DMA Current x-count register */
	unsigned short dummy8;

	unsigned long reserved2;

	unsigned short curr_y_count;	/* DMA Current y-count register */
	unsigned short dummy9;

	unsigned long reserved3;
159
#endif
Bryan Wu's avatar
Bryan Wu committed
160 161 162 163

};

struct dma_channel {
164
	const char *device_id;
165
	atomic_t chan_status;
166
	volatile struct dma_register *regs;
Bryan Wu's avatar
Bryan Wu committed
167
	struct dmasg *sg;		/* large mode descriptor */
168
	unsigned int irq;
Bryan Wu's avatar
Bryan Wu committed
169
	void *data;
170 171 172
#ifdef CONFIG_PM
	unsigned short saved_peripheral_map;
#endif
Bryan Wu's avatar
Bryan Wu committed
173 174
};

175 176 177 178 179
#ifdef CONFIG_PM
int blackfin_dma_suspend(void);
void blackfin_dma_resume(void);
#endif

Bryan Wu's avatar
Bryan Wu committed
180 181 182
/*******************************************************************************
*	DMA API's
*******************************************************************************/
183
extern struct dma_channel dma_ch[MAX_DMA_CHANNELS];
184
extern struct dma_register * const dma_io_base_addr[MAX_DMA_CHANNELS];
185 186 187 188 189 190
extern int channel2irq(unsigned int channel);

static inline void set_dma_start_addr(unsigned int channel, unsigned long addr)
{
	dma_ch[channel].regs->start_addr = addr;
}
191
static inline void set_dma_next_desc_addr(unsigned int channel, void *addr)
192 193 194
{
	dma_ch[channel].regs->next_desc_ptr = addr;
}
195
static inline void set_dma_curr_desc_addr(unsigned int channel, void *addr)
196 197 198
{
	dma_ch[channel].regs->curr_desc_ptr = addr;
}
199
static inline void set_dma_x_count(unsigned int channel, unsigned DMA_MMR_SIZE_TYPE x_count)
200 201 202
{
	dma_ch[channel].regs->x_count = x_count;
}
203
static inline void set_dma_y_count(unsigned int channel, unsigned DMA_MMR_SIZE_TYPE y_count)
204 205 206
{
	dma_ch[channel].regs->y_count = y_count;
}
207
static inline void set_dma_x_modify(unsigned int channel, DMA_MMR_SIZE_TYPE x_modify)
208 209 210
{
	dma_ch[channel].regs->x_modify = x_modify;
}
211
static inline void set_dma_y_modify(unsigned int channel, DMA_MMR_SIZE_TYPE y_modify)
212 213 214
{
	dma_ch[channel].regs->y_modify = y_modify;
}
215
static inline void set_dma_config(unsigned int channel, unsigned DMA_MMR_SIZE_TYPE config)
216 217 218 219 220 221 222 223
{
	dma_ch[channel].regs->cfg = config;
}
static inline void set_dma_curr_addr(unsigned int channel, unsigned long addr)
{
	dma_ch[channel].regs->curr_addr_ptr = addr;
}

224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
#ifdef CONFIG_BF60x
static inline unsigned long
set_bfin_dma_config2(char direction, char flow_mode, char intr_mode,
		     char dma_mode, char mem_width, char syncmode, char peri_width)
{
	unsigned long config = 0;

	switch (intr_mode) {
	case INTR_ON_BUF:
		if (dma_mode == DIMENSION_2D)
			config = DI_EN_Y;
		else
			config = DI_EN_X;
		break;
	case INTR_ON_ROW:
		config = DI_EN_X;
		break;
	case INTR_ON_PERI:
		config = DI_EN_P;
		break;
	};

	return config | (direction << 1) | (mem_width << 8) | (dma_mode << 26) |
		(flow_mode << 12) | (syncmode << 2) | (peri_width << 4);
}
#endif

static inline unsigned DMA_MMR_SIZE_TYPE
252
set_bfin_dma_config(char direction, char flow_mode,
253
		    char intr_mode, char dma_mode, char mem_width, char syncmode)
254
{
255 256 257 258 259
#ifdef CONFIG_BF60x
	return set_bfin_dma_config2(direction, flow_mode, intr_mode, dma_mode,
		mem_width, syncmode, mem_width);
#else
	return (direction << 1) | (mem_width << 2) | (dma_mode << 4) |
260
		(intr_mode << 6) | (flow_mode << 12) | (syncmode << 5);
261
#endif
262 263
}

264
static inline unsigned DMA_MMR_SIZE_TYPE get_dma_curr_irqstat(unsigned int channel)
265 266 267
{
	return dma_ch[channel].regs->irq_status;
}
268
static inline unsigned DMA_MMR_SIZE_TYPE get_dma_curr_xcount(unsigned int channel)
269 270 271
{
	return dma_ch[channel].regs->curr_x_count;
}
272
static inline unsigned DMA_MMR_SIZE_TYPE get_dma_curr_ycount(unsigned int channel)
273 274 275
{
	return dma_ch[channel].regs->curr_y_count;
}
276
static inline void *get_dma_next_desc_ptr(unsigned int channel)
277 278 279
{
	return dma_ch[channel].regs->next_desc_ptr;
}
280
static inline void *get_dma_curr_desc_ptr(unsigned int channel)
281 282 283
{
	return dma_ch[channel].regs->curr_desc_ptr;
}
284
static inline unsigned DMA_MMR_SIZE_TYPE get_dma_config(unsigned int channel)
285 286 287
{
	return dma_ch[channel].regs->cfg;
}
288 289 290 291 292 293 294
static inline unsigned long get_dma_curr_addr(unsigned int channel)
{
	return dma_ch[channel].regs->curr_addr_ptr;
}

static inline void set_dma_sg(unsigned int channel, struct dmasg *sg, int ndsize)
{
295 296 297 298 299 300 301
	/* Make sure the internal data buffers in the core are drained
	 * so that the DMA descriptors are completely written when the
	 * DMA engine goes to fetch them below.
	 */
	SSYNC();

	dma_ch[channel].regs->next_desc_ptr = sg;
302
	dma_ch[channel].regs->cfg =
303 304
		(dma_ch[channel].regs->cfg & ~NDSIZE) |
		((ndsize << NDSIZE_OFFSET) & NDSIZE);
305 306 307 308
}

static inline int dma_channel_active(unsigned int channel)
{
309
	return atomic_read(&dma_ch[channel].chan_status);
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
}

static inline void disable_dma(unsigned int channel)
{
	dma_ch[channel].regs->cfg &= ~DMAEN;
	SSYNC();
}
static inline void enable_dma(unsigned int channel)
{
	dma_ch[channel].regs->cfg |= DMAEN;
}
int set_dma_callback(unsigned int channel, irq_handler_t callback, void *data);

static inline void dma_disable_irq(unsigned int channel)
{
	disable_irq(dma_ch[channel].irq);
}
327 328 329 330
static inline void dma_disable_irq_nosync(unsigned int channel)
{
	disable_irq_nosync(dma_ch[channel].irq);
}
331 332 333 334 335 336
static inline void dma_enable_irq(unsigned int channel)
{
	enable_irq(dma_ch[channel].irq);
}
static inline void clear_dma_irqstat(unsigned int channel)
{
337
	dma_ch[channel].regs->irq_status = DMA_DONE | DMA_ERR | DMA_PIRQ;
338 339
}

Bryan Wu's avatar
Bryan Wu committed
340
void *dma_memcpy(void *dest, const void *src, size_t count);
341
void *dma_memcpy_nocache(void *dest, const void *src, size_t count);
Bryan Wu's avatar
Bryan Wu committed
342
void *safe_dma_memcpy(void *dest, const void *src, size_t count);
343
void blackfin_dma_early_init(void);
344 345
void early_dma_memcpy(void *dest, const void *src, size_t count);
void early_dma_memcpy_done(void);
Bryan Wu's avatar
Bryan Wu committed
346 347

#endif