Merge branch 'misc' of git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild-2.6
[pandora-kernel.git] / arch / arm / mach-omap1 / lcd_dma.c
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ä <juha.yrjola@nokia.com>
7  * DMA channel linking for 1610 by Samuel Ortiz <samuel.ortiz@nokia.com>
8  * Graphics DMA and LCD DMA graphics tranformations
9  * by Imre Deak <imre.deak@nokia.com>
10  * OMAP2/3 support Copyright (C) 2004-2007 Texas Instruments, Inc.
11  * Merged to support both OMAP1 and OMAP2 by Tony Lindgren <tony@atomide.com>
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 <santosh.shilimkar@ti.com>
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 <mach/hardware.h>
31 #include <mach/lcdc.h>
32 #include <plat/dma.h>
33
34 int omap_lcd_dma_running(void)
35 {
36         /*
37          * On OMAP1510, internal LCD controller will start the transfer
38          * when it gets enabled, so assume DMA running if LCD enabled.
39          */
40         if (cpu_is_omap1510())
41                 if (omap_readw(OMAP_LCDC_CONTROL) & OMAP_LCDC_CTRL_LCD_EN)
42                         return 1;
43
44         /* Check if LCD DMA is running */
45         if (cpu_is_omap16xx())
46                 if (omap_readw(OMAP1610_DMA_LCD_CCR) & OMAP_DMA_CCR_EN)
47                         return 1;
48
49         return 0;
50 }
51
52 static struct lcd_dma_info {
53         spinlock_t lock;
54         int reserved;
55         void (*callback)(u16 status, void *data);
56         void *cb_data;
57
58         int active;
59         unsigned long addr, size;
60         int rotate, data_type, xres, yres;
61         int vxres;
62         int mirror;
63         int xscale, yscale;
64         int ext_ctrl;
65         int src_port;
66         int single_transfer;
67 } lcd_dma;
68
69 void omap_set_lcd_dma_b1(unsigned long addr, u16 fb_xres, u16 fb_yres,
70                          int data_type)
71 {
72         lcd_dma.addr = addr;
73         lcd_dma.data_type = data_type;
74         lcd_dma.xres = fb_xres;
75         lcd_dma.yres = fb_yres;
76 }
77 EXPORT_SYMBOL(omap_set_lcd_dma_b1);
78
79 void omap_set_lcd_dma_src_port(int port)
80 {
81         lcd_dma.src_port = port;
82 }
83
84 void omap_set_lcd_dma_ext_controller(int external)
85 {
86         lcd_dma.ext_ctrl = external;
87 }
88 EXPORT_SYMBOL(omap_set_lcd_dma_ext_controller);
89
90 void omap_set_lcd_dma_single_transfer(int single)
91 {
92         lcd_dma.single_transfer = single;
93 }
94 EXPORT_SYMBOL(omap_set_lcd_dma_single_transfer);
95
96 void omap_set_lcd_dma_b1_rotation(int rotate)
97 {
98         if (cpu_is_omap1510()) {
99                 printk(KERN_ERR "DMA rotation is not supported in 1510 mode\n");
100                 BUG();
101                 return;
102         }
103         lcd_dma.rotate = rotate;
104 }
105 EXPORT_SYMBOL(omap_set_lcd_dma_b1_rotation);
106
107 void omap_set_lcd_dma_b1_mirror(int mirror)
108 {
109         if (cpu_is_omap1510()) {
110                 printk(KERN_ERR "DMA mirror is not supported in 1510 mode\n");
111                 BUG();
112         }
113         lcd_dma.mirror = mirror;
114 }
115 EXPORT_SYMBOL(omap_set_lcd_dma_b1_mirror);
116
117 void omap_set_lcd_dma_b1_vxres(unsigned long vxres)
118 {
119         if (cpu_is_omap1510()) {
120                 printk(KERN_ERR "DMA virtual resulotion is not supported "
121                                 "in 1510 mode\n");
122                 BUG();
123         }
124         lcd_dma.vxres = vxres;
125 }
126 EXPORT_SYMBOL(omap_set_lcd_dma_b1_vxres);
127
128 void omap_set_lcd_dma_b1_scale(unsigned int xscale, unsigned int yscale)
129 {
130         if (cpu_is_omap1510()) {
131                 printk(KERN_ERR "DMA scale is not supported in 1510 mode\n");
132                 BUG();
133         }
134         lcd_dma.xscale = xscale;
135         lcd_dma.yscale = yscale;
136 }
137 EXPORT_SYMBOL(omap_set_lcd_dma_b1_scale);
138
139 static void set_b1_regs(void)
140 {
141         unsigned long top, bottom;
142         int es;
143         u16 w;
144         unsigned long en, fn;
145         long ei, fi;
146         unsigned long vxres;
147         unsigned int xscale, yscale;
148
149         switch (lcd_dma.data_type) {
150         case OMAP_DMA_DATA_TYPE_S8:
151                 es = 1;
152                 break;
153         case OMAP_DMA_DATA_TYPE_S16:
154                 es = 2;
155                 break;
156         case OMAP_DMA_DATA_TYPE_S32:
157                 es = 4;
158                 break;
159         default:
160                 BUG();
161                 return;
162         }
163
164         vxres = lcd_dma.vxres ? lcd_dma.vxres : lcd_dma.xres;
165         xscale = lcd_dma.xscale ? lcd_dma.xscale : 1;
166         yscale = lcd_dma.yscale ? lcd_dma.yscale : 1;
167         BUG_ON(vxres < lcd_dma.xres);
168
169 #define PIXADDR(x, y) (lcd_dma.addr +                                   \
170                 ((y) * vxres * yscale + (x) * xscale) * es)
171 #define PIXSTEP(sx, sy, dx, dy) (PIXADDR(dx, dy) - PIXADDR(sx, sy) - es + 1)
172
173         switch (lcd_dma.rotate) {
174         case 0:
175                 if (!lcd_dma.mirror) {
176                         top = PIXADDR(0, 0);
177                         bottom = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);
178                         /* 1510 DMA requires the bottom address to be 2 more
179                          * than the actual last memory access location. */
180                         if (cpu_is_omap1510() &&
181                                 lcd_dma.data_type == OMAP_DMA_DATA_TYPE_S32)
182                                         bottom += 2;
183                         ei = PIXSTEP(0, 0, 1, 0);
184                         fi = PIXSTEP(lcd_dma.xres - 1, 0, 0, 1);
185                 } else {
186                         top = PIXADDR(lcd_dma.xres - 1, 0);
187                         bottom = PIXADDR(0, lcd_dma.yres - 1);
188                         ei = PIXSTEP(1, 0, 0, 0);
189                         fi = PIXSTEP(0, 0, lcd_dma.xres - 1, 1);
190                 }
191                 en = lcd_dma.xres;
192                 fn = lcd_dma.yres;
193                 break;
194         case 90:
195                 if (!lcd_dma.mirror) {
196                         top = PIXADDR(0, lcd_dma.yres - 1);
197                         bottom = PIXADDR(lcd_dma.xres - 1, 0);
198                         ei = PIXSTEP(0, 1, 0, 0);
199                         fi = PIXSTEP(0, 0, 1, lcd_dma.yres - 1);
200                 } else {
201                         top = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);
202                         bottom = PIXADDR(0, 0);
203                         ei = PIXSTEP(0, 1, 0, 0);
204                         fi = PIXSTEP(1, 0, 0, lcd_dma.yres - 1);
205                 }
206                 en = lcd_dma.yres;
207                 fn = lcd_dma.xres;
208                 break;
209         case 180:
210                 if (!lcd_dma.mirror) {
211                         top = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);
212                         bottom = PIXADDR(0, 0);
213                         ei = PIXSTEP(1, 0, 0, 0);
214                         fi = PIXSTEP(0, 1, lcd_dma.xres - 1, 0);
215                 } else {
216                         top = PIXADDR(0, lcd_dma.yres - 1);
217                         bottom = PIXADDR(lcd_dma.xres - 1, 0);
218                         ei = PIXSTEP(0, 0, 1, 0);
219                         fi = PIXSTEP(lcd_dma.xres - 1, 1, 0, 0);
220                 }
221                 en = lcd_dma.xres;
222                 fn = lcd_dma.yres;
223                 break;
224         case 270:
225                 if (!lcd_dma.mirror) {
226                         top = PIXADDR(lcd_dma.xres - 1, 0);
227                         bottom = PIXADDR(0, lcd_dma.yres - 1);
228                         ei = PIXSTEP(0, 0, 0, 1);
229                         fi = PIXSTEP(1, lcd_dma.yres - 1, 0, 0);
230                 } else {
231                         top = PIXADDR(0, 0);
232                         bottom = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);
233                         ei = PIXSTEP(0, 0, 0, 1);
234                         fi = PIXSTEP(0, lcd_dma.yres - 1, 1, 0);
235                 }
236                 en = lcd_dma.yres;
237                 fn = lcd_dma.xres;
238                 break;
239         default:
240                 BUG();
241                 return; /* Suppress warning about uninitialized vars */
242         }
243
244         if (cpu_is_omap1510()) {
245                 omap_writew(top >> 16, OMAP1510_DMA_LCD_TOP_F1_U);
246                 omap_writew(top, OMAP1510_DMA_LCD_TOP_F1_L);
247                 omap_writew(bottom >> 16, OMAP1510_DMA_LCD_BOT_F1_U);
248                 omap_writew(bottom, OMAP1510_DMA_LCD_BOT_F1_L);
249
250                 return;
251         }
252
253         /* 1610 regs */
254         omap_writew(top >> 16, OMAP1610_DMA_LCD_TOP_B1_U);
255         omap_writew(top, OMAP1610_DMA_LCD_TOP_B1_L);
256         omap_writew(bottom >> 16, OMAP1610_DMA_LCD_BOT_B1_U);
257         omap_writew(bottom, OMAP1610_DMA_LCD_BOT_B1_L);
258
259         omap_writew(en, OMAP1610_DMA_LCD_SRC_EN_B1);
260         omap_writew(fn, OMAP1610_DMA_LCD_SRC_FN_B1);
261
262         w = omap_readw(OMAP1610_DMA_LCD_CSDP);
263         w &= ~0x03;
264         w |= lcd_dma.data_type;
265         omap_writew(w, OMAP1610_DMA_LCD_CSDP);
266
267         w = omap_readw(OMAP1610_DMA_LCD_CTRL);
268         /* Always set the source port as SDRAM for now*/
269         w &= ~(0x03 << 6);
270         if (lcd_dma.callback != NULL)
271                 w |= 1 << 1;            /* Block interrupt enable */
272         else
273                 w &= ~(1 << 1);
274         omap_writew(w, OMAP1610_DMA_LCD_CTRL);
275
276         if (!(lcd_dma.rotate || lcd_dma.mirror ||
277               lcd_dma.vxres || lcd_dma.xscale || lcd_dma.yscale))
278                 return;
279
280         w = omap_readw(OMAP1610_DMA_LCD_CCR);
281         /* Set the double-indexed addressing mode */
282         w |= (0x03 << 12);
283         omap_writew(w, OMAP1610_DMA_LCD_CCR);
284
285         omap_writew(ei, OMAP1610_DMA_LCD_SRC_EI_B1);
286         omap_writew(fi >> 16, OMAP1610_DMA_LCD_SRC_FI_B1_U);
287         omap_writew(fi, OMAP1610_DMA_LCD_SRC_FI_B1_L);
288 }
289
290 static irqreturn_t lcd_dma_irq_handler(int irq, void *dev_id)
291 {
292         u16 w;
293
294         w = omap_readw(OMAP1610_DMA_LCD_CTRL);
295         if (unlikely(!(w & (1 << 3)))) {
296                 printk(KERN_WARNING "Spurious LCD DMA IRQ\n");
297                 return IRQ_NONE;
298         }
299         /* Ack the IRQ */
300         w |= (1 << 3);
301         omap_writew(w, OMAP1610_DMA_LCD_CTRL);
302         lcd_dma.active = 0;
303         if (lcd_dma.callback != NULL)
304                 lcd_dma.callback(w, lcd_dma.cb_data);
305
306         return IRQ_HANDLED;
307 }
308
309 int omap_request_lcd_dma(void (*callback)(u16 status, void *data),
310                          void *data)
311 {
312         spin_lock_irq(&lcd_dma.lock);
313         if (lcd_dma.reserved) {
314                 spin_unlock_irq(&lcd_dma.lock);
315                 printk(KERN_ERR "LCD DMA channel already reserved\n");
316                 BUG();
317                 return -EBUSY;
318         }
319         lcd_dma.reserved = 1;
320         spin_unlock_irq(&lcd_dma.lock);
321         lcd_dma.callback = callback;
322         lcd_dma.cb_data = data;
323         lcd_dma.active = 0;
324         lcd_dma.single_transfer = 0;
325         lcd_dma.rotate = 0;
326         lcd_dma.vxres = 0;
327         lcd_dma.mirror = 0;
328         lcd_dma.xscale = 0;
329         lcd_dma.yscale = 0;
330         lcd_dma.ext_ctrl = 0;
331         lcd_dma.src_port = 0;
332
333         return 0;
334 }
335 EXPORT_SYMBOL(omap_request_lcd_dma);
336
337 void omap_free_lcd_dma(void)
338 {
339         spin_lock(&lcd_dma.lock);
340         if (!lcd_dma.reserved) {
341                 spin_unlock(&lcd_dma.lock);
342                 printk(KERN_ERR "LCD DMA is not reserved\n");
343                 BUG();
344                 return;
345         }
346         if (!cpu_is_omap1510())
347                 omap_writew(omap_readw(OMAP1610_DMA_LCD_CCR) & ~1,
348                             OMAP1610_DMA_LCD_CCR);
349         lcd_dma.reserved = 0;
350         spin_unlock(&lcd_dma.lock);
351 }
352 EXPORT_SYMBOL(omap_free_lcd_dma);
353
354 void omap_enable_lcd_dma(void)
355 {
356         u16 w;
357
358         /*
359          * Set the Enable bit only if an external controller is
360          * connected. Otherwise the OMAP internal controller will
361          * start the transfer when it gets enabled.
362          */
363         if (cpu_is_omap1510() || !lcd_dma.ext_ctrl)
364                 return;
365
366         w = omap_readw(OMAP1610_DMA_LCD_CTRL);
367         w |= 1 << 8;
368         omap_writew(w, OMAP1610_DMA_LCD_CTRL);
369
370         lcd_dma.active = 1;
371
372         w = omap_readw(OMAP1610_DMA_LCD_CCR);
373         w |= 1 << 7;
374         omap_writew(w, OMAP1610_DMA_LCD_CCR);
375 }
376 EXPORT_SYMBOL(omap_enable_lcd_dma);
377
378 void omap_setup_lcd_dma(void)
379 {
380         BUG_ON(lcd_dma.active);
381         if (!cpu_is_omap1510()) {
382                 /* Set some reasonable defaults */
383                 omap_writew(0x5440, OMAP1610_DMA_LCD_CCR);
384                 omap_writew(0x9102, OMAP1610_DMA_LCD_CSDP);
385                 omap_writew(0x0004, OMAP1610_DMA_LCD_LCH_CTRL);
386         }
387         set_b1_regs();
388         if (!cpu_is_omap1510()) {
389                 u16 w;
390
391                 w = omap_readw(OMAP1610_DMA_LCD_CCR);
392                 /*
393                  * If DMA was already active set the end_prog bit to have
394                  * the programmed register set loaded into the active
395                  * register set.
396                  */
397                 w |= 1 << 11;           /* End_prog */
398                 if (!lcd_dma.single_transfer)
399                         w |= (3 << 8);  /* Auto_init, repeat */
400                 omap_writew(w, OMAP1610_DMA_LCD_CCR);
401         }
402 }
403 EXPORT_SYMBOL(omap_setup_lcd_dma);
404
405 void omap_stop_lcd_dma(void)
406 {
407         u16 w;
408
409         lcd_dma.active = 0;
410         if (cpu_is_omap1510() || !lcd_dma.ext_ctrl)
411                 return;
412
413         w = omap_readw(OMAP1610_DMA_LCD_CCR);
414         w &= ~(1 << 7);
415         omap_writew(w, OMAP1610_DMA_LCD_CCR);
416
417         w = omap_readw(OMAP1610_DMA_LCD_CTRL);
418         w &= ~(1 << 8);
419         omap_writew(w, OMAP1610_DMA_LCD_CTRL);
420 }
421 EXPORT_SYMBOL(omap_stop_lcd_dma);
422
423 static int __init omap_init_lcd_dma(void)
424 {
425         int r;
426
427         if (!cpu_class_is_omap1())
428                 return -ENODEV;
429
430         if (cpu_is_omap16xx()) {
431                 u16 w;
432
433                 /* this would prevent OMAP sleep */
434                 w = omap_readw(OMAP1610_DMA_LCD_CTRL);
435                 w &= ~(1 << 8);
436                 omap_writew(w, OMAP1610_DMA_LCD_CTRL);
437         }
438
439         spin_lock_init(&lcd_dma.lock);
440
441         r = request_irq(INT_DMA_LCD, lcd_dma_irq_handler, 0,
442                         "LCD DMA", NULL);
443         if (r != 0)
444                 printk(KERN_ERR "unable to request IRQ for LCD DMA "
445                                "(error %d)\n", r);
446
447         return r;
448 }
449
450 arch_initcall(omap_init_lcd_dma);
451