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