| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame^] | 1 | /* | 
|  | 2 | * linux/arch/arm/omap/dma.c | 
|  | 3 | * | 
|  | 4 | * Copyright (C) 2003 Nokia Corporation | 
|  | 5 | * Author: Juha Yrjölä <juha.yrjola@nokia.com> | 
|  | 6 | * DMA channel linking for 1610 by Samuel Ortiz <samuel.ortiz@nokia.com> | 
|  | 7 | * Graphics DMA and LCD DMA graphics tranformations | 
|  | 8 | * by Imre Deak <imre.deak@nokia.com> | 
|  | 9 | * Some functions based on earlier dma-omap.c Copyright (C) 2001 RidgeRun, Inc. | 
|  | 10 | * | 
|  | 11 | * Support functions for the OMAP internal DMA channels. | 
|  | 12 | * | 
|  | 13 | * This program is free software; you can redistribute it and/or modify | 
|  | 14 | * it under the terms of the GNU General Public License version 2 as | 
|  | 15 | * published by the Free Software Foundation. | 
|  | 16 | * | 
|  | 17 | */ | 
|  | 18 |  | 
|  | 19 | #include <linux/module.h> | 
|  | 20 | #include <linux/init.h> | 
|  | 21 | #include <linux/sched.h> | 
|  | 22 | #include <linux/spinlock.h> | 
|  | 23 | #include <linux/errno.h> | 
|  | 24 | #include <linux/interrupt.h> | 
|  | 25 |  | 
|  | 26 | #include <asm/system.h> | 
|  | 27 | #include <asm/irq.h> | 
|  | 28 | #include <asm/hardware.h> | 
|  | 29 | #include <asm/dma.h> | 
|  | 30 | #include <asm/io.h> | 
|  | 31 |  | 
|  | 32 | #include <asm/arch/tc.h> | 
|  | 33 |  | 
|  | 34 | #define OMAP_DMA_ACTIVE		0x01 | 
|  | 35 |  | 
|  | 36 | #define OMAP_DMA_CCR_EN		(1 << 7) | 
|  | 37 |  | 
|  | 38 | #define OMAP_FUNC_MUX_ARM_BASE	(0xfffe1000 + 0xec) | 
|  | 39 |  | 
|  | 40 | static int enable_1510_mode = 0; | 
|  | 41 |  | 
|  | 42 | struct omap_dma_lch { | 
|  | 43 | int next_lch; | 
|  | 44 | int dev_id; | 
|  | 45 | u16 saved_csr; | 
|  | 46 | u16 enabled_irqs; | 
|  | 47 | const char *dev_name; | 
|  | 48 | void (* callback)(int lch, u16 ch_status, void *data); | 
|  | 49 | void *data; | 
|  | 50 | long flags; | 
|  | 51 | }; | 
|  | 52 |  | 
|  | 53 | static int dma_chan_count; | 
|  | 54 |  | 
|  | 55 | static spinlock_t dma_chan_lock; | 
|  | 56 | static struct omap_dma_lch dma_chan[OMAP_LOGICAL_DMA_CH_COUNT]; | 
|  | 57 |  | 
|  | 58 | const static u8 dma_irq[OMAP_LOGICAL_DMA_CH_COUNT] = { | 
|  | 59 | INT_DMA_CH0_6, INT_DMA_CH1_7, INT_DMA_CH2_8, INT_DMA_CH3, | 
|  | 60 | INT_DMA_CH4, INT_DMA_CH5, INT_1610_DMA_CH6, INT_1610_DMA_CH7, | 
|  | 61 | INT_1610_DMA_CH8, INT_1610_DMA_CH9, INT_1610_DMA_CH10, | 
|  | 62 | INT_1610_DMA_CH11, INT_1610_DMA_CH12, INT_1610_DMA_CH13, | 
|  | 63 | INT_1610_DMA_CH14, INT_1610_DMA_CH15, INT_DMA_LCD | 
|  | 64 | }; | 
|  | 65 |  | 
|  | 66 | static inline int get_gdma_dev(int req) | 
|  | 67 | { | 
|  | 68 | u32 reg = OMAP_FUNC_MUX_ARM_BASE + ((req - 1) / 5) * 4; | 
|  | 69 | int shift = ((req - 1) % 5) * 6; | 
|  | 70 |  | 
|  | 71 | return ((omap_readl(reg) >> shift) & 0x3f) + 1; | 
|  | 72 | } | 
|  | 73 |  | 
|  | 74 | static inline void set_gdma_dev(int req, int dev) | 
|  | 75 | { | 
|  | 76 | u32 reg = OMAP_FUNC_MUX_ARM_BASE + ((req - 1) / 5) * 4; | 
|  | 77 | int shift = ((req - 1) % 5) * 6; | 
|  | 78 | u32 l; | 
|  | 79 |  | 
|  | 80 | l = omap_readl(reg); | 
|  | 81 | l &= ~(0x3f << shift); | 
|  | 82 | l |= (dev - 1) << shift; | 
|  | 83 | omap_writel(l, reg); | 
|  | 84 | } | 
|  | 85 |  | 
|  | 86 | static void clear_lch_regs(int lch) | 
|  | 87 | { | 
|  | 88 | int i; | 
|  | 89 | u32 lch_base = OMAP_DMA_BASE + lch * 0x40; | 
|  | 90 |  | 
|  | 91 | for (i = 0; i < 0x2c; i += 2) | 
|  | 92 | omap_writew(0, lch_base + i); | 
|  | 93 | } | 
|  | 94 |  | 
|  | 95 | void omap_set_dma_priority(int dst_port, int priority) | 
|  | 96 | { | 
|  | 97 | unsigned long reg; | 
|  | 98 | u32 l; | 
|  | 99 |  | 
|  | 100 | switch (dst_port) { | 
|  | 101 | case OMAP_DMA_PORT_OCP_T1:	/* FFFECC00 */ | 
|  | 102 | reg = OMAP_TC_OCPT1_PRIOR; | 
|  | 103 | break; | 
|  | 104 | case OMAP_DMA_PORT_OCP_T2:	/* FFFECCD0 */ | 
|  | 105 | reg = OMAP_TC_OCPT2_PRIOR; | 
|  | 106 | break; | 
|  | 107 | case OMAP_DMA_PORT_EMIFF:	/* FFFECC08 */ | 
|  | 108 | reg = OMAP_TC_EMIFF_PRIOR; | 
|  | 109 | break; | 
|  | 110 | case OMAP_DMA_PORT_EMIFS:	/* FFFECC04 */ | 
|  | 111 | reg = OMAP_TC_EMIFS_PRIOR; | 
|  | 112 | break; | 
|  | 113 | default: | 
|  | 114 | BUG(); | 
|  | 115 | return; | 
|  | 116 | } | 
|  | 117 | l = omap_readl(reg); | 
|  | 118 | l &= ~(0xf << 8); | 
|  | 119 | l |= (priority & 0xf) << 8; | 
|  | 120 | omap_writel(l, reg); | 
|  | 121 | } | 
|  | 122 |  | 
|  | 123 | void omap_set_dma_transfer_params(int lch, int data_type, int elem_count, | 
|  | 124 | int frame_count, int sync_mode) | 
|  | 125 | { | 
|  | 126 | u16 w; | 
|  | 127 |  | 
|  | 128 | w = omap_readw(OMAP_DMA_CSDP(lch)); | 
|  | 129 | w &= ~0x03; | 
|  | 130 | w |= data_type; | 
|  | 131 | omap_writew(w, OMAP_DMA_CSDP(lch)); | 
|  | 132 |  | 
|  | 133 | w = omap_readw(OMAP_DMA_CCR(lch)); | 
|  | 134 | w &= ~(1 << 5); | 
|  | 135 | if (sync_mode == OMAP_DMA_SYNC_FRAME) | 
|  | 136 | w |= 1 << 5; | 
|  | 137 | omap_writew(w, OMAP_DMA_CCR(lch)); | 
|  | 138 |  | 
|  | 139 | w = omap_readw(OMAP_DMA_CCR2(lch)); | 
|  | 140 | w &= ~(1 << 2); | 
|  | 141 | if (sync_mode == OMAP_DMA_SYNC_BLOCK) | 
|  | 142 | w |= 1 << 2; | 
|  | 143 | omap_writew(w, OMAP_DMA_CCR2(lch)); | 
|  | 144 |  | 
|  | 145 | omap_writew(elem_count, OMAP_DMA_CEN(lch)); | 
|  | 146 | omap_writew(frame_count, OMAP_DMA_CFN(lch)); | 
|  | 147 |  | 
|  | 148 | } | 
|  | 149 | void omap_set_dma_color_mode(int lch, enum omap_dma_color_mode mode, u32 color) | 
|  | 150 | { | 
|  | 151 | u16 w; | 
|  | 152 |  | 
|  | 153 | BUG_ON(omap_dma_in_1510_mode()); | 
|  | 154 |  | 
|  | 155 | w = omap_readw(OMAP_DMA_CCR2(lch)) & ~0x03; | 
|  | 156 | switch (mode) { | 
|  | 157 | case OMAP_DMA_CONSTANT_FILL: | 
|  | 158 | w |= 0x01; | 
|  | 159 | break; | 
|  | 160 | case OMAP_DMA_TRANSPARENT_COPY: | 
|  | 161 | w |= 0x02; | 
|  | 162 | break; | 
|  | 163 | case OMAP_DMA_COLOR_DIS: | 
|  | 164 | break; | 
|  | 165 | default: | 
|  | 166 | BUG(); | 
|  | 167 | } | 
|  | 168 | omap_writew(w, OMAP_DMA_CCR2(lch)); | 
|  | 169 |  | 
|  | 170 | w = omap_readw(OMAP_DMA_LCH_CTRL(lch)) & ~0x0f; | 
|  | 171 | /* Default is channel type 2D */ | 
|  | 172 | if (mode) { | 
|  | 173 | omap_writew((u16)color, OMAP_DMA_COLOR_L(lch)); | 
|  | 174 | omap_writew((u16)(color >> 16), OMAP_DMA_COLOR_U(lch)); | 
|  | 175 | w |= 1;		/* Channel type G */ | 
|  | 176 | } | 
|  | 177 | omap_writew(w, OMAP_DMA_LCH_CTRL(lch)); | 
|  | 178 | } | 
|  | 179 |  | 
|  | 180 |  | 
|  | 181 | void omap_set_dma_src_params(int lch, int src_port, int src_amode, | 
|  | 182 | unsigned long src_start) | 
|  | 183 | { | 
|  | 184 | u16 w; | 
|  | 185 |  | 
|  | 186 | w = omap_readw(OMAP_DMA_CSDP(lch)); | 
|  | 187 | w &= ~(0x1f << 2); | 
|  | 188 | w |= src_port << 2; | 
|  | 189 | omap_writew(w, OMAP_DMA_CSDP(lch)); | 
|  | 190 |  | 
|  | 191 | w = omap_readw(OMAP_DMA_CCR(lch)); | 
|  | 192 | w &= ~(0x03 << 12); | 
|  | 193 | w |= src_amode << 12; | 
|  | 194 | omap_writew(w, OMAP_DMA_CCR(lch)); | 
|  | 195 |  | 
|  | 196 | omap_writew(src_start >> 16, OMAP_DMA_CSSA_U(lch)); | 
|  | 197 | omap_writew(src_start, OMAP_DMA_CSSA_L(lch)); | 
|  | 198 | } | 
|  | 199 |  | 
|  | 200 | void omap_set_dma_src_index(int lch, int eidx, int fidx) | 
|  | 201 | { | 
|  | 202 | omap_writew(eidx, OMAP_DMA_CSEI(lch)); | 
|  | 203 | omap_writew(fidx, OMAP_DMA_CSFI(lch)); | 
|  | 204 | } | 
|  | 205 |  | 
|  | 206 | void omap_set_dma_src_data_pack(int lch, int enable) | 
|  | 207 | { | 
|  | 208 | u16 w; | 
|  | 209 |  | 
|  | 210 | w = omap_readw(OMAP_DMA_CSDP(lch)) & ~(1 << 6); | 
|  | 211 | w |= enable ? (1 << 6) : 0; | 
|  | 212 | omap_writew(w, OMAP_DMA_CSDP(lch)); | 
|  | 213 | } | 
|  | 214 |  | 
|  | 215 | void omap_set_dma_src_burst_mode(int lch, enum omap_dma_burst_mode burst_mode) | 
|  | 216 | { | 
|  | 217 | u16 w; | 
|  | 218 |  | 
|  | 219 | w = omap_readw(OMAP_DMA_CSDP(lch)) & ~(0x03 << 7); | 
|  | 220 | switch (burst_mode) { | 
|  | 221 | case OMAP_DMA_DATA_BURST_DIS: | 
|  | 222 | break; | 
|  | 223 | case OMAP_DMA_DATA_BURST_4: | 
|  | 224 | w |= (0x01 << 7); | 
|  | 225 | break; | 
|  | 226 | case OMAP_DMA_DATA_BURST_8: | 
|  | 227 | /* not supported by current hardware | 
|  | 228 | * w |= (0x03 << 7); | 
|  | 229 | * fall through | 
|  | 230 | */ | 
|  | 231 | default: | 
|  | 232 | BUG(); | 
|  | 233 | } | 
|  | 234 | omap_writew(w, OMAP_DMA_CSDP(lch)); | 
|  | 235 | } | 
|  | 236 |  | 
|  | 237 | void omap_set_dma_dest_params(int lch, int dest_port, int dest_amode, | 
|  | 238 | unsigned long dest_start) | 
|  | 239 | { | 
|  | 240 | u16 w; | 
|  | 241 |  | 
|  | 242 | w = omap_readw(OMAP_DMA_CSDP(lch)); | 
|  | 243 | w &= ~(0x1f << 9); | 
|  | 244 | w |= dest_port << 9; | 
|  | 245 | omap_writew(w, OMAP_DMA_CSDP(lch)); | 
|  | 246 |  | 
|  | 247 | w = omap_readw(OMAP_DMA_CCR(lch)); | 
|  | 248 | w &= ~(0x03 << 14); | 
|  | 249 | w |= dest_amode << 14; | 
|  | 250 | omap_writew(w, OMAP_DMA_CCR(lch)); | 
|  | 251 |  | 
|  | 252 | omap_writew(dest_start >> 16, OMAP_DMA_CDSA_U(lch)); | 
|  | 253 | omap_writew(dest_start, OMAP_DMA_CDSA_L(lch)); | 
|  | 254 | } | 
|  | 255 |  | 
|  | 256 | void omap_set_dma_dest_index(int lch, int eidx, int fidx) | 
|  | 257 | { | 
|  | 258 | omap_writew(eidx, OMAP_DMA_CDEI(lch)); | 
|  | 259 | omap_writew(fidx, OMAP_DMA_CDFI(lch)); | 
|  | 260 | } | 
|  | 261 |  | 
|  | 262 | void omap_set_dma_dest_data_pack(int lch, int enable) | 
|  | 263 | { | 
|  | 264 | u16 w; | 
|  | 265 |  | 
|  | 266 | w = omap_readw(OMAP_DMA_CSDP(lch)) & ~(1 << 13); | 
|  | 267 | w |= enable ? (1 << 13) : 0; | 
|  | 268 | omap_writew(w, OMAP_DMA_CSDP(lch)); | 
|  | 269 | } | 
|  | 270 |  | 
|  | 271 | void omap_set_dma_dest_burst_mode(int lch, enum omap_dma_burst_mode burst_mode) | 
|  | 272 | { | 
|  | 273 | u16 w; | 
|  | 274 |  | 
|  | 275 | w = omap_readw(OMAP_DMA_CSDP(lch)) & ~(0x03 << 14); | 
|  | 276 | switch (burst_mode) { | 
|  | 277 | case OMAP_DMA_DATA_BURST_DIS: | 
|  | 278 | break; | 
|  | 279 | case OMAP_DMA_DATA_BURST_4: | 
|  | 280 | w |= (0x01 << 14); | 
|  | 281 | break; | 
|  | 282 | case OMAP_DMA_DATA_BURST_8: | 
|  | 283 | w |= (0x03 << 14); | 
|  | 284 | break; | 
|  | 285 | default: | 
|  | 286 | printk(KERN_ERR "Invalid DMA burst mode\n"); | 
|  | 287 | BUG(); | 
|  | 288 | return; | 
|  | 289 | } | 
|  | 290 | omap_writew(w, OMAP_DMA_CSDP(lch)); | 
|  | 291 | } | 
|  | 292 |  | 
|  | 293 | static inline void init_intr(int lch) | 
|  | 294 | { | 
|  | 295 | u16 w; | 
|  | 296 |  | 
|  | 297 | /* Read CSR to make sure it's cleared. */ | 
|  | 298 | w = omap_readw(OMAP_DMA_CSR(lch)); | 
|  | 299 | /* Enable some nice interrupts. */ | 
|  | 300 | omap_writew(dma_chan[lch].enabled_irqs, OMAP_DMA_CICR(lch)); | 
|  | 301 | dma_chan[lch].flags |= OMAP_DMA_ACTIVE; | 
|  | 302 | } | 
|  | 303 |  | 
|  | 304 | static inline void enable_lnk(int lch) | 
|  | 305 | { | 
|  | 306 | u16 w; | 
|  | 307 |  | 
|  | 308 | /* Clear the STOP_LNK bits */ | 
|  | 309 | w = omap_readw(OMAP_DMA_CLNK_CTRL(lch)); | 
|  | 310 | w &= ~(1 << 14); | 
|  | 311 | omap_writew(w, OMAP_DMA_CLNK_CTRL(lch)); | 
|  | 312 |  | 
|  | 313 | /* And set the ENABLE_LNK bits */ | 
|  | 314 | if (dma_chan[lch].next_lch != -1) | 
|  | 315 | omap_writew(dma_chan[lch].next_lch | (1 << 15), | 
|  | 316 | OMAP_DMA_CLNK_CTRL(lch)); | 
|  | 317 | } | 
|  | 318 |  | 
|  | 319 | static inline void disable_lnk(int lch) | 
|  | 320 | { | 
|  | 321 | u16 w; | 
|  | 322 |  | 
|  | 323 | /* Disable interrupts */ | 
|  | 324 | omap_writew(0, OMAP_DMA_CICR(lch)); | 
|  | 325 |  | 
|  | 326 | /* Set the STOP_LNK bit */ | 
|  | 327 | w = omap_readw(OMAP_DMA_CLNK_CTRL(lch)); | 
|  | 328 | w |= (1 << 14); | 
|  | 329 | w = omap_writew(w, OMAP_DMA_CLNK_CTRL(lch)); | 
|  | 330 |  | 
|  | 331 | dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE; | 
|  | 332 | } | 
|  | 333 |  | 
|  | 334 | void omap_start_dma(int lch) | 
|  | 335 | { | 
|  | 336 | u16 w; | 
|  | 337 |  | 
|  | 338 | if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) { | 
|  | 339 | int next_lch, cur_lch; | 
|  | 340 | char dma_chan_link_map[OMAP_LOGICAL_DMA_CH_COUNT]; | 
|  | 341 |  | 
|  | 342 | dma_chan_link_map[lch] = 1; | 
|  | 343 | /* Set the link register of the first channel */ | 
|  | 344 | enable_lnk(lch); | 
|  | 345 |  | 
|  | 346 | memset(dma_chan_link_map, 0, sizeof(dma_chan_link_map)); | 
|  | 347 | cur_lch = dma_chan[lch].next_lch; | 
|  | 348 | do { | 
|  | 349 | next_lch = dma_chan[cur_lch].next_lch; | 
|  | 350 |  | 
|  | 351 | /* The loop case: we've been here already */ | 
|  | 352 | if (dma_chan_link_map[cur_lch]) | 
|  | 353 | break; | 
|  | 354 | /* Mark the current channel */ | 
|  | 355 | dma_chan_link_map[cur_lch] = 1; | 
|  | 356 |  | 
|  | 357 | enable_lnk(cur_lch); | 
|  | 358 | init_intr(cur_lch); | 
|  | 359 |  | 
|  | 360 | cur_lch = next_lch; | 
|  | 361 | } while (next_lch != -1); | 
|  | 362 | } | 
|  | 363 |  | 
|  | 364 | init_intr(lch); | 
|  | 365 |  | 
|  | 366 | w = omap_readw(OMAP_DMA_CCR(lch)); | 
|  | 367 | w |= OMAP_DMA_CCR_EN; | 
|  | 368 | omap_writew(w, OMAP_DMA_CCR(lch)); | 
|  | 369 | dma_chan[lch].flags |= OMAP_DMA_ACTIVE; | 
|  | 370 | } | 
|  | 371 |  | 
|  | 372 | void omap_stop_dma(int lch) | 
|  | 373 | { | 
|  | 374 | u16 w; | 
|  | 375 |  | 
|  | 376 | if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) { | 
|  | 377 | int next_lch, cur_lch = lch; | 
|  | 378 | char dma_chan_link_map[OMAP_LOGICAL_DMA_CH_COUNT]; | 
|  | 379 |  | 
|  | 380 | memset(dma_chan_link_map, 0, sizeof(dma_chan_link_map)); | 
|  | 381 | do { | 
|  | 382 | /* The loop case: we've been here already */ | 
|  | 383 | if (dma_chan_link_map[cur_lch]) | 
|  | 384 | break; | 
|  | 385 | /* Mark the current channel */ | 
|  | 386 | dma_chan_link_map[cur_lch] = 1; | 
|  | 387 |  | 
|  | 388 | disable_lnk(cur_lch); | 
|  | 389 |  | 
|  | 390 | next_lch = dma_chan[cur_lch].next_lch; | 
|  | 391 | cur_lch = next_lch; | 
|  | 392 | } while (next_lch != -1); | 
|  | 393 |  | 
|  | 394 | return; | 
|  | 395 | } | 
|  | 396 | /* Disable all interrupts on the channel */ | 
|  | 397 | omap_writew(0, OMAP_DMA_CICR(lch)); | 
|  | 398 |  | 
|  | 399 | w = omap_readw(OMAP_DMA_CCR(lch)); | 
|  | 400 | w &= ~OMAP_DMA_CCR_EN; | 
|  | 401 | omap_writew(w, OMAP_DMA_CCR(lch)); | 
|  | 402 | dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE; | 
|  | 403 | } | 
|  | 404 |  | 
|  | 405 | void omap_enable_dma_irq(int lch, u16 bits) | 
|  | 406 | { | 
|  | 407 | dma_chan[lch].enabled_irqs |= bits; | 
|  | 408 | } | 
|  | 409 |  | 
|  | 410 | void omap_disable_dma_irq(int lch, u16 bits) | 
|  | 411 | { | 
|  | 412 | dma_chan[lch].enabled_irqs &= ~bits; | 
|  | 413 | } | 
|  | 414 |  | 
|  | 415 | static int dma_handle_ch(int ch) | 
|  | 416 | { | 
|  | 417 | u16 csr; | 
|  | 418 |  | 
|  | 419 | if (enable_1510_mode && ch >= 6) { | 
|  | 420 | csr = dma_chan[ch].saved_csr; | 
|  | 421 | dma_chan[ch].saved_csr = 0; | 
|  | 422 | } else | 
|  | 423 | csr = omap_readw(OMAP_DMA_CSR(ch)); | 
|  | 424 | if (enable_1510_mode && ch <= 2 && (csr >> 7) != 0) { | 
|  | 425 | dma_chan[ch + 6].saved_csr = csr >> 7; | 
|  | 426 | csr &= 0x7f; | 
|  | 427 | } | 
|  | 428 | if (!csr) | 
|  | 429 | return 0; | 
|  | 430 | if (unlikely(dma_chan[ch].dev_id == -1)) { | 
|  | 431 | printk(KERN_WARNING "Spurious interrupt from DMA channel %d (CSR %04x)\n", | 
|  | 432 | ch, csr); | 
|  | 433 | return 0; | 
|  | 434 | } | 
|  | 435 | if (unlikely(csr & OMAP_DMA_TOUT_IRQ)) | 
|  | 436 | printk(KERN_WARNING "DMA timeout with device %d\n", dma_chan[ch].dev_id); | 
|  | 437 | if (unlikely(csr & OMAP_DMA_DROP_IRQ)) | 
|  | 438 | printk(KERN_WARNING "DMA synchronization event drop occurred with device %d\n", | 
|  | 439 | dma_chan[ch].dev_id); | 
|  | 440 | if (likely(csr & OMAP_DMA_BLOCK_IRQ)) | 
|  | 441 | dma_chan[ch].flags &= ~OMAP_DMA_ACTIVE; | 
|  | 442 | if (likely(dma_chan[ch].callback != NULL)) | 
|  | 443 | dma_chan[ch].callback(ch, csr, dma_chan[ch].data); | 
|  | 444 | return 1; | 
|  | 445 | } | 
|  | 446 |  | 
|  | 447 | static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) | 
|  | 448 | { | 
|  | 449 | int ch = ((int) dev_id) - 1; | 
|  | 450 | int handled = 0; | 
|  | 451 |  | 
|  | 452 | for (;;) { | 
|  | 453 | int handled_now = 0; | 
|  | 454 |  | 
|  | 455 | handled_now += dma_handle_ch(ch); | 
|  | 456 | if (enable_1510_mode && dma_chan[ch + 6].saved_csr) | 
|  | 457 | handled_now += dma_handle_ch(ch + 6); | 
|  | 458 | if (!handled_now) | 
|  | 459 | break; | 
|  | 460 | handled += handled_now; | 
|  | 461 | } | 
|  | 462 |  | 
|  | 463 | return handled ? IRQ_HANDLED : IRQ_NONE; | 
|  | 464 | } | 
|  | 465 |  | 
|  | 466 | int omap_request_dma(int dev_id, const char *dev_name, | 
|  | 467 | void (* callback)(int lch, u16 ch_status, void *data), | 
|  | 468 | void *data, int *dma_ch_out) | 
|  | 469 | { | 
|  | 470 | int ch, free_ch = -1; | 
|  | 471 | unsigned long flags; | 
|  | 472 | struct omap_dma_lch *chan; | 
|  | 473 |  | 
|  | 474 | spin_lock_irqsave(&dma_chan_lock, flags); | 
|  | 475 | for (ch = 0; ch < dma_chan_count; ch++) { | 
|  | 476 | if (free_ch == -1 && dma_chan[ch].dev_id == -1) { | 
|  | 477 | free_ch = ch; | 
|  | 478 | if (dev_id == 0) | 
|  | 479 | break; | 
|  | 480 | } | 
|  | 481 | } | 
|  | 482 | if (free_ch == -1) { | 
|  | 483 | spin_unlock_irqrestore(&dma_chan_lock, flags); | 
|  | 484 | return -EBUSY; | 
|  | 485 | } | 
|  | 486 | chan = dma_chan + free_ch; | 
|  | 487 | chan->dev_id = dev_id; | 
|  | 488 | clear_lch_regs(free_ch); | 
|  | 489 | spin_unlock_irqrestore(&dma_chan_lock, flags); | 
|  | 490 |  | 
|  | 491 | chan->dev_id = dev_id; | 
|  | 492 | chan->dev_name = dev_name; | 
|  | 493 | chan->callback = callback; | 
|  | 494 | chan->data = data; | 
|  | 495 | chan->enabled_irqs = OMAP_DMA_TOUT_IRQ | OMAP_DMA_DROP_IRQ | OMAP_DMA_BLOCK_IRQ; | 
|  | 496 |  | 
|  | 497 | if (cpu_is_omap16xx()) { | 
|  | 498 | /* If the sync device is set, configure it dynamically. */ | 
|  | 499 | if (dev_id != 0) { | 
|  | 500 | set_gdma_dev(free_ch + 1, dev_id); | 
|  | 501 | dev_id = free_ch + 1; | 
|  | 502 | } | 
|  | 503 | /* Disable the 1510 compatibility mode and set the sync device | 
|  | 504 | * id. */ | 
|  | 505 | omap_writew(dev_id | (1 << 10), OMAP_DMA_CCR(free_ch)); | 
|  | 506 | } else { | 
|  | 507 | omap_writew(dev_id, OMAP_DMA_CCR(free_ch)); | 
|  | 508 | } | 
|  | 509 | *dma_ch_out = free_ch; | 
|  | 510 |  | 
|  | 511 | return 0; | 
|  | 512 | } | 
|  | 513 |  | 
|  | 514 | void omap_free_dma(int ch) | 
|  | 515 | { | 
|  | 516 | unsigned long flags; | 
|  | 517 |  | 
|  | 518 | spin_lock_irqsave(&dma_chan_lock, flags); | 
|  | 519 | if (dma_chan[ch].dev_id == -1) { | 
|  | 520 | printk("omap_dma: trying to free nonallocated DMA channel %d\n", ch); | 
|  | 521 | spin_unlock_irqrestore(&dma_chan_lock, flags); | 
|  | 522 | return; | 
|  | 523 | } | 
|  | 524 | dma_chan[ch].dev_id = -1; | 
|  | 525 | spin_unlock_irqrestore(&dma_chan_lock, flags); | 
|  | 526 |  | 
|  | 527 | /* Disable all DMA interrupts for the channel. */ | 
|  | 528 | omap_writew(0, OMAP_DMA_CICR(ch)); | 
|  | 529 | /* Make sure the DMA transfer is stopped. */ | 
|  | 530 | omap_writew(0, OMAP_DMA_CCR(ch)); | 
|  | 531 | } | 
|  | 532 |  | 
|  | 533 | int omap_dma_in_1510_mode(void) | 
|  | 534 | { | 
|  | 535 | return enable_1510_mode; | 
|  | 536 | } | 
|  | 537 |  | 
|  | 538 | /* | 
|  | 539 | * lch_queue DMA will start right after lch_head one is finished. | 
|  | 540 | * For this DMA link to start, you still need to start (see omap_start_dma) | 
|  | 541 | * the first one. That will fire up the entire queue. | 
|  | 542 | */ | 
|  | 543 | void omap_dma_link_lch (int lch_head, int lch_queue) | 
|  | 544 | { | 
|  | 545 | if (omap_dma_in_1510_mode()) { | 
|  | 546 | printk(KERN_ERR "DMA linking is not supported in 1510 mode\n"); | 
|  | 547 | BUG(); | 
|  | 548 | return; | 
|  | 549 | } | 
|  | 550 |  | 
|  | 551 | if ((dma_chan[lch_head].dev_id == -1) || | 
|  | 552 | (dma_chan[lch_queue].dev_id == -1)) { | 
|  | 553 | printk(KERN_ERR "omap_dma: trying to link non requested channels\n"); | 
|  | 554 | dump_stack(); | 
|  | 555 | } | 
|  | 556 |  | 
|  | 557 | dma_chan[lch_head].next_lch = lch_queue; | 
|  | 558 | } | 
|  | 559 |  | 
|  | 560 | /* | 
|  | 561 | * Once the DMA queue is stopped, we can destroy it. | 
|  | 562 | */ | 
|  | 563 | void omap_dma_unlink_lch (int lch_head, int lch_queue) | 
|  | 564 | { | 
|  | 565 | if (omap_dma_in_1510_mode()) { | 
|  | 566 | printk(KERN_ERR "DMA linking is not supported in 1510 mode\n"); | 
|  | 567 | BUG(); | 
|  | 568 | return; | 
|  | 569 | } | 
|  | 570 |  | 
|  | 571 | if (dma_chan[lch_head].next_lch != lch_queue || | 
|  | 572 | dma_chan[lch_head].next_lch == -1) { | 
|  | 573 | printk(KERN_ERR "omap_dma: trying to unlink non linked channels\n"); | 
|  | 574 | dump_stack(); | 
|  | 575 | } | 
|  | 576 |  | 
|  | 577 |  | 
|  | 578 | if ((dma_chan[lch_head].flags & OMAP_DMA_ACTIVE) || | 
|  | 579 | (dma_chan[lch_head].flags & OMAP_DMA_ACTIVE)) { | 
|  | 580 | printk(KERN_ERR "omap_dma: You need to stop the DMA channels before unlinking\n"); | 
|  | 581 | dump_stack(); | 
|  | 582 | } | 
|  | 583 |  | 
|  | 584 | dma_chan[lch_head].next_lch = -1; | 
|  | 585 | } | 
|  | 586 |  | 
|  | 587 |  | 
|  | 588 | static struct lcd_dma_info { | 
|  | 589 | spinlock_t lock; | 
|  | 590 | int reserved; | 
|  | 591 | void (* callback)(u16 status, void *data); | 
|  | 592 | void *cb_data; | 
|  | 593 |  | 
|  | 594 | int active; | 
|  | 595 | unsigned long addr, size; | 
|  | 596 | int rotate, data_type, xres, yres; | 
|  | 597 | int vxres; | 
|  | 598 | int mirror; | 
|  | 599 | int xscale, yscale; | 
|  | 600 | int ext_ctrl; | 
|  | 601 | int src_port; | 
|  | 602 | int single_transfer; | 
|  | 603 | } lcd_dma; | 
|  | 604 |  | 
|  | 605 | void omap_set_lcd_dma_b1(unsigned long addr, u16 fb_xres, u16 fb_yres, | 
|  | 606 | int data_type) | 
|  | 607 | { | 
|  | 608 | lcd_dma.addr = addr; | 
|  | 609 | lcd_dma.data_type = data_type; | 
|  | 610 | lcd_dma.xres = fb_xres; | 
|  | 611 | lcd_dma.yres = fb_yres; | 
|  | 612 | } | 
|  | 613 |  | 
|  | 614 | void omap_set_lcd_dma_src_port(int port) | 
|  | 615 | { | 
|  | 616 | lcd_dma.src_port = port; | 
|  | 617 | } | 
|  | 618 |  | 
|  | 619 | void omap_set_lcd_dma_ext_controller(int external) | 
|  | 620 | { | 
|  | 621 | lcd_dma.ext_ctrl = external; | 
|  | 622 | } | 
|  | 623 |  | 
|  | 624 | void omap_set_lcd_dma_single_transfer(int single) | 
|  | 625 | { | 
|  | 626 | lcd_dma.single_transfer = single; | 
|  | 627 | } | 
|  | 628 |  | 
|  | 629 |  | 
|  | 630 | void omap_set_lcd_dma_b1_rotation(int rotate) | 
|  | 631 | { | 
|  | 632 | if (omap_dma_in_1510_mode()) { | 
|  | 633 | printk(KERN_ERR "DMA rotation is not supported in 1510 mode\n"); | 
|  | 634 | BUG(); | 
|  | 635 | return; | 
|  | 636 | } | 
|  | 637 | lcd_dma.rotate = rotate; | 
|  | 638 | } | 
|  | 639 |  | 
|  | 640 | void omap_set_lcd_dma_b1_mirror(int mirror) | 
|  | 641 | { | 
|  | 642 | if (omap_dma_in_1510_mode()) { | 
|  | 643 | printk(KERN_ERR "DMA mirror is not supported in 1510 mode\n"); | 
|  | 644 | BUG(); | 
|  | 645 | } | 
|  | 646 | lcd_dma.mirror = mirror; | 
|  | 647 | } | 
|  | 648 |  | 
|  | 649 | void omap_set_lcd_dma_b1_vxres(unsigned long vxres) | 
|  | 650 | { | 
|  | 651 | if (omap_dma_in_1510_mode()) { | 
|  | 652 | printk(KERN_ERR "DMA virtual resulotion is not supported " | 
|  | 653 | "in 1510 mode\n"); | 
|  | 654 | BUG(); | 
|  | 655 | } | 
|  | 656 | lcd_dma.vxres = vxres; | 
|  | 657 | } | 
|  | 658 |  | 
|  | 659 | void omap_set_lcd_dma_b1_scale(unsigned int xscale, unsigned int yscale) | 
|  | 660 | { | 
|  | 661 | if (omap_dma_in_1510_mode()) { | 
|  | 662 | printk(KERN_ERR "DMA scale is not supported in 1510 mode\n"); | 
|  | 663 | BUG(); | 
|  | 664 | } | 
|  | 665 | lcd_dma.xscale = xscale; | 
|  | 666 | lcd_dma.yscale = yscale; | 
|  | 667 | } | 
|  | 668 |  | 
|  | 669 | static void set_b1_regs(void) | 
|  | 670 | { | 
|  | 671 | unsigned long top, bottom; | 
|  | 672 | int es; | 
|  | 673 | u16 w; | 
|  | 674 | unsigned long en, fn; | 
|  | 675 | long ei, fi; | 
|  | 676 | unsigned long vxres; | 
|  | 677 | unsigned int xscale, yscale; | 
|  | 678 |  | 
|  | 679 | switch (lcd_dma.data_type) { | 
|  | 680 | case OMAP_DMA_DATA_TYPE_S8: | 
|  | 681 | es = 1; | 
|  | 682 | break; | 
|  | 683 | case OMAP_DMA_DATA_TYPE_S16: | 
|  | 684 | es = 2; | 
|  | 685 | break; | 
|  | 686 | case OMAP_DMA_DATA_TYPE_S32: | 
|  | 687 | es = 4; | 
|  | 688 | break; | 
|  | 689 | default: | 
|  | 690 | BUG(); | 
|  | 691 | return; | 
|  | 692 | } | 
|  | 693 |  | 
|  | 694 | vxres = lcd_dma.vxres ? lcd_dma.vxres : lcd_dma.xres; | 
|  | 695 | xscale = lcd_dma.xscale ? lcd_dma.xscale : 1; | 
|  | 696 | yscale = lcd_dma.yscale ? lcd_dma.yscale : 1; | 
|  | 697 | BUG_ON(vxres < lcd_dma.xres); | 
|  | 698 | #define PIXADDR(x,y) (lcd_dma.addr + ((y) * vxres * yscale + (x) * xscale) * es) | 
|  | 699 | #define PIXSTEP(sx, sy, dx, dy) (PIXADDR(dx, dy) - PIXADDR(sx, sy) - es + 1) | 
|  | 700 | switch (lcd_dma.rotate) { | 
|  | 701 | case 0: | 
|  | 702 | if (!lcd_dma.mirror) { | 
|  | 703 | top = PIXADDR(0, 0); | 
|  | 704 | bottom = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1); | 
|  | 705 | /* 1510 DMA requires the bottom address to be 2 more | 
|  | 706 | * than the actual last memory access location. */ | 
|  | 707 | if (omap_dma_in_1510_mode() && | 
|  | 708 | lcd_dma.data_type == OMAP_DMA_DATA_TYPE_S32) | 
|  | 709 | bottom += 2; | 
|  | 710 | ei = PIXSTEP(0, 0, 1, 0); | 
|  | 711 | fi = PIXSTEP(lcd_dma.xres - 1, 0, 0, 1); | 
|  | 712 | } else { | 
|  | 713 | top = PIXADDR(lcd_dma.xres - 1, 0); | 
|  | 714 | bottom = PIXADDR(0, lcd_dma.yres - 1); | 
|  | 715 | ei = PIXSTEP(1, 0, 0, 0); | 
|  | 716 | fi = PIXSTEP(0, 0, lcd_dma.xres - 1, 1); | 
|  | 717 | } | 
|  | 718 | en = lcd_dma.xres; | 
|  | 719 | fn = lcd_dma.yres; | 
|  | 720 | break; | 
|  | 721 | case 90: | 
|  | 722 | if (!lcd_dma.mirror) { | 
|  | 723 | top = PIXADDR(0, lcd_dma.yres - 1); | 
|  | 724 | bottom = PIXADDR(lcd_dma.xres - 1, 0); | 
|  | 725 | ei = PIXSTEP(0, 1, 0, 0); | 
|  | 726 | fi = PIXSTEP(0, 0, 1, lcd_dma.yres - 1); | 
|  | 727 | } else { | 
|  | 728 | top = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1); | 
|  | 729 | bottom = PIXADDR(0, 0); | 
|  | 730 | ei = PIXSTEP(0, 1, 0, 0); | 
|  | 731 | fi = PIXSTEP(1, 0, 0, lcd_dma.yres - 1); | 
|  | 732 | } | 
|  | 733 | en = lcd_dma.yres; | 
|  | 734 | fn = lcd_dma.xres; | 
|  | 735 | break; | 
|  | 736 | case 180: | 
|  | 737 | if (!lcd_dma.mirror) { | 
|  | 738 | top = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1); | 
|  | 739 | bottom = PIXADDR(0, 0); | 
|  | 740 | ei = PIXSTEP(1, 0, 0, 0); | 
|  | 741 | fi = PIXSTEP(0, 1, lcd_dma.xres - 1, 0); | 
|  | 742 | } else { | 
|  | 743 | top = PIXADDR(0, lcd_dma.yres - 1); | 
|  | 744 | bottom = PIXADDR(lcd_dma.xres - 1, 0); | 
|  | 745 | ei = PIXSTEP(0, 0, 1, 0); | 
|  | 746 | fi = PIXSTEP(lcd_dma.xres - 1, 1, 0, 0); | 
|  | 747 | } | 
|  | 748 | en = lcd_dma.xres; | 
|  | 749 | fn = lcd_dma.yres; | 
|  | 750 | break; | 
|  | 751 | case 270: | 
|  | 752 | if (!lcd_dma.mirror) { | 
|  | 753 | top = PIXADDR(lcd_dma.xres - 1, 0); | 
|  | 754 | bottom = PIXADDR(0, lcd_dma.yres - 1); | 
|  | 755 | ei = PIXSTEP(0, 0, 0, 1); | 
|  | 756 | fi = PIXSTEP(1, lcd_dma.yres - 1, 0, 0); | 
|  | 757 | } else { | 
|  | 758 | top = PIXADDR(0, 0); | 
|  | 759 | bottom = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1); | 
|  | 760 | ei = PIXSTEP(0, 0, 0, 1); | 
|  | 761 | fi = PIXSTEP(0, lcd_dma.yres - 1, 1, 0); | 
|  | 762 | } | 
|  | 763 | en = lcd_dma.yres; | 
|  | 764 | fn = lcd_dma.xres; | 
|  | 765 | break; | 
|  | 766 | default: | 
|  | 767 | BUG(); | 
|  | 768 | return;	/* Supress warning about uninitialized vars */ | 
|  | 769 | } | 
|  | 770 |  | 
|  | 771 | if (omap_dma_in_1510_mode()) { | 
|  | 772 | omap_writew(top >> 16, OMAP1510_DMA_LCD_TOP_F1_U); | 
|  | 773 | omap_writew(top, OMAP1510_DMA_LCD_TOP_F1_L); | 
|  | 774 | omap_writew(bottom >> 16, OMAP1510_DMA_LCD_BOT_F1_U); | 
|  | 775 | omap_writew(bottom, OMAP1510_DMA_LCD_BOT_F1_L); | 
|  | 776 |  | 
|  | 777 | return; | 
|  | 778 | } | 
|  | 779 |  | 
|  | 780 | /* 1610 regs */ | 
|  | 781 | omap_writew(top >> 16, OMAP1610_DMA_LCD_TOP_B1_U); | 
|  | 782 | omap_writew(top, OMAP1610_DMA_LCD_TOP_B1_L); | 
|  | 783 | omap_writew(bottom >> 16, OMAP1610_DMA_LCD_BOT_B1_U); | 
|  | 784 | omap_writew(bottom, OMAP1610_DMA_LCD_BOT_B1_L); | 
|  | 785 |  | 
|  | 786 | omap_writew(en, OMAP1610_DMA_LCD_SRC_EN_B1); | 
|  | 787 | omap_writew(fn, OMAP1610_DMA_LCD_SRC_FN_B1); | 
|  | 788 |  | 
|  | 789 | w = omap_readw(OMAP1610_DMA_LCD_CSDP); | 
|  | 790 | w &= ~0x03; | 
|  | 791 | w |= lcd_dma.data_type; | 
|  | 792 | omap_writew(w, OMAP1610_DMA_LCD_CSDP); | 
|  | 793 |  | 
|  | 794 | w = omap_readw(OMAP1610_DMA_LCD_CTRL); | 
|  | 795 | /* Always set the source port as SDRAM for now*/ | 
|  | 796 | w &= ~(0x03 << 6); | 
|  | 797 | if (lcd_dma.ext_ctrl) | 
|  | 798 | w |= 1 << 8; | 
|  | 799 | else | 
|  | 800 | w &= ~(1 << 8); | 
|  | 801 | if (lcd_dma.callback != NULL) | 
|  | 802 | w |= 1 << 1;            /* Block interrupt enable */ | 
|  | 803 | else | 
|  | 804 | w &= ~(1 << 1); | 
|  | 805 | omap_writew(w, OMAP1610_DMA_LCD_CTRL); | 
|  | 806 |  | 
|  | 807 | if (!(lcd_dma.rotate || lcd_dma.mirror || | 
|  | 808 | lcd_dma.vxres || lcd_dma.xscale || lcd_dma.yscale)) | 
|  | 809 | return; | 
|  | 810 |  | 
|  | 811 | w = omap_readw(OMAP1610_DMA_LCD_CCR); | 
|  | 812 | /* Set the double-indexed addressing mode */ | 
|  | 813 | w |= (0x03 << 12); | 
|  | 814 | omap_writew(w, OMAP1610_DMA_LCD_CCR); | 
|  | 815 |  | 
|  | 816 | omap_writew(ei, OMAP1610_DMA_LCD_SRC_EI_B1); | 
|  | 817 | omap_writew(fi >> 16, OMAP1610_DMA_LCD_SRC_FI_B1_U); | 
|  | 818 | omap_writew(fi, OMAP1610_DMA_LCD_SRC_FI_B1_L); | 
|  | 819 | } | 
|  | 820 |  | 
|  | 821 | static irqreturn_t lcd_dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) | 
|  | 822 | { | 
|  | 823 | u16 w; | 
|  | 824 |  | 
|  | 825 | w = omap_readw(OMAP1610_DMA_LCD_CTRL); | 
|  | 826 | if (unlikely(!(w & (1 << 3)))) { | 
|  | 827 | printk(KERN_WARNING "Spurious LCD DMA IRQ\n"); | 
|  | 828 | return IRQ_NONE; | 
|  | 829 | } | 
|  | 830 | /* Ack the IRQ */ | 
|  | 831 | w |= (1 << 3); | 
|  | 832 | omap_writew(w, OMAP1610_DMA_LCD_CTRL); | 
|  | 833 | lcd_dma.active = 0; | 
|  | 834 | if (lcd_dma.callback != NULL) | 
|  | 835 | lcd_dma.callback(w, lcd_dma.cb_data); | 
|  | 836 |  | 
|  | 837 | return IRQ_HANDLED; | 
|  | 838 | } | 
|  | 839 |  | 
|  | 840 | int omap_request_lcd_dma(void (* callback)(u16 status, void *data), | 
|  | 841 | void *data) | 
|  | 842 | { | 
|  | 843 | spin_lock_irq(&lcd_dma.lock); | 
|  | 844 | if (lcd_dma.reserved) { | 
|  | 845 | spin_unlock_irq(&lcd_dma.lock); | 
|  | 846 | printk(KERN_ERR "LCD DMA channel already reserved\n"); | 
|  | 847 | BUG(); | 
|  | 848 | return -EBUSY; | 
|  | 849 | } | 
|  | 850 | lcd_dma.reserved = 1; | 
|  | 851 | spin_unlock_irq(&lcd_dma.lock); | 
|  | 852 | lcd_dma.callback = callback; | 
|  | 853 | lcd_dma.cb_data = data; | 
|  | 854 | lcd_dma.active = 0; | 
|  | 855 | lcd_dma.single_transfer = 0; | 
|  | 856 | lcd_dma.rotate = 0; | 
|  | 857 | lcd_dma.vxres = 0; | 
|  | 858 | lcd_dma.mirror = 0; | 
|  | 859 | lcd_dma.xscale = 0; | 
|  | 860 | lcd_dma.yscale = 0; | 
|  | 861 | lcd_dma.ext_ctrl = 0; | 
|  | 862 | lcd_dma.src_port = 0; | 
|  | 863 |  | 
|  | 864 | return 0; | 
|  | 865 | } | 
|  | 866 |  | 
|  | 867 | void omap_free_lcd_dma(void) | 
|  | 868 | { | 
|  | 869 | spin_lock(&lcd_dma.lock); | 
|  | 870 | if (!lcd_dma.reserved) { | 
|  | 871 | spin_unlock(&lcd_dma.lock); | 
|  | 872 | printk(KERN_ERR "LCD DMA is not reserved\n"); | 
|  | 873 | BUG(); | 
|  | 874 | return; | 
|  | 875 | } | 
|  | 876 | if (!enable_1510_mode) | 
|  | 877 | omap_writew(omap_readw(OMAP1610_DMA_LCD_CCR) & ~1, OMAP1610_DMA_LCD_CCR); | 
|  | 878 | lcd_dma.reserved = 0; | 
|  | 879 | spin_unlock(&lcd_dma.lock); | 
|  | 880 | } | 
|  | 881 |  | 
|  | 882 | void omap_enable_lcd_dma(void) | 
|  | 883 | { | 
|  | 884 | u16 w; | 
|  | 885 |  | 
|  | 886 | /* Set the Enable bit only if an external controller is | 
|  | 887 | * connected. Otherwise the OMAP internal controller will | 
|  | 888 | * start the transfer when it gets enabled. | 
|  | 889 | */ | 
|  | 890 | if (enable_1510_mode || !lcd_dma.ext_ctrl) | 
|  | 891 | return; | 
|  | 892 | w = omap_readw(OMAP1610_DMA_LCD_CCR); | 
|  | 893 | w |= 1 << 7; | 
|  | 894 | omap_writew(w, OMAP1610_DMA_LCD_CCR); | 
|  | 895 | lcd_dma.active = 1; | 
|  | 896 | } | 
|  | 897 |  | 
|  | 898 | void omap_setup_lcd_dma(void) | 
|  | 899 | { | 
|  | 900 | BUG_ON(lcd_dma.active); | 
|  | 901 | if (!enable_1510_mode) { | 
|  | 902 | /* Set some reasonable defaults */ | 
|  | 903 | omap_writew(0x5440, OMAP1610_DMA_LCD_CCR); | 
|  | 904 | omap_writew(0x9102, OMAP1610_DMA_LCD_CSDP); | 
|  | 905 | omap_writew(0x0004, OMAP1610_DMA_LCD_LCH_CTRL); | 
|  | 906 | } | 
|  | 907 | set_b1_regs(); | 
|  | 908 | if (!enable_1510_mode) { | 
|  | 909 | u16 w; | 
|  | 910 |  | 
|  | 911 | w = omap_readw(OMAP1610_DMA_LCD_CCR); | 
|  | 912 | /* If DMA was already active set the end_prog bit to have | 
|  | 913 | * the programmed register set loaded into the active | 
|  | 914 | * register set. | 
|  | 915 | */ | 
|  | 916 | w |= 1 << 11;		/* End_prog */ | 
|  | 917 | if (!lcd_dma.single_transfer) | 
|  | 918 | w |= (3 << 8);	/* Auto_init, repeat */ | 
|  | 919 | omap_writew(w, OMAP1610_DMA_LCD_CCR); | 
|  | 920 | } | 
|  | 921 | } | 
|  | 922 |  | 
|  | 923 | void omap_stop_lcd_dma(void) | 
|  | 924 | { | 
|  | 925 | lcd_dma.active = 0; | 
|  | 926 | if (!enable_1510_mode && lcd_dma.ext_ctrl) | 
|  | 927 | omap_writew(omap_readw(OMAP1610_DMA_LCD_CCR) & ~(1 << 7), | 
|  | 928 | OMAP1610_DMA_LCD_CCR); | 
|  | 929 | } | 
|  | 930 |  | 
|  | 931 | /* | 
|  | 932 | * Clears any DMA state so the DMA engine is ready to restart with new buffers | 
|  | 933 | * through omap_start_dma(). Any buffers in flight are discarded. | 
|  | 934 | */ | 
|  | 935 | void omap_clear_dma(int lch) | 
|  | 936 | { | 
|  | 937 | unsigned long flags; | 
|  | 938 | int status; | 
|  | 939 |  | 
|  | 940 | local_irq_save(flags); | 
|  | 941 | omap_writew(omap_readw(OMAP_DMA_CCR(lch)) & ~OMAP_DMA_CCR_EN, | 
|  | 942 | OMAP_DMA_CCR(lch)); | 
|  | 943 | status = OMAP_DMA_CSR(lch);	/* clear pending interrupts */ | 
|  | 944 | local_irq_restore(flags); | 
|  | 945 | } | 
|  | 946 |  | 
|  | 947 | /* | 
|  | 948 | * Returns current physical source address for the given DMA channel. | 
|  | 949 | * If the channel is running the caller must disable interrupts prior calling | 
|  | 950 | * this function and process the returned value before re-enabling interrupt to | 
|  | 951 | * prevent races with the interrupt handler. Note that in continuous mode there | 
|  | 952 | * is a chance for CSSA_L register overflow inbetween the two reads resulting | 
|  | 953 | * in incorrect return value. | 
|  | 954 | */ | 
|  | 955 | dma_addr_t omap_get_dma_src_pos(int lch) | 
|  | 956 | { | 
|  | 957 | return (dma_addr_t) (OMAP_DMA_CSSA_L(lch) | | 
|  | 958 | (OMAP_DMA_CSSA_U(lch) << 16)); | 
|  | 959 | } | 
|  | 960 |  | 
|  | 961 | /* | 
|  | 962 | * Returns current physical destination address for the given DMA channel. | 
|  | 963 | * If the channel is running the caller must disable interrupts prior calling | 
|  | 964 | * this function and process the returned value before re-enabling interrupt to | 
|  | 965 | * prevent races with the interrupt handler. Note that in continuous mode there | 
|  | 966 | * is a chance for CDSA_L register overflow inbetween the two reads resulting | 
|  | 967 | * in incorrect return value. | 
|  | 968 | */ | 
|  | 969 | dma_addr_t omap_get_dma_dst_pos(int lch) | 
|  | 970 | { | 
|  | 971 | return (dma_addr_t) (OMAP_DMA_CDSA_L(lch) | | 
|  | 972 | (OMAP_DMA_CDSA_U(lch) << 16)); | 
|  | 973 | } | 
|  | 974 |  | 
|  | 975 | static int __init omap_init_dma(void) | 
|  | 976 | { | 
|  | 977 | int ch, r; | 
|  | 978 |  | 
|  | 979 | if (cpu_is_omap1510()) { | 
|  | 980 | printk(KERN_INFO "DMA support for OMAP1510 initialized\n"); | 
|  | 981 | dma_chan_count = 9; | 
|  | 982 | enable_1510_mode = 1; | 
|  | 983 | } else if (cpu_is_omap16xx() || cpu_is_omap730()) { | 
|  | 984 | printk(KERN_INFO "OMAP DMA hardware version %d\n", | 
|  | 985 | omap_readw(OMAP_DMA_HW_ID)); | 
|  | 986 | printk(KERN_INFO "DMA capabilities: %08x:%08x:%04x:%04x:%04x\n", | 
|  | 987 | (omap_readw(OMAP_DMA_CAPS_0_U) << 16) | omap_readw(OMAP_DMA_CAPS_0_L), | 
|  | 988 | (omap_readw(OMAP_DMA_CAPS_1_U) << 16) | omap_readw(OMAP_DMA_CAPS_1_L), | 
|  | 989 | omap_readw(OMAP_DMA_CAPS_2), omap_readw(OMAP_DMA_CAPS_3), | 
|  | 990 | omap_readw(OMAP_DMA_CAPS_4)); | 
|  | 991 | if (!enable_1510_mode) { | 
|  | 992 | u16 w; | 
|  | 993 |  | 
|  | 994 | /* Disable OMAP 3.0/3.1 compatibility mode. */ | 
|  | 995 | w = omap_readw(OMAP_DMA_GSCR); | 
|  | 996 | w |= 1 << 3; | 
|  | 997 | omap_writew(w, OMAP_DMA_GSCR); | 
|  | 998 | dma_chan_count = 16; | 
|  | 999 | } else | 
|  | 1000 | dma_chan_count = 9; | 
|  | 1001 | } else { | 
|  | 1002 | dma_chan_count = 0; | 
|  | 1003 | return 0; | 
|  | 1004 | } | 
|  | 1005 |  | 
|  | 1006 | memset(&lcd_dma, 0, sizeof(lcd_dma)); | 
|  | 1007 | spin_lock_init(&lcd_dma.lock); | 
|  | 1008 | spin_lock_init(&dma_chan_lock); | 
|  | 1009 | memset(&dma_chan, 0, sizeof(dma_chan)); | 
|  | 1010 |  | 
|  | 1011 | for (ch = 0; ch < dma_chan_count; ch++) { | 
|  | 1012 | dma_chan[ch].dev_id = -1; | 
|  | 1013 | dma_chan[ch].next_lch = -1; | 
|  | 1014 |  | 
|  | 1015 | if (ch >= 6 && enable_1510_mode) | 
|  | 1016 | continue; | 
|  | 1017 |  | 
|  | 1018 | /* request_irq() doesn't like dev_id (ie. ch) being zero, | 
|  | 1019 | * so we have to kludge around this. */ | 
|  | 1020 | r = request_irq(dma_irq[ch], dma_irq_handler, 0, "DMA", | 
|  | 1021 | (void *) (ch + 1)); | 
|  | 1022 | if (r != 0) { | 
|  | 1023 | int i; | 
|  | 1024 |  | 
|  | 1025 | printk(KERN_ERR "unable to request IRQ %d for DMA (error %d)\n", | 
|  | 1026 | dma_irq[ch], r); | 
|  | 1027 | for (i = 0; i < ch; i++) | 
|  | 1028 | free_irq(dma_irq[i], (void *) (i + 1)); | 
|  | 1029 | return r; | 
|  | 1030 | } | 
|  | 1031 | } | 
|  | 1032 | r = request_irq(INT_DMA_LCD, lcd_dma_irq_handler, 0, "LCD DMA", NULL); | 
|  | 1033 | if (r != 0) { | 
|  | 1034 | int i; | 
|  | 1035 |  | 
|  | 1036 | printk(KERN_ERR "unable to request IRQ for LCD DMA (error %d)\n", r); | 
|  | 1037 | for (i = 0; i < dma_chan_count; i++) | 
|  | 1038 | free_irq(dma_irq[i], (void *) (i + 1)); | 
|  | 1039 | return r; | 
|  | 1040 | } | 
|  | 1041 | return 0; | 
|  | 1042 | } | 
|  | 1043 |  | 
|  | 1044 | arch_initcall(omap_init_dma); | 
|  | 1045 |  | 
|  | 1046 |  | 
|  | 1047 | EXPORT_SYMBOL(omap_get_dma_src_pos); | 
|  | 1048 | EXPORT_SYMBOL(omap_get_dma_dst_pos); | 
|  | 1049 | EXPORT_SYMBOL(omap_clear_dma); | 
|  | 1050 | EXPORT_SYMBOL(omap_set_dma_priority); | 
|  | 1051 | EXPORT_SYMBOL(omap_request_dma); | 
|  | 1052 | EXPORT_SYMBOL(omap_free_dma); | 
|  | 1053 | EXPORT_SYMBOL(omap_start_dma); | 
|  | 1054 | EXPORT_SYMBOL(omap_stop_dma); | 
|  | 1055 | EXPORT_SYMBOL(omap_enable_dma_irq); | 
|  | 1056 | EXPORT_SYMBOL(omap_disable_dma_irq); | 
|  | 1057 |  | 
|  | 1058 | EXPORT_SYMBOL(omap_set_dma_transfer_params); | 
|  | 1059 | EXPORT_SYMBOL(omap_set_dma_color_mode); | 
|  | 1060 |  | 
|  | 1061 | EXPORT_SYMBOL(omap_set_dma_src_params); | 
|  | 1062 | EXPORT_SYMBOL(omap_set_dma_src_index); | 
|  | 1063 | EXPORT_SYMBOL(omap_set_dma_src_data_pack); | 
|  | 1064 | EXPORT_SYMBOL(omap_set_dma_src_burst_mode); | 
|  | 1065 |  | 
|  | 1066 | EXPORT_SYMBOL(omap_set_dma_dest_params); | 
|  | 1067 | EXPORT_SYMBOL(omap_set_dma_dest_index); | 
|  | 1068 | EXPORT_SYMBOL(omap_set_dma_dest_data_pack); | 
|  | 1069 | EXPORT_SYMBOL(omap_set_dma_dest_burst_mode); | 
|  | 1070 |  | 
|  | 1071 | EXPORT_SYMBOL(omap_dma_link_lch); | 
|  | 1072 | EXPORT_SYMBOL(omap_dma_unlink_lch); | 
|  | 1073 |  | 
|  | 1074 | EXPORT_SYMBOL(omap_request_lcd_dma); | 
|  | 1075 | EXPORT_SYMBOL(omap_free_lcd_dma); | 
|  | 1076 | EXPORT_SYMBOL(omap_enable_lcd_dma); | 
|  | 1077 | EXPORT_SYMBOL(omap_setup_lcd_dma); | 
|  | 1078 | EXPORT_SYMBOL(omap_stop_lcd_dma); | 
|  | 1079 | EXPORT_SYMBOL(omap_set_lcd_dma_b1); | 
|  | 1080 | EXPORT_SYMBOL(omap_set_lcd_dma_single_transfer); | 
|  | 1081 | EXPORT_SYMBOL(omap_set_lcd_dma_ext_controller); | 
|  | 1082 | EXPORT_SYMBOL(omap_set_lcd_dma_b1_rotation); | 
|  | 1083 | EXPORT_SYMBOL(omap_set_lcd_dma_b1_vxres); | 
|  | 1084 | EXPORT_SYMBOL(omap_set_lcd_dma_b1_scale); | 
|  | 1085 | EXPORT_SYMBOL(omap_set_lcd_dma_b1_mirror); | 
|  | 1086 |  |