Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
lcd_dma.c
Go to the documentation of this file.
1 /*
2  * linux/arch/arm/mach-omap1/lcd_dma.c
3  *
4  * Extracted from arch/arm/plat-omap/dma.c
5  * Copyright (C) 2003 - 2008 Nokia Corporation
6  * Author: Juha Yrjölä <[email protected]>
7  * DMA channel linking for 1610 by Samuel Ortiz <[email protected]>
8  * Graphics DMA and LCD DMA graphics tranformations
9  * by Imre Deak <[email protected]>
10  * OMAP2/3 support Copyright (C) 2004-2007 Texas Instruments, Inc.
11  * Merged to support both OMAP1 and OMAP2 by Tony Lindgren <[email protected]>
12  * Some functions based on earlier dma-omap.c Copyright (C) 2001 RidgeRun, Inc.
13  *
14  * Copyright (C) 2009 Texas Instruments
15  * Added OMAP4 support - Santosh Shilimkar <[email protected]>
16  *
17  * Support functions for the OMAP internal DMA channels.
18  *
19  * This program is free software; you can redistribute it and/or modify
20  * it under the terms of the GNU General Public License version 2 as
21  * published by the Free Software Foundation.
22  *
23  */
24 
25 #include <linux/module.h>
26 #include <linux/spinlock.h>
27 #include <linux/interrupt.h>
28 #include <linux/io.h>
29 
30 #include <plat/dma.h>
31 
32 #include <mach/hardware.h>
33 #include <mach/lcdc.h>
34 
36 {
37  /*
38  * On OMAP1510, internal LCD controller will start the transfer
39  * when it gets enabled, so assume DMA running if LCD enabled.
40  */
41  if (cpu_is_omap15xx())
43  return 1;
44 
45  /* Check if LCD DMA is running */
46  if (cpu_is_omap16xx())
48  return 1;
49 
50  return 0;
51 }
52 
53 static struct lcd_dma_info {
55  int reserved;
56  void (*callback)(u16 status, void *data);
57  void *cb_data;
58 
59  int active;
60  unsigned long addr;
61  int rotate, data_type, xres, yres;
62  int vxres;
63  int mirror;
64  int xscale, yscale;
65  int ext_ctrl;
66  int src_port;
67  int single_transfer;
68 } lcd_dma;
69 
70 void omap_set_lcd_dma_b1(unsigned long addr, u16 fb_xres, u16 fb_yres,
71  int data_type)
72 {
73  lcd_dma.addr = addr;
74  lcd_dma.data_type = data_type;
75  lcd_dma.xres = fb_xres;
76  lcd_dma.yres = fb_yres;
77 }
79 
81 {
82  lcd_dma.ext_ctrl = external;
83 }
85 
87 {
88  lcd_dma.single_transfer = single;
89 }
91 
93 {
94  if (cpu_is_omap15xx()) {
95  printk(KERN_ERR "DMA rotation is not supported in 1510 mode\n");
96  BUG();
97  return;
98  }
99  lcd_dma.rotate = rotate;
100 }
102 
104 {
105  if (cpu_is_omap15xx()) {
106  printk(KERN_ERR "DMA mirror is not supported in 1510 mode\n");
107  BUG();
108  }
109  lcd_dma.mirror = mirror;
110 }
112 
113 void omap_set_lcd_dma_b1_vxres(unsigned long vxres)
114 {
115  if (cpu_is_omap15xx()) {
116  pr_err("DMA virtual resolution is not supported in 1510 mode\n");
117  BUG();
118  }
119  lcd_dma.vxres = vxres;
120 }
122 
123 void omap_set_lcd_dma_b1_scale(unsigned int xscale, unsigned int yscale)
124 {
125  if (cpu_is_omap15xx()) {
126  printk(KERN_ERR "DMA scale is not supported in 1510 mode\n");
127  BUG();
128  }
129  lcd_dma.xscale = xscale;
130  lcd_dma.yscale = yscale;
131 }
133 
134 static void set_b1_regs(void)
135 {
136  unsigned long top, bottom;
137  int es;
138  u16 w;
139  unsigned long en, fn;
140  long ei, fi;
141  unsigned long vxres;
142  unsigned int xscale, yscale;
143 
144  switch (lcd_dma.data_type) {
146  es = 1;
147  break;
149  es = 2;
150  break;
152  es = 4;
153  break;
154  default:
155  BUG();
156  return;
157  }
158 
159  vxres = lcd_dma.vxres ? lcd_dma.vxres : lcd_dma.xres;
160  xscale = lcd_dma.xscale ? lcd_dma.xscale : 1;
161  yscale = lcd_dma.yscale ? lcd_dma.yscale : 1;
162  BUG_ON(vxres < lcd_dma.xres);
163 
164 #define PIXADDR(x, y) (lcd_dma.addr + \
165  ((y) * vxres * yscale + (x) * xscale) * es)
166 #define PIXSTEP(sx, sy, dx, dy) (PIXADDR(dx, dy) - PIXADDR(sx, sy) - es + 1)
167 
168  switch (lcd_dma.rotate) {
169  case 0:
170  if (!lcd_dma.mirror) {
171  top = PIXADDR(0, 0);
172  bottom = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);
173  /* 1510 DMA requires the bottom address to be 2 more
174  * than the actual last memory access location. */
175  if (cpu_is_omap15xx() &&
176  lcd_dma.data_type == OMAP_DMA_DATA_TYPE_S32)
177  bottom += 2;
178  ei = PIXSTEP(0, 0, 1, 0);
179  fi = PIXSTEP(lcd_dma.xres - 1, 0, 0, 1);
180  } else {
181  top = PIXADDR(lcd_dma.xres - 1, 0);
182  bottom = PIXADDR(0, lcd_dma.yres - 1);
183  ei = PIXSTEP(1, 0, 0, 0);
184  fi = PIXSTEP(0, 0, lcd_dma.xres - 1, 1);
185  }
186  en = lcd_dma.xres;
187  fn = lcd_dma.yres;
188  break;
189  case 90:
190  if (!lcd_dma.mirror) {
191  top = PIXADDR(0, lcd_dma.yres - 1);
192  bottom = PIXADDR(lcd_dma.xres - 1, 0);
193  ei = PIXSTEP(0, 1, 0, 0);
194  fi = PIXSTEP(0, 0, 1, lcd_dma.yres - 1);
195  } else {
196  top = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);
197  bottom = PIXADDR(0, 0);
198  ei = PIXSTEP(0, 1, 0, 0);
199  fi = PIXSTEP(1, 0, 0, lcd_dma.yres - 1);
200  }
201  en = lcd_dma.yres;
202  fn = lcd_dma.xres;
203  break;
204  case 180:
205  if (!lcd_dma.mirror) {
206  top = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);
207  bottom = PIXADDR(0, 0);
208  ei = PIXSTEP(1, 0, 0, 0);
209  fi = PIXSTEP(0, 1, lcd_dma.xres - 1, 0);
210  } else {
211  top = PIXADDR(0, lcd_dma.yres - 1);
212  bottom = PIXADDR(lcd_dma.xres - 1, 0);
213  ei = PIXSTEP(0, 0, 1, 0);
214  fi = PIXSTEP(lcd_dma.xres - 1, 1, 0, 0);
215  }
216  en = lcd_dma.xres;
217  fn = lcd_dma.yres;
218  break;
219  case 270:
220  if (!lcd_dma.mirror) {
221  top = PIXADDR(lcd_dma.xres - 1, 0);
222  bottom = PIXADDR(0, lcd_dma.yres - 1);
223  ei = PIXSTEP(0, 0, 0, 1);
224  fi = PIXSTEP(1, lcd_dma.yres - 1, 0, 0);
225  } else {
226  top = PIXADDR(0, 0);
227  bottom = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);
228  ei = PIXSTEP(0, 0, 0, 1);
229  fi = PIXSTEP(0, lcd_dma.yres - 1, 1, 0);
230  }
231  en = lcd_dma.yres;
232  fn = lcd_dma.xres;
233  break;
234  default:
235  BUG();
236  return; /* Suppress warning about uninitialized vars */
237  }
238 
239  if (cpu_is_omap15xx()) {
242  omap_writew(bottom >> 16, OMAP1510_DMA_LCD_BOT_F1_U);
244 
245  return;
246  }
247 
248  /* 1610 regs */
251  omap_writew(bottom >> 16, OMAP1610_DMA_LCD_BOT_B1_U);
253 
256 
258  w &= ~0x03;
259  w |= lcd_dma.data_type;
261 
263  /* Always set the source port as SDRAM for now*/
264  w &= ~(0x03 << 6);
265  if (lcd_dma.callback != NULL)
266  w |= 1 << 1; /* Block interrupt enable */
267  else
268  w &= ~(1 << 1);
270 
271  if (!(lcd_dma.rotate || lcd_dma.mirror ||
272  lcd_dma.vxres || lcd_dma.xscale || lcd_dma.yscale))
273  return;
274 
276  /* Set the double-indexed addressing mode */
277  w |= (0x03 << 12);
279 
283 }
284 
285 static irqreturn_t lcd_dma_irq_handler(int irq, void *dev_id)
286 {
287  u16 w;
288 
290  if (unlikely(!(w & (1 << 3)))) {
291  printk(KERN_WARNING "Spurious LCD DMA IRQ\n");
292  return IRQ_NONE;
293  }
294  /* Ack the IRQ */
295  w |= (1 << 3);
297  lcd_dma.active = 0;
298  if (lcd_dma.callback != NULL)
299  lcd_dma.callback(w, lcd_dma.cb_data);
300 
301  return IRQ_HANDLED;
302 }
303 
305  void *data)
306 {
307  spin_lock_irq(&lcd_dma.lock);
308  if (lcd_dma.reserved) {
309  spin_unlock_irq(&lcd_dma.lock);
310  printk(KERN_ERR "LCD DMA channel already reserved\n");
311  BUG();
312  return -EBUSY;
313  }
314  lcd_dma.reserved = 1;
315  spin_unlock_irq(&lcd_dma.lock);
316  lcd_dma.callback = callback;
317  lcd_dma.cb_data = data;
318  lcd_dma.active = 0;
319  lcd_dma.single_transfer = 0;
320  lcd_dma.rotate = 0;
321  lcd_dma.vxres = 0;
322  lcd_dma.mirror = 0;
323  lcd_dma.xscale = 0;
324  lcd_dma.yscale = 0;
325  lcd_dma.ext_ctrl = 0;
326  lcd_dma.src_port = 0;
327 
328  return 0;
329 }
331 
333 {
334  spin_lock(&lcd_dma.lock);
335  if (!lcd_dma.reserved) {
336  spin_unlock(&lcd_dma.lock);
337  printk(KERN_ERR "LCD DMA is not reserved\n");
338  BUG();
339  return;
340  }
341  if (!cpu_is_omap15xx())
344  lcd_dma.reserved = 0;
345  spin_unlock(&lcd_dma.lock);
346 }
348 
350 {
351  u16 w;
352 
353  /*
354  * Set the Enable bit only if an external controller is
355  * connected. Otherwise the OMAP internal controller will
356  * start the transfer when it gets enabled.
357  */
358  if (cpu_is_omap15xx() || !lcd_dma.ext_ctrl)
359  return;
360 
362  w |= 1 << 8;
364 
365  lcd_dma.active = 1;
366 
368  w |= 1 << 7;
370 }
372 
374 {
375  BUG_ON(lcd_dma.active);
376  if (!cpu_is_omap15xx()) {
377  /* Set some reasonable defaults */
381  }
382  set_b1_regs();
383  if (!cpu_is_omap15xx()) {
384  u16 w;
385 
387  /*
388  * If DMA was already active set the end_prog bit to have
389  * the programmed register set loaded into the active
390  * register set.
391  */
392  w |= 1 << 11; /* End_prog */
393  if (!lcd_dma.single_transfer)
394  w |= (3 << 8); /* Auto_init, repeat */
396  }
397 }
399 
401 {
402  u16 w;
403 
404  lcd_dma.active = 0;
405  if (cpu_is_omap15xx() || !lcd_dma.ext_ctrl)
406  return;
407 
409  w &= ~(1 << 7);
411 
413  w &= ~(1 << 8);
415 }
417 
418 static int __init omap_init_lcd_dma(void)
419 {
420  int r;
421 
422  if (!cpu_class_is_omap1())
423  return -ENODEV;
424 
425  if (cpu_is_omap16xx()) {
426  u16 w;
427 
428  /* this would prevent OMAP sleep */
430  w &= ~(1 << 8);
432  }
433 
434  spin_lock_init(&lcd_dma.lock);
435 
436  r = request_irq(INT_DMA_LCD, lcd_dma_irq_handler, 0,
437  "LCD DMA", NULL);
438  if (r != 0)
439  pr_err("unable to request IRQ for LCD DMA (error %d)\n", r);
440 
441  return r;
442 }
443 
444 arch_initcall(omap_init_lcd_dma);
445