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