Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.5 3784 lines 91 kB view raw
1/* 2 * linux/drivers/video/omap2/dss/dispc.c 3 * 4 * Copyright (C) 2009 Nokia Corporation 5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> 6 * 7 * Some code and ideas taken from drivers/video/omap/ driver 8 * by Imre Deak. 9 * 10 * This program is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License version 2 as published by 12 * the Free Software Foundation. 13 * 14 * This program is distributed in the hope that it will be useful, but WITHOUT 15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 17 * more details. 18 * 19 * You should have received a copy of the GNU General Public License along with 20 * this program. If not, see <http://www.gnu.org/licenses/>. 21 */ 22 23#define DSS_SUBSYS_NAME "DISPC" 24 25#include <linux/kernel.h> 26#include <linux/dma-mapping.h> 27#include <linux/vmalloc.h> 28#include <linux/export.h> 29#include <linux/clk.h> 30#include <linux/io.h> 31#include <linux/jiffies.h> 32#include <linux/seq_file.h> 33#include <linux/delay.h> 34#include <linux/workqueue.h> 35#include <linux/hardirq.h> 36#include <linux/interrupt.h> 37#include <linux/platform_device.h> 38#include <linux/pm_runtime.h> 39 40#include <plat/clock.h> 41 42#include <video/omapdss.h> 43 44#include "dss.h" 45#include "dss_features.h" 46#include "dispc.h" 47 48/* DISPC */ 49#define DISPC_SZ_REGS SZ_4K 50 51#define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \ 52 DISPC_IRQ_OCP_ERR | \ 53 DISPC_IRQ_VID1_FIFO_UNDERFLOW | \ 54 DISPC_IRQ_VID2_FIFO_UNDERFLOW | \ 55 DISPC_IRQ_SYNC_LOST | \ 56 DISPC_IRQ_SYNC_LOST_DIGIT) 57 58#define DISPC_MAX_NR_ISRS 8 59 60struct omap_dispc_isr_data { 61 omap_dispc_isr_t isr; 62 void *arg; 63 u32 mask; 64}; 65 66enum omap_burst_size { 67 BURST_SIZE_X2 = 0, 68 BURST_SIZE_X4 = 1, 69 BURST_SIZE_X8 = 2, 70}; 71 72#define REG_GET(idx, start, end) \ 73 FLD_GET(dispc_read_reg(idx), start, end) 74 75#define REG_FLD_MOD(idx, val, start, end) \ 76 dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end)) 77 78struct dispc_irq_stats { 79 unsigned long last_reset; 80 unsigned irq_count; 81 unsigned irqs[32]; 82}; 83 84static struct { 85 struct platform_device *pdev; 86 void __iomem *base; 87 88 int ctx_loss_cnt; 89 90 int irq; 91 struct clk *dss_clk; 92 93 u32 fifo_size[MAX_DSS_OVERLAYS]; 94 95 spinlock_t irq_lock; 96 u32 irq_error_mask; 97 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS]; 98 u32 error_irqs; 99 struct work_struct error_work; 100 101 bool ctx_valid; 102 u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; 103 104#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS 105 spinlock_t irq_stats_lock; 106 struct dispc_irq_stats irq_stats; 107#endif 108} dispc; 109 110enum omap_color_component { 111 /* used for all color formats for OMAP3 and earlier 112 * and for RGB and Y color component on OMAP4 113 */ 114 DISPC_COLOR_COMPONENT_RGB_Y = 1 << 0, 115 /* used for UV component for 116 * OMAP_DSS_COLOR_YUV2, OMAP_DSS_COLOR_UYVY, OMAP_DSS_COLOR_NV12 117 * color formats on OMAP4 118 */ 119 DISPC_COLOR_COMPONENT_UV = 1 << 1, 120}; 121 122static void _omap_dispc_set_irqs(void); 123 124static inline void dispc_write_reg(const u16 idx, u32 val) 125{ 126 __raw_writel(val, dispc.base + idx); 127} 128 129static inline u32 dispc_read_reg(const u16 idx) 130{ 131 return __raw_readl(dispc.base + idx); 132} 133 134#define SR(reg) \ 135 dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg) 136#define RR(reg) \ 137 dispc_write_reg(DISPC_##reg, dispc.ctx[DISPC_##reg / sizeof(u32)]) 138 139static void dispc_save_context(void) 140{ 141 int i, j; 142 143 DSSDBG("dispc_save_context\n"); 144 145 SR(IRQENABLE); 146 SR(CONTROL); 147 SR(CONFIG); 148 SR(LINE_NUMBER); 149 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) || 150 dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) 151 SR(GLOBAL_ALPHA); 152 if (dss_has_feature(FEAT_MGR_LCD2)) { 153 SR(CONTROL2); 154 SR(CONFIG2); 155 } 156 157 for (i = 0; i < dss_feat_get_num_mgrs(); i++) { 158 SR(DEFAULT_COLOR(i)); 159 SR(TRANS_COLOR(i)); 160 SR(SIZE_MGR(i)); 161 if (i == OMAP_DSS_CHANNEL_DIGIT) 162 continue; 163 SR(TIMING_H(i)); 164 SR(TIMING_V(i)); 165 SR(POL_FREQ(i)); 166 SR(DIVISORo(i)); 167 168 SR(DATA_CYCLE1(i)); 169 SR(DATA_CYCLE2(i)); 170 SR(DATA_CYCLE3(i)); 171 172 if (dss_has_feature(FEAT_CPR)) { 173 SR(CPR_COEF_R(i)); 174 SR(CPR_COEF_G(i)); 175 SR(CPR_COEF_B(i)); 176 } 177 } 178 179 for (i = 0; i < dss_feat_get_num_ovls(); i++) { 180 SR(OVL_BA0(i)); 181 SR(OVL_BA1(i)); 182 SR(OVL_POSITION(i)); 183 SR(OVL_SIZE(i)); 184 SR(OVL_ATTRIBUTES(i)); 185 SR(OVL_FIFO_THRESHOLD(i)); 186 SR(OVL_ROW_INC(i)); 187 SR(OVL_PIXEL_INC(i)); 188 if (dss_has_feature(FEAT_PRELOAD)) 189 SR(OVL_PRELOAD(i)); 190 if (i == OMAP_DSS_GFX) { 191 SR(OVL_WINDOW_SKIP(i)); 192 SR(OVL_TABLE_BA(i)); 193 continue; 194 } 195 SR(OVL_FIR(i)); 196 SR(OVL_PICTURE_SIZE(i)); 197 SR(OVL_ACCU0(i)); 198 SR(OVL_ACCU1(i)); 199 200 for (j = 0; j < 8; j++) 201 SR(OVL_FIR_COEF_H(i, j)); 202 203 for (j = 0; j < 8; j++) 204 SR(OVL_FIR_COEF_HV(i, j)); 205 206 for (j = 0; j < 5; j++) 207 SR(OVL_CONV_COEF(i, j)); 208 209 if (dss_has_feature(FEAT_FIR_COEF_V)) { 210 for (j = 0; j < 8; j++) 211 SR(OVL_FIR_COEF_V(i, j)); 212 } 213 214 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { 215 SR(OVL_BA0_UV(i)); 216 SR(OVL_BA1_UV(i)); 217 SR(OVL_FIR2(i)); 218 SR(OVL_ACCU2_0(i)); 219 SR(OVL_ACCU2_1(i)); 220 221 for (j = 0; j < 8; j++) 222 SR(OVL_FIR_COEF_H2(i, j)); 223 224 for (j = 0; j < 8; j++) 225 SR(OVL_FIR_COEF_HV2(i, j)); 226 227 for (j = 0; j < 8; j++) 228 SR(OVL_FIR_COEF_V2(i, j)); 229 } 230 if (dss_has_feature(FEAT_ATTR2)) 231 SR(OVL_ATTRIBUTES2(i)); 232 } 233 234 if (dss_has_feature(FEAT_CORE_CLK_DIV)) 235 SR(DIVISOR); 236 237 dispc.ctx_loss_cnt = dss_get_ctx_loss_count(&dispc.pdev->dev); 238 dispc.ctx_valid = true; 239 240 DSSDBG("context saved, ctx_loss_count %d\n", dispc.ctx_loss_cnt); 241} 242 243static void dispc_restore_context(void) 244{ 245 int i, j, ctx; 246 247 DSSDBG("dispc_restore_context\n"); 248 249 if (!dispc.ctx_valid) 250 return; 251 252 ctx = dss_get_ctx_loss_count(&dispc.pdev->dev); 253 254 if (ctx >= 0 && ctx == dispc.ctx_loss_cnt) 255 return; 256 257 DSSDBG("ctx_loss_count: saved %d, current %d\n", 258 dispc.ctx_loss_cnt, ctx); 259 260 /*RR(IRQENABLE);*/ 261 /*RR(CONTROL);*/ 262 RR(CONFIG); 263 RR(LINE_NUMBER); 264 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) || 265 dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) 266 RR(GLOBAL_ALPHA); 267 if (dss_has_feature(FEAT_MGR_LCD2)) 268 RR(CONFIG2); 269 270 for (i = 0; i < dss_feat_get_num_mgrs(); i++) { 271 RR(DEFAULT_COLOR(i)); 272 RR(TRANS_COLOR(i)); 273 RR(SIZE_MGR(i)); 274 if (i == OMAP_DSS_CHANNEL_DIGIT) 275 continue; 276 RR(TIMING_H(i)); 277 RR(TIMING_V(i)); 278 RR(POL_FREQ(i)); 279 RR(DIVISORo(i)); 280 281 RR(DATA_CYCLE1(i)); 282 RR(DATA_CYCLE2(i)); 283 RR(DATA_CYCLE3(i)); 284 285 if (dss_has_feature(FEAT_CPR)) { 286 RR(CPR_COEF_R(i)); 287 RR(CPR_COEF_G(i)); 288 RR(CPR_COEF_B(i)); 289 } 290 } 291 292 for (i = 0; i < dss_feat_get_num_ovls(); i++) { 293 RR(OVL_BA0(i)); 294 RR(OVL_BA1(i)); 295 RR(OVL_POSITION(i)); 296 RR(OVL_SIZE(i)); 297 RR(OVL_ATTRIBUTES(i)); 298 RR(OVL_FIFO_THRESHOLD(i)); 299 RR(OVL_ROW_INC(i)); 300 RR(OVL_PIXEL_INC(i)); 301 if (dss_has_feature(FEAT_PRELOAD)) 302 RR(OVL_PRELOAD(i)); 303 if (i == OMAP_DSS_GFX) { 304 RR(OVL_WINDOW_SKIP(i)); 305 RR(OVL_TABLE_BA(i)); 306 continue; 307 } 308 RR(OVL_FIR(i)); 309 RR(OVL_PICTURE_SIZE(i)); 310 RR(OVL_ACCU0(i)); 311 RR(OVL_ACCU1(i)); 312 313 for (j = 0; j < 8; j++) 314 RR(OVL_FIR_COEF_H(i, j)); 315 316 for (j = 0; j < 8; j++) 317 RR(OVL_FIR_COEF_HV(i, j)); 318 319 for (j = 0; j < 5; j++) 320 RR(OVL_CONV_COEF(i, j)); 321 322 if (dss_has_feature(FEAT_FIR_COEF_V)) { 323 for (j = 0; j < 8; j++) 324 RR(OVL_FIR_COEF_V(i, j)); 325 } 326 327 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { 328 RR(OVL_BA0_UV(i)); 329 RR(OVL_BA1_UV(i)); 330 RR(OVL_FIR2(i)); 331 RR(OVL_ACCU2_0(i)); 332 RR(OVL_ACCU2_1(i)); 333 334 for (j = 0; j < 8; j++) 335 RR(OVL_FIR_COEF_H2(i, j)); 336 337 for (j = 0; j < 8; j++) 338 RR(OVL_FIR_COEF_HV2(i, j)); 339 340 for (j = 0; j < 8; j++) 341 RR(OVL_FIR_COEF_V2(i, j)); 342 } 343 if (dss_has_feature(FEAT_ATTR2)) 344 RR(OVL_ATTRIBUTES2(i)); 345 } 346 347 if (dss_has_feature(FEAT_CORE_CLK_DIV)) 348 RR(DIVISOR); 349 350 /* enable last, because LCD & DIGIT enable are here */ 351 RR(CONTROL); 352 if (dss_has_feature(FEAT_MGR_LCD2)) 353 RR(CONTROL2); 354 /* clear spurious SYNC_LOST_DIGIT interrupts */ 355 dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT); 356 357 /* 358 * enable last so IRQs won't trigger before 359 * the context is fully restored 360 */ 361 RR(IRQENABLE); 362 363 DSSDBG("context restored\n"); 364} 365 366#undef SR 367#undef RR 368 369int dispc_runtime_get(void) 370{ 371 int r; 372 373 DSSDBG("dispc_runtime_get\n"); 374 375 r = pm_runtime_get_sync(&dispc.pdev->dev); 376 WARN_ON(r < 0); 377 return r < 0 ? r : 0; 378} 379 380void dispc_runtime_put(void) 381{ 382 int r; 383 384 DSSDBG("dispc_runtime_put\n"); 385 386 r = pm_runtime_put_sync(&dispc.pdev->dev); 387 WARN_ON(r < 0 && r != -ENOSYS); 388} 389 390static inline bool dispc_mgr_is_lcd(enum omap_channel channel) 391{ 392 if (channel == OMAP_DSS_CHANNEL_LCD || 393 channel == OMAP_DSS_CHANNEL_LCD2) 394 return true; 395 else 396 return false; 397} 398 399u32 dispc_mgr_get_vsync_irq(enum omap_channel channel) 400{ 401 switch (channel) { 402 case OMAP_DSS_CHANNEL_LCD: 403 return DISPC_IRQ_VSYNC; 404 case OMAP_DSS_CHANNEL_LCD2: 405 return DISPC_IRQ_VSYNC2; 406 case OMAP_DSS_CHANNEL_DIGIT: 407 return DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; 408 default: 409 BUG(); 410 return 0; 411 } 412} 413 414u32 dispc_mgr_get_framedone_irq(enum omap_channel channel) 415{ 416 switch (channel) { 417 case OMAP_DSS_CHANNEL_LCD: 418 return DISPC_IRQ_FRAMEDONE; 419 case OMAP_DSS_CHANNEL_LCD2: 420 return DISPC_IRQ_FRAMEDONE2; 421 case OMAP_DSS_CHANNEL_DIGIT: 422 return 0; 423 default: 424 BUG(); 425 return 0; 426 } 427} 428 429bool dispc_mgr_go_busy(enum omap_channel channel) 430{ 431 int bit; 432 433 if (dispc_mgr_is_lcd(channel)) 434 bit = 5; /* GOLCD */ 435 else 436 bit = 6; /* GODIGIT */ 437 438 if (channel == OMAP_DSS_CHANNEL_LCD2) 439 return REG_GET(DISPC_CONTROL2, bit, bit) == 1; 440 else 441 return REG_GET(DISPC_CONTROL, bit, bit) == 1; 442} 443 444void dispc_mgr_go(enum omap_channel channel) 445{ 446 int bit; 447 bool enable_bit, go_bit; 448 449 if (dispc_mgr_is_lcd(channel)) 450 bit = 0; /* LCDENABLE */ 451 else 452 bit = 1; /* DIGITALENABLE */ 453 454 /* if the channel is not enabled, we don't need GO */ 455 if (channel == OMAP_DSS_CHANNEL_LCD2) 456 enable_bit = REG_GET(DISPC_CONTROL2, bit, bit) == 1; 457 else 458 enable_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1; 459 460 if (!enable_bit) 461 return; 462 463 if (dispc_mgr_is_lcd(channel)) 464 bit = 5; /* GOLCD */ 465 else 466 bit = 6; /* GODIGIT */ 467 468 if (channel == OMAP_DSS_CHANNEL_LCD2) 469 go_bit = REG_GET(DISPC_CONTROL2, bit, bit) == 1; 470 else 471 go_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1; 472 473 if (go_bit) { 474 DSSERR("GO bit not down for channel %d\n", channel); 475 return; 476 } 477 478 DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : 479 (channel == OMAP_DSS_CHANNEL_LCD2 ? "LCD2" : "DIGIT")); 480 481 if (channel == OMAP_DSS_CHANNEL_LCD2) 482 REG_FLD_MOD(DISPC_CONTROL2, 1, bit, bit); 483 else 484 REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit); 485} 486 487static void dispc_ovl_write_firh_reg(enum omap_plane plane, int reg, u32 value) 488{ 489 dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value); 490} 491 492static void dispc_ovl_write_firhv_reg(enum omap_plane plane, int reg, u32 value) 493{ 494 dispc_write_reg(DISPC_OVL_FIR_COEF_HV(plane, reg), value); 495} 496 497static void dispc_ovl_write_firv_reg(enum omap_plane plane, int reg, u32 value) 498{ 499 dispc_write_reg(DISPC_OVL_FIR_COEF_V(plane, reg), value); 500} 501 502static void dispc_ovl_write_firh2_reg(enum omap_plane plane, int reg, u32 value) 503{ 504 BUG_ON(plane == OMAP_DSS_GFX); 505 506 dispc_write_reg(DISPC_OVL_FIR_COEF_H2(plane, reg), value); 507} 508 509static void dispc_ovl_write_firhv2_reg(enum omap_plane plane, int reg, 510 u32 value) 511{ 512 BUG_ON(plane == OMAP_DSS_GFX); 513 514 dispc_write_reg(DISPC_OVL_FIR_COEF_HV2(plane, reg), value); 515} 516 517static void dispc_ovl_write_firv2_reg(enum omap_plane plane, int reg, u32 value) 518{ 519 BUG_ON(plane == OMAP_DSS_GFX); 520 521 dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value); 522} 523 524static void dispc_ovl_set_scale_coef(enum omap_plane plane, int fir_hinc, 525 int fir_vinc, int five_taps, 526 enum omap_color_component color_comp) 527{ 528 const struct dispc_coef *h_coef, *v_coef; 529 int i; 530 531 h_coef = dispc_ovl_get_scale_coef(fir_hinc, true); 532 v_coef = dispc_ovl_get_scale_coef(fir_vinc, five_taps); 533 534 for (i = 0; i < 8; i++) { 535 u32 h, hv; 536 537 h = FLD_VAL(h_coef[i].hc0_vc00, 7, 0) 538 | FLD_VAL(h_coef[i].hc1_vc0, 15, 8) 539 | FLD_VAL(h_coef[i].hc2_vc1, 23, 16) 540 | FLD_VAL(h_coef[i].hc3_vc2, 31, 24); 541 hv = FLD_VAL(h_coef[i].hc4_vc22, 7, 0) 542 | FLD_VAL(v_coef[i].hc1_vc0, 15, 8) 543 | FLD_VAL(v_coef[i].hc2_vc1, 23, 16) 544 | FLD_VAL(v_coef[i].hc3_vc2, 31, 24); 545 546 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) { 547 dispc_ovl_write_firh_reg(plane, i, h); 548 dispc_ovl_write_firhv_reg(plane, i, hv); 549 } else { 550 dispc_ovl_write_firh2_reg(plane, i, h); 551 dispc_ovl_write_firhv2_reg(plane, i, hv); 552 } 553 554 } 555 556 if (five_taps) { 557 for (i = 0; i < 8; i++) { 558 u32 v; 559 v = FLD_VAL(v_coef[i].hc0_vc00, 7, 0) 560 | FLD_VAL(v_coef[i].hc4_vc22, 15, 8); 561 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) 562 dispc_ovl_write_firv_reg(plane, i, v); 563 else 564 dispc_ovl_write_firv2_reg(plane, i, v); 565 } 566 } 567} 568 569static void _dispc_setup_color_conv_coef(void) 570{ 571 int i; 572 const struct color_conv_coef { 573 int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb; 574 int full_range; 575 } ctbl_bt601_5 = { 576 298, 409, 0, 298, -208, -100, 298, 0, 517, 0, 577 }; 578 579 const struct color_conv_coef *ct; 580 581#define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0)) 582 583 ct = &ctbl_bt601_5; 584 585 for (i = 1; i < dss_feat_get_num_ovls(); i++) { 586 dispc_write_reg(DISPC_OVL_CONV_COEF(i, 0), 587 CVAL(ct->rcr, ct->ry)); 588 dispc_write_reg(DISPC_OVL_CONV_COEF(i, 1), 589 CVAL(ct->gy, ct->rcb)); 590 dispc_write_reg(DISPC_OVL_CONV_COEF(i, 2), 591 CVAL(ct->gcb, ct->gcr)); 592 dispc_write_reg(DISPC_OVL_CONV_COEF(i, 3), 593 CVAL(ct->bcr, ct->by)); 594 dispc_write_reg(DISPC_OVL_CONV_COEF(i, 4), 595 CVAL(0, ct->bcb)); 596 597 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), ct->full_range, 598 11, 11); 599 } 600 601#undef CVAL 602} 603 604 605static void dispc_ovl_set_ba0(enum omap_plane plane, u32 paddr) 606{ 607 dispc_write_reg(DISPC_OVL_BA0(plane), paddr); 608} 609 610static void dispc_ovl_set_ba1(enum omap_plane plane, u32 paddr) 611{ 612 dispc_write_reg(DISPC_OVL_BA1(plane), paddr); 613} 614 615static void dispc_ovl_set_ba0_uv(enum omap_plane plane, u32 paddr) 616{ 617 dispc_write_reg(DISPC_OVL_BA0_UV(plane), paddr); 618} 619 620static void dispc_ovl_set_ba1_uv(enum omap_plane plane, u32 paddr) 621{ 622 dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr); 623} 624 625static void dispc_ovl_set_pos(enum omap_plane plane, int x, int y) 626{ 627 u32 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0); 628 629 dispc_write_reg(DISPC_OVL_POSITION(plane), val); 630} 631 632static void dispc_ovl_set_pic_size(enum omap_plane plane, int width, int height) 633{ 634 u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); 635 636 if (plane == OMAP_DSS_GFX) 637 dispc_write_reg(DISPC_OVL_SIZE(plane), val); 638 else 639 dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val); 640} 641 642static void dispc_ovl_set_vid_size(enum omap_plane plane, int width, int height) 643{ 644 u32 val; 645 646 BUG_ON(plane == OMAP_DSS_GFX); 647 648 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); 649 650 dispc_write_reg(DISPC_OVL_SIZE(plane), val); 651} 652 653static void dispc_ovl_set_zorder(enum omap_plane plane, u8 zorder) 654{ 655 struct omap_overlay *ovl = omap_dss_get_overlay(plane); 656 657 if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) 658 return; 659 660 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26); 661} 662 663static void dispc_ovl_enable_zorder_planes(void) 664{ 665 int i; 666 667 if (!dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) 668 return; 669 670 for (i = 0; i < dss_feat_get_num_ovls(); i++) 671 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25); 672} 673 674static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane, bool enable) 675{ 676 struct omap_overlay *ovl = omap_dss_get_overlay(plane); 677 678 if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) 679 return; 680 681 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28); 682} 683 684static void dispc_ovl_setup_global_alpha(enum omap_plane plane, u8 global_alpha) 685{ 686 static const unsigned shifts[] = { 0, 8, 16, 24, }; 687 int shift; 688 struct omap_overlay *ovl = omap_dss_get_overlay(plane); 689 690 if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) 691 return; 692 693 shift = shifts[plane]; 694 REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, shift + 7, shift); 695} 696 697static void dispc_ovl_set_pix_inc(enum omap_plane plane, s32 inc) 698{ 699 dispc_write_reg(DISPC_OVL_PIXEL_INC(plane), inc); 700} 701 702static void dispc_ovl_set_row_inc(enum omap_plane plane, s32 inc) 703{ 704 dispc_write_reg(DISPC_OVL_ROW_INC(plane), inc); 705} 706 707static void dispc_ovl_set_color_mode(enum omap_plane plane, 708 enum omap_color_mode color_mode) 709{ 710 u32 m = 0; 711 if (plane != OMAP_DSS_GFX) { 712 switch (color_mode) { 713 case OMAP_DSS_COLOR_NV12: 714 m = 0x0; break; 715 case OMAP_DSS_COLOR_RGBX16: 716 m = 0x1; break; 717 case OMAP_DSS_COLOR_RGBA16: 718 m = 0x2; break; 719 case OMAP_DSS_COLOR_RGB12U: 720 m = 0x4; break; 721 case OMAP_DSS_COLOR_ARGB16: 722 m = 0x5; break; 723 case OMAP_DSS_COLOR_RGB16: 724 m = 0x6; break; 725 case OMAP_DSS_COLOR_ARGB16_1555: 726 m = 0x7; break; 727 case OMAP_DSS_COLOR_RGB24U: 728 m = 0x8; break; 729 case OMAP_DSS_COLOR_RGB24P: 730 m = 0x9; break; 731 case OMAP_DSS_COLOR_YUV2: 732 m = 0xa; break; 733 case OMAP_DSS_COLOR_UYVY: 734 m = 0xb; break; 735 case OMAP_DSS_COLOR_ARGB32: 736 m = 0xc; break; 737 case OMAP_DSS_COLOR_RGBA32: 738 m = 0xd; break; 739 case OMAP_DSS_COLOR_RGBX32: 740 m = 0xe; break; 741 case OMAP_DSS_COLOR_XRGB16_1555: 742 m = 0xf; break; 743 default: 744 BUG(); return; 745 } 746 } else { 747 switch (color_mode) { 748 case OMAP_DSS_COLOR_CLUT1: 749 m = 0x0; break; 750 case OMAP_DSS_COLOR_CLUT2: 751 m = 0x1; break; 752 case OMAP_DSS_COLOR_CLUT4: 753 m = 0x2; break; 754 case OMAP_DSS_COLOR_CLUT8: 755 m = 0x3; break; 756 case OMAP_DSS_COLOR_RGB12U: 757 m = 0x4; break; 758 case OMAP_DSS_COLOR_ARGB16: 759 m = 0x5; break; 760 case OMAP_DSS_COLOR_RGB16: 761 m = 0x6; break; 762 case OMAP_DSS_COLOR_ARGB16_1555: 763 m = 0x7; break; 764 case OMAP_DSS_COLOR_RGB24U: 765 m = 0x8; break; 766 case OMAP_DSS_COLOR_RGB24P: 767 m = 0x9; break; 768 case OMAP_DSS_COLOR_RGBX16: 769 m = 0xa; break; 770 case OMAP_DSS_COLOR_RGBA16: 771 m = 0xb; break; 772 case OMAP_DSS_COLOR_ARGB32: 773 m = 0xc; break; 774 case OMAP_DSS_COLOR_RGBA32: 775 m = 0xd; break; 776 case OMAP_DSS_COLOR_RGBX32: 777 m = 0xe; break; 778 case OMAP_DSS_COLOR_XRGB16_1555: 779 m = 0xf; break; 780 default: 781 BUG(); return; 782 } 783 } 784 785 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1); 786} 787 788static void dispc_ovl_configure_burst_type(enum omap_plane plane, 789 enum omap_dss_rotation_type rotation_type) 790{ 791 if (dss_has_feature(FEAT_BURST_2D) == 0) 792 return; 793 794 if (rotation_type == OMAP_DSS_ROT_TILER) 795 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 1, 29, 29); 796 else 797 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 0, 29, 29); 798} 799 800void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel) 801{ 802 int shift; 803 u32 val; 804 int chan = 0, chan2 = 0; 805 806 switch (plane) { 807 case OMAP_DSS_GFX: 808 shift = 8; 809 break; 810 case OMAP_DSS_VIDEO1: 811 case OMAP_DSS_VIDEO2: 812 case OMAP_DSS_VIDEO3: 813 shift = 16; 814 break; 815 default: 816 BUG(); 817 return; 818 } 819 820 val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); 821 if (dss_has_feature(FEAT_MGR_LCD2)) { 822 switch (channel) { 823 case OMAP_DSS_CHANNEL_LCD: 824 chan = 0; 825 chan2 = 0; 826 break; 827 case OMAP_DSS_CHANNEL_DIGIT: 828 chan = 1; 829 chan2 = 0; 830 break; 831 case OMAP_DSS_CHANNEL_LCD2: 832 chan = 0; 833 chan2 = 1; 834 break; 835 default: 836 BUG(); 837 return; 838 } 839 840 val = FLD_MOD(val, chan, shift, shift); 841 val = FLD_MOD(val, chan2, 31, 30); 842 } else { 843 val = FLD_MOD(val, channel, shift, shift); 844 } 845 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); 846} 847 848static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane) 849{ 850 int shift; 851 u32 val; 852 enum omap_channel channel; 853 854 switch (plane) { 855 case OMAP_DSS_GFX: 856 shift = 8; 857 break; 858 case OMAP_DSS_VIDEO1: 859 case OMAP_DSS_VIDEO2: 860 case OMAP_DSS_VIDEO3: 861 shift = 16; 862 break; 863 default: 864 BUG(); 865 return 0; 866 } 867 868 val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); 869 870 if (dss_has_feature(FEAT_MGR_LCD2)) { 871 if (FLD_GET(val, 31, 30) == 0) 872 channel = FLD_GET(val, shift, shift); 873 else 874 channel = OMAP_DSS_CHANNEL_LCD2; 875 } else { 876 channel = FLD_GET(val, shift, shift); 877 } 878 879 return channel; 880} 881 882static void dispc_ovl_set_burst_size(enum omap_plane plane, 883 enum omap_burst_size burst_size) 884{ 885 static const unsigned shifts[] = { 6, 14, 14, 14, }; 886 int shift; 887 888 shift = shifts[plane]; 889 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), burst_size, shift + 1, shift); 890} 891 892static void dispc_configure_burst_sizes(void) 893{ 894 int i; 895 const int burst_size = BURST_SIZE_X8; 896 897 /* Configure burst size always to maximum size */ 898 for (i = 0; i < omap_dss_get_num_overlays(); ++i) 899 dispc_ovl_set_burst_size(i, burst_size); 900} 901 902static u32 dispc_ovl_get_burst_size(enum omap_plane plane) 903{ 904 unsigned unit = dss_feat_get_burst_size_unit(); 905 /* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */ 906 return unit * 8; 907} 908 909void dispc_enable_gamma_table(bool enable) 910{ 911 /* 912 * This is partially implemented to support only disabling of 913 * the gamma table. 914 */ 915 if (enable) { 916 DSSWARN("Gamma table enabling for TV not yet supported"); 917 return; 918 } 919 920 REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9); 921} 922 923static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable) 924{ 925 u16 reg; 926 927 if (channel == OMAP_DSS_CHANNEL_LCD) 928 reg = DISPC_CONFIG; 929 else if (channel == OMAP_DSS_CHANNEL_LCD2) 930 reg = DISPC_CONFIG2; 931 else 932 return; 933 934 REG_FLD_MOD(reg, enable, 15, 15); 935} 936 937static void dispc_mgr_set_cpr_coef(enum omap_channel channel, 938 struct omap_dss_cpr_coefs *coefs) 939{ 940 u32 coef_r, coef_g, coef_b; 941 942 if (!dispc_mgr_is_lcd(channel)) 943 return; 944 945 coef_r = FLD_VAL(coefs->rr, 31, 22) | FLD_VAL(coefs->rg, 20, 11) | 946 FLD_VAL(coefs->rb, 9, 0); 947 coef_g = FLD_VAL(coefs->gr, 31, 22) | FLD_VAL(coefs->gg, 20, 11) | 948 FLD_VAL(coefs->gb, 9, 0); 949 coef_b = FLD_VAL(coefs->br, 31, 22) | FLD_VAL(coefs->bg, 20, 11) | 950 FLD_VAL(coefs->bb, 9, 0); 951 952 dispc_write_reg(DISPC_CPR_COEF_R(channel), coef_r); 953 dispc_write_reg(DISPC_CPR_COEF_G(channel), coef_g); 954 dispc_write_reg(DISPC_CPR_COEF_B(channel), coef_b); 955} 956 957static void dispc_ovl_set_vid_color_conv(enum omap_plane plane, bool enable) 958{ 959 u32 val; 960 961 BUG_ON(plane == OMAP_DSS_GFX); 962 963 val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); 964 val = FLD_MOD(val, enable, 9, 9); 965 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); 966} 967 968static void dispc_ovl_enable_replication(enum omap_plane plane, bool enable) 969{ 970 static const unsigned shifts[] = { 5, 10, 10, 10 }; 971 int shift; 972 973 shift = shifts[plane]; 974 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift); 975} 976 977static void dispc_mgr_set_size(enum omap_channel channel, u16 width, 978 u16 height) 979{ 980 u32 val; 981 982 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); 983 dispc_write_reg(DISPC_SIZE_MGR(channel), val); 984} 985 986static void dispc_read_plane_fifo_sizes(void) 987{ 988 u32 size; 989 int plane; 990 u8 start, end; 991 u32 unit; 992 993 unit = dss_feat_get_buffer_size_unit(); 994 995 dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end); 996 997 for (plane = 0; plane < dss_feat_get_num_ovls(); ++plane) { 998 size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(plane), start, end); 999 size *= unit; 1000 dispc.fifo_size[plane] = size; 1001 } 1002} 1003 1004static u32 dispc_ovl_get_fifo_size(enum omap_plane plane) 1005{ 1006 return dispc.fifo_size[plane]; 1007} 1008 1009void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high) 1010{ 1011 u8 hi_start, hi_end, lo_start, lo_end; 1012 u32 unit; 1013 1014 unit = dss_feat_get_buffer_size_unit(); 1015 1016 WARN_ON(low % unit != 0); 1017 WARN_ON(high % unit != 0); 1018 1019 low /= unit; 1020 high /= unit; 1021 1022 dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end); 1023 dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end); 1024 1025 DSSDBG("fifo(%d) threshold (bytes), old %u/%u, new %u/%u\n", 1026 plane, 1027 REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane), 1028 lo_start, lo_end) * unit, 1029 REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane), 1030 hi_start, hi_end) * unit, 1031 low * unit, high * unit); 1032 1033 dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane), 1034 FLD_VAL(high, hi_start, hi_end) | 1035 FLD_VAL(low, lo_start, lo_end)); 1036} 1037 1038void dispc_enable_fifomerge(bool enable) 1039{ 1040 if (!dss_has_feature(FEAT_FIFO_MERGE)) { 1041 WARN_ON(enable); 1042 return; 1043 } 1044 1045 DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled"); 1046 REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14); 1047} 1048 1049void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, 1050 u32 *fifo_low, u32 *fifo_high, bool use_fifomerge, 1051 bool manual_update) 1052{ 1053 /* 1054 * All sizes are in bytes. Both the buffer and burst are made of 1055 * buffer_units, and the fifo thresholds must be buffer_unit aligned. 1056 */ 1057 1058 unsigned buf_unit = dss_feat_get_buffer_size_unit(); 1059 unsigned ovl_fifo_size, total_fifo_size, burst_size; 1060 int i; 1061 1062 burst_size = dispc_ovl_get_burst_size(plane); 1063 ovl_fifo_size = dispc_ovl_get_fifo_size(plane); 1064 1065 if (use_fifomerge) { 1066 total_fifo_size = 0; 1067 for (i = 0; i < omap_dss_get_num_overlays(); ++i) 1068 total_fifo_size += dispc_ovl_get_fifo_size(i); 1069 } else { 1070 total_fifo_size = ovl_fifo_size; 1071 } 1072 1073 /* 1074 * We use the same low threshold for both fifomerge and non-fifomerge 1075 * cases, but for fifomerge we calculate the high threshold using the 1076 * combined fifo size 1077 */ 1078 1079 if (manual_update && dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) { 1080 *fifo_low = ovl_fifo_size - burst_size * 2; 1081 *fifo_high = total_fifo_size - burst_size; 1082 } else { 1083 *fifo_low = ovl_fifo_size - burst_size; 1084 *fifo_high = total_fifo_size - buf_unit; 1085 } 1086} 1087 1088static void dispc_ovl_set_fir(enum omap_plane plane, 1089 int hinc, int vinc, 1090 enum omap_color_component color_comp) 1091{ 1092 u32 val; 1093 1094 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) { 1095 u8 hinc_start, hinc_end, vinc_start, vinc_end; 1096 1097 dss_feat_get_reg_field(FEAT_REG_FIRHINC, 1098 &hinc_start, &hinc_end); 1099 dss_feat_get_reg_field(FEAT_REG_FIRVINC, 1100 &vinc_start, &vinc_end); 1101 val = FLD_VAL(vinc, vinc_start, vinc_end) | 1102 FLD_VAL(hinc, hinc_start, hinc_end); 1103 1104 dispc_write_reg(DISPC_OVL_FIR(plane), val); 1105 } else { 1106 val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0); 1107 dispc_write_reg(DISPC_OVL_FIR2(plane), val); 1108 } 1109} 1110 1111static void dispc_ovl_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu) 1112{ 1113 u32 val; 1114 u8 hor_start, hor_end, vert_start, vert_end; 1115 1116 dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end); 1117 dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end); 1118 1119 val = FLD_VAL(vaccu, vert_start, vert_end) | 1120 FLD_VAL(haccu, hor_start, hor_end); 1121 1122 dispc_write_reg(DISPC_OVL_ACCU0(plane), val); 1123} 1124 1125static void dispc_ovl_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu) 1126{ 1127 u32 val; 1128 u8 hor_start, hor_end, vert_start, vert_end; 1129 1130 dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end); 1131 dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end); 1132 1133 val = FLD_VAL(vaccu, vert_start, vert_end) | 1134 FLD_VAL(haccu, hor_start, hor_end); 1135 1136 dispc_write_reg(DISPC_OVL_ACCU1(plane), val); 1137} 1138 1139static void dispc_ovl_set_vid_accu2_0(enum omap_plane plane, int haccu, 1140 int vaccu) 1141{ 1142 u32 val; 1143 1144 val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0); 1145 dispc_write_reg(DISPC_OVL_ACCU2_0(plane), val); 1146} 1147 1148static void dispc_ovl_set_vid_accu2_1(enum omap_plane plane, int haccu, 1149 int vaccu) 1150{ 1151 u32 val; 1152 1153 val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0); 1154 dispc_write_reg(DISPC_OVL_ACCU2_1(plane), val); 1155} 1156 1157static void dispc_ovl_set_scale_param(enum omap_plane plane, 1158 u16 orig_width, u16 orig_height, 1159 u16 out_width, u16 out_height, 1160 bool five_taps, u8 rotation, 1161 enum omap_color_component color_comp) 1162{ 1163 int fir_hinc, fir_vinc; 1164 1165 fir_hinc = 1024 * orig_width / out_width; 1166 fir_vinc = 1024 * orig_height / out_height; 1167 1168 dispc_ovl_set_scale_coef(plane, fir_hinc, fir_vinc, five_taps, 1169 color_comp); 1170 dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp); 1171} 1172 1173static void dispc_ovl_set_accu_uv(enum omap_plane plane, 1174 u16 orig_width, u16 orig_height, u16 out_width, u16 out_height, 1175 bool ilace, enum omap_color_mode color_mode, u8 rotation) 1176{ 1177 int h_accu2_0, h_accu2_1; 1178 int v_accu2_0, v_accu2_1; 1179 int chroma_hinc, chroma_vinc; 1180 int idx; 1181 1182 struct accu { 1183 s8 h0_m, h0_n; 1184 s8 h1_m, h1_n; 1185 s8 v0_m, v0_n; 1186 s8 v1_m, v1_n; 1187 }; 1188 1189 const struct accu *accu_table; 1190 const struct accu *accu_val; 1191 1192 static const struct accu accu_nv12[4] = { 1193 { 0, 1, 0, 1 , -1, 2, 0, 1 }, 1194 { 1, 2, -3, 4 , 0, 1, 0, 1 }, 1195 { -1, 1, 0, 1 , -1, 2, 0, 1 }, 1196 { -1, 2, -1, 2 , -1, 1, 0, 1 }, 1197 }; 1198 1199 static const struct accu accu_nv12_ilace[4] = { 1200 { 0, 1, 0, 1 , -3, 4, -1, 4 }, 1201 { -1, 4, -3, 4 , 0, 1, 0, 1 }, 1202 { -1, 1, 0, 1 , -1, 4, -3, 4 }, 1203 { -3, 4, -3, 4 , -1, 1, 0, 1 }, 1204 }; 1205 1206 static const struct accu accu_yuv[4] = { 1207 { 0, 1, 0, 1, 0, 1, 0, 1 }, 1208 { 0, 1, 0, 1, 0, 1, 0, 1 }, 1209 { -1, 1, 0, 1, 0, 1, 0, 1 }, 1210 { 0, 1, 0, 1, -1, 1, 0, 1 }, 1211 }; 1212 1213 switch (rotation) { 1214 case OMAP_DSS_ROT_0: 1215 idx = 0; 1216 break; 1217 case OMAP_DSS_ROT_90: 1218 idx = 1; 1219 break; 1220 case OMAP_DSS_ROT_180: 1221 idx = 2; 1222 break; 1223 case OMAP_DSS_ROT_270: 1224 idx = 3; 1225 break; 1226 default: 1227 BUG(); 1228 return; 1229 } 1230 1231 switch (color_mode) { 1232 case OMAP_DSS_COLOR_NV12: 1233 if (ilace) 1234 accu_table = accu_nv12_ilace; 1235 else 1236 accu_table = accu_nv12; 1237 break; 1238 case OMAP_DSS_COLOR_YUV2: 1239 case OMAP_DSS_COLOR_UYVY: 1240 accu_table = accu_yuv; 1241 break; 1242 default: 1243 BUG(); 1244 return; 1245 } 1246 1247 accu_val = &accu_table[idx]; 1248 1249 chroma_hinc = 1024 * orig_width / out_width; 1250 chroma_vinc = 1024 * orig_height / out_height; 1251 1252 h_accu2_0 = (accu_val->h0_m * chroma_hinc / accu_val->h0_n) % 1024; 1253 h_accu2_1 = (accu_val->h1_m * chroma_hinc / accu_val->h1_n) % 1024; 1254 v_accu2_0 = (accu_val->v0_m * chroma_vinc / accu_val->v0_n) % 1024; 1255 v_accu2_1 = (accu_val->v1_m * chroma_vinc / accu_val->v1_n) % 1024; 1256 1257 dispc_ovl_set_vid_accu2_0(plane, h_accu2_0, v_accu2_0); 1258 dispc_ovl_set_vid_accu2_1(plane, h_accu2_1, v_accu2_1); 1259} 1260 1261static void dispc_ovl_set_scaling_common(enum omap_plane plane, 1262 u16 orig_width, u16 orig_height, 1263 u16 out_width, u16 out_height, 1264 bool ilace, bool five_taps, 1265 bool fieldmode, enum omap_color_mode color_mode, 1266 u8 rotation) 1267{ 1268 int accu0 = 0; 1269 int accu1 = 0; 1270 u32 l; 1271 1272 dispc_ovl_set_scale_param(plane, orig_width, orig_height, 1273 out_width, out_height, five_taps, 1274 rotation, DISPC_COLOR_COMPONENT_RGB_Y); 1275 l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); 1276 1277 /* RESIZEENABLE and VERTICALTAPS */ 1278 l &= ~((0x3 << 5) | (0x1 << 21)); 1279 l |= (orig_width != out_width) ? (1 << 5) : 0; 1280 l |= (orig_height != out_height) ? (1 << 6) : 0; 1281 l |= five_taps ? (1 << 21) : 0; 1282 1283 /* VRESIZECONF and HRESIZECONF */ 1284 if (dss_has_feature(FEAT_RESIZECONF)) { 1285 l &= ~(0x3 << 7); 1286 l |= (orig_width <= out_width) ? 0 : (1 << 7); 1287 l |= (orig_height <= out_height) ? 0 : (1 << 8); 1288 } 1289 1290 /* LINEBUFFERSPLIT */ 1291 if (dss_has_feature(FEAT_LINEBUFFERSPLIT)) { 1292 l &= ~(0x1 << 22); 1293 l |= five_taps ? (1 << 22) : 0; 1294 } 1295 1296 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l); 1297 1298 /* 1299 * field 0 = even field = bottom field 1300 * field 1 = odd field = top field 1301 */ 1302 if (ilace && !fieldmode) { 1303 accu1 = 0; 1304 accu0 = ((1024 * orig_height / out_height) / 2) & 0x3ff; 1305 if (accu0 >= 1024/2) { 1306 accu1 = 1024/2; 1307 accu0 -= accu1; 1308 } 1309 } 1310 1311 dispc_ovl_set_vid_accu0(plane, 0, accu0); 1312 dispc_ovl_set_vid_accu1(plane, 0, accu1); 1313} 1314 1315static void dispc_ovl_set_scaling_uv(enum omap_plane plane, 1316 u16 orig_width, u16 orig_height, 1317 u16 out_width, u16 out_height, 1318 bool ilace, bool five_taps, 1319 bool fieldmode, enum omap_color_mode color_mode, 1320 u8 rotation) 1321{ 1322 int scale_x = out_width != orig_width; 1323 int scale_y = out_height != orig_height; 1324 1325 if (!dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) 1326 return; 1327 if ((color_mode != OMAP_DSS_COLOR_YUV2 && 1328 color_mode != OMAP_DSS_COLOR_UYVY && 1329 color_mode != OMAP_DSS_COLOR_NV12)) { 1330 /* reset chroma resampling for RGB formats */ 1331 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8); 1332 return; 1333 } 1334 1335 dispc_ovl_set_accu_uv(plane, orig_width, orig_height, out_width, 1336 out_height, ilace, color_mode, rotation); 1337 1338 switch (color_mode) { 1339 case OMAP_DSS_COLOR_NV12: 1340 /* UV is subsampled by 2 vertically*/ 1341 orig_height >>= 1; 1342 /* UV is subsampled by 2 horz.*/ 1343 orig_width >>= 1; 1344 break; 1345 case OMAP_DSS_COLOR_YUV2: 1346 case OMAP_DSS_COLOR_UYVY: 1347 /*For YUV422 with 90/270 rotation, 1348 *we don't upsample chroma 1349 */ 1350 if (rotation == OMAP_DSS_ROT_0 || 1351 rotation == OMAP_DSS_ROT_180) 1352 /* UV is subsampled by 2 hrz*/ 1353 orig_width >>= 1; 1354 /* must use FIR for YUV422 if rotated */ 1355 if (rotation != OMAP_DSS_ROT_0) 1356 scale_x = scale_y = true; 1357 break; 1358 default: 1359 BUG(); 1360 return; 1361 } 1362 1363 if (out_width != orig_width) 1364 scale_x = true; 1365 if (out_height != orig_height) 1366 scale_y = true; 1367 1368 dispc_ovl_set_scale_param(plane, orig_width, orig_height, 1369 out_width, out_height, five_taps, 1370 rotation, DISPC_COLOR_COMPONENT_UV); 1371 1372 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 1373 (scale_x || scale_y) ? 1 : 0, 8, 8); 1374 /* set H scaling */ 1375 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5); 1376 /* set V scaling */ 1377 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6); 1378} 1379 1380static void dispc_ovl_set_scaling(enum omap_plane plane, 1381 u16 orig_width, u16 orig_height, 1382 u16 out_width, u16 out_height, 1383 bool ilace, bool five_taps, 1384 bool fieldmode, enum omap_color_mode color_mode, 1385 u8 rotation) 1386{ 1387 BUG_ON(plane == OMAP_DSS_GFX); 1388 1389 dispc_ovl_set_scaling_common(plane, 1390 orig_width, orig_height, 1391 out_width, out_height, 1392 ilace, five_taps, 1393 fieldmode, color_mode, 1394 rotation); 1395 1396 dispc_ovl_set_scaling_uv(plane, 1397 orig_width, orig_height, 1398 out_width, out_height, 1399 ilace, five_taps, 1400 fieldmode, color_mode, 1401 rotation); 1402} 1403 1404static void dispc_ovl_set_rotation_attrs(enum omap_plane plane, u8 rotation, 1405 bool mirroring, enum omap_color_mode color_mode) 1406{ 1407 bool row_repeat = false; 1408 int vidrot = 0; 1409 1410 if (color_mode == OMAP_DSS_COLOR_YUV2 || 1411 color_mode == OMAP_DSS_COLOR_UYVY) { 1412 1413 if (mirroring) { 1414 switch (rotation) { 1415 case OMAP_DSS_ROT_0: 1416 vidrot = 2; 1417 break; 1418 case OMAP_DSS_ROT_90: 1419 vidrot = 1; 1420 break; 1421 case OMAP_DSS_ROT_180: 1422 vidrot = 0; 1423 break; 1424 case OMAP_DSS_ROT_270: 1425 vidrot = 3; 1426 break; 1427 } 1428 } else { 1429 switch (rotation) { 1430 case OMAP_DSS_ROT_0: 1431 vidrot = 0; 1432 break; 1433 case OMAP_DSS_ROT_90: 1434 vidrot = 1; 1435 break; 1436 case OMAP_DSS_ROT_180: 1437 vidrot = 2; 1438 break; 1439 case OMAP_DSS_ROT_270: 1440 vidrot = 3; 1441 break; 1442 } 1443 } 1444 1445 if (rotation == OMAP_DSS_ROT_90 || rotation == OMAP_DSS_ROT_270) 1446 row_repeat = true; 1447 else 1448 row_repeat = false; 1449 } 1450 1451 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), vidrot, 13, 12); 1452 if (dss_has_feature(FEAT_ROWREPEATENABLE)) 1453 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 1454 row_repeat ? 1 : 0, 18, 18); 1455} 1456 1457static int color_mode_to_bpp(enum omap_color_mode color_mode) 1458{ 1459 switch (color_mode) { 1460 case OMAP_DSS_COLOR_CLUT1: 1461 return 1; 1462 case OMAP_DSS_COLOR_CLUT2: 1463 return 2; 1464 case OMAP_DSS_COLOR_CLUT4: 1465 return 4; 1466 case OMAP_DSS_COLOR_CLUT8: 1467 case OMAP_DSS_COLOR_NV12: 1468 return 8; 1469 case OMAP_DSS_COLOR_RGB12U: 1470 case OMAP_DSS_COLOR_RGB16: 1471 case OMAP_DSS_COLOR_ARGB16: 1472 case OMAP_DSS_COLOR_YUV2: 1473 case OMAP_DSS_COLOR_UYVY: 1474 case OMAP_DSS_COLOR_RGBA16: 1475 case OMAP_DSS_COLOR_RGBX16: 1476 case OMAP_DSS_COLOR_ARGB16_1555: 1477 case OMAP_DSS_COLOR_XRGB16_1555: 1478 return 16; 1479 case OMAP_DSS_COLOR_RGB24P: 1480 return 24; 1481 case OMAP_DSS_COLOR_RGB24U: 1482 case OMAP_DSS_COLOR_ARGB32: 1483 case OMAP_DSS_COLOR_RGBA32: 1484 case OMAP_DSS_COLOR_RGBX32: 1485 return 32; 1486 default: 1487 BUG(); 1488 return 0; 1489 } 1490} 1491 1492static s32 pixinc(int pixels, u8 ps) 1493{ 1494 if (pixels == 1) 1495 return 1; 1496 else if (pixels > 1) 1497 return 1 + (pixels - 1) * ps; 1498 else if (pixels < 0) 1499 return 1 - (-pixels + 1) * ps; 1500 else 1501 BUG(); 1502 return 0; 1503} 1504 1505static void calc_vrfb_rotation_offset(u8 rotation, bool mirror, 1506 u16 screen_width, 1507 u16 width, u16 height, 1508 enum omap_color_mode color_mode, bool fieldmode, 1509 unsigned int field_offset, 1510 unsigned *offset0, unsigned *offset1, 1511 s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim) 1512{ 1513 u8 ps; 1514 1515 /* FIXME CLUT formats */ 1516 switch (color_mode) { 1517 case OMAP_DSS_COLOR_CLUT1: 1518 case OMAP_DSS_COLOR_CLUT2: 1519 case OMAP_DSS_COLOR_CLUT4: 1520 case OMAP_DSS_COLOR_CLUT8: 1521 BUG(); 1522 return; 1523 case OMAP_DSS_COLOR_YUV2: 1524 case OMAP_DSS_COLOR_UYVY: 1525 ps = 4; 1526 break; 1527 default: 1528 ps = color_mode_to_bpp(color_mode) / 8; 1529 break; 1530 } 1531 1532 DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width, 1533 width, height); 1534 1535 /* 1536 * field 0 = even field = bottom field 1537 * field 1 = odd field = top field 1538 */ 1539 switch (rotation + mirror * 4) { 1540 case OMAP_DSS_ROT_0: 1541 case OMAP_DSS_ROT_180: 1542 /* 1543 * If the pixel format is YUV or UYVY divide the width 1544 * of the image by 2 for 0 and 180 degree rotation. 1545 */ 1546 if (color_mode == OMAP_DSS_COLOR_YUV2 || 1547 color_mode == OMAP_DSS_COLOR_UYVY) 1548 width = width >> 1; 1549 case OMAP_DSS_ROT_90: 1550 case OMAP_DSS_ROT_270: 1551 *offset1 = 0; 1552 if (field_offset) 1553 *offset0 = field_offset * screen_width * ps; 1554 else 1555 *offset0 = 0; 1556 1557 *row_inc = pixinc(1 + 1558 (y_predecim * screen_width - x_predecim * width) + 1559 (fieldmode ? screen_width : 0), ps); 1560 *pix_inc = pixinc(x_predecim, ps); 1561 break; 1562 1563 case OMAP_DSS_ROT_0 + 4: 1564 case OMAP_DSS_ROT_180 + 4: 1565 /* If the pixel format is YUV or UYVY divide the width 1566 * of the image by 2 for 0 degree and 180 degree 1567 */ 1568 if (color_mode == OMAP_DSS_COLOR_YUV2 || 1569 color_mode == OMAP_DSS_COLOR_UYVY) 1570 width = width >> 1; 1571 case OMAP_DSS_ROT_90 + 4: 1572 case OMAP_DSS_ROT_270 + 4: 1573 *offset1 = 0; 1574 if (field_offset) 1575 *offset0 = field_offset * screen_width * ps; 1576 else 1577 *offset0 = 0; 1578 *row_inc = pixinc(1 - 1579 (y_predecim * screen_width + x_predecim * width) - 1580 (fieldmode ? screen_width : 0), ps); 1581 *pix_inc = pixinc(x_predecim, ps); 1582 break; 1583 1584 default: 1585 BUG(); 1586 return; 1587 } 1588} 1589 1590static void calc_dma_rotation_offset(u8 rotation, bool mirror, 1591 u16 screen_width, 1592 u16 width, u16 height, 1593 enum omap_color_mode color_mode, bool fieldmode, 1594 unsigned int field_offset, 1595 unsigned *offset0, unsigned *offset1, 1596 s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim) 1597{ 1598 u8 ps; 1599 u16 fbw, fbh; 1600 1601 /* FIXME CLUT formats */ 1602 switch (color_mode) { 1603 case OMAP_DSS_COLOR_CLUT1: 1604 case OMAP_DSS_COLOR_CLUT2: 1605 case OMAP_DSS_COLOR_CLUT4: 1606 case OMAP_DSS_COLOR_CLUT8: 1607 BUG(); 1608 return; 1609 default: 1610 ps = color_mode_to_bpp(color_mode) / 8; 1611 break; 1612 } 1613 1614 DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width, 1615 width, height); 1616 1617 /* width & height are overlay sizes, convert to fb sizes */ 1618 1619 if (rotation == OMAP_DSS_ROT_0 || rotation == OMAP_DSS_ROT_180) { 1620 fbw = width; 1621 fbh = height; 1622 } else { 1623 fbw = height; 1624 fbh = width; 1625 } 1626 1627 /* 1628 * field 0 = even field = bottom field 1629 * field 1 = odd field = top field 1630 */ 1631 switch (rotation + mirror * 4) { 1632 case OMAP_DSS_ROT_0: 1633 *offset1 = 0; 1634 if (field_offset) 1635 *offset0 = *offset1 + field_offset * screen_width * ps; 1636 else 1637 *offset0 = *offset1; 1638 *row_inc = pixinc(1 + 1639 (y_predecim * screen_width - fbw * x_predecim) + 1640 (fieldmode ? screen_width : 0), ps); 1641 if (color_mode == OMAP_DSS_COLOR_YUV2 || 1642 color_mode == OMAP_DSS_COLOR_UYVY) 1643 *pix_inc = pixinc(x_predecim, 2 * ps); 1644 else 1645 *pix_inc = pixinc(x_predecim, ps); 1646 break; 1647 case OMAP_DSS_ROT_90: 1648 *offset1 = screen_width * (fbh - 1) * ps; 1649 if (field_offset) 1650 *offset0 = *offset1 + field_offset * ps; 1651 else 1652 *offset0 = *offset1; 1653 *row_inc = pixinc(screen_width * (fbh * x_predecim - 1) + 1654 y_predecim + (fieldmode ? 1 : 0), ps); 1655 *pix_inc = pixinc(-x_predecim * screen_width, ps); 1656 break; 1657 case OMAP_DSS_ROT_180: 1658 *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps; 1659 if (field_offset) 1660 *offset0 = *offset1 - field_offset * screen_width * ps; 1661 else 1662 *offset0 = *offset1; 1663 *row_inc = pixinc(-1 - 1664 (y_predecim * screen_width - fbw * x_predecim) - 1665 (fieldmode ? screen_width : 0), ps); 1666 if (color_mode == OMAP_DSS_COLOR_YUV2 || 1667 color_mode == OMAP_DSS_COLOR_UYVY) 1668 *pix_inc = pixinc(-x_predecim, 2 * ps); 1669 else 1670 *pix_inc = pixinc(-x_predecim, ps); 1671 break; 1672 case OMAP_DSS_ROT_270: 1673 *offset1 = (fbw - 1) * ps; 1674 if (field_offset) 1675 *offset0 = *offset1 - field_offset * ps; 1676 else 1677 *offset0 = *offset1; 1678 *row_inc = pixinc(-screen_width * (fbh * x_predecim - 1) - 1679 y_predecim - (fieldmode ? 1 : 0), ps); 1680 *pix_inc = pixinc(x_predecim * screen_width, ps); 1681 break; 1682 1683 /* mirroring */ 1684 case OMAP_DSS_ROT_0 + 4: 1685 *offset1 = (fbw - 1) * ps; 1686 if (field_offset) 1687 *offset0 = *offset1 + field_offset * screen_width * ps; 1688 else 1689 *offset0 = *offset1; 1690 *row_inc = pixinc(y_predecim * screen_width * 2 - 1 + 1691 (fieldmode ? screen_width : 0), 1692 ps); 1693 if (color_mode == OMAP_DSS_COLOR_YUV2 || 1694 color_mode == OMAP_DSS_COLOR_UYVY) 1695 *pix_inc = pixinc(-x_predecim, 2 * ps); 1696 else 1697 *pix_inc = pixinc(-x_predecim, ps); 1698 break; 1699 1700 case OMAP_DSS_ROT_90 + 4: 1701 *offset1 = 0; 1702 if (field_offset) 1703 *offset0 = *offset1 + field_offset * ps; 1704 else 1705 *offset0 = *offset1; 1706 *row_inc = pixinc(-screen_width * (fbh * x_predecim - 1) + 1707 y_predecim + (fieldmode ? 1 : 0), 1708 ps); 1709 *pix_inc = pixinc(x_predecim * screen_width, ps); 1710 break; 1711 1712 case OMAP_DSS_ROT_180 + 4: 1713 *offset1 = screen_width * (fbh - 1) * ps; 1714 if (field_offset) 1715 *offset0 = *offset1 - field_offset * screen_width * ps; 1716 else 1717 *offset0 = *offset1; 1718 *row_inc = pixinc(1 - y_predecim * screen_width * 2 - 1719 (fieldmode ? screen_width : 0), 1720 ps); 1721 if (color_mode == OMAP_DSS_COLOR_YUV2 || 1722 color_mode == OMAP_DSS_COLOR_UYVY) 1723 *pix_inc = pixinc(x_predecim, 2 * ps); 1724 else 1725 *pix_inc = pixinc(x_predecim, ps); 1726 break; 1727 1728 case OMAP_DSS_ROT_270 + 4: 1729 *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps; 1730 if (field_offset) 1731 *offset0 = *offset1 - field_offset * ps; 1732 else 1733 *offset0 = *offset1; 1734 *row_inc = pixinc(screen_width * (fbh * x_predecim - 1) - 1735 y_predecim - (fieldmode ? 1 : 0), 1736 ps); 1737 *pix_inc = pixinc(-x_predecim * screen_width, ps); 1738 break; 1739 1740 default: 1741 BUG(); 1742 return; 1743 } 1744} 1745 1746static void calc_tiler_rotation_offset(u16 screen_width, u16 width, 1747 enum omap_color_mode color_mode, bool fieldmode, 1748 unsigned int field_offset, unsigned *offset0, unsigned *offset1, 1749 s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim) 1750{ 1751 u8 ps; 1752 1753 switch (color_mode) { 1754 case OMAP_DSS_COLOR_CLUT1: 1755 case OMAP_DSS_COLOR_CLUT2: 1756 case OMAP_DSS_COLOR_CLUT4: 1757 case OMAP_DSS_COLOR_CLUT8: 1758 BUG(); 1759 return; 1760 default: 1761 ps = color_mode_to_bpp(color_mode) / 8; 1762 break; 1763 } 1764 1765 DSSDBG("scrw %d, width %d\n", screen_width, width); 1766 1767 /* 1768 * field 0 = even field = bottom field 1769 * field 1 = odd field = top field 1770 */ 1771 *offset1 = 0; 1772 if (field_offset) 1773 *offset0 = *offset1 + field_offset * screen_width * ps; 1774 else 1775 *offset0 = *offset1; 1776 *row_inc = pixinc(1 + (y_predecim * screen_width - width * x_predecim) + 1777 (fieldmode ? screen_width : 0), ps); 1778 if (color_mode == OMAP_DSS_COLOR_YUV2 || 1779 color_mode == OMAP_DSS_COLOR_UYVY) 1780 *pix_inc = pixinc(x_predecim, 2 * ps); 1781 else 1782 *pix_inc = pixinc(x_predecim, ps); 1783} 1784 1785/* 1786 * This function is used to avoid synclosts in OMAP3, because of some 1787 * undocumented horizontal position and timing related limitations. 1788 */ 1789static int check_horiz_timing_omap3(enum omap_channel channel, 1790 const struct omap_video_timings *t, u16 pos_x, 1791 u16 width, u16 height, u16 out_width, u16 out_height) 1792{ 1793 int DS = DIV_ROUND_UP(height, out_height); 1794 unsigned long nonactive, lclk, pclk; 1795 static const u8 limits[3] = { 8, 10, 20 }; 1796 u64 val, blank; 1797 int i; 1798 1799 nonactive = t->x_res + t->hfp + t->hsw + t->hbp - out_width; 1800 pclk = dispc_mgr_pclk_rate(channel); 1801 if (dispc_mgr_is_lcd(channel)) 1802 lclk = dispc_mgr_lclk_rate(channel); 1803 else 1804 lclk = dispc_fclk_rate(); 1805 1806 i = 0; 1807 if (out_height < height) 1808 i++; 1809 if (out_width < width) 1810 i++; 1811 blank = div_u64((u64)(t->hbp + t->hsw + t->hfp) * lclk, pclk); 1812 DSSDBG("blanking period + ppl = %llu (limit = %u)\n", blank, limits[i]); 1813 if (blank <= limits[i]) 1814 return -EINVAL; 1815 1816 /* 1817 * Pixel data should be prepared before visible display point starts. 1818 * So, atleast DS-2 lines must have already been fetched by DISPC 1819 * during nonactive - pos_x period. 1820 */ 1821 val = div_u64((u64)(nonactive - pos_x) * lclk, pclk); 1822 DSSDBG("(nonactive - pos_x) * pcd = %llu max(0, DS - 2) * width = %d\n", 1823 val, max(0, DS - 2) * width); 1824 if (val < max(0, DS - 2) * width) 1825 return -EINVAL; 1826 1827 /* 1828 * All lines need to be refilled during the nonactive period of which 1829 * only one line can be loaded during the active period. So, atleast 1830 * DS - 1 lines should be loaded during nonactive period. 1831 */ 1832 val = div_u64((u64)nonactive * lclk, pclk); 1833 DSSDBG("nonactive * pcd = %llu, max(0, DS - 1) * width = %d\n", 1834 val, max(0, DS - 1) * width); 1835 if (val < max(0, DS - 1) * width) 1836 return -EINVAL; 1837 1838 return 0; 1839} 1840 1841static unsigned long calc_core_clk_five_taps(enum omap_channel channel, 1842 const struct omap_video_timings *mgr_timings, u16 width, 1843 u16 height, u16 out_width, u16 out_height, 1844 enum omap_color_mode color_mode) 1845{ 1846 u32 core_clk = 0; 1847 u64 tmp, pclk = dispc_mgr_pclk_rate(channel); 1848 1849 if (height <= out_height && width <= out_width) 1850 return (unsigned long) pclk; 1851 1852 if (height > out_height) { 1853 unsigned int ppl = mgr_timings->x_res; 1854 1855 tmp = pclk * height * out_width; 1856 do_div(tmp, 2 * out_height * ppl); 1857 core_clk = tmp; 1858 1859 if (height > 2 * out_height) { 1860 if (ppl == out_width) 1861 return 0; 1862 1863 tmp = pclk * (height - 2 * out_height) * out_width; 1864 do_div(tmp, 2 * out_height * (ppl - out_width)); 1865 core_clk = max_t(u32, core_clk, tmp); 1866 } 1867 } 1868 1869 if (width > out_width) { 1870 tmp = pclk * width; 1871 do_div(tmp, out_width); 1872 core_clk = max_t(u32, core_clk, tmp); 1873 1874 if (color_mode == OMAP_DSS_COLOR_RGB24U) 1875 core_clk <<= 1; 1876 } 1877 1878 return core_clk; 1879} 1880 1881static unsigned long calc_core_clk(enum omap_channel channel, u16 width, 1882 u16 height, u16 out_width, u16 out_height) 1883{ 1884 unsigned int hf, vf; 1885 unsigned long pclk = dispc_mgr_pclk_rate(channel); 1886 1887 /* 1888 * FIXME how to determine the 'A' factor 1889 * for the no downscaling case ? 1890 */ 1891 1892 if (width > 3 * out_width) 1893 hf = 4; 1894 else if (width > 2 * out_width) 1895 hf = 3; 1896 else if (width > out_width) 1897 hf = 2; 1898 else 1899 hf = 1; 1900 1901 if (height > out_height) 1902 vf = 2; 1903 else 1904 vf = 1; 1905 1906 if (cpu_is_omap24xx()) { 1907 if (vf > 1 && hf > 1) 1908 return pclk * 4; 1909 else 1910 return pclk * 2; 1911 } else if (cpu_is_omap34xx()) { 1912 return pclk * vf * hf; 1913 } else { 1914 if (hf > 1) 1915 return DIV_ROUND_UP(pclk, out_width) * width; 1916 else 1917 return pclk; 1918 } 1919} 1920 1921static int dispc_ovl_calc_scaling(enum omap_plane plane, 1922 enum omap_channel channel, 1923 const struct omap_video_timings *mgr_timings, 1924 u16 width, u16 height, u16 out_width, u16 out_height, 1925 enum omap_color_mode color_mode, bool *five_taps, 1926 int *x_predecim, int *y_predecim, u16 pos_x) 1927{ 1928 struct omap_overlay *ovl = omap_dss_get_overlay(plane); 1929 const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); 1930 const int maxsinglelinewidth = 1931 dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); 1932 const int max_decim_limit = 16; 1933 unsigned long core_clk = 0; 1934 int decim_x, decim_y, error, min_factor; 1935 u16 in_width, in_height, in_width_max = 0; 1936 1937 if (width == out_width && height == out_height) 1938 return 0; 1939 1940 if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) 1941 return -EINVAL; 1942 1943 *x_predecim = max_decim_limit; 1944 *y_predecim = max_decim_limit; 1945 1946 if (color_mode == OMAP_DSS_COLOR_CLUT1 || 1947 color_mode == OMAP_DSS_COLOR_CLUT2 || 1948 color_mode == OMAP_DSS_COLOR_CLUT4 || 1949 color_mode == OMAP_DSS_COLOR_CLUT8) { 1950 *x_predecim = 1; 1951 *y_predecim = 1; 1952 *five_taps = false; 1953 return 0; 1954 } 1955 1956 decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale); 1957 decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale); 1958 1959 min_factor = min(decim_x, decim_y); 1960 1961 if (decim_x > *x_predecim || out_width > width * 8) 1962 return -EINVAL; 1963 1964 if (decim_y > *y_predecim || out_height > height * 8) 1965 return -EINVAL; 1966 1967 if (cpu_is_omap24xx()) { 1968 *five_taps = false; 1969 1970 do { 1971 in_height = DIV_ROUND_UP(height, decim_y); 1972 in_width = DIV_ROUND_UP(width, decim_x); 1973 core_clk = calc_core_clk(channel, in_width, in_height, 1974 out_width, out_height); 1975 error = (in_width > maxsinglelinewidth || !core_clk || 1976 core_clk > dispc_core_clk_rate()); 1977 if (error) { 1978 if (decim_x == decim_y) { 1979 decim_x = min_factor; 1980 decim_y++; 1981 } else { 1982 swap(decim_x, decim_y); 1983 if (decim_x < decim_y) 1984 decim_x++; 1985 } 1986 } 1987 } while (decim_x <= *x_predecim && decim_y <= *y_predecim && 1988 error); 1989 1990 if (in_width > maxsinglelinewidth) { 1991 DSSERR("Cannot scale max input width exceeded"); 1992 return -EINVAL; 1993 } 1994 } else if (cpu_is_omap34xx()) { 1995 1996 do { 1997 in_height = DIV_ROUND_UP(height, decim_y); 1998 in_width = DIV_ROUND_UP(width, decim_x); 1999 core_clk = calc_core_clk_five_taps(channel, mgr_timings, 2000 in_width, in_height, out_width, out_height, 2001 color_mode); 2002 2003 error = check_horiz_timing_omap3(channel, mgr_timings, 2004 pos_x, in_width, in_height, out_width, 2005 out_height); 2006 2007 if (in_width > maxsinglelinewidth) 2008 if (in_height > out_height && 2009 in_height < out_height * 2) 2010 *five_taps = false; 2011 if (!*five_taps) 2012 core_clk = calc_core_clk(channel, in_width, 2013 in_height, out_width, out_height); 2014 error = (error || in_width > maxsinglelinewidth * 2 || 2015 (in_width > maxsinglelinewidth && *five_taps) || 2016 !core_clk || core_clk > dispc_core_clk_rate()); 2017 if (error) { 2018 if (decim_x == decim_y) { 2019 decim_x = min_factor; 2020 decim_y++; 2021 } else { 2022 swap(decim_x, decim_y); 2023 if (decim_x < decim_y) 2024 decim_x++; 2025 } 2026 } 2027 } while (decim_x <= *x_predecim && decim_y <= *y_predecim 2028 && error); 2029 2030 if (check_horiz_timing_omap3(channel, mgr_timings, pos_x, width, 2031 height, out_width, out_height)){ 2032 DSSERR("horizontal timing too tight\n"); 2033 return -EINVAL; 2034 } 2035 2036 if (in_width > (maxsinglelinewidth * 2)) { 2037 DSSERR("Cannot setup scaling"); 2038 DSSERR("width exceeds maximum width possible"); 2039 return -EINVAL; 2040 } 2041 2042 if (in_width > maxsinglelinewidth && *five_taps) { 2043 DSSERR("cannot setup scaling with five taps"); 2044 return -EINVAL; 2045 } 2046 } else { 2047 int decim_x_min = decim_x; 2048 in_height = DIV_ROUND_UP(height, decim_y); 2049 in_width_max = dispc_core_clk_rate() / 2050 DIV_ROUND_UP(dispc_mgr_pclk_rate(channel), 2051 out_width); 2052 decim_x = DIV_ROUND_UP(width, in_width_max); 2053 2054 decim_x = decim_x > decim_x_min ? decim_x : decim_x_min; 2055 if (decim_x > *x_predecim) 2056 return -EINVAL; 2057 2058 do { 2059 in_width = DIV_ROUND_UP(width, decim_x); 2060 } while (decim_x <= *x_predecim && 2061 in_width > maxsinglelinewidth && decim_x++); 2062 2063 if (in_width > maxsinglelinewidth) { 2064 DSSERR("Cannot scale width exceeds max line width"); 2065 return -EINVAL; 2066 } 2067 2068 core_clk = calc_core_clk(channel, in_width, in_height, 2069 out_width, out_height); 2070 } 2071 2072 DSSDBG("required core clk rate = %lu Hz\n", core_clk); 2073 DSSDBG("current core clk rate = %lu Hz\n", dispc_core_clk_rate()); 2074 2075 if (!core_clk || core_clk > dispc_core_clk_rate()) { 2076 DSSERR("failed to set up scaling, " 2077 "required core clk rate = %lu Hz, " 2078 "current core clk rate = %lu Hz\n", 2079 core_clk, dispc_core_clk_rate()); 2080 return -EINVAL; 2081 } 2082 2083 *x_predecim = decim_x; 2084 *y_predecim = decim_y; 2085 return 0; 2086} 2087 2088int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, 2089 bool ilace, bool replication, 2090 const struct omap_video_timings *mgr_timings) 2091{ 2092 struct omap_overlay *ovl = omap_dss_get_overlay(plane); 2093 bool five_taps = true; 2094 bool fieldmode = 0; 2095 int r, cconv = 0; 2096 unsigned offset0, offset1; 2097 s32 row_inc; 2098 s32 pix_inc; 2099 u16 frame_height = oi->height; 2100 unsigned int field_offset = 0; 2101 u16 in_height = oi->height; 2102 u16 in_width = oi->width; 2103 u16 out_width, out_height; 2104 enum omap_channel channel; 2105 int x_predecim = 1, y_predecim = 1; 2106 2107 channel = dispc_ovl_get_channel_out(plane); 2108 2109 DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> " 2110 "%dx%d, cmode %x, rot %d, mir %d, ilace %d chan %d repl %d\n", 2111 plane, oi->paddr, oi->p_uv_addr, 2112 oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, 2113 oi->out_width, oi->out_height, oi->color_mode, oi->rotation, 2114 oi->mirror, ilace, channel, replication); 2115 2116 if (oi->paddr == 0) 2117 return -EINVAL; 2118 2119 out_width = oi->out_width == 0 ? oi->width : oi->out_width; 2120 out_height = oi->out_height == 0 ? oi->height : oi->out_height; 2121 2122 if (ilace && oi->height == out_height) 2123 fieldmode = 1; 2124 2125 if (ilace) { 2126 if (fieldmode) 2127 in_height /= 2; 2128 oi->pos_y /= 2; 2129 out_height /= 2; 2130 2131 DSSDBG("adjusting for ilace: height %d, pos_y %d, " 2132 "out_height %d\n", 2133 in_height, oi->pos_y, out_height); 2134 } 2135 2136 if (!dss_feat_color_mode_supported(plane, oi->color_mode)) 2137 return -EINVAL; 2138 2139 r = dispc_ovl_calc_scaling(plane, channel, mgr_timings, in_width, 2140 in_height, out_width, out_height, oi->color_mode, 2141 &five_taps, &x_predecim, &y_predecim, oi->pos_x); 2142 if (r) 2143 return r; 2144 2145 in_width = DIV_ROUND_UP(in_width, x_predecim); 2146 in_height = DIV_ROUND_UP(in_height, y_predecim); 2147 2148 if (oi->color_mode == OMAP_DSS_COLOR_YUV2 || 2149 oi->color_mode == OMAP_DSS_COLOR_UYVY || 2150 oi->color_mode == OMAP_DSS_COLOR_NV12) 2151 cconv = 1; 2152 2153 if (ilace && !fieldmode) { 2154 /* 2155 * when downscaling the bottom field may have to start several 2156 * source lines below the top field. Unfortunately ACCUI 2157 * registers will only hold the fractional part of the offset 2158 * so the integer part must be added to the base address of the 2159 * bottom field. 2160 */ 2161 if (!in_height || in_height == out_height) 2162 field_offset = 0; 2163 else 2164 field_offset = in_height / out_height / 2; 2165 } 2166 2167 /* Fields are independent but interleaved in memory. */ 2168 if (fieldmode) 2169 field_offset = 1; 2170 2171 offset0 = 0; 2172 offset1 = 0; 2173 row_inc = 0; 2174 pix_inc = 0; 2175 2176 if (oi->rotation_type == OMAP_DSS_ROT_TILER) 2177 calc_tiler_rotation_offset(oi->screen_width, in_width, 2178 oi->color_mode, fieldmode, field_offset, 2179 &offset0, &offset1, &row_inc, &pix_inc, 2180 x_predecim, y_predecim); 2181 else if (oi->rotation_type == OMAP_DSS_ROT_DMA) 2182 calc_dma_rotation_offset(oi->rotation, oi->mirror, 2183 oi->screen_width, in_width, frame_height, 2184 oi->color_mode, fieldmode, field_offset, 2185 &offset0, &offset1, &row_inc, &pix_inc, 2186 x_predecim, y_predecim); 2187 else 2188 calc_vrfb_rotation_offset(oi->rotation, oi->mirror, 2189 oi->screen_width, in_width, frame_height, 2190 oi->color_mode, fieldmode, field_offset, 2191 &offset0, &offset1, &row_inc, &pix_inc, 2192 x_predecim, y_predecim); 2193 2194 DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n", 2195 offset0, offset1, row_inc, pix_inc); 2196 2197 dispc_ovl_set_color_mode(plane, oi->color_mode); 2198 2199 dispc_ovl_configure_burst_type(plane, oi->rotation_type); 2200 2201 dispc_ovl_set_ba0(plane, oi->paddr + offset0); 2202 dispc_ovl_set_ba1(plane, oi->paddr + offset1); 2203 2204 if (OMAP_DSS_COLOR_NV12 == oi->color_mode) { 2205 dispc_ovl_set_ba0_uv(plane, oi->p_uv_addr + offset0); 2206 dispc_ovl_set_ba1_uv(plane, oi->p_uv_addr + offset1); 2207 } 2208 2209 2210 dispc_ovl_set_row_inc(plane, row_inc); 2211 dispc_ovl_set_pix_inc(plane, pix_inc); 2212 2213 DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, in_width, 2214 in_height, out_width, out_height); 2215 2216 dispc_ovl_set_pos(plane, oi->pos_x, oi->pos_y); 2217 2218 dispc_ovl_set_pic_size(plane, in_width, in_height); 2219 2220 if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) { 2221 dispc_ovl_set_scaling(plane, in_width, in_height, out_width, 2222 out_height, ilace, five_taps, fieldmode, 2223 oi->color_mode, oi->rotation); 2224 dispc_ovl_set_vid_size(plane, out_width, out_height); 2225 dispc_ovl_set_vid_color_conv(plane, cconv); 2226 } 2227 2228 dispc_ovl_set_rotation_attrs(plane, oi->rotation, oi->mirror, 2229 oi->color_mode); 2230 2231 dispc_ovl_set_zorder(plane, oi->zorder); 2232 dispc_ovl_set_pre_mult_alpha(plane, oi->pre_mult_alpha); 2233 dispc_ovl_setup_global_alpha(plane, oi->global_alpha); 2234 2235 dispc_ovl_enable_replication(plane, replication); 2236 2237 return 0; 2238} 2239 2240int dispc_ovl_enable(enum omap_plane plane, bool enable) 2241{ 2242 DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); 2243 2244 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0); 2245 2246 return 0; 2247} 2248 2249static void dispc_disable_isr(void *data, u32 mask) 2250{ 2251 struct completion *compl = data; 2252 complete(compl); 2253} 2254 2255static void _enable_lcd_out(enum omap_channel channel, bool enable) 2256{ 2257 if (channel == OMAP_DSS_CHANNEL_LCD2) { 2258 REG_FLD_MOD(DISPC_CONTROL2, enable ? 1 : 0, 0, 0); 2259 /* flush posted write */ 2260 dispc_read_reg(DISPC_CONTROL2); 2261 } else { 2262 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0); 2263 dispc_read_reg(DISPC_CONTROL); 2264 } 2265} 2266 2267static void dispc_mgr_enable_lcd_out(enum omap_channel channel, bool enable) 2268{ 2269 struct completion frame_done_completion; 2270 bool is_on; 2271 int r; 2272 u32 irq; 2273 2274 /* When we disable LCD output, we need to wait until frame is done. 2275 * Otherwise the DSS is still working, and turning off the clocks 2276 * prevents DSS from going to OFF mode */ 2277 is_on = channel == OMAP_DSS_CHANNEL_LCD2 ? 2278 REG_GET(DISPC_CONTROL2, 0, 0) : 2279 REG_GET(DISPC_CONTROL, 0, 0); 2280 2281 irq = channel == OMAP_DSS_CHANNEL_LCD2 ? DISPC_IRQ_FRAMEDONE2 : 2282 DISPC_IRQ_FRAMEDONE; 2283 2284 if (!enable && is_on) { 2285 init_completion(&frame_done_completion); 2286 2287 r = omap_dispc_register_isr(dispc_disable_isr, 2288 &frame_done_completion, irq); 2289 2290 if (r) 2291 DSSERR("failed to register FRAMEDONE isr\n"); 2292 } 2293 2294 _enable_lcd_out(channel, enable); 2295 2296 if (!enable && is_on) { 2297 if (!wait_for_completion_timeout(&frame_done_completion, 2298 msecs_to_jiffies(100))) 2299 DSSERR("timeout waiting for FRAME DONE\n"); 2300 2301 r = omap_dispc_unregister_isr(dispc_disable_isr, 2302 &frame_done_completion, irq); 2303 2304 if (r) 2305 DSSERR("failed to unregister FRAMEDONE isr\n"); 2306 } 2307} 2308 2309static void _enable_digit_out(bool enable) 2310{ 2311 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1); 2312 /* flush posted write */ 2313 dispc_read_reg(DISPC_CONTROL); 2314} 2315 2316static void dispc_mgr_enable_digit_out(bool enable) 2317{ 2318 struct completion frame_done_completion; 2319 enum dss_hdmi_venc_clk_source_select src; 2320 int r, i; 2321 u32 irq_mask; 2322 int num_irqs; 2323 2324 if (REG_GET(DISPC_CONTROL, 1, 1) == enable) 2325 return; 2326 2327 src = dss_get_hdmi_venc_clk_source(); 2328 2329 if (enable) { 2330 unsigned long flags; 2331 /* When we enable digit output, we'll get an extra digit 2332 * sync lost interrupt, that we need to ignore */ 2333 spin_lock_irqsave(&dispc.irq_lock, flags); 2334 dispc.irq_error_mask &= ~DISPC_IRQ_SYNC_LOST_DIGIT; 2335 _omap_dispc_set_irqs(); 2336 spin_unlock_irqrestore(&dispc.irq_lock, flags); 2337 } 2338 2339 /* When we disable digit output, we need to wait until fields are done. 2340 * Otherwise the DSS is still working, and turning off the clocks 2341 * prevents DSS from going to OFF mode. And when enabling, we need to 2342 * wait for the extra sync losts */ 2343 init_completion(&frame_done_completion); 2344 2345 if (src == DSS_HDMI_M_PCLK && enable == false) { 2346 irq_mask = DISPC_IRQ_FRAMEDONETV; 2347 num_irqs = 1; 2348 } else { 2349 irq_mask = DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD; 2350 /* XXX I understand from TRM that we should only wait for the 2351 * current field to complete. But it seems we have to wait for 2352 * both fields */ 2353 num_irqs = 2; 2354 } 2355 2356 r = omap_dispc_register_isr(dispc_disable_isr, &frame_done_completion, 2357 irq_mask); 2358 if (r) 2359 DSSERR("failed to register %x isr\n", irq_mask); 2360 2361 _enable_digit_out(enable); 2362 2363 for (i = 0; i < num_irqs; ++i) { 2364 if (!wait_for_completion_timeout(&frame_done_completion, 2365 msecs_to_jiffies(100))) 2366 DSSERR("timeout waiting for digit out to %s\n", 2367 enable ? "start" : "stop"); 2368 } 2369 2370 r = omap_dispc_unregister_isr(dispc_disable_isr, &frame_done_completion, 2371 irq_mask); 2372 if (r) 2373 DSSERR("failed to unregister %x isr\n", irq_mask); 2374 2375 if (enable) { 2376 unsigned long flags; 2377 spin_lock_irqsave(&dispc.irq_lock, flags); 2378 dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST_DIGIT; 2379 dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT); 2380 _omap_dispc_set_irqs(); 2381 spin_unlock_irqrestore(&dispc.irq_lock, flags); 2382 } 2383} 2384 2385bool dispc_mgr_is_enabled(enum omap_channel channel) 2386{ 2387 if (channel == OMAP_DSS_CHANNEL_LCD) 2388 return !!REG_GET(DISPC_CONTROL, 0, 0); 2389 else if (channel == OMAP_DSS_CHANNEL_DIGIT) 2390 return !!REG_GET(DISPC_CONTROL, 1, 1); 2391 else if (channel == OMAP_DSS_CHANNEL_LCD2) 2392 return !!REG_GET(DISPC_CONTROL2, 0, 0); 2393 else { 2394 BUG(); 2395 return false; 2396 } 2397} 2398 2399void dispc_mgr_enable(enum omap_channel channel, bool enable) 2400{ 2401 if (dispc_mgr_is_lcd(channel)) 2402 dispc_mgr_enable_lcd_out(channel, enable); 2403 else if (channel == OMAP_DSS_CHANNEL_DIGIT) 2404 dispc_mgr_enable_digit_out(enable); 2405 else 2406 BUG(); 2407} 2408 2409void dispc_lcd_enable_signal_polarity(bool act_high) 2410{ 2411 if (!dss_has_feature(FEAT_LCDENABLEPOL)) 2412 return; 2413 2414 REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29); 2415} 2416 2417void dispc_lcd_enable_signal(bool enable) 2418{ 2419 if (!dss_has_feature(FEAT_LCDENABLESIGNAL)) 2420 return; 2421 2422 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28); 2423} 2424 2425void dispc_pck_free_enable(bool enable) 2426{ 2427 if (!dss_has_feature(FEAT_PCKFREEENABLE)) 2428 return; 2429 2430 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27); 2431} 2432 2433void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable) 2434{ 2435 if (channel == OMAP_DSS_CHANNEL_LCD2) 2436 REG_FLD_MOD(DISPC_CONFIG2, enable ? 1 : 0, 16, 16); 2437 else 2438 REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16); 2439} 2440 2441 2442void dispc_mgr_set_lcd_display_type(enum omap_channel channel, 2443 enum omap_lcd_display_type type) 2444{ 2445 int mode; 2446 2447 switch (type) { 2448 case OMAP_DSS_LCD_DISPLAY_STN: 2449 mode = 0; 2450 break; 2451 2452 case OMAP_DSS_LCD_DISPLAY_TFT: 2453 mode = 1; 2454 break; 2455 2456 default: 2457 BUG(); 2458 return; 2459 } 2460 2461 if (channel == OMAP_DSS_CHANNEL_LCD2) 2462 REG_FLD_MOD(DISPC_CONTROL2, mode, 3, 3); 2463 else 2464 REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3); 2465} 2466 2467void dispc_set_loadmode(enum omap_dss_load_mode mode) 2468{ 2469 REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1); 2470} 2471 2472 2473static void dispc_mgr_set_default_color(enum omap_channel channel, u32 color) 2474{ 2475 dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color); 2476} 2477 2478static void dispc_mgr_set_trans_key(enum omap_channel ch, 2479 enum omap_dss_trans_key_type type, 2480 u32 trans_key) 2481{ 2482 if (ch == OMAP_DSS_CHANNEL_LCD) 2483 REG_FLD_MOD(DISPC_CONFIG, type, 11, 11); 2484 else if (ch == OMAP_DSS_CHANNEL_DIGIT) 2485 REG_FLD_MOD(DISPC_CONFIG, type, 13, 13); 2486 else /* OMAP_DSS_CHANNEL_LCD2 */ 2487 REG_FLD_MOD(DISPC_CONFIG2, type, 11, 11); 2488 2489 dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key); 2490} 2491 2492static void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable) 2493{ 2494 if (ch == OMAP_DSS_CHANNEL_LCD) 2495 REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10); 2496 else if (ch == OMAP_DSS_CHANNEL_DIGIT) 2497 REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12); 2498 else /* OMAP_DSS_CHANNEL_LCD2 */ 2499 REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10); 2500} 2501 2502static void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, 2503 bool enable) 2504{ 2505 if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) 2506 return; 2507 2508 if (ch == OMAP_DSS_CHANNEL_LCD) 2509 REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18); 2510 else if (ch == OMAP_DSS_CHANNEL_DIGIT) 2511 REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19); 2512} 2513 2514void dispc_mgr_setup(enum omap_channel channel, 2515 struct omap_overlay_manager_info *info) 2516{ 2517 dispc_mgr_set_default_color(channel, info->default_color); 2518 dispc_mgr_set_trans_key(channel, info->trans_key_type, info->trans_key); 2519 dispc_mgr_enable_trans_key(channel, info->trans_enabled); 2520 dispc_mgr_enable_alpha_fixed_zorder(channel, 2521 info->partial_alpha_enabled); 2522 if (dss_has_feature(FEAT_CPR)) { 2523 dispc_mgr_enable_cpr(channel, info->cpr_enable); 2524 dispc_mgr_set_cpr_coef(channel, &info->cpr_coefs); 2525 } 2526} 2527 2528void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines) 2529{ 2530 int code; 2531 2532 switch (data_lines) { 2533 case 12: 2534 code = 0; 2535 break; 2536 case 16: 2537 code = 1; 2538 break; 2539 case 18: 2540 code = 2; 2541 break; 2542 case 24: 2543 code = 3; 2544 break; 2545 default: 2546 BUG(); 2547 return; 2548 } 2549 2550 if (channel == OMAP_DSS_CHANNEL_LCD2) 2551 REG_FLD_MOD(DISPC_CONTROL2, code, 9, 8); 2552 else 2553 REG_FLD_MOD(DISPC_CONTROL, code, 9, 8); 2554} 2555 2556void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode) 2557{ 2558 u32 l; 2559 int gpout0, gpout1; 2560 2561 switch (mode) { 2562 case DSS_IO_PAD_MODE_RESET: 2563 gpout0 = 0; 2564 gpout1 = 0; 2565 break; 2566 case DSS_IO_PAD_MODE_RFBI: 2567 gpout0 = 1; 2568 gpout1 = 0; 2569 break; 2570 case DSS_IO_PAD_MODE_BYPASS: 2571 gpout0 = 1; 2572 gpout1 = 1; 2573 break; 2574 default: 2575 BUG(); 2576 return; 2577 } 2578 2579 l = dispc_read_reg(DISPC_CONTROL); 2580 l = FLD_MOD(l, gpout0, 15, 15); 2581 l = FLD_MOD(l, gpout1, 16, 16); 2582 dispc_write_reg(DISPC_CONTROL, l); 2583} 2584 2585void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable) 2586{ 2587 if (channel == OMAP_DSS_CHANNEL_LCD2) 2588 REG_FLD_MOD(DISPC_CONTROL2, enable, 11, 11); 2589 else 2590 REG_FLD_MOD(DISPC_CONTROL, enable, 11, 11); 2591} 2592 2593static bool _dispc_mgr_size_ok(u16 width, u16 height) 2594{ 2595 return width <= dss_feat_get_param_max(FEAT_PARAM_MGR_WIDTH) && 2596 height <= dss_feat_get_param_max(FEAT_PARAM_MGR_HEIGHT); 2597} 2598 2599static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, 2600 int vsw, int vfp, int vbp) 2601{ 2602 if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) { 2603 if (hsw < 1 || hsw > 64 || 2604 hfp < 1 || hfp > 256 || 2605 hbp < 1 || hbp > 256 || 2606 vsw < 1 || vsw > 64 || 2607 vfp < 0 || vfp > 255 || 2608 vbp < 0 || vbp > 255) 2609 return false; 2610 } else { 2611 if (hsw < 1 || hsw > 256 || 2612 hfp < 1 || hfp > 4096 || 2613 hbp < 1 || hbp > 4096 || 2614 vsw < 1 || vsw > 256 || 2615 vfp < 0 || vfp > 4095 || 2616 vbp < 0 || vbp > 4095) 2617 return false; 2618 } 2619 2620 return true; 2621} 2622 2623bool dispc_mgr_timings_ok(enum omap_channel channel, 2624 const struct omap_video_timings *timings) 2625{ 2626 bool timings_ok; 2627 2628 timings_ok = _dispc_mgr_size_ok(timings->x_res, timings->y_res); 2629 2630 if (dispc_mgr_is_lcd(channel)) 2631 timings_ok = timings_ok && _dispc_lcd_timings_ok(timings->hsw, 2632 timings->hfp, timings->hbp, 2633 timings->vsw, timings->vfp, 2634 timings->vbp); 2635 2636 return timings_ok; 2637} 2638 2639static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw, 2640 int hfp, int hbp, int vsw, int vfp, int vbp) 2641{ 2642 u32 timing_h, timing_v; 2643 2644 if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) { 2645 timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) | 2646 FLD_VAL(hbp-1, 27, 20); 2647 2648 timing_v = FLD_VAL(vsw-1, 5, 0) | FLD_VAL(vfp, 15, 8) | 2649 FLD_VAL(vbp, 27, 20); 2650 } else { 2651 timing_h = FLD_VAL(hsw-1, 7, 0) | FLD_VAL(hfp-1, 19, 8) | 2652 FLD_VAL(hbp-1, 31, 20); 2653 2654 timing_v = FLD_VAL(vsw-1, 7, 0) | FLD_VAL(vfp, 19, 8) | 2655 FLD_VAL(vbp, 31, 20); 2656 } 2657 2658 dispc_write_reg(DISPC_TIMING_H(channel), timing_h); 2659 dispc_write_reg(DISPC_TIMING_V(channel), timing_v); 2660} 2661 2662/* change name to mode? */ 2663void dispc_mgr_set_timings(enum omap_channel channel, 2664 struct omap_video_timings *timings) 2665{ 2666 unsigned xtot, ytot; 2667 unsigned long ht, vt; 2668 struct omap_video_timings t = *timings; 2669 2670 DSSDBG("channel %d xres %u yres %u\n", channel, t.x_res, t.y_res); 2671 2672 if (!dispc_mgr_timings_ok(channel, &t)) { 2673 BUG(); 2674 return; 2675 } 2676 2677 if (dispc_mgr_is_lcd(channel)) { 2678 _dispc_mgr_set_lcd_timings(channel, t.hsw, t.hfp, t.hbp, t.vsw, 2679 t.vfp, t.vbp); 2680 2681 xtot = t.x_res + t.hfp + t.hsw + t.hbp; 2682 ytot = t.y_res + t.vfp + t.vsw + t.vbp; 2683 2684 ht = (timings->pixel_clock * 1000) / xtot; 2685 vt = (timings->pixel_clock * 1000) / xtot / ytot; 2686 2687 DSSDBG("pck %u\n", timings->pixel_clock); 2688 DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n", 2689 t.hsw, t.hfp, t.hbp, t.vsw, t.vfp, t.vbp); 2690 2691 DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt); 2692 } else { 2693 enum dss_hdmi_venc_clk_source_select source; 2694 2695 source = dss_get_hdmi_venc_clk_source(); 2696 2697 if (source == DSS_VENC_TV_CLK) 2698 t.y_res /= 2; 2699 } 2700 2701 dispc_mgr_set_size(channel, t.x_res, t.y_res); 2702} 2703 2704static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div, 2705 u16 pck_div) 2706{ 2707 BUG_ON(lck_div < 1); 2708 BUG_ON(pck_div < 1); 2709 2710 dispc_write_reg(DISPC_DIVISORo(channel), 2711 FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0)); 2712} 2713 2714static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div, 2715 int *pck_div) 2716{ 2717 u32 l; 2718 l = dispc_read_reg(DISPC_DIVISORo(channel)); 2719 *lck_div = FLD_GET(l, 23, 16); 2720 *pck_div = FLD_GET(l, 7, 0); 2721} 2722 2723unsigned long dispc_fclk_rate(void) 2724{ 2725 struct platform_device *dsidev; 2726 unsigned long r = 0; 2727 2728 switch (dss_get_dispc_clk_source()) { 2729 case OMAP_DSS_CLK_SRC_FCK: 2730 r = clk_get_rate(dispc.dss_clk); 2731 break; 2732 case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: 2733 dsidev = dsi_get_dsidev_from_id(0); 2734 r = dsi_get_pll_hsdiv_dispc_rate(dsidev); 2735 break; 2736 case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: 2737 dsidev = dsi_get_dsidev_from_id(1); 2738 r = dsi_get_pll_hsdiv_dispc_rate(dsidev); 2739 break; 2740 default: 2741 BUG(); 2742 return 0; 2743 } 2744 2745 return r; 2746} 2747 2748unsigned long dispc_mgr_lclk_rate(enum omap_channel channel) 2749{ 2750 struct platform_device *dsidev; 2751 int lcd; 2752 unsigned long r; 2753 u32 l; 2754 2755 l = dispc_read_reg(DISPC_DIVISORo(channel)); 2756 2757 lcd = FLD_GET(l, 23, 16); 2758 2759 switch (dss_get_lcd_clk_source(channel)) { 2760 case OMAP_DSS_CLK_SRC_FCK: 2761 r = clk_get_rate(dispc.dss_clk); 2762 break; 2763 case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: 2764 dsidev = dsi_get_dsidev_from_id(0); 2765 r = dsi_get_pll_hsdiv_dispc_rate(dsidev); 2766 break; 2767 case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: 2768 dsidev = dsi_get_dsidev_from_id(1); 2769 r = dsi_get_pll_hsdiv_dispc_rate(dsidev); 2770 break; 2771 default: 2772 BUG(); 2773 return 0; 2774 } 2775 2776 return r / lcd; 2777} 2778 2779unsigned long dispc_mgr_pclk_rate(enum omap_channel channel) 2780{ 2781 unsigned long r; 2782 2783 if (dispc_mgr_is_lcd(channel)) { 2784 int pcd; 2785 u32 l; 2786 2787 l = dispc_read_reg(DISPC_DIVISORo(channel)); 2788 2789 pcd = FLD_GET(l, 7, 0); 2790 2791 r = dispc_mgr_lclk_rate(channel); 2792 2793 return r / pcd; 2794 } else { 2795 enum dss_hdmi_venc_clk_source_select source; 2796 2797 source = dss_get_hdmi_venc_clk_source(); 2798 2799 switch (source) { 2800 case DSS_VENC_TV_CLK: 2801 return venc_get_pixel_clock(); 2802 case DSS_HDMI_M_PCLK: 2803 return hdmi_get_pixel_clock(); 2804 default: 2805 BUG(); 2806 return 0; 2807 } 2808 } 2809} 2810 2811unsigned long dispc_core_clk_rate(void) 2812{ 2813 int lcd; 2814 unsigned long fclk = dispc_fclk_rate(); 2815 2816 if (dss_has_feature(FEAT_CORE_CLK_DIV)) 2817 lcd = REG_GET(DISPC_DIVISOR, 23, 16); 2818 else 2819 lcd = REG_GET(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD), 23, 16); 2820 2821 return fclk / lcd; 2822} 2823 2824void dispc_dump_clocks(struct seq_file *s) 2825{ 2826 int lcd, pcd; 2827 u32 l; 2828 enum omap_dss_clk_source dispc_clk_src = dss_get_dispc_clk_source(); 2829 enum omap_dss_clk_source lcd_clk_src; 2830 2831 if (dispc_runtime_get()) 2832 return; 2833 2834 seq_printf(s, "- DISPC -\n"); 2835 2836 seq_printf(s, "dispc fclk source = %s (%s)\n", 2837 dss_get_generic_clk_source_name(dispc_clk_src), 2838 dss_feat_get_clk_source_name(dispc_clk_src)); 2839 2840 seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate()); 2841 2842 if (dss_has_feature(FEAT_CORE_CLK_DIV)) { 2843 seq_printf(s, "- DISPC-CORE-CLK -\n"); 2844 l = dispc_read_reg(DISPC_DIVISOR); 2845 lcd = FLD_GET(l, 23, 16); 2846 2847 seq_printf(s, "lck\t\t%-16lulck div\t%u\n", 2848 (dispc_fclk_rate()/lcd), lcd); 2849 } 2850 seq_printf(s, "- LCD1 -\n"); 2851 2852 lcd_clk_src = dss_get_lcd_clk_source(OMAP_DSS_CHANNEL_LCD); 2853 2854 seq_printf(s, "lcd1_clk source = %s (%s)\n", 2855 dss_get_generic_clk_source_name(lcd_clk_src), 2856 dss_feat_get_clk_source_name(lcd_clk_src)); 2857 2858 dispc_mgr_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD, &lcd, &pcd); 2859 2860 seq_printf(s, "lck\t\t%-16lulck div\t%u\n", 2861 dispc_mgr_lclk_rate(OMAP_DSS_CHANNEL_LCD), lcd); 2862 seq_printf(s, "pck\t\t%-16lupck div\t%u\n", 2863 dispc_mgr_pclk_rate(OMAP_DSS_CHANNEL_LCD), pcd); 2864 if (dss_has_feature(FEAT_MGR_LCD2)) { 2865 seq_printf(s, "- LCD2 -\n"); 2866 2867 lcd_clk_src = dss_get_lcd_clk_source(OMAP_DSS_CHANNEL_LCD2); 2868 2869 seq_printf(s, "lcd2_clk source = %s (%s)\n", 2870 dss_get_generic_clk_source_name(lcd_clk_src), 2871 dss_feat_get_clk_source_name(lcd_clk_src)); 2872 2873 dispc_mgr_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD2, &lcd, &pcd); 2874 2875 seq_printf(s, "lck\t\t%-16lulck div\t%u\n", 2876 dispc_mgr_lclk_rate(OMAP_DSS_CHANNEL_LCD2), lcd); 2877 seq_printf(s, "pck\t\t%-16lupck div\t%u\n", 2878 dispc_mgr_pclk_rate(OMAP_DSS_CHANNEL_LCD2), pcd); 2879 } 2880 2881 dispc_runtime_put(); 2882} 2883 2884#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS 2885void dispc_dump_irqs(struct seq_file *s) 2886{ 2887 unsigned long flags; 2888 struct dispc_irq_stats stats; 2889 2890 spin_lock_irqsave(&dispc.irq_stats_lock, flags); 2891 2892 stats = dispc.irq_stats; 2893 memset(&dispc.irq_stats, 0, sizeof(dispc.irq_stats)); 2894 dispc.irq_stats.last_reset = jiffies; 2895 2896 spin_unlock_irqrestore(&dispc.irq_stats_lock, flags); 2897 2898 seq_printf(s, "period %u ms\n", 2899 jiffies_to_msecs(jiffies - stats.last_reset)); 2900 2901 seq_printf(s, "irqs %d\n", stats.irq_count); 2902#define PIS(x) \ 2903 seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]); 2904 2905 PIS(FRAMEDONE); 2906 PIS(VSYNC); 2907 PIS(EVSYNC_EVEN); 2908 PIS(EVSYNC_ODD); 2909 PIS(ACBIAS_COUNT_STAT); 2910 PIS(PROG_LINE_NUM); 2911 PIS(GFX_FIFO_UNDERFLOW); 2912 PIS(GFX_END_WIN); 2913 PIS(PAL_GAMMA_MASK); 2914 PIS(OCP_ERR); 2915 PIS(VID1_FIFO_UNDERFLOW); 2916 PIS(VID1_END_WIN); 2917 PIS(VID2_FIFO_UNDERFLOW); 2918 PIS(VID2_END_WIN); 2919 if (dss_feat_get_num_ovls() > 3) { 2920 PIS(VID3_FIFO_UNDERFLOW); 2921 PIS(VID3_END_WIN); 2922 } 2923 PIS(SYNC_LOST); 2924 PIS(SYNC_LOST_DIGIT); 2925 PIS(WAKEUP); 2926 if (dss_has_feature(FEAT_MGR_LCD2)) { 2927 PIS(FRAMEDONE2); 2928 PIS(VSYNC2); 2929 PIS(ACBIAS_COUNT_STAT2); 2930 PIS(SYNC_LOST2); 2931 } 2932#undef PIS 2933} 2934#endif 2935 2936static void dispc_dump_regs(struct seq_file *s) 2937{ 2938 int i, j; 2939 const char *mgr_names[] = { 2940 [OMAP_DSS_CHANNEL_LCD] = "LCD", 2941 [OMAP_DSS_CHANNEL_DIGIT] = "TV", 2942 [OMAP_DSS_CHANNEL_LCD2] = "LCD2", 2943 }; 2944 const char *ovl_names[] = { 2945 [OMAP_DSS_GFX] = "GFX", 2946 [OMAP_DSS_VIDEO1] = "VID1", 2947 [OMAP_DSS_VIDEO2] = "VID2", 2948 [OMAP_DSS_VIDEO3] = "VID3", 2949 }; 2950 const char **p_names; 2951 2952#define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r)) 2953 2954 if (dispc_runtime_get()) 2955 return; 2956 2957 /* DISPC common registers */ 2958 DUMPREG(DISPC_REVISION); 2959 DUMPREG(DISPC_SYSCONFIG); 2960 DUMPREG(DISPC_SYSSTATUS); 2961 DUMPREG(DISPC_IRQSTATUS); 2962 DUMPREG(DISPC_IRQENABLE); 2963 DUMPREG(DISPC_CONTROL); 2964 DUMPREG(DISPC_CONFIG); 2965 DUMPREG(DISPC_CAPABLE); 2966 DUMPREG(DISPC_LINE_STATUS); 2967 DUMPREG(DISPC_LINE_NUMBER); 2968 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) || 2969 dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) 2970 DUMPREG(DISPC_GLOBAL_ALPHA); 2971 if (dss_has_feature(FEAT_MGR_LCD2)) { 2972 DUMPREG(DISPC_CONTROL2); 2973 DUMPREG(DISPC_CONFIG2); 2974 } 2975 2976#undef DUMPREG 2977 2978#define DISPC_REG(i, name) name(i) 2979#define DUMPREG(i, r) seq_printf(s, "%s(%s)%*s %08x\n", #r, p_names[i], \ 2980 48 - strlen(#r) - strlen(p_names[i]), " ", \ 2981 dispc_read_reg(DISPC_REG(i, r))) 2982 2983 p_names = mgr_names; 2984 2985 /* DISPC channel specific registers */ 2986 for (i = 0; i < dss_feat_get_num_mgrs(); i++) { 2987 DUMPREG(i, DISPC_DEFAULT_COLOR); 2988 DUMPREG(i, DISPC_TRANS_COLOR); 2989 DUMPREG(i, DISPC_SIZE_MGR); 2990 2991 if (i == OMAP_DSS_CHANNEL_DIGIT) 2992 continue; 2993 2994 DUMPREG(i, DISPC_DEFAULT_COLOR); 2995 DUMPREG(i, DISPC_TRANS_COLOR); 2996 DUMPREG(i, DISPC_TIMING_H); 2997 DUMPREG(i, DISPC_TIMING_V); 2998 DUMPREG(i, DISPC_POL_FREQ); 2999 DUMPREG(i, DISPC_DIVISORo); 3000 DUMPREG(i, DISPC_SIZE_MGR); 3001 3002 DUMPREG(i, DISPC_DATA_CYCLE1); 3003 DUMPREG(i, DISPC_DATA_CYCLE2); 3004 DUMPREG(i, DISPC_DATA_CYCLE3); 3005 3006 if (dss_has_feature(FEAT_CPR)) { 3007 DUMPREG(i, DISPC_CPR_COEF_R); 3008 DUMPREG(i, DISPC_CPR_COEF_G); 3009 DUMPREG(i, DISPC_CPR_COEF_B); 3010 } 3011 } 3012 3013 p_names = ovl_names; 3014 3015 for (i = 0; i < dss_feat_get_num_ovls(); i++) { 3016 DUMPREG(i, DISPC_OVL_BA0); 3017 DUMPREG(i, DISPC_OVL_BA1); 3018 DUMPREG(i, DISPC_OVL_POSITION); 3019 DUMPREG(i, DISPC_OVL_SIZE); 3020 DUMPREG(i, DISPC_OVL_ATTRIBUTES); 3021 DUMPREG(i, DISPC_OVL_FIFO_THRESHOLD); 3022 DUMPREG(i, DISPC_OVL_FIFO_SIZE_STATUS); 3023 DUMPREG(i, DISPC_OVL_ROW_INC); 3024 DUMPREG(i, DISPC_OVL_PIXEL_INC); 3025 if (dss_has_feature(FEAT_PRELOAD)) 3026 DUMPREG(i, DISPC_OVL_PRELOAD); 3027 3028 if (i == OMAP_DSS_GFX) { 3029 DUMPREG(i, DISPC_OVL_WINDOW_SKIP); 3030 DUMPREG(i, DISPC_OVL_TABLE_BA); 3031 continue; 3032 } 3033 3034 DUMPREG(i, DISPC_OVL_FIR); 3035 DUMPREG(i, DISPC_OVL_PICTURE_SIZE); 3036 DUMPREG(i, DISPC_OVL_ACCU0); 3037 DUMPREG(i, DISPC_OVL_ACCU1); 3038 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { 3039 DUMPREG(i, DISPC_OVL_BA0_UV); 3040 DUMPREG(i, DISPC_OVL_BA1_UV); 3041 DUMPREG(i, DISPC_OVL_FIR2); 3042 DUMPREG(i, DISPC_OVL_ACCU2_0); 3043 DUMPREG(i, DISPC_OVL_ACCU2_1); 3044 } 3045 if (dss_has_feature(FEAT_ATTR2)) 3046 DUMPREG(i, DISPC_OVL_ATTRIBUTES2); 3047 if (dss_has_feature(FEAT_PRELOAD)) 3048 DUMPREG(i, DISPC_OVL_PRELOAD); 3049 } 3050 3051#undef DISPC_REG 3052#undef DUMPREG 3053 3054#define DISPC_REG(plane, name, i) name(plane, i) 3055#define DUMPREG(plane, name, i) \ 3056 seq_printf(s, "%s_%d(%s)%*s %08x\n", #name, i, p_names[plane], \ 3057 46 - strlen(#name) - strlen(p_names[plane]), " ", \ 3058 dispc_read_reg(DISPC_REG(plane, name, i))) 3059 3060 /* Video pipeline coefficient registers */ 3061 3062 /* start from OMAP_DSS_VIDEO1 */ 3063 for (i = 1; i < dss_feat_get_num_ovls(); i++) { 3064 for (j = 0; j < 8; j++) 3065 DUMPREG(i, DISPC_OVL_FIR_COEF_H, j); 3066 3067 for (j = 0; j < 8; j++) 3068 DUMPREG(i, DISPC_OVL_FIR_COEF_HV, j); 3069 3070 for (j = 0; j < 5; j++) 3071 DUMPREG(i, DISPC_OVL_CONV_COEF, j); 3072 3073 if (dss_has_feature(FEAT_FIR_COEF_V)) { 3074 for (j = 0; j < 8; j++) 3075 DUMPREG(i, DISPC_OVL_FIR_COEF_V, j); 3076 } 3077 3078 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { 3079 for (j = 0; j < 8; j++) 3080 DUMPREG(i, DISPC_OVL_FIR_COEF_H2, j); 3081 3082 for (j = 0; j < 8; j++) 3083 DUMPREG(i, DISPC_OVL_FIR_COEF_HV2, j); 3084 3085 for (j = 0; j < 8; j++) 3086 DUMPREG(i, DISPC_OVL_FIR_COEF_V2, j); 3087 } 3088 } 3089 3090 dispc_runtime_put(); 3091 3092#undef DISPC_REG 3093#undef DUMPREG 3094} 3095 3096static void _dispc_mgr_set_pol_freq(enum omap_channel channel, bool onoff, 3097 bool rf, bool ieo, bool ipc, bool ihs, bool ivs, u8 acbi, 3098 u8 acb) 3099{ 3100 u32 l = 0; 3101 3102 DSSDBG("onoff %d rf %d ieo %d ipc %d ihs %d ivs %d acbi %d acb %d\n", 3103 onoff, rf, ieo, ipc, ihs, ivs, acbi, acb); 3104 3105 l |= FLD_VAL(onoff, 17, 17); 3106 l |= FLD_VAL(rf, 16, 16); 3107 l |= FLD_VAL(ieo, 15, 15); 3108 l |= FLD_VAL(ipc, 14, 14); 3109 l |= FLD_VAL(ihs, 13, 13); 3110 l |= FLD_VAL(ivs, 12, 12); 3111 l |= FLD_VAL(acbi, 11, 8); 3112 l |= FLD_VAL(acb, 7, 0); 3113 3114 dispc_write_reg(DISPC_POL_FREQ(channel), l); 3115} 3116 3117void dispc_mgr_set_pol_freq(enum omap_channel channel, 3118 enum omap_panel_config config, u8 acbi, u8 acb) 3119{ 3120 _dispc_mgr_set_pol_freq(channel, (config & OMAP_DSS_LCD_ONOFF) != 0, 3121 (config & OMAP_DSS_LCD_RF) != 0, 3122 (config & OMAP_DSS_LCD_IEO) != 0, 3123 (config & OMAP_DSS_LCD_IPC) != 0, 3124 (config & OMAP_DSS_LCD_IHS) != 0, 3125 (config & OMAP_DSS_LCD_IVS) != 0, 3126 acbi, acb); 3127} 3128 3129/* with fck as input clock rate, find dispc dividers that produce req_pck */ 3130void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck, 3131 struct dispc_clock_info *cinfo) 3132{ 3133 u16 pcd_min, pcd_max; 3134 unsigned long best_pck; 3135 u16 best_ld, cur_ld; 3136 u16 best_pd, cur_pd; 3137 3138 pcd_min = dss_feat_get_param_min(FEAT_PARAM_DSS_PCD); 3139 pcd_max = dss_feat_get_param_max(FEAT_PARAM_DSS_PCD); 3140 3141 if (!is_tft) 3142 pcd_min = 3; 3143 3144 best_pck = 0; 3145 best_ld = 0; 3146 best_pd = 0; 3147 3148 for (cur_ld = 1; cur_ld <= 255; ++cur_ld) { 3149 unsigned long lck = fck / cur_ld; 3150 3151 for (cur_pd = pcd_min; cur_pd <= pcd_max; ++cur_pd) { 3152 unsigned long pck = lck / cur_pd; 3153 long old_delta = abs(best_pck - req_pck); 3154 long new_delta = abs(pck - req_pck); 3155 3156 if (best_pck == 0 || new_delta < old_delta) { 3157 best_pck = pck; 3158 best_ld = cur_ld; 3159 best_pd = cur_pd; 3160 3161 if (pck == req_pck) 3162 goto found; 3163 } 3164 3165 if (pck < req_pck) 3166 break; 3167 } 3168 3169 if (lck / pcd_min < req_pck) 3170 break; 3171 } 3172 3173found: 3174 cinfo->lck_div = best_ld; 3175 cinfo->pck_div = best_pd; 3176 cinfo->lck = fck / cinfo->lck_div; 3177 cinfo->pck = cinfo->lck / cinfo->pck_div; 3178} 3179 3180/* calculate clock rates using dividers in cinfo */ 3181int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, 3182 struct dispc_clock_info *cinfo) 3183{ 3184 if (cinfo->lck_div > 255 || cinfo->lck_div == 0) 3185 return -EINVAL; 3186 if (cinfo->pck_div < 1 || cinfo->pck_div > 255) 3187 return -EINVAL; 3188 3189 cinfo->lck = dispc_fclk_rate / cinfo->lck_div; 3190 cinfo->pck = cinfo->lck / cinfo->pck_div; 3191 3192 return 0; 3193} 3194 3195int dispc_mgr_set_clock_div(enum omap_channel channel, 3196 struct dispc_clock_info *cinfo) 3197{ 3198 DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div); 3199 DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div); 3200 3201 dispc_mgr_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div); 3202 3203 return 0; 3204} 3205 3206int dispc_mgr_get_clock_div(enum omap_channel channel, 3207 struct dispc_clock_info *cinfo) 3208{ 3209 unsigned long fck; 3210 3211 fck = dispc_fclk_rate(); 3212 3213 cinfo->lck_div = REG_GET(DISPC_DIVISORo(channel), 23, 16); 3214 cinfo->pck_div = REG_GET(DISPC_DIVISORo(channel), 7, 0); 3215 3216 cinfo->lck = fck / cinfo->lck_div; 3217 cinfo->pck = cinfo->lck / cinfo->pck_div; 3218 3219 return 0; 3220} 3221 3222/* dispc.irq_lock has to be locked by the caller */ 3223static void _omap_dispc_set_irqs(void) 3224{ 3225 u32 mask; 3226 u32 old_mask; 3227 int i; 3228 struct omap_dispc_isr_data *isr_data; 3229 3230 mask = dispc.irq_error_mask; 3231 3232 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { 3233 isr_data = &dispc.registered_isr[i]; 3234 3235 if (isr_data->isr == NULL) 3236 continue; 3237 3238 mask |= isr_data->mask; 3239 } 3240 3241 old_mask = dispc_read_reg(DISPC_IRQENABLE); 3242 /* clear the irqstatus for newly enabled irqs */ 3243 dispc_write_reg(DISPC_IRQSTATUS, (mask ^ old_mask) & mask); 3244 3245 dispc_write_reg(DISPC_IRQENABLE, mask); 3246} 3247 3248int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask) 3249{ 3250 int i; 3251 int ret; 3252 unsigned long flags; 3253 struct omap_dispc_isr_data *isr_data; 3254 3255 if (isr == NULL) 3256 return -EINVAL; 3257 3258 spin_lock_irqsave(&dispc.irq_lock, flags); 3259 3260 /* check for duplicate entry */ 3261 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { 3262 isr_data = &dispc.registered_isr[i]; 3263 if (isr_data->isr == isr && isr_data->arg == arg && 3264 isr_data->mask == mask) { 3265 ret = -EINVAL; 3266 goto err; 3267 } 3268 } 3269 3270 isr_data = NULL; 3271 ret = -EBUSY; 3272 3273 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { 3274 isr_data = &dispc.registered_isr[i]; 3275 3276 if (isr_data->isr != NULL) 3277 continue; 3278 3279 isr_data->isr = isr; 3280 isr_data->arg = arg; 3281 isr_data->mask = mask; 3282 ret = 0; 3283 3284 break; 3285 } 3286 3287 if (ret) 3288 goto err; 3289 3290 _omap_dispc_set_irqs(); 3291 3292 spin_unlock_irqrestore(&dispc.irq_lock, flags); 3293 3294 return 0; 3295err: 3296 spin_unlock_irqrestore(&dispc.irq_lock, flags); 3297 3298 return ret; 3299} 3300EXPORT_SYMBOL(omap_dispc_register_isr); 3301 3302int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask) 3303{ 3304 int i; 3305 unsigned long flags; 3306 int ret = -EINVAL; 3307 struct omap_dispc_isr_data *isr_data; 3308 3309 spin_lock_irqsave(&dispc.irq_lock, flags); 3310 3311 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { 3312 isr_data = &dispc.registered_isr[i]; 3313 if (isr_data->isr != isr || isr_data->arg != arg || 3314 isr_data->mask != mask) 3315 continue; 3316 3317 /* found the correct isr */ 3318 3319 isr_data->isr = NULL; 3320 isr_data->arg = NULL; 3321 isr_data->mask = 0; 3322 3323 ret = 0; 3324 break; 3325 } 3326 3327 if (ret == 0) 3328 _omap_dispc_set_irqs(); 3329 3330 spin_unlock_irqrestore(&dispc.irq_lock, flags); 3331 3332 return ret; 3333} 3334EXPORT_SYMBOL(omap_dispc_unregister_isr); 3335 3336#ifdef DEBUG 3337static void print_irq_status(u32 status) 3338{ 3339 if ((status & dispc.irq_error_mask) == 0) 3340 return; 3341 3342 printk(KERN_DEBUG "DISPC IRQ: 0x%x: ", status); 3343 3344#define PIS(x) \ 3345 if (status & DISPC_IRQ_##x) \ 3346 printk(#x " "); 3347 PIS(GFX_FIFO_UNDERFLOW); 3348 PIS(OCP_ERR); 3349 PIS(VID1_FIFO_UNDERFLOW); 3350 PIS(VID2_FIFO_UNDERFLOW); 3351 if (dss_feat_get_num_ovls() > 3) 3352 PIS(VID3_FIFO_UNDERFLOW); 3353 PIS(SYNC_LOST); 3354 PIS(SYNC_LOST_DIGIT); 3355 if (dss_has_feature(FEAT_MGR_LCD2)) 3356 PIS(SYNC_LOST2); 3357#undef PIS 3358 3359 printk("\n"); 3360} 3361#endif 3362 3363/* Called from dss.c. Note that we don't touch clocks here, 3364 * but we presume they are on because we got an IRQ. However, 3365 * an irq handler may turn the clocks off, so we may not have 3366 * clock later in the function. */ 3367static irqreturn_t omap_dispc_irq_handler(int irq, void *arg) 3368{ 3369 int i; 3370 u32 irqstatus, irqenable; 3371 u32 handledirqs = 0; 3372 u32 unhandled_errors; 3373 struct omap_dispc_isr_data *isr_data; 3374 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS]; 3375 3376 spin_lock(&dispc.irq_lock); 3377 3378 irqstatus = dispc_read_reg(DISPC_IRQSTATUS); 3379 irqenable = dispc_read_reg(DISPC_IRQENABLE); 3380 3381 /* IRQ is not for us */ 3382 if (!(irqstatus & irqenable)) { 3383 spin_unlock(&dispc.irq_lock); 3384 return IRQ_NONE; 3385 } 3386 3387#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS 3388 spin_lock(&dispc.irq_stats_lock); 3389 dispc.irq_stats.irq_count++; 3390 dss_collect_irq_stats(irqstatus, dispc.irq_stats.irqs); 3391 spin_unlock(&dispc.irq_stats_lock); 3392#endif 3393 3394#ifdef DEBUG 3395 if (dss_debug) 3396 print_irq_status(irqstatus); 3397#endif 3398 /* Ack the interrupt. Do it here before clocks are possibly turned 3399 * off */ 3400 dispc_write_reg(DISPC_IRQSTATUS, irqstatus); 3401 /* flush posted write */ 3402 dispc_read_reg(DISPC_IRQSTATUS); 3403 3404 /* make a copy and unlock, so that isrs can unregister 3405 * themselves */ 3406 memcpy(registered_isr, dispc.registered_isr, 3407 sizeof(registered_isr)); 3408 3409 spin_unlock(&dispc.irq_lock); 3410 3411 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { 3412 isr_data = &registered_isr[i]; 3413 3414 if (!isr_data->isr) 3415 continue; 3416 3417 if (isr_data->mask & irqstatus) { 3418 isr_data->isr(isr_data->arg, irqstatus); 3419 handledirqs |= isr_data->mask; 3420 } 3421 } 3422 3423 spin_lock(&dispc.irq_lock); 3424 3425 unhandled_errors = irqstatus & ~handledirqs & dispc.irq_error_mask; 3426 3427 if (unhandled_errors) { 3428 dispc.error_irqs |= unhandled_errors; 3429 3430 dispc.irq_error_mask &= ~unhandled_errors; 3431 _omap_dispc_set_irqs(); 3432 3433 schedule_work(&dispc.error_work); 3434 } 3435 3436 spin_unlock(&dispc.irq_lock); 3437 3438 return IRQ_HANDLED; 3439} 3440 3441static void dispc_error_worker(struct work_struct *work) 3442{ 3443 int i; 3444 u32 errors; 3445 unsigned long flags; 3446 static const unsigned fifo_underflow_bits[] = { 3447 DISPC_IRQ_GFX_FIFO_UNDERFLOW, 3448 DISPC_IRQ_VID1_FIFO_UNDERFLOW, 3449 DISPC_IRQ_VID2_FIFO_UNDERFLOW, 3450 DISPC_IRQ_VID3_FIFO_UNDERFLOW, 3451 }; 3452 3453 static const unsigned sync_lost_bits[] = { 3454 DISPC_IRQ_SYNC_LOST, 3455 DISPC_IRQ_SYNC_LOST_DIGIT, 3456 DISPC_IRQ_SYNC_LOST2, 3457 }; 3458 3459 spin_lock_irqsave(&dispc.irq_lock, flags); 3460 errors = dispc.error_irqs; 3461 dispc.error_irqs = 0; 3462 spin_unlock_irqrestore(&dispc.irq_lock, flags); 3463 3464 dispc_runtime_get(); 3465 3466 for (i = 0; i < omap_dss_get_num_overlays(); ++i) { 3467 struct omap_overlay *ovl; 3468 unsigned bit; 3469 3470 ovl = omap_dss_get_overlay(i); 3471 bit = fifo_underflow_bits[i]; 3472 3473 if (bit & errors) { 3474 DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n", 3475 ovl->name); 3476 dispc_ovl_enable(ovl->id, false); 3477 dispc_mgr_go(ovl->manager->id); 3478 mdelay(50); 3479 } 3480 } 3481 3482 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { 3483 struct omap_overlay_manager *mgr; 3484 unsigned bit; 3485 3486 mgr = omap_dss_get_overlay_manager(i); 3487 bit = sync_lost_bits[i]; 3488 3489 if (bit & errors) { 3490 struct omap_dss_device *dssdev = mgr->device; 3491 bool enable; 3492 3493 DSSERR("SYNC_LOST on channel %s, restarting the output " 3494 "with video overlays disabled\n", 3495 mgr->name); 3496 3497 enable = dssdev->state == OMAP_DSS_DISPLAY_ACTIVE; 3498 dssdev->driver->disable(dssdev); 3499 3500 for (i = 0; i < omap_dss_get_num_overlays(); ++i) { 3501 struct omap_overlay *ovl; 3502 ovl = omap_dss_get_overlay(i); 3503 3504 if (ovl->id != OMAP_DSS_GFX && 3505 ovl->manager == mgr) 3506 dispc_ovl_enable(ovl->id, false); 3507 } 3508 3509 dispc_mgr_go(mgr->id); 3510 mdelay(50); 3511 3512 if (enable) 3513 dssdev->driver->enable(dssdev); 3514 } 3515 } 3516 3517 if (errors & DISPC_IRQ_OCP_ERR) { 3518 DSSERR("OCP_ERR\n"); 3519 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { 3520 struct omap_overlay_manager *mgr; 3521 mgr = omap_dss_get_overlay_manager(i); 3522 if (mgr->device && mgr->device->driver) 3523 mgr->device->driver->disable(mgr->device); 3524 } 3525 } 3526 3527 spin_lock_irqsave(&dispc.irq_lock, flags); 3528 dispc.irq_error_mask |= errors; 3529 _omap_dispc_set_irqs(); 3530 spin_unlock_irqrestore(&dispc.irq_lock, flags); 3531 3532 dispc_runtime_put(); 3533} 3534 3535int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout) 3536{ 3537 void dispc_irq_wait_handler(void *data, u32 mask) 3538 { 3539 complete((struct completion *)data); 3540 } 3541 3542 int r; 3543 DECLARE_COMPLETION_ONSTACK(completion); 3544 3545 r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion, 3546 irqmask); 3547 3548 if (r) 3549 return r; 3550 3551 timeout = wait_for_completion_timeout(&completion, timeout); 3552 3553 omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask); 3554 3555 if (timeout == 0) 3556 return -ETIMEDOUT; 3557 3558 if (timeout == -ERESTARTSYS) 3559 return -ERESTARTSYS; 3560 3561 return 0; 3562} 3563 3564int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask, 3565 unsigned long timeout) 3566{ 3567 void dispc_irq_wait_handler(void *data, u32 mask) 3568 { 3569 complete((struct completion *)data); 3570 } 3571 3572 int r; 3573 DECLARE_COMPLETION_ONSTACK(completion); 3574 3575 r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion, 3576 irqmask); 3577 3578 if (r) 3579 return r; 3580 3581 timeout = wait_for_completion_interruptible_timeout(&completion, 3582 timeout); 3583 3584 omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask); 3585 3586 if (timeout == 0) 3587 return -ETIMEDOUT; 3588 3589 if (timeout == -ERESTARTSYS) 3590 return -ERESTARTSYS; 3591 3592 return 0; 3593} 3594 3595static void _omap_dispc_initialize_irq(void) 3596{ 3597 unsigned long flags; 3598 3599 spin_lock_irqsave(&dispc.irq_lock, flags); 3600 3601 memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr)); 3602 3603 dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR; 3604 if (dss_has_feature(FEAT_MGR_LCD2)) 3605 dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2; 3606 if (dss_feat_get_num_ovls() > 3) 3607 dispc.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW; 3608 3609 /* there's SYNC_LOST_DIGIT waiting after enabling the DSS, 3610 * so clear it */ 3611 dispc_write_reg(DISPC_IRQSTATUS, dispc_read_reg(DISPC_IRQSTATUS)); 3612 3613 _omap_dispc_set_irqs(); 3614 3615 spin_unlock_irqrestore(&dispc.irq_lock, flags); 3616} 3617 3618void dispc_enable_sidle(void) 3619{ 3620 REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3); /* SIDLEMODE: smart idle */ 3621} 3622 3623void dispc_disable_sidle(void) 3624{ 3625 REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */ 3626} 3627 3628static void _omap_dispc_initial_config(void) 3629{ 3630 u32 l; 3631 3632 /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */ 3633 if (dss_has_feature(FEAT_CORE_CLK_DIV)) { 3634 l = dispc_read_reg(DISPC_DIVISOR); 3635 /* Use DISPC_DIVISOR.LCD, instead of DISPC_DIVISOR1.LCD */ 3636 l = FLD_MOD(l, 1, 0, 0); 3637 l = FLD_MOD(l, 1, 23, 16); 3638 dispc_write_reg(DISPC_DIVISOR, l); 3639 } 3640 3641 /* FUNCGATED */ 3642 if (dss_has_feature(FEAT_FUNCGATED)) 3643 REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); 3644 3645 _dispc_setup_color_conv_coef(); 3646 3647 dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY); 3648 3649 dispc_read_plane_fifo_sizes(); 3650 3651 dispc_configure_burst_sizes(); 3652 3653 dispc_ovl_enable_zorder_planes(); 3654} 3655 3656/* DISPC HW IP initialisation */ 3657static int __init omap_dispchw_probe(struct platform_device *pdev) 3658{ 3659 u32 rev; 3660 int r = 0; 3661 struct resource *dispc_mem; 3662 struct clk *clk; 3663 3664 dispc.pdev = pdev; 3665 3666 spin_lock_init(&dispc.irq_lock); 3667 3668#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS 3669 spin_lock_init(&dispc.irq_stats_lock); 3670 dispc.irq_stats.last_reset = jiffies; 3671#endif 3672 3673 INIT_WORK(&dispc.error_work, dispc_error_worker); 3674 3675 dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0); 3676 if (!dispc_mem) { 3677 DSSERR("can't get IORESOURCE_MEM DISPC\n"); 3678 return -EINVAL; 3679 } 3680 3681 dispc.base = devm_ioremap(&pdev->dev, dispc_mem->start, 3682 resource_size(dispc_mem)); 3683 if (!dispc.base) { 3684 DSSERR("can't ioremap DISPC\n"); 3685 return -ENOMEM; 3686 } 3687 3688 dispc.irq = platform_get_irq(dispc.pdev, 0); 3689 if (dispc.irq < 0) { 3690 DSSERR("platform_get_irq failed\n"); 3691 return -ENODEV; 3692 } 3693 3694 r = devm_request_irq(&pdev->dev, dispc.irq, omap_dispc_irq_handler, 3695 IRQF_SHARED, "OMAP DISPC", dispc.pdev); 3696 if (r < 0) { 3697 DSSERR("request_irq failed\n"); 3698 return r; 3699 } 3700 3701 clk = clk_get(&pdev->dev, "fck"); 3702 if (IS_ERR(clk)) { 3703 DSSERR("can't get fck\n"); 3704 r = PTR_ERR(clk); 3705 return r; 3706 } 3707 3708 dispc.dss_clk = clk; 3709 3710 pm_runtime_enable(&pdev->dev); 3711 3712 r = dispc_runtime_get(); 3713 if (r) 3714 goto err_runtime_get; 3715 3716 _omap_dispc_initial_config(); 3717 3718 _omap_dispc_initialize_irq(); 3719 3720 rev = dispc_read_reg(DISPC_REVISION); 3721 dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n", 3722 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); 3723 3724 dispc_runtime_put(); 3725 3726 dss_debugfs_create_file("dispc", dispc_dump_regs); 3727 3728#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS 3729 dss_debugfs_create_file("dispc_irq", dispc_dump_irqs); 3730#endif 3731 return 0; 3732 3733err_runtime_get: 3734 pm_runtime_disable(&pdev->dev); 3735 clk_put(dispc.dss_clk); 3736 return r; 3737} 3738 3739static int __exit omap_dispchw_remove(struct platform_device *pdev) 3740{ 3741 pm_runtime_disable(&pdev->dev); 3742 3743 clk_put(dispc.dss_clk); 3744 3745 return 0; 3746} 3747 3748static int dispc_runtime_suspend(struct device *dev) 3749{ 3750 dispc_save_context(); 3751 3752 return 0; 3753} 3754 3755static int dispc_runtime_resume(struct device *dev) 3756{ 3757 dispc_restore_context(); 3758 3759 return 0; 3760} 3761 3762static const struct dev_pm_ops dispc_pm_ops = { 3763 .runtime_suspend = dispc_runtime_suspend, 3764 .runtime_resume = dispc_runtime_resume, 3765}; 3766 3767static struct platform_driver omap_dispchw_driver = { 3768 .remove = __exit_p(omap_dispchw_remove), 3769 .driver = { 3770 .name = "omapdss_dispc", 3771 .owner = THIS_MODULE, 3772 .pm = &dispc_pm_ops, 3773 }, 3774}; 3775 3776int __init dispc_init_platform_driver(void) 3777{ 3778 return platform_driver_probe(&omap_dispchw_driver, omap_dispchw_probe); 3779} 3780 3781void __exit dispc_uninit_platform_driver(void) 3782{ 3783 platform_driver_unregister(&omap_dispchw_driver); 3784}