Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * linux/arch/arm/mach-omap1/lcd_dma.c
0004  *
0005  * Extracted from arch/arm/plat-omap/dma.c
0006  * Copyright (C) 2003 - 2008 Nokia Corporation
0007  * Author: Juha Yrjölä <juha.yrjola@nokia.com>
0008  * DMA channel linking for 1610 by Samuel Ortiz <samuel.ortiz@nokia.com>
0009  * Graphics DMA and LCD DMA graphics tranformations
0010  * by Imre Deak <imre.deak@nokia.com>
0011  * OMAP2/3 support Copyright (C) 2004-2007 Texas Instruments, Inc.
0012  * Merged to support both OMAP1 and OMAP2 by Tony Lindgren <tony@atomide.com>
0013  * Some functions based on earlier dma-omap.c Copyright (C) 2001 RidgeRun, Inc.
0014  *
0015  * Copyright (C) 2009 Texas Instruments
0016  * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
0017  *
0018  * Support functions for the OMAP internal DMA channels.
0019  */
0020 
0021 #include <linux/module.h>
0022 #include <linux/spinlock.h>
0023 #include <linux/interrupt.h>
0024 #include <linux/io.h>
0025 
0026 #include <linux/omap-dma.h>
0027 
0028 #include <linux/soc/ti/omap1-soc.h>
0029 #include <linux/soc/ti/omap1-io.h>
0030 
0031 #include "lcdc.h"
0032 #include "lcd_dma.h"
0033 
0034 int omap_lcd_dma_running(void)
0035 {
0036     /*
0037      * On OMAP1510, internal LCD controller will start the transfer
0038      * when it gets enabled, so assume DMA running if LCD enabled.
0039      */
0040     if (cpu_is_omap15xx())
0041         if (omap_readw(OMAP_LCDC_CONTROL) & OMAP_LCDC_CTRL_LCD_EN)
0042             return 1;
0043 
0044     /* Check if LCD DMA is running */
0045     if (cpu_is_omap16xx())
0046         if (omap_readw(OMAP1610_DMA_LCD_CCR) & OMAP_DMA_CCR_EN)
0047             return 1;
0048 
0049     return 0;
0050 }
0051 
0052 static struct lcd_dma_info {
0053     spinlock_t lock;
0054     int reserved;
0055     void (*callback)(u16 status, void *data);
0056     void *cb_data;
0057 
0058     int active;
0059     unsigned long addr;
0060     int rotate, data_type, xres, yres;
0061     int vxres;
0062     int mirror;
0063     int xscale, yscale;
0064     int ext_ctrl;
0065     int src_port;
0066     int single_transfer;
0067 } lcd_dma;
0068 
0069 void omap_set_lcd_dma_b1(unsigned long addr, u16 fb_xres, u16 fb_yres,
0070              int data_type)
0071 {
0072     lcd_dma.addr = addr;
0073     lcd_dma.data_type = data_type;
0074     lcd_dma.xres = fb_xres;
0075     lcd_dma.yres = fb_yres;
0076 }
0077 EXPORT_SYMBOL(omap_set_lcd_dma_b1);
0078 
0079 void omap_set_lcd_dma_ext_controller(int external)
0080 {
0081     lcd_dma.ext_ctrl = external;
0082 }
0083 EXPORT_SYMBOL(omap_set_lcd_dma_ext_controller);
0084 
0085 void omap_set_lcd_dma_single_transfer(int single)
0086 {
0087     lcd_dma.single_transfer = single;
0088 }
0089 EXPORT_SYMBOL(omap_set_lcd_dma_single_transfer);
0090 
0091 void omap_set_lcd_dma_b1_rotation(int rotate)
0092 {
0093     if (cpu_is_omap15xx()) {
0094         printk(KERN_ERR "DMA rotation is not supported in 1510 mode\n");
0095         BUG();
0096         return;
0097     }
0098     lcd_dma.rotate = rotate;
0099 }
0100 EXPORT_SYMBOL(omap_set_lcd_dma_b1_rotation);
0101 
0102 void omap_set_lcd_dma_b1_mirror(int mirror)
0103 {
0104     if (cpu_is_omap15xx()) {
0105         printk(KERN_ERR "DMA mirror is not supported in 1510 mode\n");
0106         BUG();
0107     }
0108     lcd_dma.mirror = mirror;
0109 }
0110 EXPORT_SYMBOL(omap_set_lcd_dma_b1_mirror);
0111 
0112 void omap_set_lcd_dma_b1_vxres(unsigned long vxres)
0113 {
0114     if (cpu_is_omap15xx()) {
0115         pr_err("DMA virtual resolution is not supported in 1510 mode\n");
0116         BUG();
0117     }
0118     lcd_dma.vxres = vxres;
0119 }
0120 EXPORT_SYMBOL(omap_set_lcd_dma_b1_vxres);
0121 
0122 void omap_set_lcd_dma_b1_scale(unsigned int xscale, unsigned int yscale)
0123 {
0124     if (cpu_is_omap15xx()) {
0125         printk(KERN_ERR "DMA scale is not supported in 1510 mode\n");
0126         BUG();
0127     }
0128     lcd_dma.xscale = xscale;
0129     lcd_dma.yscale = yscale;
0130 }
0131 EXPORT_SYMBOL(omap_set_lcd_dma_b1_scale);
0132 
0133 static void set_b1_regs(void)
0134 {
0135     unsigned long top, bottom;
0136     int es;
0137     u16 w;
0138     unsigned long en, fn;
0139     long ei, fi;
0140     unsigned long vxres;
0141     unsigned int xscale, yscale;
0142 
0143     switch (lcd_dma.data_type) {
0144     case OMAP_DMA_DATA_TYPE_S8:
0145         es = 1;
0146         break;
0147     case OMAP_DMA_DATA_TYPE_S16:
0148         es = 2;
0149         break;
0150     case OMAP_DMA_DATA_TYPE_S32:
0151         es = 4;
0152         break;
0153     default:
0154         BUG();
0155         return;
0156     }
0157 
0158     vxres = lcd_dma.vxres ? lcd_dma.vxres : lcd_dma.xres;
0159     xscale = lcd_dma.xscale ? lcd_dma.xscale : 1;
0160     yscale = lcd_dma.yscale ? lcd_dma.yscale : 1;
0161     BUG_ON(vxres < lcd_dma.xres);
0162 
0163 #define PIXADDR(x, y) (lcd_dma.addr +                   \
0164         ((y) * vxres * yscale + (x) * xscale) * es)
0165 #define PIXSTEP(sx, sy, dx, dy) (PIXADDR(dx, dy) - PIXADDR(sx, sy) - es + 1)
0166 
0167     switch (lcd_dma.rotate) {
0168     case 0:
0169         if (!lcd_dma.mirror) {
0170             top = PIXADDR(0, 0);
0171             bottom = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);
0172             /* 1510 DMA requires the bottom address to be 2 more
0173              * than the actual last memory access location. */
0174             if (cpu_is_omap15xx() &&
0175                 lcd_dma.data_type == OMAP_DMA_DATA_TYPE_S32)
0176                     bottom += 2;
0177             ei = PIXSTEP(0, 0, 1, 0);
0178             fi = PIXSTEP(lcd_dma.xres - 1, 0, 0, 1);
0179         } else {
0180             top = PIXADDR(lcd_dma.xres - 1, 0);
0181             bottom = PIXADDR(0, lcd_dma.yres - 1);
0182             ei = PIXSTEP(1, 0, 0, 0);
0183             fi = PIXSTEP(0, 0, lcd_dma.xres - 1, 1);
0184         }
0185         en = lcd_dma.xres;
0186         fn = lcd_dma.yres;
0187         break;
0188     case 90:
0189         if (!lcd_dma.mirror) {
0190             top = PIXADDR(0, lcd_dma.yres - 1);
0191             bottom = PIXADDR(lcd_dma.xres - 1, 0);
0192             ei = PIXSTEP(0, 1, 0, 0);
0193             fi = PIXSTEP(0, 0, 1, lcd_dma.yres - 1);
0194         } else {
0195             top = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);
0196             bottom = PIXADDR(0, 0);
0197             ei = PIXSTEP(0, 1, 0, 0);
0198             fi = PIXSTEP(1, 0, 0, lcd_dma.yres - 1);
0199         }
0200         en = lcd_dma.yres;
0201         fn = lcd_dma.xres;
0202         break;
0203     case 180:
0204         if (!lcd_dma.mirror) {
0205             top = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);
0206             bottom = PIXADDR(0, 0);
0207             ei = PIXSTEP(1, 0, 0, 0);
0208             fi = PIXSTEP(0, 1, lcd_dma.xres - 1, 0);
0209         } else {
0210             top = PIXADDR(0, lcd_dma.yres - 1);
0211             bottom = PIXADDR(lcd_dma.xres - 1, 0);
0212             ei = PIXSTEP(0, 0, 1, 0);
0213             fi = PIXSTEP(lcd_dma.xres - 1, 1, 0, 0);
0214         }
0215         en = lcd_dma.xres;
0216         fn = lcd_dma.yres;
0217         break;
0218     case 270:
0219         if (!lcd_dma.mirror) {
0220             top = PIXADDR(lcd_dma.xres - 1, 0);
0221             bottom = PIXADDR(0, lcd_dma.yres - 1);
0222             ei = PIXSTEP(0, 0, 0, 1);
0223             fi = PIXSTEP(1, lcd_dma.yres - 1, 0, 0);
0224         } else {
0225             top = PIXADDR(0, 0);
0226             bottom = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);
0227             ei = PIXSTEP(0, 0, 0, 1);
0228             fi = PIXSTEP(0, lcd_dma.yres - 1, 1, 0);
0229         }
0230         en = lcd_dma.yres;
0231         fn = lcd_dma.xres;
0232         break;
0233     default:
0234         BUG();
0235         return; /* Suppress warning about uninitialized vars */
0236     }
0237 
0238     if (cpu_is_omap15xx()) {
0239         omap_writew(top >> 16, OMAP1510_DMA_LCD_TOP_F1_U);
0240         omap_writew(top, OMAP1510_DMA_LCD_TOP_F1_L);
0241         omap_writew(bottom >> 16, OMAP1510_DMA_LCD_BOT_F1_U);
0242         omap_writew(bottom, OMAP1510_DMA_LCD_BOT_F1_L);
0243 
0244         return;
0245     }
0246 
0247     /* 1610 regs */
0248     omap_writew(top >> 16, OMAP1610_DMA_LCD_TOP_B1_U);
0249     omap_writew(top, OMAP1610_DMA_LCD_TOP_B1_L);
0250     omap_writew(bottom >> 16, OMAP1610_DMA_LCD_BOT_B1_U);
0251     omap_writew(bottom, OMAP1610_DMA_LCD_BOT_B1_L);
0252 
0253     omap_writew(en, OMAP1610_DMA_LCD_SRC_EN_B1);
0254     omap_writew(fn, OMAP1610_DMA_LCD_SRC_FN_B1);
0255 
0256     w = omap_readw(OMAP1610_DMA_LCD_CSDP);
0257     w &= ~0x03;
0258     w |= lcd_dma.data_type;
0259     omap_writew(w, OMAP1610_DMA_LCD_CSDP);
0260 
0261     w = omap_readw(OMAP1610_DMA_LCD_CTRL);
0262     /* Always set the source port as SDRAM for now*/
0263     w &= ~(0x03 << 6);
0264     if (lcd_dma.callback != NULL)
0265         w |= 1 << 1;        /* Block interrupt enable */
0266     else
0267         w &= ~(1 << 1);
0268     omap_writew(w, OMAP1610_DMA_LCD_CTRL);
0269 
0270     if (!(lcd_dma.rotate || lcd_dma.mirror ||
0271           lcd_dma.vxres || lcd_dma.xscale || lcd_dma.yscale))
0272         return;
0273 
0274     w = omap_readw(OMAP1610_DMA_LCD_CCR);
0275     /* Set the double-indexed addressing mode */
0276     w |= (0x03 << 12);
0277     omap_writew(w, OMAP1610_DMA_LCD_CCR);
0278 
0279     omap_writew(ei, OMAP1610_DMA_LCD_SRC_EI_B1);
0280     omap_writew(fi >> 16, OMAP1610_DMA_LCD_SRC_FI_B1_U);
0281     omap_writew(fi, OMAP1610_DMA_LCD_SRC_FI_B1_L);
0282 }
0283 
0284 static irqreturn_t lcd_dma_irq_handler(int irq, void *dev_id)
0285 {
0286     u16 w;
0287 
0288     w = omap_readw(OMAP1610_DMA_LCD_CTRL);
0289     if (unlikely(!(w & (1 << 3)))) {
0290         printk(KERN_WARNING "Spurious LCD DMA IRQ\n");
0291         return IRQ_NONE;
0292     }
0293     /* Ack the IRQ */
0294     w |= (1 << 3);
0295     omap_writew(w, OMAP1610_DMA_LCD_CTRL);
0296     lcd_dma.active = 0;
0297     if (lcd_dma.callback != NULL)
0298         lcd_dma.callback(w, lcd_dma.cb_data);
0299 
0300     return IRQ_HANDLED;
0301 }
0302 
0303 int omap_request_lcd_dma(void (*callback)(u16 status, void *data),
0304              void *data)
0305 {
0306     spin_lock_irq(&lcd_dma.lock);
0307     if (lcd_dma.reserved) {
0308         spin_unlock_irq(&lcd_dma.lock);
0309         printk(KERN_ERR "LCD DMA channel already reserved\n");
0310         BUG();
0311         return -EBUSY;
0312     }
0313     lcd_dma.reserved = 1;
0314     spin_unlock_irq(&lcd_dma.lock);
0315     lcd_dma.callback = callback;
0316     lcd_dma.cb_data = data;
0317     lcd_dma.active = 0;
0318     lcd_dma.single_transfer = 0;
0319     lcd_dma.rotate = 0;
0320     lcd_dma.vxres = 0;
0321     lcd_dma.mirror = 0;
0322     lcd_dma.xscale = 0;
0323     lcd_dma.yscale = 0;
0324     lcd_dma.ext_ctrl = 0;
0325     lcd_dma.src_port = 0;
0326 
0327     return 0;
0328 }
0329 EXPORT_SYMBOL(omap_request_lcd_dma);
0330 
0331 void omap_free_lcd_dma(void)
0332 {
0333     spin_lock(&lcd_dma.lock);
0334     if (!lcd_dma.reserved) {
0335         spin_unlock(&lcd_dma.lock);
0336         printk(KERN_ERR "LCD DMA is not reserved\n");
0337         BUG();
0338         return;
0339     }
0340     if (!cpu_is_omap15xx())
0341         omap_writew(omap_readw(OMAP1610_DMA_LCD_CCR) & ~1,
0342                 OMAP1610_DMA_LCD_CCR);
0343     lcd_dma.reserved = 0;
0344     spin_unlock(&lcd_dma.lock);
0345 }
0346 EXPORT_SYMBOL(omap_free_lcd_dma);
0347 
0348 void omap_enable_lcd_dma(void)
0349 {
0350     u16 w;
0351 
0352     /*
0353      * Set the Enable bit only if an external controller is
0354      * connected. Otherwise the OMAP internal controller will
0355      * start the transfer when it gets enabled.
0356      */
0357     if (cpu_is_omap15xx() || !lcd_dma.ext_ctrl)
0358         return;
0359 
0360     w = omap_readw(OMAP1610_DMA_LCD_CTRL);
0361     w |= 1 << 8;
0362     omap_writew(w, OMAP1610_DMA_LCD_CTRL);
0363 
0364     lcd_dma.active = 1;
0365 
0366     w = omap_readw(OMAP1610_DMA_LCD_CCR);
0367     w |= 1 << 7;
0368     omap_writew(w, OMAP1610_DMA_LCD_CCR);
0369 }
0370 EXPORT_SYMBOL(omap_enable_lcd_dma);
0371 
0372 void omap_setup_lcd_dma(void)
0373 {
0374     BUG_ON(lcd_dma.active);
0375     if (!cpu_is_omap15xx()) {
0376         /* Set some reasonable defaults */
0377         omap_writew(0x5440, OMAP1610_DMA_LCD_CCR);
0378         omap_writew(0x9102, OMAP1610_DMA_LCD_CSDP);
0379         omap_writew(0x0004, OMAP1610_DMA_LCD_LCH_CTRL);
0380     }
0381     set_b1_regs();
0382     if (!cpu_is_omap15xx()) {
0383         u16 w;
0384 
0385         w = omap_readw(OMAP1610_DMA_LCD_CCR);
0386         /*
0387          * If DMA was already active set the end_prog bit to have
0388          * the programmed register set loaded into the active
0389          * register set.
0390          */
0391         w |= 1 << 11;       /* End_prog */
0392         if (!lcd_dma.single_transfer)
0393             w |= (3 << 8);  /* Auto_init, repeat */
0394         omap_writew(w, OMAP1610_DMA_LCD_CCR);
0395     }
0396 }
0397 EXPORT_SYMBOL(omap_setup_lcd_dma);
0398 
0399 void omap_stop_lcd_dma(void)
0400 {
0401     u16 w;
0402 
0403     lcd_dma.active = 0;
0404     if (cpu_is_omap15xx() || !lcd_dma.ext_ctrl)
0405         return;
0406 
0407     w = omap_readw(OMAP1610_DMA_LCD_CCR);
0408     w &= ~(1 << 7);
0409     omap_writew(w, OMAP1610_DMA_LCD_CCR);
0410 
0411     w = omap_readw(OMAP1610_DMA_LCD_CTRL);
0412     w &= ~(1 << 8);
0413     omap_writew(w, OMAP1610_DMA_LCD_CTRL);
0414 }
0415 EXPORT_SYMBOL(omap_stop_lcd_dma);
0416 
0417 static int __init omap_init_lcd_dma(void)
0418 {
0419     int r;
0420 
0421     if (!cpu_class_is_omap1())
0422         return -ENODEV;
0423 
0424     if (cpu_is_omap16xx()) {
0425         u16 w;
0426 
0427         /* this would prevent OMAP sleep */
0428         w = omap_readw(OMAP1610_DMA_LCD_CTRL);
0429         w &= ~(1 << 8);
0430         omap_writew(w, OMAP1610_DMA_LCD_CTRL);
0431     }
0432 
0433     spin_lock_init(&lcd_dma.lock);
0434 
0435     r = request_irq(INT_DMA_LCD, lcd_dma_irq_handler, 0,
0436             "LCD DMA", NULL);
0437     if (r != 0)
0438         pr_err("unable to request IRQ for LCD DMA (error %d)\n", r);
0439 
0440     return r;
0441 }
0442 
0443 arch_initcall(omap_init_lcd_dma);
0444