0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
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
0038
0039
0040 if (cpu_is_omap15xx())
0041 if (omap_readw(OMAP_LCDC_CONTROL) & OMAP_LCDC_CTRL_LCD_EN)
0042 return 1;
0043
0044
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
0173
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;
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
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
0263 w &= ~(0x03 << 6);
0264 if (lcd_dma.callback != NULL)
0265 w |= 1 << 1;
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
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
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
0354
0355
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
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
0388
0389
0390
0391 w |= 1 << 11;
0392 if (!lcd_dma.single_transfer)
0393 w |= (3 << 8);
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
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