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 445