18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/arch/arm/mach-omap1/lcd_dma.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Extracted from arch/arm/plat-omap/dma.c 68c2ecf20Sopenharmony_ci * Copyright (C) 2003 - 2008 Nokia Corporation 78c2ecf20Sopenharmony_ci * Author: Juha Yrjölä <juha.yrjola@nokia.com> 88c2ecf20Sopenharmony_ci * DMA channel linking for 1610 by Samuel Ortiz <samuel.ortiz@nokia.com> 98c2ecf20Sopenharmony_ci * Graphics DMA and LCD DMA graphics tranformations 108c2ecf20Sopenharmony_ci * by Imre Deak <imre.deak@nokia.com> 118c2ecf20Sopenharmony_ci * OMAP2/3 support Copyright (C) 2004-2007 Texas Instruments, Inc. 128c2ecf20Sopenharmony_ci * Merged to support both OMAP1 and OMAP2 by Tony Lindgren <tony@atomide.com> 138c2ecf20Sopenharmony_ci * Some functions based on earlier dma-omap.c Copyright (C) 2001 RidgeRun, Inc. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Copyright (C) 2009 Texas Instruments 168c2ecf20Sopenharmony_ci * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com> 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * Support functions for the OMAP internal DMA channels. 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/module.h> 228c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 238c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 248c2ecf20Sopenharmony_ci#include <linux/io.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <linux/omap-dma.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include <mach/hardware.h> 298c2ecf20Sopenharmony_ci#include <mach/lcdc.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ciint omap_lcd_dma_running(void) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci /* 348c2ecf20Sopenharmony_ci * On OMAP1510, internal LCD controller will start the transfer 358c2ecf20Sopenharmony_ci * when it gets enabled, so assume DMA running if LCD enabled. 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_ci if (cpu_is_omap15xx()) 388c2ecf20Sopenharmony_ci if (omap_readw(OMAP_LCDC_CONTROL) & OMAP_LCDC_CTRL_LCD_EN) 398c2ecf20Sopenharmony_ci return 1; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci /* Check if LCD DMA is running */ 428c2ecf20Sopenharmony_ci if (cpu_is_omap16xx()) 438c2ecf20Sopenharmony_ci if (omap_readw(OMAP1610_DMA_LCD_CCR) & OMAP_DMA_CCR_EN) 448c2ecf20Sopenharmony_ci return 1; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci return 0; 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic struct lcd_dma_info { 508c2ecf20Sopenharmony_ci spinlock_t lock; 518c2ecf20Sopenharmony_ci int reserved; 528c2ecf20Sopenharmony_ci void (*callback)(u16 status, void *data); 538c2ecf20Sopenharmony_ci void *cb_data; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci int active; 568c2ecf20Sopenharmony_ci unsigned long addr; 578c2ecf20Sopenharmony_ci int rotate, data_type, xres, yres; 588c2ecf20Sopenharmony_ci int vxres; 598c2ecf20Sopenharmony_ci int mirror; 608c2ecf20Sopenharmony_ci int xscale, yscale; 618c2ecf20Sopenharmony_ci int ext_ctrl; 628c2ecf20Sopenharmony_ci int src_port; 638c2ecf20Sopenharmony_ci int single_transfer; 648c2ecf20Sopenharmony_ci} lcd_dma; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_civoid omap_set_lcd_dma_b1(unsigned long addr, u16 fb_xres, u16 fb_yres, 678c2ecf20Sopenharmony_ci int data_type) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci lcd_dma.addr = addr; 708c2ecf20Sopenharmony_ci lcd_dma.data_type = data_type; 718c2ecf20Sopenharmony_ci lcd_dma.xres = fb_xres; 728c2ecf20Sopenharmony_ci lcd_dma.yres = fb_yres; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ciEXPORT_SYMBOL(omap_set_lcd_dma_b1); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_civoid omap_set_lcd_dma_ext_controller(int external) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci lcd_dma.ext_ctrl = external; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ciEXPORT_SYMBOL(omap_set_lcd_dma_ext_controller); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_civoid omap_set_lcd_dma_single_transfer(int single) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci lcd_dma.single_transfer = single; 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ciEXPORT_SYMBOL(omap_set_lcd_dma_single_transfer); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_civoid omap_set_lcd_dma_b1_rotation(int rotate) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci if (cpu_is_omap15xx()) { 918c2ecf20Sopenharmony_ci printk(KERN_ERR "DMA rotation is not supported in 1510 mode\n"); 928c2ecf20Sopenharmony_ci BUG(); 938c2ecf20Sopenharmony_ci return; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci lcd_dma.rotate = rotate; 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ciEXPORT_SYMBOL(omap_set_lcd_dma_b1_rotation); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_civoid omap_set_lcd_dma_b1_mirror(int mirror) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci if (cpu_is_omap15xx()) { 1028c2ecf20Sopenharmony_ci printk(KERN_ERR "DMA mirror is not supported in 1510 mode\n"); 1038c2ecf20Sopenharmony_ci BUG(); 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci lcd_dma.mirror = mirror; 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ciEXPORT_SYMBOL(omap_set_lcd_dma_b1_mirror); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_civoid omap_set_lcd_dma_b1_vxres(unsigned long vxres) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci if (cpu_is_omap15xx()) { 1128c2ecf20Sopenharmony_ci pr_err("DMA virtual resolution is not supported in 1510 mode\n"); 1138c2ecf20Sopenharmony_ci BUG(); 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci lcd_dma.vxres = vxres; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ciEXPORT_SYMBOL(omap_set_lcd_dma_b1_vxres); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_civoid omap_set_lcd_dma_b1_scale(unsigned int xscale, unsigned int yscale) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci if (cpu_is_omap15xx()) { 1228c2ecf20Sopenharmony_ci printk(KERN_ERR "DMA scale is not supported in 1510 mode\n"); 1238c2ecf20Sopenharmony_ci BUG(); 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci lcd_dma.xscale = xscale; 1268c2ecf20Sopenharmony_ci lcd_dma.yscale = yscale; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ciEXPORT_SYMBOL(omap_set_lcd_dma_b1_scale); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic void set_b1_regs(void) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci unsigned long top, bottom; 1338c2ecf20Sopenharmony_ci int es; 1348c2ecf20Sopenharmony_ci u16 w; 1358c2ecf20Sopenharmony_ci unsigned long en, fn; 1368c2ecf20Sopenharmony_ci long ei, fi; 1378c2ecf20Sopenharmony_ci unsigned long vxres; 1388c2ecf20Sopenharmony_ci unsigned int xscale, yscale; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci switch (lcd_dma.data_type) { 1418c2ecf20Sopenharmony_ci case OMAP_DMA_DATA_TYPE_S8: 1428c2ecf20Sopenharmony_ci es = 1; 1438c2ecf20Sopenharmony_ci break; 1448c2ecf20Sopenharmony_ci case OMAP_DMA_DATA_TYPE_S16: 1458c2ecf20Sopenharmony_ci es = 2; 1468c2ecf20Sopenharmony_ci break; 1478c2ecf20Sopenharmony_ci case OMAP_DMA_DATA_TYPE_S32: 1488c2ecf20Sopenharmony_ci es = 4; 1498c2ecf20Sopenharmony_ci break; 1508c2ecf20Sopenharmony_ci default: 1518c2ecf20Sopenharmony_ci BUG(); 1528c2ecf20Sopenharmony_ci return; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci vxres = lcd_dma.vxres ? lcd_dma.vxres : lcd_dma.xres; 1568c2ecf20Sopenharmony_ci xscale = lcd_dma.xscale ? lcd_dma.xscale : 1; 1578c2ecf20Sopenharmony_ci yscale = lcd_dma.yscale ? lcd_dma.yscale : 1; 1588c2ecf20Sopenharmony_ci BUG_ON(vxres < lcd_dma.xres); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci#define PIXADDR(x, y) (lcd_dma.addr + \ 1618c2ecf20Sopenharmony_ci ((y) * vxres * yscale + (x) * xscale) * es) 1628c2ecf20Sopenharmony_ci#define PIXSTEP(sx, sy, dx, dy) (PIXADDR(dx, dy) - PIXADDR(sx, sy) - es + 1) 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci switch (lcd_dma.rotate) { 1658c2ecf20Sopenharmony_ci case 0: 1668c2ecf20Sopenharmony_ci if (!lcd_dma.mirror) { 1678c2ecf20Sopenharmony_ci top = PIXADDR(0, 0); 1688c2ecf20Sopenharmony_ci bottom = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1); 1698c2ecf20Sopenharmony_ci /* 1510 DMA requires the bottom address to be 2 more 1708c2ecf20Sopenharmony_ci * than the actual last memory access location. */ 1718c2ecf20Sopenharmony_ci if (cpu_is_omap15xx() && 1728c2ecf20Sopenharmony_ci lcd_dma.data_type == OMAP_DMA_DATA_TYPE_S32) 1738c2ecf20Sopenharmony_ci bottom += 2; 1748c2ecf20Sopenharmony_ci ei = PIXSTEP(0, 0, 1, 0); 1758c2ecf20Sopenharmony_ci fi = PIXSTEP(lcd_dma.xres - 1, 0, 0, 1); 1768c2ecf20Sopenharmony_ci } else { 1778c2ecf20Sopenharmony_ci top = PIXADDR(lcd_dma.xres - 1, 0); 1788c2ecf20Sopenharmony_ci bottom = PIXADDR(0, lcd_dma.yres - 1); 1798c2ecf20Sopenharmony_ci ei = PIXSTEP(1, 0, 0, 0); 1808c2ecf20Sopenharmony_ci fi = PIXSTEP(0, 0, lcd_dma.xres - 1, 1); 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci en = lcd_dma.xres; 1838c2ecf20Sopenharmony_ci fn = lcd_dma.yres; 1848c2ecf20Sopenharmony_ci break; 1858c2ecf20Sopenharmony_ci case 90: 1868c2ecf20Sopenharmony_ci if (!lcd_dma.mirror) { 1878c2ecf20Sopenharmony_ci top = PIXADDR(0, lcd_dma.yres - 1); 1888c2ecf20Sopenharmony_ci bottom = PIXADDR(lcd_dma.xres - 1, 0); 1898c2ecf20Sopenharmony_ci ei = PIXSTEP(0, 1, 0, 0); 1908c2ecf20Sopenharmony_ci fi = PIXSTEP(0, 0, 1, lcd_dma.yres - 1); 1918c2ecf20Sopenharmony_ci } else { 1928c2ecf20Sopenharmony_ci top = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1); 1938c2ecf20Sopenharmony_ci bottom = PIXADDR(0, 0); 1948c2ecf20Sopenharmony_ci ei = PIXSTEP(0, 1, 0, 0); 1958c2ecf20Sopenharmony_ci fi = PIXSTEP(1, 0, 0, lcd_dma.yres - 1); 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci en = lcd_dma.yres; 1988c2ecf20Sopenharmony_ci fn = lcd_dma.xres; 1998c2ecf20Sopenharmony_ci break; 2008c2ecf20Sopenharmony_ci case 180: 2018c2ecf20Sopenharmony_ci if (!lcd_dma.mirror) { 2028c2ecf20Sopenharmony_ci top = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1); 2038c2ecf20Sopenharmony_ci bottom = PIXADDR(0, 0); 2048c2ecf20Sopenharmony_ci ei = PIXSTEP(1, 0, 0, 0); 2058c2ecf20Sopenharmony_ci fi = PIXSTEP(0, 1, lcd_dma.xres - 1, 0); 2068c2ecf20Sopenharmony_ci } else { 2078c2ecf20Sopenharmony_ci top = PIXADDR(0, lcd_dma.yres - 1); 2088c2ecf20Sopenharmony_ci bottom = PIXADDR(lcd_dma.xres - 1, 0); 2098c2ecf20Sopenharmony_ci ei = PIXSTEP(0, 0, 1, 0); 2108c2ecf20Sopenharmony_ci fi = PIXSTEP(lcd_dma.xres - 1, 1, 0, 0); 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci en = lcd_dma.xres; 2138c2ecf20Sopenharmony_ci fn = lcd_dma.yres; 2148c2ecf20Sopenharmony_ci break; 2158c2ecf20Sopenharmony_ci case 270: 2168c2ecf20Sopenharmony_ci if (!lcd_dma.mirror) { 2178c2ecf20Sopenharmony_ci top = PIXADDR(lcd_dma.xres - 1, 0); 2188c2ecf20Sopenharmony_ci bottom = PIXADDR(0, lcd_dma.yres - 1); 2198c2ecf20Sopenharmony_ci ei = PIXSTEP(0, 0, 0, 1); 2208c2ecf20Sopenharmony_ci fi = PIXSTEP(1, lcd_dma.yres - 1, 0, 0); 2218c2ecf20Sopenharmony_ci } else { 2228c2ecf20Sopenharmony_ci top = PIXADDR(0, 0); 2238c2ecf20Sopenharmony_ci bottom = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1); 2248c2ecf20Sopenharmony_ci ei = PIXSTEP(0, 0, 0, 1); 2258c2ecf20Sopenharmony_ci fi = PIXSTEP(0, lcd_dma.yres - 1, 1, 0); 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci en = lcd_dma.yres; 2288c2ecf20Sopenharmony_ci fn = lcd_dma.xres; 2298c2ecf20Sopenharmony_ci break; 2308c2ecf20Sopenharmony_ci default: 2318c2ecf20Sopenharmony_ci BUG(); 2328c2ecf20Sopenharmony_ci return; /* Suppress warning about uninitialized vars */ 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if (cpu_is_omap15xx()) { 2368c2ecf20Sopenharmony_ci omap_writew(top >> 16, OMAP1510_DMA_LCD_TOP_F1_U); 2378c2ecf20Sopenharmony_ci omap_writew(top, OMAP1510_DMA_LCD_TOP_F1_L); 2388c2ecf20Sopenharmony_ci omap_writew(bottom >> 16, OMAP1510_DMA_LCD_BOT_F1_U); 2398c2ecf20Sopenharmony_ci omap_writew(bottom, OMAP1510_DMA_LCD_BOT_F1_L); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci return; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* 1610 regs */ 2458c2ecf20Sopenharmony_ci omap_writew(top >> 16, OMAP1610_DMA_LCD_TOP_B1_U); 2468c2ecf20Sopenharmony_ci omap_writew(top, OMAP1610_DMA_LCD_TOP_B1_L); 2478c2ecf20Sopenharmony_ci omap_writew(bottom >> 16, OMAP1610_DMA_LCD_BOT_B1_U); 2488c2ecf20Sopenharmony_ci omap_writew(bottom, OMAP1610_DMA_LCD_BOT_B1_L); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci omap_writew(en, OMAP1610_DMA_LCD_SRC_EN_B1); 2518c2ecf20Sopenharmony_ci omap_writew(fn, OMAP1610_DMA_LCD_SRC_FN_B1); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci w = omap_readw(OMAP1610_DMA_LCD_CSDP); 2548c2ecf20Sopenharmony_ci w &= ~0x03; 2558c2ecf20Sopenharmony_ci w |= lcd_dma.data_type; 2568c2ecf20Sopenharmony_ci omap_writew(w, OMAP1610_DMA_LCD_CSDP); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci w = omap_readw(OMAP1610_DMA_LCD_CTRL); 2598c2ecf20Sopenharmony_ci /* Always set the source port as SDRAM for now*/ 2608c2ecf20Sopenharmony_ci w &= ~(0x03 << 6); 2618c2ecf20Sopenharmony_ci if (lcd_dma.callback != NULL) 2628c2ecf20Sopenharmony_ci w |= 1 << 1; /* Block interrupt enable */ 2638c2ecf20Sopenharmony_ci else 2648c2ecf20Sopenharmony_ci w &= ~(1 << 1); 2658c2ecf20Sopenharmony_ci omap_writew(w, OMAP1610_DMA_LCD_CTRL); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (!(lcd_dma.rotate || lcd_dma.mirror || 2688c2ecf20Sopenharmony_ci lcd_dma.vxres || lcd_dma.xscale || lcd_dma.yscale)) 2698c2ecf20Sopenharmony_ci return; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci w = omap_readw(OMAP1610_DMA_LCD_CCR); 2728c2ecf20Sopenharmony_ci /* Set the double-indexed addressing mode */ 2738c2ecf20Sopenharmony_ci w |= (0x03 << 12); 2748c2ecf20Sopenharmony_ci omap_writew(w, OMAP1610_DMA_LCD_CCR); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci omap_writew(ei, OMAP1610_DMA_LCD_SRC_EI_B1); 2778c2ecf20Sopenharmony_ci omap_writew(fi >> 16, OMAP1610_DMA_LCD_SRC_FI_B1_U); 2788c2ecf20Sopenharmony_ci omap_writew(fi, OMAP1610_DMA_LCD_SRC_FI_B1_L); 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic irqreturn_t lcd_dma_irq_handler(int irq, void *dev_id) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci u16 w; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci w = omap_readw(OMAP1610_DMA_LCD_CTRL); 2868c2ecf20Sopenharmony_ci if (unlikely(!(w & (1 << 3)))) { 2878c2ecf20Sopenharmony_ci printk(KERN_WARNING "Spurious LCD DMA IRQ\n"); 2888c2ecf20Sopenharmony_ci return IRQ_NONE; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci /* Ack the IRQ */ 2918c2ecf20Sopenharmony_ci w |= (1 << 3); 2928c2ecf20Sopenharmony_ci omap_writew(w, OMAP1610_DMA_LCD_CTRL); 2938c2ecf20Sopenharmony_ci lcd_dma.active = 0; 2948c2ecf20Sopenharmony_ci if (lcd_dma.callback != NULL) 2958c2ecf20Sopenharmony_ci lcd_dma.callback(w, lcd_dma.cb_data); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ciint omap_request_lcd_dma(void (*callback)(u16 status, void *data), 3018c2ecf20Sopenharmony_ci void *data) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci spin_lock_irq(&lcd_dma.lock); 3048c2ecf20Sopenharmony_ci if (lcd_dma.reserved) { 3058c2ecf20Sopenharmony_ci spin_unlock_irq(&lcd_dma.lock); 3068c2ecf20Sopenharmony_ci printk(KERN_ERR "LCD DMA channel already reserved\n"); 3078c2ecf20Sopenharmony_ci BUG(); 3088c2ecf20Sopenharmony_ci return -EBUSY; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci lcd_dma.reserved = 1; 3118c2ecf20Sopenharmony_ci spin_unlock_irq(&lcd_dma.lock); 3128c2ecf20Sopenharmony_ci lcd_dma.callback = callback; 3138c2ecf20Sopenharmony_ci lcd_dma.cb_data = data; 3148c2ecf20Sopenharmony_ci lcd_dma.active = 0; 3158c2ecf20Sopenharmony_ci lcd_dma.single_transfer = 0; 3168c2ecf20Sopenharmony_ci lcd_dma.rotate = 0; 3178c2ecf20Sopenharmony_ci lcd_dma.vxres = 0; 3188c2ecf20Sopenharmony_ci lcd_dma.mirror = 0; 3198c2ecf20Sopenharmony_ci lcd_dma.xscale = 0; 3208c2ecf20Sopenharmony_ci lcd_dma.yscale = 0; 3218c2ecf20Sopenharmony_ci lcd_dma.ext_ctrl = 0; 3228c2ecf20Sopenharmony_ci lcd_dma.src_port = 0; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci return 0; 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ciEXPORT_SYMBOL(omap_request_lcd_dma); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_civoid omap_free_lcd_dma(void) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci spin_lock(&lcd_dma.lock); 3318c2ecf20Sopenharmony_ci if (!lcd_dma.reserved) { 3328c2ecf20Sopenharmony_ci spin_unlock(&lcd_dma.lock); 3338c2ecf20Sopenharmony_ci printk(KERN_ERR "LCD DMA is not reserved\n"); 3348c2ecf20Sopenharmony_ci BUG(); 3358c2ecf20Sopenharmony_ci return; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci if (!cpu_is_omap15xx()) 3388c2ecf20Sopenharmony_ci omap_writew(omap_readw(OMAP1610_DMA_LCD_CCR) & ~1, 3398c2ecf20Sopenharmony_ci OMAP1610_DMA_LCD_CCR); 3408c2ecf20Sopenharmony_ci lcd_dma.reserved = 0; 3418c2ecf20Sopenharmony_ci spin_unlock(&lcd_dma.lock); 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(omap_free_lcd_dma); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_civoid omap_enable_lcd_dma(void) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci u16 w; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci /* 3508c2ecf20Sopenharmony_ci * Set the Enable bit only if an external controller is 3518c2ecf20Sopenharmony_ci * connected. Otherwise the OMAP internal controller will 3528c2ecf20Sopenharmony_ci * start the transfer when it gets enabled. 3538c2ecf20Sopenharmony_ci */ 3548c2ecf20Sopenharmony_ci if (cpu_is_omap15xx() || !lcd_dma.ext_ctrl) 3558c2ecf20Sopenharmony_ci return; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci w = omap_readw(OMAP1610_DMA_LCD_CTRL); 3588c2ecf20Sopenharmony_ci w |= 1 << 8; 3598c2ecf20Sopenharmony_ci omap_writew(w, OMAP1610_DMA_LCD_CTRL); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci lcd_dma.active = 1; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci w = omap_readw(OMAP1610_DMA_LCD_CCR); 3648c2ecf20Sopenharmony_ci w |= 1 << 7; 3658c2ecf20Sopenharmony_ci omap_writew(w, OMAP1610_DMA_LCD_CCR); 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ciEXPORT_SYMBOL(omap_enable_lcd_dma); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_civoid omap_setup_lcd_dma(void) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci BUG_ON(lcd_dma.active); 3728c2ecf20Sopenharmony_ci if (!cpu_is_omap15xx()) { 3738c2ecf20Sopenharmony_ci /* Set some reasonable defaults */ 3748c2ecf20Sopenharmony_ci omap_writew(0x5440, OMAP1610_DMA_LCD_CCR); 3758c2ecf20Sopenharmony_ci omap_writew(0x9102, OMAP1610_DMA_LCD_CSDP); 3768c2ecf20Sopenharmony_ci omap_writew(0x0004, OMAP1610_DMA_LCD_LCH_CTRL); 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci set_b1_regs(); 3798c2ecf20Sopenharmony_ci if (!cpu_is_omap15xx()) { 3808c2ecf20Sopenharmony_ci u16 w; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci w = omap_readw(OMAP1610_DMA_LCD_CCR); 3838c2ecf20Sopenharmony_ci /* 3848c2ecf20Sopenharmony_ci * If DMA was already active set the end_prog bit to have 3858c2ecf20Sopenharmony_ci * the programmed register set loaded into the active 3868c2ecf20Sopenharmony_ci * register set. 3878c2ecf20Sopenharmony_ci */ 3888c2ecf20Sopenharmony_ci w |= 1 << 11; /* End_prog */ 3898c2ecf20Sopenharmony_ci if (!lcd_dma.single_transfer) 3908c2ecf20Sopenharmony_ci w |= (3 << 8); /* Auto_init, repeat */ 3918c2ecf20Sopenharmony_ci omap_writew(w, OMAP1610_DMA_LCD_CCR); 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ciEXPORT_SYMBOL(omap_setup_lcd_dma); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_civoid omap_stop_lcd_dma(void) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci u16 w; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci lcd_dma.active = 0; 4018c2ecf20Sopenharmony_ci if (cpu_is_omap15xx() || !lcd_dma.ext_ctrl) 4028c2ecf20Sopenharmony_ci return; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci w = omap_readw(OMAP1610_DMA_LCD_CCR); 4058c2ecf20Sopenharmony_ci w &= ~(1 << 7); 4068c2ecf20Sopenharmony_ci omap_writew(w, OMAP1610_DMA_LCD_CCR); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci w = omap_readw(OMAP1610_DMA_LCD_CTRL); 4098c2ecf20Sopenharmony_ci w &= ~(1 << 8); 4108c2ecf20Sopenharmony_ci omap_writew(w, OMAP1610_DMA_LCD_CTRL); 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ciEXPORT_SYMBOL(omap_stop_lcd_dma); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic int __init omap_init_lcd_dma(void) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci int r; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (!cpu_class_is_omap1()) 4198c2ecf20Sopenharmony_ci return -ENODEV; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci if (cpu_is_omap16xx()) { 4228c2ecf20Sopenharmony_ci u16 w; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci /* this would prevent OMAP sleep */ 4258c2ecf20Sopenharmony_ci w = omap_readw(OMAP1610_DMA_LCD_CTRL); 4268c2ecf20Sopenharmony_ci w &= ~(1 << 8); 4278c2ecf20Sopenharmony_ci omap_writew(w, OMAP1610_DMA_LCD_CTRL); 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci spin_lock_init(&lcd_dma.lock); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci r = request_irq(INT_DMA_LCD, lcd_dma_irq_handler, 0, 4338c2ecf20Sopenharmony_ci "LCD DMA", NULL); 4348c2ecf20Sopenharmony_ci if (r != 0) 4358c2ecf20Sopenharmony_ci pr_err("unable to request IRQ for LCD DMA (error %d)\n", r); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci return r; 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ciarch_initcall(omap_init_lcd_dma); 4418c2ecf20Sopenharmony_ci 442