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