1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2009 Nokia Corporation 4 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> 5 * 6 * Some code and ideas taken from drivers/video/omap/ driver 7 * by Imre Deak. 8 */ 9 10 #define DSS_SUBSYS_NAME "DISPC" 11 12 #include <linux/kernel.h> 13 #include <linux/dma-mapping.h> 14 #include <linux/vmalloc.h> 15 #include <linux/export.h> 16 #include <linux/clk.h> 17 #include <linux/io.h> 18 #include <linux/jiffies.h> 19 #include <linux/seq_file.h> 20 #include <linux/delay.h> 21 #include <linux/workqueue.h> 22 #include <linux/hardirq.h> 23 #include <linux/platform_device.h> 24 #include <linux/pm_runtime.h> 25 #include <linux/sizes.h> 26 #include <linux/mfd/syscon.h> 27 #include <linux/regmap.h> 28 #include <linux/of.h> 29 #include <linux/of_device.h> 30 #include <linux/component.h> 31 #include <linux/sys_soc.h> 32 #include <drm/drm_fourcc.h> 33 #include <drm/drm_blend.h> 34 35 #include "omapdss.h" 36 #include "dss.h" 37 #include "dispc.h" 38 39 struct dispc_device; 40 41 /* DISPC */ 42 #define DISPC_SZ_REGS SZ_4K 43 44 enum omap_burst_size { 45 BURST_SIZE_X2 = 0, 46 BURST_SIZE_X4 = 1, 47 BURST_SIZE_X8 = 2, 48 }; 49 50 #define REG_GET(dispc, idx, start, end) \ 51 FLD_GET(dispc_read_reg(dispc, idx), start, end) 52 53 #define REG_FLD_MOD(dispc, idx, val, start, end) \ 54 dispc_write_reg(dispc, idx, \ 55 FLD_MOD(dispc_read_reg(dispc, idx), val, start, end)) 56 57 /* DISPC has feature id */ 58 enum dispc_feature_id { 59 FEAT_LCDENABLEPOL, 60 FEAT_LCDENABLESIGNAL, 61 FEAT_PCKFREEENABLE, 62 FEAT_FUNCGATED, 63 FEAT_MGR_LCD2, 64 FEAT_MGR_LCD3, 65 FEAT_LINEBUFFERSPLIT, 66 FEAT_ROWREPEATENABLE, 67 FEAT_RESIZECONF, 68 /* Independent core clk divider */ 69 FEAT_CORE_CLK_DIV, 70 FEAT_HANDLE_UV_SEPARATE, 71 FEAT_ATTR2, 72 FEAT_CPR, 73 FEAT_PRELOAD, 74 FEAT_FIR_COEF_V, 75 FEAT_ALPHA_FIXED_ZORDER, 76 FEAT_ALPHA_FREE_ZORDER, 77 FEAT_FIFO_MERGE, 78 /* An unknown HW bug causing the normal FIFO thresholds not to work */ 79 FEAT_OMAP3_DSI_FIFO_BUG, 80 FEAT_BURST_2D, 81 FEAT_MFLAG, 82 }; 83 84 struct dispc_features { 85 u8 sw_start; 86 u8 fp_start; 87 u8 bp_start; 88 u16 sw_max; 89 u16 vp_max; 90 u16 hp_max; 91 u8 mgr_width_start; 92 u8 mgr_height_start; 93 u16 mgr_width_max; 94 u16 mgr_height_max; 95 unsigned long max_lcd_pclk; 96 unsigned long max_tv_pclk; 97 unsigned int max_downscale; 98 unsigned int max_line_width; 99 unsigned int min_pcd; 100 int (*calc_scaling)(struct dispc_device *dispc, 101 unsigned long pclk, unsigned long lclk, 102 const struct videomode *vm, 103 u16 width, u16 height, u16 out_width, u16 out_height, 104 u32 fourcc, bool *five_taps, 105 int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, 106 u16 pos_x, unsigned long *core_clk, bool mem_to_mem); 107 unsigned long (*calc_core_clk) (unsigned long pclk, 108 u16 width, u16 height, u16 out_width, u16 out_height, 109 bool mem_to_mem); 110 u8 num_fifos; 111 const enum dispc_feature_id *features; 112 unsigned int num_features; 113 const struct dss_reg_field *reg_fields; 114 const unsigned int num_reg_fields; 115 const enum omap_overlay_caps *overlay_caps; 116 const u32 **supported_color_modes; 117 unsigned int num_mgrs; 118 unsigned int num_ovls; 119 unsigned int buffer_size_unit; 120 unsigned int burst_size_unit; 121 122 /* swap GFX & WB fifos */ 123 bool gfx_fifo_workaround:1; 124 125 /* no DISPC_IRQ_FRAMEDONETV on this SoC */ 126 bool no_framedone_tv:1; 127 128 /* revert to the OMAP4 mechanism of DISPC Smart Standby operation */ 129 bool mstandby_workaround:1; 130 131 bool set_max_preload:1; 132 133 /* PIXEL_INC is not added to the last pixel of a line */ 134 bool last_pixel_inc_missing:1; 135 136 /* POL_FREQ has ALIGN bit */ 137 bool supports_sync_align:1; 138 139 bool has_writeback:1; 140 141 bool supports_double_pixel:1; 142 143 /* 144 * Field order for VENC is different than HDMI. We should handle this in 145 * some intelligent manner, but as the SoCs have either HDMI or VENC, 146 * never both, we can just use this flag for now. 147 */ 148 bool reverse_ilace_field_order:1; 149 150 bool has_gamma_table:1; 151 152 bool has_gamma_i734_bug:1; 153 }; 154 155 #define DISPC_MAX_NR_FIFOS 5 156 #define DISPC_MAX_CHANNEL_GAMMA 4 157 158 struct dispc_device { 159 struct platform_device *pdev; 160 void __iomem *base; 161 struct dss_device *dss; 162 163 struct dss_debugfs_entry *debugfs; 164 165 int irq; 166 irq_handler_t user_handler; 167 void *user_data; 168 169 unsigned long core_clk_rate; 170 unsigned long tv_pclk_rate; 171 172 u32 fifo_size[DISPC_MAX_NR_FIFOS]; 173 /* maps which plane is using a fifo. fifo-id -> plane-id */ 174 int fifo_assignment[DISPC_MAX_NR_FIFOS]; 175 176 bool ctx_valid; 177 u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; 178 179 u32 *gamma_table[DISPC_MAX_CHANNEL_GAMMA]; 180 181 const struct dispc_features *feat; 182 183 bool is_enabled; 184 185 struct regmap *syscon_pol; 186 u32 syscon_pol_offset; 187 188 /* DISPC_CONTROL & DISPC_CONFIG lock*/ 189 spinlock_t control_lock; 190 }; 191 192 enum omap_color_component { 193 /* used for all color formats for OMAP3 and earlier 194 * and for RGB and Y color component on OMAP4 195 */ 196 DISPC_COLOR_COMPONENT_RGB_Y = 1 << 0, 197 /* used for UV component for 198 * DRM_FORMAT_YUYV, DRM_FORMAT_UYVY, DRM_FORMAT_NV12 199 * color formats on OMAP4 200 */ 201 DISPC_COLOR_COMPONENT_UV = 1 << 1, 202 }; 203 204 enum mgr_reg_fields { 205 DISPC_MGR_FLD_ENABLE, 206 DISPC_MGR_FLD_STNTFT, 207 DISPC_MGR_FLD_GO, 208 DISPC_MGR_FLD_TFTDATALINES, 209 DISPC_MGR_FLD_STALLMODE, 210 DISPC_MGR_FLD_TCKENABLE, 211 DISPC_MGR_FLD_TCKSELECTION, 212 DISPC_MGR_FLD_CPR, 213 DISPC_MGR_FLD_FIFOHANDCHECK, 214 /* used to maintain a count of the above fields */ 215 DISPC_MGR_FLD_NUM, 216 }; 217 218 /* DISPC register field id */ 219 enum dispc_feat_reg_field { 220 FEAT_REG_FIRHINC, 221 FEAT_REG_FIRVINC, 222 FEAT_REG_FIFOHIGHTHRESHOLD, 223 FEAT_REG_FIFOLOWTHRESHOLD, 224 FEAT_REG_FIFOSIZE, 225 FEAT_REG_HORIZONTALACCU, 226 FEAT_REG_VERTICALACCU, 227 }; 228 229 struct dispc_reg_field { 230 u16 reg; 231 u8 high; 232 u8 low; 233 }; 234 235 struct dispc_gamma_desc { 236 u32 len; 237 u32 bits; 238 u16 reg; 239 bool has_index; 240 }; 241 242 static const struct { 243 const char *name; 244 u32 vsync_irq; 245 u32 framedone_irq; 246 u32 sync_lost_irq; 247 struct dispc_gamma_desc gamma; 248 struct dispc_reg_field reg_desc[DISPC_MGR_FLD_NUM]; 249 } mgr_desc[] = { 250 [OMAP_DSS_CHANNEL_LCD] = { 251 .name = "LCD", 252 .vsync_irq = DISPC_IRQ_VSYNC, 253 .framedone_irq = DISPC_IRQ_FRAMEDONE, 254 .sync_lost_irq = DISPC_IRQ_SYNC_LOST, 255 .gamma = { 256 .len = 256, 257 .bits = 8, 258 .reg = DISPC_GAMMA_TABLE0, 259 .has_index = true, 260 }, 261 .reg_desc = { 262 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 0, 0 }, 263 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL, 3, 3 }, 264 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL, 5, 5 }, 265 [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL, 9, 8 }, 266 [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL, 11, 11 }, 267 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG, 10, 10 }, 268 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG, 11, 11 }, 269 [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG, 15, 15 }, 270 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG, 16, 16 }, 271 }, 272 }, 273 [OMAP_DSS_CHANNEL_DIGIT] = { 274 .name = "DIGIT", 275 .vsync_irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN, 276 .framedone_irq = DISPC_IRQ_FRAMEDONETV, 277 .sync_lost_irq = DISPC_IRQ_SYNC_LOST_DIGIT, 278 .gamma = { 279 .len = 1024, 280 .bits = 10, 281 .reg = DISPC_GAMMA_TABLE2, 282 .has_index = false, 283 }, 284 .reg_desc = { 285 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 1, 1 }, 286 [DISPC_MGR_FLD_STNTFT] = { }, 287 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL, 6, 6 }, 288 [DISPC_MGR_FLD_TFTDATALINES] = { }, 289 [DISPC_MGR_FLD_STALLMODE] = { }, 290 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG, 12, 12 }, 291 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG, 13, 13 }, 292 [DISPC_MGR_FLD_CPR] = { }, 293 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG, 16, 16 }, 294 }, 295 }, 296 [OMAP_DSS_CHANNEL_LCD2] = { 297 .name = "LCD2", 298 .vsync_irq = DISPC_IRQ_VSYNC2, 299 .framedone_irq = DISPC_IRQ_FRAMEDONE2, 300 .sync_lost_irq = DISPC_IRQ_SYNC_LOST2, 301 .gamma = { 302 .len = 256, 303 .bits = 8, 304 .reg = DISPC_GAMMA_TABLE1, 305 .has_index = true, 306 }, 307 .reg_desc = { 308 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL2, 0, 0 }, 309 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL2, 3, 3 }, 310 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL2, 5, 5 }, 311 [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL2, 9, 8 }, 312 [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL2, 11, 11 }, 313 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG2, 10, 10 }, 314 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG2, 11, 11 }, 315 [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG2, 15, 15 }, 316 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG2, 16, 16 }, 317 }, 318 }, 319 [OMAP_DSS_CHANNEL_LCD3] = { 320 .name = "LCD3", 321 .vsync_irq = DISPC_IRQ_VSYNC3, 322 .framedone_irq = DISPC_IRQ_FRAMEDONE3, 323 .sync_lost_irq = DISPC_IRQ_SYNC_LOST3, 324 .gamma = { 325 .len = 256, 326 .bits = 8, 327 .reg = DISPC_GAMMA_TABLE3, 328 .has_index = true, 329 }, 330 .reg_desc = { 331 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL3, 0, 0 }, 332 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL3, 3, 3 }, 333 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL3, 5, 5 }, 334 [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL3, 9, 8 }, 335 [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL3, 11, 11 }, 336 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG3, 10, 10 }, 337 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG3, 11, 11 }, 338 [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG3, 15, 15 }, 339 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG3, 16, 16 }, 340 }, 341 }, 342 }; 343 344 static unsigned long dispc_fclk_rate(struct dispc_device *dispc); 345 static unsigned long dispc_core_clk_rate(struct dispc_device *dispc); 346 static unsigned long dispc_mgr_lclk_rate(struct dispc_device *dispc, 347 enum omap_channel channel); 348 static unsigned long dispc_mgr_pclk_rate(struct dispc_device *dispc, 349 enum omap_channel channel); 350 351 static unsigned long dispc_plane_pclk_rate(struct dispc_device *dispc, 352 enum omap_plane_id plane); 353 static unsigned long dispc_plane_lclk_rate(struct dispc_device *dispc, 354 enum omap_plane_id plane); 355 356 static void dispc_clear_irqstatus(struct dispc_device *dispc, u32 mask); 357 358 static inline void dispc_write_reg(struct dispc_device *dispc, u16 idx, u32 val) 359 { 360 __raw_writel(val, dispc->base + idx); 361 } 362 363 static inline u32 dispc_read_reg(struct dispc_device *dispc, u16 idx) 364 { 365 return __raw_readl(dispc->base + idx); 366 } 367 368 static u32 mgr_fld_read(struct dispc_device *dispc, enum omap_channel channel, 369 enum mgr_reg_fields regfld) 370 { 371 const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld]; 372 373 return REG_GET(dispc, rfld.reg, rfld.high, rfld.low); 374 } 375 376 static void mgr_fld_write(struct dispc_device *dispc, enum omap_channel channel, 377 enum mgr_reg_fields regfld, int val) 378 { 379 const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld]; 380 const bool need_lock = rfld.reg == DISPC_CONTROL || rfld.reg == DISPC_CONFIG; 381 unsigned long flags; 382 383 if (need_lock) { 384 spin_lock_irqsave(&dispc->control_lock, flags); 385 REG_FLD_MOD(dispc, rfld.reg, val, rfld.high, rfld.low); 386 spin_unlock_irqrestore(&dispc->control_lock, flags); 387 } else { 388 REG_FLD_MOD(dispc, rfld.reg, val, rfld.high, rfld.low); 389 } 390 } 391 392 static int dispc_get_num_ovls(struct dispc_device *dispc) 393 { 394 return dispc->feat->num_ovls; 395 } 396 397 static int dispc_get_num_mgrs(struct dispc_device *dispc) 398 { 399 return dispc->feat->num_mgrs; 400 } 401 402 static void dispc_get_reg_field(struct dispc_device *dispc, 403 enum dispc_feat_reg_field id, 404 u8 *start, u8 *end) 405 { 406 if (id >= dispc->feat->num_reg_fields) 407 BUG(); 408 409 *start = dispc->feat->reg_fields[id].start; 410 *end = dispc->feat->reg_fields[id].end; 411 } 412 413 static bool dispc_has_feature(struct dispc_device *dispc, 414 enum dispc_feature_id id) 415 { 416 unsigned int i; 417 418 for (i = 0; i < dispc->feat->num_features; i++) { 419 if (dispc->feat->features[i] == id) 420 return true; 421 } 422 423 return false; 424 } 425 426 #define SR(dispc, reg) \ 427 dispc->ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(dispc, DISPC_##reg) 428 #define RR(dispc, reg) \ 429 dispc_write_reg(dispc, DISPC_##reg, dispc->ctx[DISPC_##reg / sizeof(u32)]) 430 431 static void dispc_save_context(struct dispc_device *dispc) 432 { 433 int i, j; 434 435 DSSDBG("dispc_save_context\n"); 436 437 SR(dispc, IRQENABLE); 438 SR(dispc, CONTROL); 439 SR(dispc, CONFIG); 440 SR(dispc, LINE_NUMBER); 441 if (dispc_has_feature(dispc, FEAT_ALPHA_FIXED_ZORDER) || 442 dispc_has_feature(dispc, FEAT_ALPHA_FREE_ZORDER)) 443 SR(dispc, GLOBAL_ALPHA); 444 if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) { 445 SR(dispc, CONTROL2); 446 SR(dispc, CONFIG2); 447 } 448 if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) { 449 SR(dispc, CONTROL3); 450 SR(dispc, CONFIG3); 451 } 452 453 for (i = 0; i < dispc_get_num_mgrs(dispc); i++) { 454 SR(dispc, DEFAULT_COLOR(i)); 455 SR(dispc, TRANS_COLOR(i)); 456 SR(dispc, SIZE_MGR(i)); 457 if (i == OMAP_DSS_CHANNEL_DIGIT) 458 continue; 459 SR(dispc, TIMING_H(i)); 460 SR(dispc, TIMING_V(i)); 461 SR(dispc, POL_FREQ(i)); 462 SR(dispc, DIVISORo(i)); 463 464 SR(dispc, DATA_CYCLE1(i)); 465 SR(dispc, DATA_CYCLE2(i)); 466 SR(dispc, DATA_CYCLE3(i)); 467 468 if (dispc_has_feature(dispc, FEAT_CPR)) { 469 SR(dispc, CPR_COEF_R(i)); 470 SR(dispc, CPR_COEF_G(i)); 471 SR(dispc, CPR_COEF_B(i)); 472 } 473 } 474 475 for (i = 0; i < dispc_get_num_ovls(dispc); i++) { 476 SR(dispc, OVL_BA0(i)); 477 SR(dispc, OVL_BA1(i)); 478 SR(dispc, OVL_POSITION(i)); 479 SR(dispc, OVL_SIZE(i)); 480 SR(dispc, OVL_ATTRIBUTES(i)); 481 SR(dispc, OVL_FIFO_THRESHOLD(i)); 482 SR(dispc, OVL_ROW_INC(i)); 483 SR(dispc, OVL_PIXEL_INC(i)); 484 if (dispc_has_feature(dispc, FEAT_PRELOAD)) 485 SR(dispc, OVL_PRELOAD(i)); 486 if (i == OMAP_DSS_GFX) { 487 SR(dispc, OVL_WINDOW_SKIP(i)); 488 SR(dispc, OVL_TABLE_BA(i)); 489 continue; 490 } 491 SR(dispc, OVL_FIR(i)); 492 SR(dispc, OVL_PICTURE_SIZE(i)); 493 SR(dispc, OVL_ACCU0(i)); 494 SR(dispc, OVL_ACCU1(i)); 495 496 for (j = 0; j < 8; j++) 497 SR(dispc, OVL_FIR_COEF_H(i, j)); 498 499 for (j = 0; j < 8; j++) 500 SR(dispc, OVL_FIR_COEF_HV(i, j)); 501 502 for (j = 0; j < 5; j++) 503 SR(dispc, OVL_CONV_COEF(i, j)); 504 505 if (dispc_has_feature(dispc, FEAT_FIR_COEF_V)) { 506 for (j = 0; j < 8; j++) 507 SR(dispc, OVL_FIR_COEF_V(i, j)); 508 } 509 510 if (dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) { 511 SR(dispc, OVL_BA0_UV(i)); 512 SR(dispc, OVL_BA1_UV(i)); 513 SR(dispc, OVL_FIR2(i)); 514 SR(dispc, OVL_ACCU2_0(i)); 515 SR(dispc, OVL_ACCU2_1(i)); 516 517 for (j = 0; j < 8; j++) 518 SR(dispc, OVL_FIR_COEF_H2(i, j)); 519 520 for (j = 0; j < 8; j++) 521 SR(dispc, OVL_FIR_COEF_HV2(i, j)); 522 523 for (j = 0; j < 8; j++) 524 SR(dispc, OVL_FIR_COEF_V2(i, j)); 525 } 526 if (dispc_has_feature(dispc, FEAT_ATTR2)) 527 SR(dispc, OVL_ATTRIBUTES2(i)); 528 } 529 530 if (dispc_has_feature(dispc, FEAT_CORE_CLK_DIV)) 531 SR(dispc, DIVISOR); 532 533 dispc->ctx_valid = true; 534 535 DSSDBG("context saved\n"); 536 } 537 538 static void dispc_restore_context(struct dispc_device *dispc) 539 { 540 int i, j; 541 542 DSSDBG("dispc_restore_context\n"); 543 544 if (!dispc->ctx_valid) 545 return; 546 547 /*RR(dispc, IRQENABLE);*/ 548 /*RR(dispc, CONTROL);*/ 549 RR(dispc, CONFIG); 550 RR(dispc, LINE_NUMBER); 551 if (dispc_has_feature(dispc, FEAT_ALPHA_FIXED_ZORDER) || 552 dispc_has_feature(dispc, FEAT_ALPHA_FREE_ZORDER)) 553 RR(dispc, GLOBAL_ALPHA); 554 if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) 555 RR(dispc, CONFIG2); 556 if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) 557 RR(dispc, CONFIG3); 558 559 for (i = 0; i < dispc_get_num_mgrs(dispc); i++) { 560 RR(dispc, DEFAULT_COLOR(i)); 561 RR(dispc, TRANS_COLOR(i)); 562 RR(dispc, SIZE_MGR(i)); 563 if (i == OMAP_DSS_CHANNEL_DIGIT) 564 continue; 565 RR(dispc, TIMING_H(i)); 566 RR(dispc, TIMING_V(i)); 567 RR(dispc, POL_FREQ(i)); 568 RR(dispc, DIVISORo(i)); 569 570 RR(dispc, DATA_CYCLE1(i)); 571 RR(dispc, DATA_CYCLE2(i)); 572 RR(dispc, DATA_CYCLE3(i)); 573 574 if (dispc_has_feature(dispc, FEAT_CPR)) { 575 RR(dispc, CPR_COEF_R(i)); 576 RR(dispc, CPR_COEF_G(i)); 577 RR(dispc, CPR_COEF_B(i)); 578 } 579 } 580 581 for (i = 0; i < dispc_get_num_ovls(dispc); i++) { 582 RR(dispc, OVL_BA0(i)); 583 RR(dispc, OVL_BA1(i)); 584 RR(dispc, OVL_POSITION(i)); 585 RR(dispc, OVL_SIZE(i)); 586 RR(dispc, OVL_ATTRIBUTES(i)); 587 RR(dispc, OVL_FIFO_THRESHOLD(i)); 588 RR(dispc, OVL_ROW_INC(i)); 589 RR(dispc, OVL_PIXEL_INC(i)); 590 if (dispc_has_feature(dispc, FEAT_PRELOAD)) 591 RR(dispc, OVL_PRELOAD(i)); 592 if (i == OMAP_DSS_GFX) { 593 RR(dispc, OVL_WINDOW_SKIP(i)); 594 RR(dispc, OVL_TABLE_BA(i)); 595 continue; 596 } 597 RR(dispc, OVL_FIR(i)); 598 RR(dispc, OVL_PICTURE_SIZE(i)); 599 RR(dispc, OVL_ACCU0(i)); 600 RR(dispc, OVL_ACCU1(i)); 601 602 for (j = 0; j < 8; j++) 603 RR(dispc, OVL_FIR_COEF_H(i, j)); 604 605 for (j = 0; j < 8; j++) 606 RR(dispc, OVL_FIR_COEF_HV(i, j)); 607 608 for (j = 0; j < 5; j++) 609 RR(dispc, OVL_CONV_COEF(i, j)); 610 611 if (dispc_has_feature(dispc, FEAT_FIR_COEF_V)) { 612 for (j = 0; j < 8; j++) 613 RR(dispc, OVL_FIR_COEF_V(i, j)); 614 } 615 616 if (dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) { 617 RR(dispc, OVL_BA0_UV(i)); 618 RR(dispc, OVL_BA1_UV(i)); 619 RR(dispc, OVL_FIR2(i)); 620 RR(dispc, OVL_ACCU2_0(i)); 621 RR(dispc, OVL_ACCU2_1(i)); 622 623 for (j = 0; j < 8; j++) 624 RR(dispc, OVL_FIR_COEF_H2(i, j)); 625 626 for (j = 0; j < 8; j++) 627 RR(dispc, OVL_FIR_COEF_HV2(i, j)); 628 629 for (j = 0; j < 8; j++) 630 RR(dispc, OVL_FIR_COEF_V2(i, j)); 631 } 632 if (dispc_has_feature(dispc, FEAT_ATTR2)) 633 RR(dispc, OVL_ATTRIBUTES2(i)); 634 } 635 636 if (dispc_has_feature(dispc, FEAT_CORE_CLK_DIV)) 637 RR(dispc, DIVISOR); 638 639 /* enable last, because LCD & DIGIT enable are here */ 640 RR(dispc, CONTROL); 641 if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) 642 RR(dispc, CONTROL2); 643 if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) 644 RR(dispc, CONTROL3); 645 /* clear spurious SYNC_LOST_DIGIT interrupts */ 646 dispc_clear_irqstatus(dispc, DISPC_IRQ_SYNC_LOST_DIGIT); 647 648 /* 649 * enable last so IRQs won't trigger before 650 * the context is fully restored 651 */ 652 RR(dispc, IRQENABLE); 653 654 DSSDBG("context restored\n"); 655 } 656 657 #undef SR 658 #undef RR 659 660 int dispc_runtime_get(struct dispc_device *dispc) 661 { 662 int r; 663 664 DSSDBG("dispc_runtime_get\n"); 665 666 r = pm_runtime_get_sync(&dispc->pdev->dev); 667 WARN_ON(r < 0); 668 return r < 0 ? r : 0; 669 } 670 671 void dispc_runtime_put(struct dispc_device *dispc) 672 { 673 int r; 674 675 DSSDBG("dispc_runtime_put\n"); 676 677 r = pm_runtime_put_sync(&dispc->pdev->dev); 678 WARN_ON(r < 0 && r != -ENOSYS); 679 } 680 681 static u32 dispc_mgr_get_vsync_irq(struct dispc_device *dispc, 682 enum omap_channel channel) 683 { 684 return mgr_desc[channel].vsync_irq; 685 } 686 687 static u32 dispc_mgr_get_framedone_irq(struct dispc_device *dispc, 688 enum omap_channel channel) 689 { 690 if (channel == OMAP_DSS_CHANNEL_DIGIT && dispc->feat->no_framedone_tv) 691 return 0; 692 693 return mgr_desc[channel].framedone_irq; 694 } 695 696 static u32 dispc_mgr_get_sync_lost_irq(struct dispc_device *dispc, 697 enum omap_channel channel) 698 { 699 return mgr_desc[channel].sync_lost_irq; 700 } 701 702 static u32 dispc_wb_get_framedone_irq(struct dispc_device *dispc) 703 { 704 return DISPC_IRQ_FRAMEDONEWB; 705 } 706 707 static void dispc_mgr_enable(struct dispc_device *dispc, 708 enum omap_channel channel, bool enable) 709 { 710 mgr_fld_write(dispc, channel, DISPC_MGR_FLD_ENABLE, enable); 711 /* flush posted write */ 712 mgr_fld_read(dispc, channel, DISPC_MGR_FLD_ENABLE); 713 } 714 715 static bool dispc_mgr_is_enabled(struct dispc_device *dispc, 716 enum omap_channel channel) 717 { 718 return !!mgr_fld_read(dispc, channel, DISPC_MGR_FLD_ENABLE); 719 } 720 721 static bool dispc_mgr_go_busy(struct dispc_device *dispc, 722 enum omap_channel channel) 723 { 724 return mgr_fld_read(dispc, channel, DISPC_MGR_FLD_GO) == 1; 725 } 726 727 static void dispc_mgr_go(struct dispc_device *dispc, enum omap_channel channel) 728 { 729 WARN_ON(!dispc_mgr_is_enabled(dispc, channel)); 730 WARN_ON(dispc_mgr_go_busy(dispc, channel)); 731 732 DSSDBG("GO %s\n", mgr_desc[channel].name); 733 734 mgr_fld_write(dispc, channel, DISPC_MGR_FLD_GO, 1); 735 } 736 737 static bool dispc_wb_go_busy(struct dispc_device *dispc) 738 { 739 return REG_GET(dispc, DISPC_CONTROL2, 6, 6) == 1; 740 } 741 742 static void dispc_wb_go(struct dispc_device *dispc) 743 { 744 enum omap_plane_id plane = OMAP_DSS_WB; 745 bool enable, go; 746 747 enable = REG_GET(dispc, DISPC_OVL_ATTRIBUTES(plane), 0, 0) == 1; 748 749 if (!enable) 750 return; 751 752 go = REG_GET(dispc, DISPC_CONTROL2, 6, 6) == 1; 753 if (go) { 754 DSSERR("GO bit not down for WB\n"); 755 return; 756 } 757 758 REG_FLD_MOD(dispc, DISPC_CONTROL2, 1, 6, 6); 759 } 760 761 static void dispc_ovl_write_firh_reg(struct dispc_device *dispc, 762 enum omap_plane_id plane, int reg, 763 u32 value) 764 { 765 dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_H(plane, reg), value); 766 } 767 768 static void dispc_ovl_write_firhv_reg(struct dispc_device *dispc, 769 enum omap_plane_id plane, int reg, 770 u32 value) 771 { 772 dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_HV(plane, reg), value); 773 } 774 775 static void dispc_ovl_write_firv_reg(struct dispc_device *dispc, 776 enum omap_plane_id plane, int reg, 777 u32 value) 778 { 779 dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_V(plane, reg), value); 780 } 781 782 static void dispc_ovl_write_firh2_reg(struct dispc_device *dispc, 783 enum omap_plane_id plane, int reg, 784 u32 value) 785 { 786 BUG_ON(plane == OMAP_DSS_GFX); 787 788 dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_H2(plane, reg), value); 789 } 790 791 static void dispc_ovl_write_firhv2_reg(struct dispc_device *dispc, 792 enum omap_plane_id plane, int reg, 793 u32 value) 794 { 795 BUG_ON(plane == OMAP_DSS_GFX); 796 797 dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_HV2(plane, reg), value); 798 } 799 800 static void dispc_ovl_write_firv2_reg(struct dispc_device *dispc, 801 enum omap_plane_id plane, int reg, 802 u32 value) 803 { 804 BUG_ON(plane == OMAP_DSS_GFX); 805 806 dispc_write_reg(dispc, DISPC_OVL_FIR_COEF_V2(plane, reg), value); 807 } 808 809 static void dispc_ovl_set_scale_coef(struct dispc_device *dispc, 810 enum omap_plane_id plane, int fir_hinc, 811 int fir_vinc, int five_taps, 812 enum omap_color_component color_comp) 813 { 814 const struct dispc_coef *h_coef, *v_coef; 815 int i; 816 817 h_coef = dispc_ovl_get_scale_coef(fir_hinc, true); 818 v_coef = dispc_ovl_get_scale_coef(fir_vinc, five_taps); 819 820 if (!h_coef || !v_coef) { 821 dev_err(&dispc->pdev->dev, "%s: failed to find scale coefs\n", 822 __func__); 823 return; 824 } 825 826 for (i = 0; i < 8; i++) { 827 u32 h, hv; 828 829 h = FLD_VAL(h_coef[i].hc0_vc00, 7, 0) 830 | FLD_VAL(h_coef[i].hc1_vc0, 15, 8) 831 | FLD_VAL(h_coef[i].hc2_vc1, 23, 16) 832 | FLD_VAL(h_coef[i].hc3_vc2, 31, 24); 833 hv = FLD_VAL(h_coef[i].hc4_vc22, 7, 0) 834 | FLD_VAL(v_coef[i].hc1_vc0, 15, 8) 835 | FLD_VAL(v_coef[i].hc2_vc1, 23, 16) 836 | FLD_VAL(v_coef[i].hc3_vc2, 31, 24); 837 838 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) { 839 dispc_ovl_write_firh_reg(dispc, plane, i, h); 840 dispc_ovl_write_firhv_reg(dispc, plane, i, hv); 841 } else { 842 dispc_ovl_write_firh2_reg(dispc, plane, i, h); 843 dispc_ovl_write_firhv2_reg(dispc, plane, i, hv); 844 } 845 846 } 847 848 if (five_taps) { 849 for (i = 0; i < 8; i++) { 850 u32 v; 851 v = FLD_VAL(v_coef[i].hc0_vc00, 7, 0) 852 | FLD_VAL(v_coef[i].hc4_vc22, 15, 8); 853 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) 854 dispc_ovl_write_firv_reg(dispc, plane, i, v); 855 else 856 dispc_ovl_write_firv2_reg(dispc, plane, i, v); 857 } 858 } 859 } 860 861 struct csc_coef_yuv2rgb { 862 int ry, rcb, rcr, gy, gcb, gcr, by, bcb, bcr; 863 bool full_range; 864 }; 865 866 struct csc_coef_rgb2yuv { 867 int yr, yg, yb, cbr, cbg, cbb, crr, crg, crb; 868 bool full_range; 869 }; 870 871 static void dispc_ovl_write_color_conv_coef(struct dispc_device *dispc, 872 enum omap_plane_id plane, 873 const struct csc_coef_yuv2rgb *ct) 874 { 875 #define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0)) 876 877 dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->rcr, ct->ry)); 878 dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->gy, ct->rcb)); 879 dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->gcb, ct->gcr)); 880 dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->bcr, ct->by)); 881 dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->bcb)); 882 883 REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11); 884 885 #undef CVAL 886 } 887 888 static void dispc_wb_write_color_conv_coef(struct dispc_device *dispc, 889 const struct csc_coef_rgb2yuv *ct) 890 { 891 const enum omap_plane_id plane = OMAP_DSS_WB; 892 893 #define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0)) 894 895 dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->yg, ct->yr)); 896 dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->crr, ct->yb)); 897 dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->crb, ct->crg)); 898 dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->cbg, ct->cbr)); 899 dispc_write_reg(dispc, DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->cbb)); 900 901 REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11); 902 903 #undef CVAL 904 } 905 906 static void dispc_setup_color_conv_coef(struct dispc_device *dispc) 907 { 908 int i; 909 int num_ovl = dispc_get_num_ovls(dispc); 910 911 /* YUV -> RGB, ITU-R BT.601, limited range */ 912 const struct csc_coef_yuv2rgb coefs_yuv2rgb_bt601_lim = { 913 298, 0, 409, /* ry, rcb, rcr */ 914 298, -100, -208, /* gy, gcb, gcr */ 915 298, 516, 0, /* by, bcb, bcr */ 916 false, /* limited range */ 917 }; 918 919 /* RGB -> YUV, ITU-R BT.601, limited range */ 920 const struct csc_coef_rgb2yuv coefs_rgb2yuv_bt601_lim = { 921 66, 129, 25, /* yr, yg, yb */ 922 -38, -74, 112, /* cbr, cbg, cbb */ 923 112, -94, -18, /* crr, crg, crb */ 924 false, /* limited range */ 925 }; 926 927 for (i = 1; i < num_ovl; i++) 928 dispc_ovl_write_color_conv_coef(dispc, i, &coefs_yuv2rgb_bt601_lim); 929 930 if (dispc->feat->has_writeback) 931 dispc_wb_write_color_conv_coef(dispc, &coefs_rgb2yuv_bt601_lim); 932 } 933 934 static void dispc_ovl_set_ba0(struct dispc_device *dispc, 935 enum omap_plane_id plane, u32 paddr) 936 { 937 dispc_write_reg(dispc, DISPC_OVL_BA0(plane), paddr); 938 } 939 940 static void dispc_ovl_set_ba1(struct dispc_device *dispc, 941 enum omap_plane_id plane, u32 paddr) 942 { 943 dispc_write_reg(dispc, DISPC_OVL_BA1(plane), paddr); 944 } 945 946 static void dispc_ovl_set_ba0_uv(struct dispc_device *dispc, 947 enum omap_plane_id plane, u32 paddr) 948 { 949 dispc_write_reg(dispc, DISPC_OVL_BA0_UV(plane), paddr); 950 } 951 952 static void dispc_ovl_set_ba1_uv(struct dispc_device *dispc, 953 enum omap_plane_id plane, u32 paddr) 954 { 955 dispc_write_reg(dispc, DISPC_OVL_BA1_UV(plane), paddr); 956 } 957 958 static void dispc_ovl_set_pos(struct dispc_device *dispc, 959 enum omap_plane_id plane, 960 enum omap_overlay_caps caps, int x, int y) 961 { 962 u32 val; 963 964 if ((caps & OMAP_DSS_OVL_CAP_POS) == 0) 965 return; 966 967 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0); 968 969 dispc_write_reg(dispc, DISPC_OVL_POSITION(plane), val); 970 } 971 972 static void dispc_ovl_set_input_size(struct dispc_device *dispc, 973 enum omap_plane_id plane, int width, 974 int height) 975 { 976 u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); 977 978 if (plane == OMAP_DSS_GFX || plane == OMAP_DSS_WB) 979 dispc_write_reg(dispc, DISPC_OVL_SIZE(plane), val); 980 else 981 dispc_write_reg(dispc, DISPC_OVL_PICTURE_SIZE(plane), val); 982 } 983 984 static void dispc_ovl_set_output_size(struct dispc_device *dispc, 985 enum omap_plane_id plane, int width, 986 int height) 987 { 988 u32 val; 989 990 BUG_ON(plane == OMAP_DSS_GFX); 991 992 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); 993 994 if (plane == OMAP_DSS_WB) 995 dispc_write_reg(dispc, DISPC_OVL_PICTURE_SIZE(plane), val); 996 else 997 dispc_write_reg(dispc, DISPC_OVL_SIZE(plane), val); 998 } 999 1000 static void dispc_ovl_set_zorder(struct dispc_device *dispc, 1001 enum omap_plane_id plane, 1002 enum omap_overlay_caps caps, u8 zorder) 1003 { 1004 if ((caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) 1005 return; 1006 1007 REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26); 1008 } 1009 1010 static void dispc_ovl_enable_zorder_planes(struct dispc_device *dispc) 1011 { 1012 int i; 1013 1014 if (!dispc_has_feature(dispc, FEAT_ALPHA_FREE_ZORDER)) 1015 return; 1016 1017 for (i = 0; i < dispc_get_num_ovls(dispc); i++) 1018 REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(i), 1, 25, 25); 1019 } 1020 1021 static void dispc_ovl_set_pre_mult_alpha(struct dispc_device *dispc, 1022 enum omap_plane_id plane, 1023 enum omap_overlay_caps caps, 1024 bool enable) 1025 { 1026 if ((caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) 1027 return; 1028 1029 REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28); 1030 } 1031 1032 static void dispc_ovl_setup_global_alpha(struct dispc_device *dispc, 1033 enum omap_plane_id plane, 1034 enum omap_overlay_caps caps, 1035 u8 global_alpha) 1036 { 1037 static const unsigned int shifts[] = { 0, 8, 16, 24, }; 1038 int shift; 1039 1040 if ((caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) 1041 return; 1042 1043 shift = shifts[plane]; 1044 REG_FLD_MOD(dispc, DISPC_GLOBAL_ALPHA, global_alpha, shift + 7, shift); 1045 } 1046 1047 static void dispc_ovl_set_pix_inc(struct dispc_device *dispc, 1048 enum omap_plane_id plane, s32 inc) 1049 { 1050 dispc_write_reg(dispc, DISPC_OVL_PIXEL_INC(plane), inc); 1051 } 1052 1053 static void dispc_ovl_set_row_inc(struct dispc_device *dispc, 1054 enum omap_plane_id plane, s32 inc) 1055 { 1056 dispc_write_reg(dispc, DISPC_OVL_ROW_INC(plane), inc); 1057 } 1058 1059 static void dispc_ovl_set_color_mode(struct dispc_device *dispc, 1060 enum omap_plane_id plane, u32 fourcc) 1061 { 1062 u32 m = 0; 1063 if (plane != OMAP_DSS_GFX) { 1064 switch (fourcc) { 1065 case DRM_FORMAT_NV12: 1066 m = 0x0; break; 1067 case DRM_FORMAT_XRGB4444: 1068 m = 0x1; break; 1069 case DRM_FORMAT_RGBA4444: 1070 m = 0x2; break; 1071 case DRM_FORMAT_RGBX4444: 1072 m = 0x4; break; 1073 case DRM_FORMAT_ARGB4444: 1074 m = 0x5; break; 1075 case DRM_FORMAT_RGB565: 1076 m = 0x6; break; 1077 case DRM_FORMAT_ARGB1555: 1078 m = 0x7; break; 1079 case DRM_FORMAT_XRGB8888: 1080 m = 0x8; break; 1081 case DRM_FORMAT_RGB888: 1082 m = 0x9; break; 1083 case DRM_FORMAT_YUYV: 1084 m = 0xa; break; 1085 case DRM_FORMAT_UYVY: 1086 m = 0xb; break; 1087 case DRM_FORMAT_ARGB8888: 1088 m = 0xc; break; 1089 case DRM_FORMAT_RGBA8888: 1090 m = 0xd; break; 1091 case DRM_FORMAT_RGBX8888: 1092 m = 0xe; break; 1093 case DRM_FORMAT_XRGB1555: 1094 m = 0xf; break; 1095 default: 1096 BUG(); return; 1097 } 1098 } else { 1099 switch (fourcc) { 1100 case DRM_FORMAT_RGBX4444: 1101 m = 0x4; break; 1102 case DRM_FORMAT_ARGB4444: 1103 m = 0x5; break; 1104 case DRM_FORMAT_RGB565: 1105 m = 0x6; break; 1106 case DRM_FORMAT_ARGB1555: 1107 m = 0x7; break; 1108 case DRM_FORMAT_XRGB8888: 1109 m = 0x8; break; 1110 case DRM_FORMAT_RGB888: 1111 m = 0x9; break; 1112 case DRM_FORMAT_XRGB4444: 1113 m = 0xa; break; 1114 case DRM_FORMAT_RGBA4444: 1115 m = 0xb; break; 1116 case DRM_FORMAT_ARGB8888: 1117 m = 0xc; break; 1118 case DRM_FORMAT_RGBA8888: 1119 m = 0xd; break; 1120 case DRM_FORMAT_RGBX8888: 1121 m = 0xe; break; 1122 case DRM_FORMAT_XRGB1555: 1123 m = 0xf; break; 1124 default: 1125 BUG(); return; 1126 } 1127 } 1128 1129 REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), m, 4, 1); 1130 } 1131 1132 static void dispc_ovl_configure_burst_type(struct dispc_device *dispc, 1133 enum omap_plane_id plane, 1134 enum omap_dss_rotation_type rotation) 1135 { 1136 if (dispc_has_feature(dispc, FEAT_BURST_2D) == 0) 1137 return; 1138 1139 if (rotation == OMAP_DSS_ROT_TILER) 1140 REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), 1, 29, 29); 1141 else 1142 REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), 0, 29, 29); 1143 } 1144 1145 static void dispc_ovl_set_channel_out(struct dispc_device *dispc, 1146 enum omap_plane_id plane, 1147 enum omap_channel channel) 1148 { 1149 int shift; 1150 u32 val; 1151 int chan = 0, chan2 = 0; 1152 1153 switch (plane) { 1154 case OMAP_DSS_GFX: 1155 shift = 8; 1156 break; 1157 case OMAP_DSS_VIDEO1: 1158 case OMAP_DSS_VIDEO2: 1159 case OMAP_DSS_VIDEO3: 1160 shift = 16; 1161 break; 1162 default: 1163 BUG(); 1164 return; 1165 } 1166 1167 val = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane)); 1168 if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) { 1169 switch (channel) { 1170 case OMAP_DSS_CHANNEL_LCD: 1171 chan = 0; 1172 chan2 = 0; 1173 break; 1174 case OMAP_DSS_CHANNEL_DIGIT: 1175 chan = 1; 1176 chan2 = 0; 1177 break; 1178 case OMAP_DSS_CHANNEL_LCD2: 1179 chan = 0; 1180 chan2 = 1; 1181 break; 1182 case OMAP_DSS_CHANNEL_LCD3: 1183 if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) { 1184 chan = 0; 1185 chan2 = 2; 1186 } else { 1187 BUG(); 1188 return; 1189 } 1190 break; 1191 case OMAP_DSS_CHANNEL_WB: 1192 chan = 0; 1193 chan2 = 3; 1194 break; 1195 default: 1196 BUG(); 1197 return; 1198 } 1199 1200 val = FLD_MOD(val, chan, shift, shift); 1201 val = FLD_MOD(val, chan2, 31, 30); 1202 } else { 1203 val = FLD_MOD(val, channel, shift, shift); 1204 } 1205 dispc_write_reg(dispc, DISPC_OVL_ATTRIBUTES(plane), val); 1206 } 1207 1208 static enum omap_channel dispc_ovl_get_channel_out(struct dispc_device *dispc, 1209 enum omap_plane_id plane) 1210 { 1211 int shift; 1212 u32 val; 1213 1214 switch (plane) { 1215 case OMAP_DSS_GFX: 1216 shift = 8; 1217 break; 1218 case OMAP_DSS_VIDEO1: 1219 case OMAP_DSS_VIDEO2: 1220 case OMAP_DSS_VIDEO3: 1221 shift = 16; 1222 break; 1223 default: 1224 BUG(); 1225 return 0; 1226 } 1227 1228 val = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane)); 1229 1230 if (FLD_GET(val, shift, shift) == 1) 1231 return OMAP_DSS_CHANNEL_DIGIT; 1232 1233 if (!dispc_has_feature(dispc, FEAT_MGR_LCD2)) 1234 return OMAP_DSS_CHANNEL_LCD; 1235 1236 switch (FLD_GET(val, 31, 30)) { 1237 case 0: 1238 default: 1239 return OMAP_DSS_CHANNEL_LCD; 1240 case 1: 1241 return OMAP_DSS_CHANNEL_LCD2; 1242 case 2: 1243 return OMAP_DSS_CHANNEL_LCD3; 1244 case 3: 1245 return OMAP_DSS_CHANNEL_WB; 1246 } 1247 } 1248 1249 static void dispc_ovl_set_burst_size(struct dispc_device *dispc, 1250 enum omap_plane_id plane, 1251 enum omap_burst_size burst_size) 1252 { 1253 static const unsigned int shifts[] = { 6, 14, 14, 14, 14, }; 1254 int shift; 1255 1256 shift = shifts[plane]; 1257 REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), burst_size, 1258 shift + 1, shift); 1259 } 1260 1261 static void dispc_configure_burst_sizes(struct dispc_device *dispc) 1262 { 1263 int i; 1264 const int burst_size = BURST_SIZE_X8; 1265 1266 /* Configure burst size always to maximum size */ 1267 for (i = 0; i < dispc_get_num_ovls(dispc); ++i) 1268 dispc_ovl_set_burst_size(dispc, i, burst_size); 1269 if (dispc->feat->has_writeback) 1270 dispc_ovl_set_burst_size(dispc, OMAP_DSS_WB, burst_size); 1271 } 1272 1273 static u32 dispc_ovl_get_burst_size(struct dispc_device *dispc, 1274 enum omap_plane_id plane) 1275 { 1276 /* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */ 1277 return dispc->feat->burst_size_unit * 8; 1278 } 1279 1280 static bool dispc_ovl_color_mode_supported(struct dispc_device *dispc, 1281 enum omap_plane_id plane, u32 fourcc) 1282 { 1283 const u32 *modes; 1284 unsigned int i; 1285 1286 modes = dispc->feat->supported_color_modes[plane]; 1287 1288 for (i = 0; modes[i]; ++i) { 1289 if (modes[i] == fourcc) 1290 return true; 1291 } 1292 1293 return false; 1294 } 1295 1296 static const u32 *dispc_ovl_get_color_modes(struct dispc_device *dispc, 1297 enum omap_plane_id plane) 1298 { 1299 return dispc->feat->supported_color_modes[plane]; 1300 } 1301 1302 static void dispc_mgr_enable_cpr(struct dispc_device *dispc, 1303 enum omap_channel channel, bool enable) 1304 { 1305 if (channel == OMAP_DSS_CHANNEL_DIGIT) 1306 return; 1307 1308 mgr_fld_write(dispc, channel, DISPC_MGR_FLD_CPR, enable); 1309 } 1310 1311 static void dispc_mgr_set_cpr_coef(struct dispc_device *dispc, 1312 enum omap_channel channel, 1313 const struct omap_dss_cpr_coefs *coefs) 1314 { 1315 u32 coef_r, coef_g, coef_b; 1316 1317 if (!dss_mgr_is_lcd(channel)) 1318 return; 1319 1320 coef_r = FLD_VAL(coefs->rr, 31, 22) | FLD_VAL(coefs->rg, 20, 11) | 1321 FLD_VAL(coefs->rb, 9, 0); 1322 coef_g = FLD_VAL(coefs->gr, 31, 22) | FLD_VAL(coefs->gg, 20, 11) | 1323 FLD_VAL(coefs->gb, 9, 0); 1324 coef_b = FLD_VAL(coefs->br, 31, 22) | FLD_VAL(coefs->bg, 20, 11) | 1325 FLD_VAL(coefs->bb, 9, 0); 1326 1327 dispc_write_reg(dispc, DISPC_CPR_COEF_R(channel), coef_r); 1328 dispc_write_reg(dispc, DISPC_CPR_COEF_G(channel), coef_g); 1329 dispc_write_reg(dispc, DISPC_CPR_COEF_B(channel), coef_b); 1330 } 1331 1332 static void dispc_ovl_set_vid_color_conv(struct dispc_device *dispc, 1333 enum omap_plane_id plane, bool enable) 1334 { 1335 u32 val; 1336 1337 BUG_ON(plane == OMAP_DSS_GFX); 1338 1339 val = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane)); 1340 val = FLD_MOD(val, enable, 9, 9); 1341 dispc_write_reg(dispc, DISPC_OVL_ATTRIBUTES(plane), val); 1342 } 1343 1344 static void dispc_ovl_enable_replication(struct dispc_device *dispc, 1345 enum omap_plane_id plane, 1346 enum omap_overlay_caps caps, 1347 bool enable) 1348 { 1349 static const unsigned int shifts[] = { 5, 10, 10, 10 }; 1350 int shift; 1351 1352 if ((caps & OMAP_DSS_OVL_CAP_REPLICATION) == 0) 1353 return; 1354 1355 shift = shifts[plane]; 1356 REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift); 1357 } 1358 1359 static void dispc_mgr_set_size(struct dispc_device *dispc, 1360 enum omap_channel channel, u16 width, u16 height) 1361 { 1362 u32 val; 1363 1364 val = FLD_VAL(height - 1, dispc->feat->mgr_height_start, 16) | 1365 FLD_VAL(width - 1, dispc->feat->mgr_width_start, 0); 1366 1367 dispc_write_reg(dispc, DISPC_SIZE_MGR(channel), val); 1368 } 1369 1370 static void dispc_init_fifos(struct dispc_device *dispc) 1371 { 1372 u32 size; 1373 int fifo; 1374 u8 start, end; 1375 u32 unit; 1376 int i; 1377 1378 unit = dispc->feat->buffer_size_unit; 1379 1380 dispc_get_reg_field(dispc, FEAT_REG_FIFOSIZE, &start, &end); 1381 1382 for (fifo = 0; fifo < dispc->feat->num_fifos; ++fifo) { 1383 size = REG_GET(dispc, DISPC_OVL_FIFO_SIZE_STATUS(fifo), 1384 start, end); 1385 size *= unit; 1386 dispc->fifo_size[fifo] = size; 1387 1388 /* 1389 * By default fifos are mapped directly to overlays, fifo 0 to 1390 * ovl 0, fifo 1 to ovl 1, etc. 1391 */ 1392 dispc->fifo_assignment[fifo] = fifo; 1393 } 1394 1395 /* 1396 * The GFX fifo on OMAP4 is smaller than the other fifos. The small fifo 1397 * causes problems with certain use cases, like using the tiler in 2D 1398 * mode. The below hack swaps the fifos of GFX and WB planes, thus 1399 * giving GFX plane a larger fifo. WB but should work fine with a 1400 * smaller fifo. 1401 */ 1402 if (dispc->feat->gfx_fifo_workaround) { 1403 u32 v; 1404 1405 v = dispc_read_reg(dispc, DISPC_GLOBAL_BUFFER); 1406 1407 v = FLD_MOD(v, 4, 2, 0); /* GFX BUF top to WB */ 1408 v = FLD_MOD(v, 4, 5, 3); /* GFX BUF bottom to WB */ 1409 v = FLD_MOD(v, 0, 26, 24); /* WB BUF top to GFX */ 1410 v = FLD_MOD(v, 0, 29, 27); /* WB BUF bottom to GFX */ 1411 1412 dispc_write_reg(dispc, DISPC_GLOBAL_BUFFER, v); 1413 1414 dispc->fifo_assignment[OMAP_DSS_GFX] = OMAP_DSS_WB; 1415 dispc->fifo_assignment[OMAP_DSS_WB] = OMAP_DSS_GFX; 1416 } 1417 1418 /* 1419 * Setup default fifo thresholds. 1420 */ 1421 for (i = 0; i < dispc_get_num_ovls(dispc); ++i) { 1422 u32 low, high; 1423 const bool use_fifomerge = false; 1424 const bool manual_update = false; 1425 1426 dispc_ovl_compute_fifo_thresholds(dispc, i, &low, &high, 1427 use_fifomerge, manual_update); 1428 1429 dispc_ovl_set_fifo_threshold(dispc, i, low, high); 1430 } 1431 1432 if (dispc->feat->has_writeback) { 1433 u32 low, high; 1434 const bool use_fifomerge = false; 1435 const bool manual_update = false; 1436 1437 dispc_ovl_compute_fifo_thresholds(dispc, OMAP_DSS_WB, 1438 &low, &high, use_fifomerge, 1439 manual_update); 1440 1441 dispc_ovl_set_fifo_threshold(dispc, OMAP_DSS_WB, low, high); 1442 } 1443 } 1444 1445 static u32 dispc_ovl_get_fifo_size(struct dispc_device *dispc, 1446 enum omap_plane_id plane) 1447 { 1448 int fifo; 1449 u32 size = 0; 1450 1451 for (fifo = 0; fifo < dispc->feat->num_fifos; ++fifo) { 1452 if (dispc->fifo_assignment[fifo] == plane) 1453 size += dispc->fifo_size[fifo]; 1454 } 1455 1456 return size; 1457 } 1458 1459 void dispc_ovl_set_fifo_threshold(struct dispc_device *dispc, 1460 enum omap_plane_id plane, 1461 u32 low, u32 high) 1462 { 1463 u8 hi_start, hi_end, lo_start, lo_end; 1464 u32 unit; 1465 1466 unit = dispc->feat->buffer_size_unit; 1467 1468 WARN_ON(low % unit != 0); 1469 WARN_ON(high % unit != 0); 1470 1471 low /= unit; 1472 high /= unit; 1473 1474 dispc_get_reg_field(dispc, FEAT_REG_FIFOHIGHTHRESHOLD, 1475 &hi_start, &hi_end); 1476 dispc_get_reg_field(dispc, FEAT_REG_FIFOLOWTHRESHOLD, 1477 &lo_start, &lo_end); 1478 1479 DSSDBG("fifo(%d) threshold (bytes), old %u/%u, new %u/%u\n", 1480 plane, 1481 REG_GET(dispc, DISPC_OVL_FIFO_THRESHOLD(plane), 1482 lo_start, lo_end) * unit, 1483 REG_GET(dispc, DISPC_OVL_FIFO_THRESHOLD(plane), 1484 hi_start, hi_end) * unit, 1485 low * unit, high * unit); 1486 1487 dispc_write_reg(dispc, DISPC_OVL_FIFO_THRESHOLD(plane), 1488 FLD_VAL(high, hi_start, hi_end) | 1489 FLD_VAL(low, lo_start, lo_end)); 1490 1491 /* 1492 * configure the preload to the pipeline's high threhold, if HT it's too 1493 * large for the preload field, set the threshold to the maximum value 1494 * that can be held by the preload register 1495 */ 1496 if (dispc_has_feature(dispc, FEAT_PRELOAD) && 1497 dispc->feat->set_max_preload && plane != OMAP_DSS_WB) 1498 dispc_write_reg(dispc, DISPC_OVL_PRELOAD(plane), 1499 min(high, 0xfffu)); 1500 } 1501 1502 void dispc_enable_fifomerge(struct dispc_device *dispc, bool enable) 1503 { 1504 if (!dispc_has_feature(dispc, FEAT_FIFO_MERGE)) { 1505 WARN_ON(enable); 1506 return; 1507 } 1508 1509 DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled"); 1510 REG_FLD_MOD(dispc, DISPC_CONFIG, enable ? 1 : 0, 14, 14); 1511 } 1512 1513 void dispc_ovl_compute_fifo_thresholds(struct dispc_device *dispc, 1514 enum omap_plane_id plane, 1515 u32 *fifo_low, u32 *fifo_high, 1516 bool use_fifomerge, bool manual_update) 1517 { 1518 /* 1519 * All sizes are in bytes. Both the buffer and burst are made of 1520 * buffer_units, and the fifo thresholds must be buffer_unit aligned. 1521 */ 1522 unsigned int buf_unit = dispc->feat->buffer_size_unit; 1523 unsigned int ovl_fifo_size, total_fifo_size, burst_size; 1524 int i; 1525 1526 burst_size = dispc_ovl_get_burst_size(dispc, plane); 1527 ovl_fifo_size = dispc_ovl_get_fifo_size(dispc, plane); 1528 1529 if (use_fifomerge) { 1530 total_fifo_size = 0; 1531 for (i = 0; i < dispc_get_num_ovls(dispc); ++i) 1532 total_fifo_size += dispc_ovl_get_fifo_size(dispc, i); 1533 } else { 1534 total_fifo_size = ovl_fifo_size; 1535 } 1536 1537 /* 1538 * We use the same low threshold for both fifomerge and non-fifomerge 1539 * cases, but for fifomerge we calculate the high threshold using the 1540 * combined fifo size 1541 */ 1542 1543 if (manual_update && dispc_has_feature(dispc, FEAT_OMAP3_DSI_FIFO_BUG)) { 1544 *fifo_low = ovl_fifo_size - burst_size * 2; 1545 *fifo_high = total_fifo_size - burst_size; 1546 } else if (plane == OMAP_DSS_WB) { 1547 /* 1548 * Most optimal configuration for writeback is to push out data 1549 * to the interconnect the moment writeback pushes enough pixels 1550 * in the FIFO to form a burst 1551 */ 1552 *fifo_low = 0; 1553 *fifo_high = burst_size; 1554 } else { 1555 *fifo_low = ovl_fifo_size - burst_size; 1556 *fifo_high = total_fifo_size - buf_unit; 1557 } 1558 } 1559 1560 static void dispc_ovl_set_mflag(struct dispc_device *dispc, 1561 enum omap_plane_id plane, bool enable) 1562 { 1563 int bit; 1564 1565 if (plane == OMAP_DSS_GFX) 1566 bit = 14; 1567 else 1568 bit = 23; 1569 1570 REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit); 1571 } 1572 1573 static void dispc_ovl_set_mflag_threshold(struct dispc_device *dispc, 1574 enum omap_plane_id plane, 1575 int low, int high) 1576 { 1577 dispc_write_reg(dispc, DISPC_OVL_MFLAG_THRESHOLD(plane), 1578 FLD_VAL(high, 31, 16) | FLD_VAL(low, 15, 0)); 1579 } 1580 1581 static void dispc_init_mflag(struct dispc_device *dispc) 1582 { 1583 int i; 1584 1585 /* 1586 * HACK: NV12 color format and MFLAG seem to have problems working 1587 * together: using two displays, and having an NV12 overlay on one of 1588 * the displays will cause underflows/synclosts when MFLAG_CTRL=2. 1589 * Changing MFLAG thresholds and PRELOAD to certain values seem to 1590 * remove the errors, but there doesn't seem to be a clear logic on 1591 * which values work and which not. 1592 * 1593 * As a work-around, set force MFLAG to always on. 1594 */ 1595 dispc_write_reg(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE, 1596 (1 << 0) | /* MFLAG_CTRL = force always on */ 1597 (0 << 2)); /* MFLAG_START = disable */ 1598 1599 for (i = 0; i < dispc_get_num_ovls(dispc); ++i) { 1600 u32 size = dispc_ovl_get_fifo_size(dispc, i); 1601 u32 unit = dispc->feat->buffer_size_unit; 1602 u32 low, high; 1603 1604 dispc_ovl_set_mflag(dispc, i, true); 1605 1606 /* 1607 * Simulation team suggests below thesholds: 1608 * HT = fifosize * 5 / 8; 1609 * LT = fifosize * 4 / 8; 1610 */ 1611 1612 low = size * 4 / 8 / unit; 1613 high = size * 5 / 8 / unit; 1614 1615 dispc_ovl_set_mflag_threshold(dispc, i, low, high); 1616 } 1617 1618 if (dispc->feat->has_writeback) { 1619 u32 size = dispc_ovl_get_fifo_size(dispc, OMAP_DSS_WB); 1620 u32 unit = dispc->feat->buffer_size_unit; 1621 u32 low, high; 1622 1623 dispc_ovl_set_mflag(dispc, OMAP_DSS_WB, true); 1624 1625 /* 1626 * Simulation team suggests below thesholds: 1627 * HT = fifosize * 5 / 8; 1628 * LT = fifosize * 4 / 8; 1629 */ 1630 1631 low = size * 4 / 8 / unit; 1632 high = size * 5 / 8 / unit; 1633 1634 dispc_ovl_set_mflag_threshold(dispc, OMAP_DSS_WB, low, high); 1635 } 1636 } 1637 1638 static void dispc_ovl_set_fir(struct dispc_device *dispc, 1639 enum omap_plane_id plane, 1640 int hinc, int vinc, 1641 enum omap_color_component color_comp) 1642 { 1643 u32 val; 1644 1645 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) { 1646 u8 hinc_start, hinc_end, vinc_start, vinc_end; 1647 1648 dispc_get_reg_field(dispc, FEAT_REG_FIRHINC, 1649 &hinc_start, &hinc_end); 1650 dispc_get_reg_field(dispc, FEAT_REG_FIRVINC, 1651 &vinc_start, &vinc_end); 1652 val = FLD_VAL(vinc, vinc_start, vinc_end) | 1653 FLD_VAL(hinc, hinc_start, hinc_end); 1654 1655 dispc_write_reg(dispc, DISPC_OVL_FIR(plane), val); 1656 } else { 1657 val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0); 1658 dispc_write_reg(dispc, DISPC_OVL_FIR2(plane), val); 1659 } 1660 } 1661 1662 static void dispc_ovl_set_vid_accu0(struct dispc_device *dispc, 1663 enum omap_plane_id plane, int haccu, 1664 int vaccu) 1665 { 1666 u32 val; 1667 u8 hor_start, hor_end, vert_start, vert_end; 1668 1669 dispc_get_reg_field(dispc, FEAT_REG_HORIZONTALACCU, 1670 &hor_start, &hor_end); 1671 dispc_get_reg_field(dispc, FEAT_REG_VERTICALACCU, 1672 &vert_start, &vert_end); 1673 1674 val = FLD_VAL(vaccu, vert_start, vert_end) | 1675 FLD_VAL(haccu, hor_start, hor_end); 1676 1677 dispc_write_reg(dispc, DISPC_OVL_ACCU0(plane), val); 1678 } 1679 1680 static void dispc_ovl_set_vid_accu1(struct dispc_device *dispc, 1681 enum omap_plane_id plane, int haccu, 1682 int vaccu) 1683 { 1684 u32 val; 1685 u8 hor_start, hor_end, vert_start, vert_end; 1686 1687 dispc_get_reg_field(dispc, FEAT_REG_HORIZONTALACCU, 1688 &hor_start, &hor_end); 1689 dispc_get_reg_field(dispc, FEAT_REG_VERTICALACCU, 1690 &vert_start, &vert_end); 1691 1692 val = FLD_VAL(vaccu, vert_start, vert_end) | 1693 FLD_VAL(haccu, hor_start, hor_end); 1694 1695 dispc_write_reg(dispc, DISPC_OVL_ACCU1(plane), val); 1696 } 1697 1698 static void dispc_ovl_set_vid_accu2_0(struct dispc_device *dispc, 1699 enum omap_plane_id plane, int haccu, 1700 int vaccu) 1701 { 1702 u32 val; 1703 1704 val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0); 1705 dispc_write_reg(dispc, DISPC_OVL_ACCU2_0(plane), val); 1706 } 1707 1708 static void dispc_ovl_set_vid_accu2_1(struct dispc_device *dispc, 1709 enum omap_plane_id plane, int haccu, 1710 int vaccu) 1711 { 1712 u32 val; 1713 1714 val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0); 1715 dispc_write_reg(dispc, DISPC_OVL_ACCU2_1(plane), val); 1716 } 1717 1718 static void dispc_ovl_set_scale_param(struct dispc_device *dispc, 1719 enum omap_plane_id plane, 1720 u16 orig_width, u16 orig_height, 1721 u16 out_width, u16 out_height, 1722 bool five_taps, u8 rotation, 1723 enum omap_color_component color_comp) 1724 { 1725 int fir_hinc, fir_vinc; 1726 1727 fir_hinc = 1024 * orig_width / out_width; 1728 fir_vinc = 1024 * orig_height / out_height; 1729 1730 dispc_ovl_set_scale_coef(dispc, plane, fir_hinc, fir_vinc, five_taps, 1731 color_comp); 1732 dispc_ovl_set_fir(dispc, plane, fir_hinc, fir_vinc, color_comp); 1733 } 1734 1735 static void dispc_ovl_set_accu_uv(struct dispc_device *dispc, 1736 enum omap_plane_id plane, 1737 u16 orig_width, u16 orig_height, 1738 u16 out_width, u16 out_height, 1739 bool ilace, u32 fourcc, u8 rotation) 1740 { 1741 int h_accu2_0, h_accu2_1; 1742 int v_accu2_0, v_accu2_1; 1743 int chroma_hinc, chroma_vinc; 1744 int idx; 1745 1746 struct accu { 1747 s8 h0_m, h0_n; 1748 s8 h1_m, h1_n; 1749 s8 v0_m, v0_n; 1750 s8 v1_m, v1_n; 1751 }; 1752 1753 const struct accu *accu_table; 1754 const struct accu *accu_val; 1755 1756 static const struct accu accu_nv12[4] = { 1757 { 0, 1, 0, 1 , -1, 2, 0, 1 }, 1758 { 1, 2, -3, 4 , 0, 1, 0, 1 }, 1759 { -1, 1, 0, 1 , -1, 2, 0, 1 }, 1760 { -1, 2, -1, 2 , -1, 1, 0, 1 }, 1761 }; 1762 1763 static const struct accu accu_nv12_ilace[4] = { 1764 { 0, 1, 0, 1 , -3, 4, -1, 4 }, 1765 { -1, 4, -3, 4 , 0, 1, 0, 1 }, 1766 { -1, 1, 0, 1 , -1, 4, -3, 4 }, 1767 { -3, 4, -3, 4 , -1, 1, 0, 1 }, 1768 }; 1769 1770 static const struct accu accu_yuv[4] = { 1771 { 0, 1, 0, 1, 0, 1, 0, 1 }, 1772 { 0, 1, 0, 1, 0, 1, 0, 1 }, 1773 { -1, 1, 0, 1, 0, 1, 0, 1 }, 1774 { 0, 1, 0, 1, -1, 1, 0, 1 }, 1775 }; 1776 1777 /* Note: DSS HW rotates clockwise, DRM_MODE_ROTATE_* counter-clockwise */ 1778 switch (rotation & DRM_MODE_ROTATE_MASK) { 1779 default: 1780 case DRM_MODE_ROTATE_0: 1781 idx = 0; 1782 break; 1783 case DRM_MODE_ROTATE_90: 1784 idx = 3; 1785 break; 1786 case DRM_MODE_ROTATE_180: 1787 idx = 2; 1788 break; 1789 case DRM_MODE_ROTATE_270: 1790 idx = 1; 1791 break; 1792 } 1793 1794 switch (fourcc) { 1795 case DRM_FORMAT_NV12: 1796 if (ilace) 1797 accu_table = accu_nv12_ilace; 1798 else 1799 accu_table = accu_nv12; 1800 break; 1801 case DRM_FORMAT_YUYV: 1802 case DRM_FORMAT_UYVY: 1803 accu_table = accu_yuv; 1804 break; 1805 default: 1806 BUG(); 1807 return; 1808 } 1809 1810 accu_val = &accu_table[idx]; 1811 1812 chroma_hinc = 1024 * orig_width / out_width; 1813 chroma_vinc = 1024 * orig_height / out_height; 1814 1815 h_accu2_0 = (accu_val->h0_m * chroma_hinc / accu_val->h0_n) % 1024; 1816 h_accu2_1 = (accu_val->h1_m * chroma_hinc / accu_val->h1_n) % 1024; 1817 v_accu2_0 = (accu_val->v0_m * chroma_vinc / accu_val->v0_n) % 1024; 1818 v_accu2_1 = (accu_val->v1_m * chroma_vinc / accu_val->v1_n) % 1024; 1819 1820 dispc_ovl_set_vid_accu2_0(dispc, plane, h_accu2_0, v_accu2_0); 1821 dispc_ovl_set_vid_accu2_1(dispc, plane, h_accu2_1, v_accu2_1); 1822 } 1823 1824 static void dispc_ovl_set_scaling_common(struct dispc_device *dispc, 1825 enum omap_plane_id plane, 1826 u16 orig_width, u16 orig_height, 1827 u16 out_width, u16 out_height, 1828 bool ilace, bool five_taps, 1829 bool fieldmode, u32 fourcc, 1830 u8 rotation) 1831 { 1832 int accu0 = 0; 1833 int accu1 = 0; 1834 u32 l; 1835 1836 dispc_ovl_set_scale_param(dispc, plane, orig_width, orig_height, 1837 out_width, out_height, five_taps, 1838 rotation, DISPC_COLOR_COMPONENT_RGB_Y); 1839 l = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane)); 1840 1841 /* RESIZEENABLE and VERTICALTAPS */ 1842 l &= ~((0x3 << 5) | (0x1 << 21)); 1843 l |= (orig_width != out_width) ? (1 << 5) : 0; 1844 l |= (orig_height != out_height) ? (1 << 6) : 0; 1845 l |= five_taps ? (1 << 21) : 0; 1846 1847 /* VRESIZECONF and HRESIZECONF */ 1848 if (dispc_has_feature(dispc, FEAT_RESIZECONF)) { 1849 l &= ~(0x3 << 7); 1850 l |= (orig_width <= out_width) ? 0 : (1 << 7); 1851 l |= (orig_height <= out_height) ? 0 : (1 << 8); 1852 } 1853 1854 /* LINEBUFFERSPLIT */ 1855 if (dispc_has_feature(dispc, FEAT_LINEBUFFERSPLIT)) { 1856 l &= ~(0x1 << 22); 1857 l |= five_taps ? (1 << 22) : 0; 1858 } 1859 1860 dispc_write_reg(dispc, DISPC_OVL_ATTRIBUTES(plane), l); 1861 1862 /* 1863 * field 0 = even field = bottom field 1864 * field 1 = odd field = top field 1865 */ 1866 if (ilace && !fieldmode) { 1867 accu1 = 0; 1868 accu0 = ((1024 * orig_height / out_height) / 2) & 0x3ff; 1869 if (accu0 >= 1024/2) { 1870 accu1 = 1024/2; 1871 accu0 -= accu1; 1872 } 1873 } 1874 1875 dispc_ovl_set_vid_accu0(dispc, plane, 0, accu0); 1876 dispc_ovl_set_vid_accu1(dispc, plane, 0, accu1); 1877 } 1878 1879 static void dispc_ovl_set_scaling_uv(struct dispc_device *dispc, 1880 enum omap_plane_id plane, 1881 u16 orig_width, u16 orig_height, 1882 u16 out_width, u16 out_height, 1883 bool ilace, bool five_taps, 1884 bool fieldmode, u32 fourcc, 1885 u8 rotation) 1886 { 1887 int scale_x = out_width != orig_width; 1888 int scale_y = out_height != orig_height; 1889 bool chroma_upscale = plane != OMAP_DSS_WB; 1890 const struct drm_format_info *info; 1891 1892 info = drm_format_info(fourcc); 1893 1894 if (!dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) 1895 return; 1896 1897 if (!info->is_yuv) { 1898 /* reset chroma resampling for RGB formats */ 1899 if (plane != OMAP_DSS_WB) 1900 REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane), 1901 0, 8, 8); 1902 return; 1903 } 1904 1905 dispc_ovl_set_accu_uv(dispc, plane, orig_width, orig_height, out_width, 1906 out_height, ilace, fourcc, rotation); 1907 1908 switch (fourcc) { 1909 case DRM_FORMAT_NV12: 1910 if (chroma_upscale) { 1911 /* UV is subsampled by 2 horizontally and vertically */ 1912 orig_height >>= 1; 1913 orig_width >>= 1; 1914 } else { 1915 /* UV is downsampled by 2 horizontally and vertically */ 1916 orig_height <<= 1; 1917 orig_width <<= 1; 1918 } 1919 1920 break; 1921 case DRM_FORMAT_YUYV: 1922 case DRM_FORMAT_UYVY: 1923 /* For YUV422 with 90/270 rotation, we don't upsample chroma */ 1924 if (!drm_rotation_90_or_270(rotation)) { 1925 if (chroma_upscale) 1926 /* UV is subsampled by 2 horizontally */ 1927 orig_width >>= 1; 1928 else 1929 /* UV is downsampled by 2 horizontally */ 1930 orig_width <<= 1; 1931 } 1932 1933 /* must use FIR for YUV422 if rotated */ 1934 if ((rotation & DRM_MODE_ROTATE_MASK) != DRM_MODE_ROTATE_0) 1935 scale_x = scale_y = true; 1936 1937 break; 1938 default: 1939 BUG(); 1940 return; 1941 } 1942 1943 if (out_width != orig_width) 1944 scale_x = true; 1945 if (out_height != orig_height) 1946 scale_y = true; 1947 1948 dispc_ovl_set_scale_param(dispc, plane, orig_width, orig_height, 1949 out_width, out_height, five_taps, 1950 rotation, DISPC_COLOR_COMPONENT_UV); 1951 1952 if (plane != OMAP_DSS_WB) 1953 REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane), 1954 (scale_x || scale_y) ? 1 : 0, 8, 8); 1955 1956 /* set H scaling */ 1957 REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5); 1958 /* set V scaling */ 1959 REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6); 1960 } 1961 1962 static void dispc_ovl_set_scaling(struct dispc_device *dispc, 1963 enum omap_plane_id plane, 1964 u16 orig_width, u16 orig_height, 1965 u16 out_width, u16 out_height, 1966 bool ilace, bool five_taps, 1967 bool fieldmode, u32 fourcc, 1968 u8 rotation) 1969 { 1970 BUG_ON(plane == OMAP_DSS_GFX); 1971 1972 dispc_ovl_set_scaling_common(dispc, plane, orig_width, orig_height, 1973 out_width, out_height, ilace, five_taps, 1974 fieldmode, fourcc, rotation); 1975 1976 dispc_ovl_set_scaling_uv(dispc, plane, orig_width, orig_height, 1977 out_width, out_height, ilace, five_taps, 1978 fieldmode, fourcc, rotation); 1979 } 1980 1981 static void dispc_ovl_set_rotation_attrs(struct dispc_device *dispc, 1982 enum omap_plane_id plane, u8 rotation, 1983 enum omap_dss_rotation_type rotation_type, 1984 u32 fourcc) 1985 { 1986 bool row_repeat = false; 1987 int vidrot = 0; 1988 1989 /* Note: DSS HW rotates clockwise, DRM_MODE_ROTATE_* counter-clockwise */ 1990 if (fourcc == DRM_FORMAT_YUYV || fourcc == DRM_FORMAT_UYVY) { 1991 1992 if (rotation & DRM_MODE_REFLECT_X) { 1993 switch (rotation & DRM_MODE_ROTATE_MASK) { 1994 case DRM_MODE_ROTATE_0: 1995 vidrot = 2; 1996 break; 1997 case DRM_MODE_ROTATE_90: 1998 vidrot = 1; 1999 break; 2000 case DRM_MODE_ROTATE_180: 2001 vidrot = 0; 2002 break; 2003 case DRM_MODE_ROTATE_270: 2004 vidrot = 3; 2005 break; 2006 } 2007 } else { 2008 switch (rotation & DRM_MODE_ROTATE_MASK) { 2009 case DRM_MODE_ROTATE_0: 2010 vidrot = 0; 2011 break; 2012 case DRM_MODE_ROTATE_90: 2013 vidrot = 3; 2014 break; 2015 case DRM_MODE_ROTATE_180: 2016 vidrot = 2; 2017 break; 2018 case DRM_MODE_ROTATE_270: 2019 vidrot = 1; 2020 break; 2021 } 2022 } 2023 2024 if (drm_rotation_90_or_270(rotation)) 2025 row_repeat = true; 2026 else 2027 row_repeat = false; 2028 } 2029 2030 /* 2031 * OMAP4/5 Errata i631: 2032 * NV12 in 1D mode must use ROTATION=1. Otherwise DSS will fetch extra 2033 * rows beyond the framebuffer, which may cause OCP error. 2034 */ 2035 if (fourcc == DRM_FORMAT_NV12 && rotation_type != OMAP_DSS_ROT_TILER) 2036 vidrot = 1; 2037 2038 REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), vidrot, 13, 12); 2039 if (dispc_has_feature(dispc, FEAT_ROWREPEATENABLE)) 2040 REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), 2041 row_repeat ? 1 : 0, 18, 18); 2042 2043 if (dispc_ovl_color_mode_supported(dispc, plane, DRM_FORMAT_NV12)) { 2044 bool doublestride = 2045 fourcc == DRM_FORMAT_NV12 && 2046 rotation_type == OMAP_DSS_ROT_TILER && 2047 !drm_rotation_90_or_270(rotation); 2048 2049 /* DOUBLESTRIDE */ 2050 REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), 2051 doublestride, 22, 22); 2052 } 2053 } 2054 2055 static int color_mode_to_bpp(u32 fourcc) 2056 { 2057 switch (fourcc) { 2058 case DRM_FORMAT_NV12: 2059 return 8; 2060 case DRM_FORMAT_RGBX4444: 2061 case DRM_FORMAT_RGB565: 2062 case DRM_FORMAT_ARGB4444: 2063 case DRM_FORMAT_YUYV: 2064 case DRM_FORMAT_UYVY: 2065 case DRM_FORMAT_RGBA4444: 2066 case DRM_FORMAT_XRGB4444: 2067 case DRM_FORMAT_ARGB1555: 2068 case DRM_FORMAT_XRGB1555: 2069 return 16; 2070 case DRM_FORMAT_RGB888: 2071 return 24; 2072 case DRM_FORMAT_XRGB8888: 2073 case DRM_FORMAT_ARGB8888: 2074 case DRM_FORMAT_RGBA8888: 2075 case DRM_FORMAT_RGBX8888: 2076 return 32; 2077 default: 2078 BUG(); 2079 return 0; 2080 } 2081 } 2082 2083 static s32 pixinc(int pixels, u8 ps) 2084 { 2085 if (pixels == 1) 2086 return 1; 2087 else if (pixels > 1) 2088 return 1 + (pixels - 1) * ps; 2089 else if (pixels < 0) 2090 return 1 - (-pixels + 1) * ps; 2091 else 2092 BUG(); 2093 return 0; 2094 } 2095 2096 static void calc_offset(u16 screen_width, u16 width, 2097 u32 fourcc, bool fieldmode, unsigned int field_offset, 2098 unsigned int *offset0, unsigned int *offset1, 2099 s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim, 2100 enum omap_dss_rotation_type rotation_type, u8 rotation) 2101 { 2102 u8 ps; 2103 2104 ps = color_mode_to_bpp(fourcc) / 8; 2105 2106 DSSDBG("scrw %d, width %d\n", screen_width, width); 2107 2108 if (rotation_type == OMAP_DSS_ROT_TILER && 2109 (fourcc == DRM_FORMAT_UYVY || fourcc == DRM_FORMAT_YUYV) && 2110 drm_rotation_90_or_270(rotation)) { 2111 /* 2112 * HACK: ROW_INC needs to be calculated with TILER units. 2113 * We get such 'screen_width' that multiplying it with the 2114 * YUV422 pixel size gives the correct TILER container width. 2115 * However, 'width' is in pixels and multiplying it with YUV422 2116 * pixel size gives incorrect result. We thus multiply it here 2117 * with 2 to match the 32 bit TILER unit size. 2118 */ 2119 width *= 2; 2120 } 2121 2122 /* 2123 * field 0 = even field = bottom field 2124 * field 1 = odd field = top field 2125 */ 2126 *offset0 = field_offset * screen_width * ps; 2127 *offset1 = 0; 2128 2129 *row_inc = pixinc(1 + (y_predecim * screen_width - width * x_predecim) + 2130 (fieldmode ? screen_width : 0), ps); 2131 if (fourcc == DRM_FORMAT_YUYV || fourcc == DRM_FORMAT_UYVY) 2132 *pix_inc = pixinc(x_predecim, 2 * ps); 2133 else 2134 *pix_inc = pixinc(x_predecim, ps); 2135 } 2136 2137 /* 2138 * This function is used to avoid synclosts in OMAP3, because of some 2139 * undocumented horizontal position and timing related limitations. 2140 */ 2141 static int check_horiz_timing_omap3(unsigned long pclk, unsigned long lclk, 2142 const struct videomode *vm, u16 pos_x, 2143 u16 width, u16 height, u16 out_width, u16 out_height, 2144 bool five_taps) 2145 { 2146 const int ds = DIV_ROUND_UP(height, out_height); 2147 unsigned long nonactive; 2148 static const u8 limits[3] = { 8, 10, 20 }; 2149 u64 val, blank; 2150 int i; 2151 2152 nonactive = vm->hactive + vm->hfront_porch + vm->hsync_len + 2153 vm->hback_porch - out_width; 2154 2155 i = 0; 2156 if (out_height < height) 2157 i++; 2158 if (out_width < width) 2159 i++; 2160 blank = div_u64((u64)(vm->hback_porch + vm->hsync_len + vm->hfront_porch) * 2161 lclk, pclk); 2162 DSSDBG("blanking period + ppl = %llu (limit = %u)\n", blank, limits[i]); 2163 if (blank <= limits[i]) 2164 return -EINVAL; 2165 2166 /* FIXME add checks for 3-tap filter once the limitations are known */ 2167 if (!five_taps) 2168 return 0; 2169 2170 /* 2171 * Pixel data should be prepared before visible display point starts. 2172 * So, atleast DS-2 lines must have already been fetched by DISPC 2173 * during nonactive - pos_x period. 2174 */ 2175 val = div_u64((u64)(nonactive - pos_x) * lclk, pclk); 2176 DSSDBG("(nonactive - pos_x) * pcd = %llu max(0, DS - 2) * width = %d\n", 2177 val, max(0, ds - 2) * width); 2178 if (val < max(0, ds - 2) * width) 2179 return -EINVAL; 2180 2181 /* 2182 * All lines need to be refilled during the nonactive period of which 2183 * only one line can be loaded during the active period. So, atleast 2184 * DS - 1 lines should be loaded during nonactive period. 2185 */ 2186 val = div_u64((u64)nonactive * lclk, pclk); 2187 DSSDBG("nonactive * pcd = %llu, max(0, DS - 1) * width = %d\n", 2188 val, max(0, ds - 1) * width); 2189 if (val < max(0, ds - 1) * width) 2190 return -EINVAL; 2191 2192 return 0; 2193 } 2194 2195 static unsigned long calc_core_clk_five_taps(unsigned long pclk, 2196 const struct videomode *vm, u16 width, 2197 u16 height, u16 out_width, u16 out_height, 2198 u32 fourcc) 2199 { 2200 u32 core_clk = 0; 2201 u64 tmp; 2202 2203 if (height <= out_height && width <= out_width) 2204 return (unsigned long) pclk; 2205 2206 if (height > out_height) { 2207 unsigned int ppl = vm->hactive; 2208 2209 tmp = (u64)pclk * height * out_width; 2210 do_div(tmp, 2 * out_height * ppl); 2211 core_clk = tmp; 2212 2213 if (height > 2 * out_height) { 2214 if (ppl == out_width) 2215 return 0; 2216 2217 tmp = (u64)pclk * (height - 2 * out_height) * out_width; 2218 do_div(tmp, 2 * out_height * (ppl - out_width)); 2219 core_clk = max_t(u32, core_clk, tmp); 2220 } 2221 } 2222 2223 if (width > out_width) { 2224 tmp = (u64)pclk * width; 2225 do_div(tmp, out_width); 2226 core_clk = max_t(u32, core_clk, tmp); 2227 2228 if (fourcc == DRM_FORMAT_XRGB8888) 2229 core_clk <<= 1; 2230 } 2231 2232 return core_clk; 2233 } 2234 2235 static unsigned long calc_core_clk_24xx(unsigned long pclk, u16 width, 2236 u16 height, u16 out_width, u16 out_height, bool mem_to_mem) 2237 { 2238 if (height > out_height && width > out_width) 2239 return pclk * 4; 2240 else 2241 return pclk * 2; 2242 } 2243 2244 static unsigned long calc_core_clk_34xx(unsigned long pclk, u16 width, 2245 u16 height, u16 out_width, u16 out_height, bool mem_to_mem) 2246 { 2247 unsigned int hf, vf; 2248 2249 /* 2250 * FIXME how to determine the 'A' factor 2251 * for the no downscaling case ? 2252 */ 2253 2254 if (width > 3 * out_width) 2255 hf = 4; 2256 else if (width > 2 * out_width) 2257 hf = 3; 2258 else if (width > out_width) 2259 hf = 2; 2260 else 2261 hf = 1; 2262 if (height > out_height) 2263 vf = 2; 2264 else 2265 vf = 1; 2266 2267 return pclk * vf * hf; 2268 } 2269 2270 static unsigned long calc_core_clk_44xx(unsigned long pclk, u16 width, 2271 u16 height, u16 out_width, u16 out_height, bool mem_to_mem) 2272 { 2273 /* 2274 * If the overlay/writeback is in mem to mem mode, there are no 2275 * downscaling limitations with respect to pixel clock, return 1 as 2276 * required core clock to represent that we have sufficient enough 2277 * core clock to do maximum downscaling 2278 */ 2279 if (mem_to_mem) 2280 return 1; 2281 2282 if (width > out_width) 2283 return DIV_ROUND_UP(pclk, out_width) * width; 2284 else 2285 return pclk; 2286 } 2287 2288 static int dispc_ovl_calc_scaling_24xx(struct dispc_device *dispc, 2289 unsigned long pclk, unsigned long lclk, 2290 const struct videomode *vm, 2291 u16 width, u16 height, 2292 u16 out_width, u16 out_height, 2293 u32 fourcc, bool *five_taps, 2294 int *x_predecim, int *y_predecim, 2295 int *decim_x, int *decim_y, 2296 u16 pos_x, unsigned long *core_clk, 2297 bool mem_to_mem) 2298 { 2299 int error; 2300 u16 in_width, in_height; 2301 int min_factor = min(*decim_x, *decim_y); 2302 const int maxsinglelinewidth = dispc->feat->max_line_width; 2303 2304 *five_taps = false; 2305 2306 do { 2307 in_height = height / *decim_y; 2308 in_width = width / *decim_x; 2309 *core_clk = dispc->feat->calc_core_clk(pclk, in_width, 2310 in_height, out_width, out_height, mem_to_mem); 2311 error = (in_width > maxsinglelinewidth || !*core_clk || 2312 *core_clk > dispc_core_clk_rate(dispc)); 2313 if (error) { 2314 if (*decim_x == *decim_y) { 2315 *decim_x = min_factor; 2316 ++*decim_y; 2317 } else { 2318 swap(*decim_x, *decim_y); 2319 if (*decim_x < *decim_y) 2320 ++*decim_x; 2321 } 2322 } 2323 } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error); 2324 2325 if (error) { 2326 DSSERR("failed to find scaling settings\n"); 2327 return -EINVAL; 2328 } 2329 2330 if (in_width > maxsinglelinewidth) { 2331 DSSERR("Cannot scale max input width exceeded\n"); 2332 return -EINVAL; 2333 } 2334 return 0; 2335 } 2336 2337 static int dispc_ovl_calc_scaling_34xx(struct dispc_device *dispc, 2338 unsigned long pclk, unsigned long lclk, 2339 const struct videomode *vm, 2340 u16 width, u16 height, 2341 u16 out_width, u16 out_height, 2342 u32 fourcc, bool *five_taps, 2343 int *x_predecim, int *y_predecim, 2344 int *decim_x, int *decim_y, 2345 u16 pos_x, unsigned long *core_clk, 2346 bool mem_to_mem) 2347 { 2348 int error; 2349 u16 in_width, in_height; 2350 const int maxsinglelinewidth = dispc->feat->max_line_width; 2351 2352 do { 2353 in_height = height / *decim_y; 2354 in_width = width / *decim_x; 2355 *five_taps = in_height > out_height; 2356 2357 if (in_width > maxsinglelinewidth) 2358 if (in_height > out_height && 2359 in_height < out_height * 2) 2360 *five_taps = false; 2361 again: 2362 if (*five_taps) 2363 *core_clk = calc_core_clk_five_taps(pclk, vm, 2364 in_width, in_height, out_width, 2365 out_height, fourcc); 2366 else 2367 *core_clk = dispc->feat->calc_core_clk(pclk, in_width, 2368 in_height, out_width, out_height, 2369 mem_to_mem); 2370 2371 error = check_horiz_timing_omap3(pclk, lclk, vm, 2372 pos_x, in_width, in_height, out_width, 2373 out_height, *five_taps); 2374 if (error && *five_taps) { 2375 *five_taps = false; 2376 goto again; 2377 } 2378 2379 error = (error || in_width > maxsinglelinewidth * 2 || 2380 (in_width > maxsinglelinewidth && *five_taps) || 2381 !*core_clk || *core_clk > dispc_core_clk_rate(dispc)); 2382 2383 if (!error) { 2384 /* verify that we're inside the limits of scaler */ 2385 if (in_width / 4 > out_width) 2386 error = 1; 2387 2388 if (*five_taps) { 2389 if (in_height / 4 > out_height) 2390 error = 1; 2391 } else { 2392 if (in_height / 2 > out_height) 2393 error = 1; 2394 } 2395 } 2396 2397 if (error) 2398 ++*decim_y; 2399 } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error); 2400 2401 if (error) { 2402 DSSERR("failed to find scaling settings\n"); 2403 return -EINVAL; 2404 } 2405 2406 if (check_horiz_timing_omap3(pclk, lclk, vm, pos_x, in_width, 2407 in_height, out_width, out_height, *five_taps)) { 2408 DSSERR("horizontal timing too tight\n"); 2409 return -EINVAL; 2410 } 2411 2412 if (in_width > (maxsinglelinewidth * 2)) { 2413 DSSERR("Cannot setup scaling\n"); 2414 DSSERR("width exceeds maximum width possible\n"); 2415 return -EINVAL; 2416 } 2417 2418 if (in_width > maxsinglelinewidth && *five_taps) { 2419 DSSERR("cannot setup scaling with five taps\n"); 2420 return -EINVAL; 2421 } 2422 return 0; 2423 } 2424 2425 static int dispc_ovl_calc_scaling_44xx(struct dispc_device *dispc, 2426 unsigned long pclk, unsigned long lclk, 2427 const struct videomode *vm, 2428 u16 width, u16 height, 2429 u16 out_width, u16 out_height, 2430 u32 fourcc, bool *five_taps, 2431 int *x_predecim, int *y_predecim, 2432 int *decim_x, int *decim_y, 2433 u16 pos_x, unsigned long *core_clk, 2434 bool mem_to_mem) 2435 { 2436 u16 in_width, in_width_max; 2437 int decim_x_min = *decim_x; 2438 u16 in_height = height / *decim_y; 2439 const int maxsinglelinewidth = dispc->feat->max_line_width; 2440 const int maxdownscale = dispc->feat->max_downscale; 2441 2442 if (mem_to_mem) { 2443 in_width_max = out_width * maxdownscale; 2444 } else { 2445 in_width_max = dispc_core_clk_rate(dispc) 2446 / DIV_ROUND_UP(pclk, out_width); 2447 } 2448 2449 *decim_x = DIV_ROUND_UP(width, in_width_max); 2450 2451 *decim_x = *decim_x > decim_x_min ? *decim_x : decim_x_min; 2452 if (*decim_x > *x_predecim) 2453 return -EINVAL; 2454 2455 do { 2456 in_width = width / *decim_x; 2457 } while (*decim_x <= *x_predecim && 2458 in_width > maxsinglelinewidth && ++*decim_x); 2459 2460 if (in_width > maxsinglelinewidth) { 2461 DSSERR("Cannot scale width exceeds max line width\n"); 2462 return -EINVAL; 2463 } 2464 2465 if (*decim_x > 4 && fourcc != DRM_FORMAT_NV12) { 2466 /* 2467 * Let's disable all scaling that requires horizontal 2468 * decimation with higher factor than 4, until we have 2469 * better estimates of what we can and can not 2470 * do. However, NV12 color format appears to work Ok 2471 * with all decimation factors. 2472 * 2473 * When decimating horizontally by more that 4 the dss 2474 * is not able to fetch the data in burst mode. When 2475 * this happens it is hard to tell if there enough 2476 * bandwidth. Despite what theory says this appears to 2477 * be true also for 16-bit color formats. 2478 */ 2479 DSSERR("Not enough bandwidth, too much downscaling (x-decimation factor %d > 4)\n", *decim_x); 2480 2481 return -EINVAL; 2482 } 2483 2484 *core_clk = dispc->feat->calc_core_clk(pclk, in_width, in_height, 2485 out_width, out_height, mem_to_mem); 2486 return 0; 2487 } 2488 2489 #define DIV_FRAC(dividend, divisor) \ 2490 ((dividend) * 100 / (divisor) - ((dividend) / (divisor) * 100)) 2491 2492 static int dispc_ovl_calc_scaling(struct dispc_device *dispc, 2493 enum omap_plane_id plane, 2494 unsigned long pclk, unsigned long lclk, 2495 enum omap_overlay_caps caps, 2496 const struct videomode *vm, 2497 u16 width, u16 height, 2498 u16 out_width, u16 out_height, 2499 u32 fourcc, bool *five_taps, 2500 int *x_predecim, int *y_predecim, u16 pos_x, 2501 enum omap_dss_rotation_type rotation_type, 2502 bool mem_to_mem) 2503 { 2504 int maxhdownscale = dispc->feat->max_downscale; 2505 int maxvdownscale = dispc->feat->max_downscale; 2506 const int max_decim_limit = 16; 2507 unsigned long core_clk = 0; 2508 int decim_x, decim_y, ret; 2509 2510 if (width == out_width && height == out_height) 2511 return 0; 2512 2513 if (plane == OMAP_DSS_WB) { 2514 switch (fourcc) { 2515 case DRM_FORMAT_NV12: 2516 maxhdownscale = maxvdownscale = 2; 2517 break; 2518 case DRM_FORMAT_YUYV: 2519 case DRM_FORMAT_UYVY: 2520 maxhdownscale = 2; 2521 maxvdownscale = 4; 2522 break; 2523 default: 2524 break; 2525 } 2526 } 2527 if (!mem_to_mem && (pclk == 0 || vm->pixelclock == 0)) { 2528 DSSERR("cannot calculate scaling settings: pclk is zero\n"); 2529 return -EINVAL; 2530 } 2531 2532 if ((caps & OMAP_DSS_OVL_CAP_SCALE) == 0) 2533 return -EINVAL; 2534 2535 if (mem_to_mem) { 2536 *x_predecim = *y_predecim = 1; 2537 } else { 2538 *x_predecim = max_decim_limit; 2539 *y_predecim = (rotation_type == OMAP_DSS_ROT_TILER && 2540 dispc_has_feature(dispc, FEAT_BURST_2D)) ? 2541 2 : max_decim_limit; 2542 } 2543 2544 decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxhdownscale); 2545 decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxvdownscale); 2546 2547 if (decim_x > *x_predecim || out_width > width * 8) 2548 return -EINVAL; 2549 2550 if (decim_y > *y_predecim || out_height > height * 8) 2551 return -EINVAL; 2552 2553 ret = dispc->feat->calc_scaling(dispc, pclk, lclk, vm, width, height, 2554 out_width, out_height, fourcc, 2555 five_taps, x_predecim, y_predecim, 2556 &decim_x, &decim_y, pos_x, &core_clk, 2557 mem_to_mem); 2558 if (ret) 2559 return ret; 2560 2561 DSSDBG("%dx%d -> %dx%d (%d.%02d x %d.%02d), decim %dx%d %dx%d (%d.%02d x %d.%02d), taps %d, req clk %lu, cur clk %lu\n", 2562 width, height, 2563 out_width, out_height, 2564 out_width / width, DIV_FRAC(out_width, width), 2565 out_height / height, DIV_FRAC(out_height, height), 2566 2567 decim_x, decim_y, 2568 width / decim_x, height / decim_y, 2569 out_width / (width / decim_x), DIV_FRAC(out_width, width / decim_x), 2570 out_height / (height / decim_y), DIV_FRAC(out_height, height / decim_y), 2571 2572 *five_taps ? 5 : 3, 2573 core_clk, dispc_core_clk_rate(dispc)); 2574 2575 if (!core_clk || core_clk > dispc_core_clk_rate(dispc)) { 2576 DSSERR("failed to set up scaling, " 2577 "required core clk rate = %lu Hz, " 2578 "current core clk rate = %lu Hz\n", 2579 core_clk, dispc_core_clk_rate(dispc)); 2580 return -EINVAL; 2581 } 2582 2583 *x_predecim = decim_x; 2584 *y_predecim = decim_y; 2585 return 0; 2586 } 2587 2588 static int dispc_ovl_setup_common(struct dispc_device *dispc, 2589 enum omap_plane_id plane, 2590 enum omap_overlay_caps caps, 2591 u32 paddr, u32 p_uv_addr, 2592 u16 screen_width, int pos_x, int pos_y, 2593 u16 width, u16 height, 2594 u16 out_width, u16 out_height, 2595 u32 fourcc, u8 rotation, u8 zorder, 2596 u8 pre_mult_alpha, u8 global_alpha, 2597 enum omap_dss_rotation_type rotation_type, 2598 bool replication, const struct videomode *vm, 2599 bool mem_to_mem) 2600 { 2601 bool five_taps = true; 2602 bool fieldmode = false; 2603 int r, cconv = 0; 2604 unsigned int offset0, offset1; 2605 s32 row_inc; 2606 s32 pix_inc; 2607 u16 frame_width; 2608 unsigned int field_offset = 0; 2609 u16 in_height = height; 2610 u16 in_width = width; 2611 int x_predecim = 1, y_predecim = 1; 2612 bool ilace = !!(vm->flags & DISPLAY_FLAGS_INTERLACED); 2613 unsigned long pclk = dispc_plane_pclk_rate(dispc, plane); 2614 unsigned long lclk = dispc_plane_lclk_rate(dispc, plane); 2615 const struct drm_format_info *info; 2616 2617 info = drm_format_info(fourcc); 2618 2619 /* when setting up WB, dispc_plane_pclk_rate() returns 0 */ 2620 if (plane == OMAP_DSS_WB) 2621 pclk = vm->pixelclock; 2622 2623 if (paddr == 0 && rotation_type != OMAP_DSS_ROT_TILER) 2624 return -EINVAL; 2625 2626 if (info->is_yuv && (in_width & 1)) { 2627 DSSERR("input width %d is not even for YUV format\n", in_width); 2628 return -EINVAL; 2629 } 2630 2631 out_width = out_width == 0 ? width : out_width; 2632 out_height = out_height == 0 ? height : out_height; 2633 2634 if (plane != OMAP_DSS_WB) { 2635 if (ilace && height == out_height) 2636 fieldmode = true; 2637 2638 if (ilace) { 2639 if (fieldmode) 2640 in_height /= 2; 2641 pos_y /= 2; 2642 out_height /= 2; 2643 2644 DSSDBG("adjusting for ilace: height %d, pos_y %d, out_height %d\n", 2645 in_height, pos_y, out_height); 2646 } 2647 } 2648 2649 if (!dispc_ovl_color_mode_supported(dispc, plane, fourcc)) 2650 return -EINVAL; 2651 2652 r = dispc_ovl_calc_scaling(dispc, plane, pclk, lclk, caps, vm, in_width, 2653 in_height, out_width, out_height, fourcc, 2654 &five_taps, &x_predecim, &y_predecim, pos_x, 2655 rotation_type, mem_to_mem); 2656 if (r) 2657 return r; 2658 2659 in_width = in_width / x_predecim; 2660 in_height = in_height / y_predecim; 2661 2662 if (x_predecim > 1 || y_predecim > 1) 2663 DSSDBG("predecimation %d x %x, new input size %d x %d\n", 2664 x_predecim, y_predecim, in_width, in_height); 2665 2666 if (info->is_yuv && (in_width & 1)) { 2667 DSSDBG("predecimated input width is not even for YUV format\n"); 2668 DSSDBG("adjusting input width %d -> %d\n", 2669 in_width, in_width & ~1); 2670 2671 in_width &= ~1; 2672 } 2673 2674 if (info->is_yuv) 2675 cconv = 1; 2676 2677 if (ilace && !fieldmode) { 2678 /* 2679 * when downscaling the bottom field may have to start several 2680 * source lines below the top field. Unfortunately ACCUI 2681 * registers will only hold the fractional part of the offset 2682 * so the integer part must be added to the base address of the 2683 * bottom field. 2684 */ 2685 if (!in_height || in_height == out_height) 2686 field_offset = 0; 2687 else 2688 field_offset = in_height / out_height / 2; 2689 } 2690 2691 /* Fields are independent but interleaved in memory. */ 2692 if (fieldmode) 2693 field_offset = 1; 2694 2695 offset0 = 0; 2696 offset1 = 0; 2697 row_inc = 0; 2698 pix_inc = 0; 2699 2700 if (plane == OMAP_DSS_WB) 2701 frame_width = out_width; 2702 else 2703 frame_width = in_width; 2704 2705 calc_offset(screen_width, frame_width, 2706 fourcc, fieldmode, field_offset, 2707 &offset0, &offset1, &row_inc, &pix_inc, 2708 x_predecim, y_predecim, 2709 rotation_type, rotation); 2710 2711 DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n", 2712 offset0, offset1, row_inc, pix_inc); 2713 2714 dispc_ovl_set_color_mode(dispc, plane, fourcc); 2715 2716 dispc_ovl_configure_burst_type(dispc, plane, rotation_type); 2717 2718 if (dispc->feat->reverse_ilace_field_order) 2719 swap(offset0, offset1); 2720 2721 dispc_ovl_set_ba0(dispc, plane, paddr + offset0); 2722 dispc_ovl_set_ba1(dispc, plane, paddr + offset1); 2723 2724 if (fourcc == DRM_FORMAT_NV12) { 2725 dispc_ovl_set_ba0_uv(dispc, plane, p_uv_addr + offset0); 2726 dispc_ovl_set_ba1_uv(dispc, plane, p_uv_addr + offset1); 2727 } 2728 2729 if (dispc->feat->last_pixel_inc_missing) 2730 row_inc += pix_inc - 1; 2731 2732 dispc_ovl_set_row_inc(dispc, plane, row_inc); 2733 dispc_ovl_set_pix_inc(dispc, plane, pix_inc); 2734 2735 DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, in_width, 2736 in_height, out_width, out_height); 2737 2738 dispc_ovl_set_pos(dispc, plane, caps, pos_x, pos_y); 2739 2740 dispc_ovl_set_input_size(dispc, plane, in_width, in_height); 2741 2742 if (caps & OMAP_DSS_OVL_CAP_SCALE) { 2743 dispc_ovl_set_scaling(dispc, plane, in_width, in_height, 2744 out_width, out_height, ilace, five_taps, 2745 fieldmode, fourcc, rotation); 2746 dispc_ovl_set_output_size(dispc, plane, out_width, out_height); 2747 dispc_ovl_set_vid_color_conv(dispc, plane, cconv); 2748 } 2749 2750 dispc_ovl_set_rotation_attrs(dispc, plane, rotation, rotation_type, 2751 fourcc); 2752 2753 dispc_ovl_set_zorder(dispc, plane, caps, zorder); 2754 dispc_ovl_set_pre_mult_alpha(dispc, plane, caps, pre_mult_alpha); 2755 dispc_ovl_setup_global_alpha(dispc, plane, caps, global_alpha); 2756 2757 dispc_ovl_enable_replication(dispc, plane, caps, replication); 2758 2759 return 0; 2760 } 2761 2762 static int dispc_ovl_setup(struct dispc_device *dispc, 2763 enum omap_plane_id plane, 2764 const struct omap_overlay_info *oi, 2765 const struct videomode *vm, bool mem_to_mem, 2766 enum omap_channel channel) 2767 { 2768 int r; 2769 enum omap_overlay_caps caps = dispc->feat->overlay_caps[plane]; 2770 const bool replication = true; 2771 2772 DSSDBG("dispc_ovl_setup %d, pa %pad, pa_uv %pad, sw %d, %d,%d, %dx%d ->" 2773 " %dx%d, cmode %x, rot %d, chan %d repl %d\n", 2774 plane, &oi->paddr, &oi->p_uv_addr, oi->screen_width, oi->pos_x, 2775 oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height, 2776 oi->fourcc, oi->rotation, channel, replication); 2777 2778 dispc_ovl_set_channel_out(dispc, plane, channel); 2779 2780 r = dispc_ovl_setup_common(dispc, plane, caps, oi->paddr, oi->p_uv_addr, 2781 oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, 2782 oi->out_width, oi->out_height, oi->fourcc, oi->rotation, 2783 oi->zorder, oi->pre_mult_alpha, oi->global_alpha, 2784 oi->rotation_type, replication, vm, mem_to_mem); 2785 2786 return r; 2787 } 2788 2789 static int dispc_wb_setup(struct dispc_device *dispc, 2790 const struct omap_dss_writeback_info *wi, 2791 bool mem_to_mem, const struct videomode *vm, 2792 enum dss_writeback_channel channel_in) 2793 { 2794 int r; 2795 u32 l; 2796 enum omap_plane_id plane = OMAP_DSS_WB; 2797 const int pos_x = 0, pos_y = 0; 2798 const u8 zorder = 0, global_alpha = 0; 2799 const bool replication = true; 2800 bool truncation; 2801 int in_width = vm->hactive; 2802 int in_height = vm->vactive; 2803 enum omap_overlay_caps caps = 2804 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA; 2805 2806 if (vm->flags & DISPLAY_FLAGS_INTERLACED) 2807 in_height /= 2; 2808 2809 DSSDBG("dispc_wb_setup, pa %x, pa_uv %x, %d,%d -> %dx%d, cmode %x, " 2810 "rot %d\n", wi->paddr, wi->p_uv_addr, in_width, 2811 in_height, wi->width, wi->height, wi->fourcc, wi->rotation); 2812 2813 r = dispc_ovl_setup_common(dispc, plane, caps, wi->paddr, wi->p_uv_addr, 2814 wi->buf_width, pos_x, pos_y, in_width, in_height, wi->width, 2815 wi->height, wi->fourcc, wi->rotation, zorder, 2816 wi->pre_mult_alpha, global_alpha, wi->rotation_type, 2817 replication, vm, mem_to_mem); 2818 if (r) 2819 return r; 2820 2821 switch (wi->fourcc) { 2822 case DRM_FORMAT_RGB565: 2823 case DRM_FORMAT_RGB888: 2824 case DRM_FORMAT_ARGB4444: 2825 case DRM_FORMAT_RGBA4444: 2826 case DRM_FORMAT_RGBX4444: 2827 case DRM_FORMAT_ARGB1555: 2828 case DRM_FORMAT_XRGB1555: 2829 case DRM_FORMAT_XRGB4444: 2830 truncation = true; 2831 break; 2832 default: 2833 truncation = false; 2834 break; 2835 } 2836 2837 /* setup extra DISPC_WB_ATTRIBUTES */ 2838 l = dispc_read_reg(dispc, DISPC_OVL_ATTRIBUTES(plane)); 2839 l = FLD_MOD(l, truncation, 10, 10); /* TRUNCATIONENABLE */ 2840 l = FLD_MOD(l, channel_in, 18, 16); /* CHANNELIN */ 2841 l = FLD_MOD(l, mem_to_mem, 19, 19); /* WRITEBACKMODE */ 2842 if (mem_to_mem) 2843 l = FLD_MOD(l, 1, 26, 24); /* CAPTUREMODE */ 2844 else 2845 l = FLD_MOD(l, 0, 26, 24); /* CAPTUREMODE */ 2846 dispc_write_reg(dispc, DISPC_OVL_ATTRIBUTES(plane), l); 2847 2848 if (mem_to_mem) { 2849 /* WBDELAYCOUNT */ 2850 REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane), 0, 7, 0); 2851 } else { 2852 u32 wbdelay; 2853 2854 if (channel_in == DSS_WB_TV_MGR) 2855 wbdelay = vm->vsync_len + vm->vback_porch; 2856 else 2857 wbdelay = vm->vfront_porch + vm->vsync_len + 2858 vm->vback_porch; 2859 2860 if (vm->flags & DISPLAY_FLAGS_INTERLACED) 2861 wbdelay /= 2; 2862 2863 wbdelay = min(wbdelay, 255u); 2864 2865 /* WBDELAYCOUNT */ 2866 REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES2(plane), wbdelay, 7, 0); 2867 } 2868 2869 return 0; 2870 } 2871 2872 static bool dispc_has_writeback(struct dispc_device *dispc) 2873 { 2874 return dispc->feat->has_writeback; 2875 } 2876 2877 static int dispc_ovl_enable(struct dispc_device *dispc, 2878 enum omap_plane_id plane, bool enable) 2879 { 2880 DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); 2881 2882 REG_FLD_MOD(dispc, DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0); 2883 2884 return 0; 2885 } 2886 2887 static void dispc_lcd_enable_signal_polarity(struct dispc_device *dispc, 2888 bool act_high) 2889 { 2890 if (!dispc_has_feature(dispc, FEAT_LCDENABLEPOL)) 2891 return; 2892 2893 REG_FLD_MOD(dispc, DISPC_CONTROL, act_high ? 1 : 0, 29, 29); 2894 } 2895 2896 void dispc_lcd_enable_signal(struct dispc_device *dispc, bool enable) 2897 { 2898 if (!dispc_has_feature(dispc, FEAT_LCDENABLESIGNAL)) 2899 return; 2900 2901 REG_FLD_MOD(dispc, DISPC_CONTROL, enable ? 1 : 0, 28, 28); 2902 } 2903 2904 void dispc_pck_free_enable(struct dispc_device *dispc, bool enable) 2905 { 2906 if (!dispc_has_feature(dispc, FEAT_PCKFREEENABLE)) 2907 return; 2908 2909 REG_FLD_MOD(dispc, DISPC_CONTROL, enable ? 1 : 0, 27, 27); 2910 } 2911 2912 static void dispc_mgr_enable_fifohandcheck(struct dispc_device *dispc, 2913 enum omap_channel channel, 2914 bool enable) 2915 { 2916 mgr_fld_write(dispc, channel, DISPC_MGR_FLD_FIFOHANDCHECK, enable); 2917 } 2918 2919 2920 static void dispc_mgr_set_lcd_type_tft(struct dispc_device *dispc, 2921 enum omap_channel channel) 2922 { 2923 mgr_fld_write(dispc, channel, DISPC_MGR_FLD_STNTFT, 1); 2924 } 2925 2926 static void dispc_set_loadmode(struct dispc_device *dispc, 2927 enum omap_dss_load_mode mode) 2928 { 2929 REG_FLD_MOD(dispc, DISPC_CONFIG, mode, 2, 1); 2930 } 2931 2932 2933 static void dispc_mgr_set_default_color(struct dispc_device *dispc, 2934 enum omap_channel channel, u32 color) 2935 { 2936 dispc_write_reg(dispc, DISPC_DEFAULT_COLOR(channel), color); 2937 } 2938 2939 static void dispc_mgr_set_trans_key(struct dispc_device *dispc, 2940 enum omap_channel ch, 2941 enum omap_dss_trans_key_type type, 2942 u32 trans_key) 2943 { 2944 mgr_fld_write(dispc, ch, DISPC_MGR_FLD_TCKSELECTION, type); 2945 2946 dispc_write_reg(dispc, DISPC_TRANS_COLOR(ch), trans_key); 2947 } 2948 2949 static void dispc_mgr_enable_trans_key(struct dispc_device *dispc, 2950 enum omap_channel ch, bool enable) 2951 { 2952 mgr_fld_write(dispc, ch, DISPC_MGR_FLD_TCKENABLE, enable); 2953 } 2954 2955 static void dispc_mgr_enable_alpha_fixed_zorder(struct dispc_device *dispc, 2956 enum omap_channel ch, 2957 bool enable) 2958 { 2959 if (!dispc_has_feature(dispc, FEAT_ALPHA_FIXED_ZORDER)) 2960 return; 2961 2962 if (ch == OMAP_DSS_CHANNEL_LCD) 2963 REG_FLD_MOD(dispc, DISPC_CONFIG, enable, 18, 18); 2964 else if (ch == OMAP_DSS_CHANNEL_DIGIT) 2965 REG_FLD_MOD(dispc, DISPC_CONFIG, enable, 19, 19); 2966 } 2967 2968 static void dispc_mgr_setup(struct dispc_device *dispc, 2969 enum omap_channel channel, 2970 const struct omap_overlay_manager_info *info) 2971 { 2972 dispc_mgr_set_default_color(dispc, channel, info->default_color); 2973 dispc_mgr_set_trans_key(dispc, channel, info->trans_key_type, 2974 info->trans_key); 2975 dispc_mgr_enable_trans_key(dispc, channel, info->trans_enabled); 2976 dispc_mgr_enable_alpha_fixed_zorder(dispc, channel, 2977 info->partial_alpha_enabled); 2978 if (dispc_has_feature(dispc, FEAT_CPR)) { 2979 dispc_mgr_enable_cpr(dispc, channel, info->cpr_enable); 2980 dispc_mgr_set_cpr_coef(dispc, channel, &info->cpr_coefs); 2981 } 2982 } 2983 2984 static void dispc_mgr_set_tft_data_lines(struct dispc_device *dispc, 2985 enum omap_channel channel, 2986 u8 data_lines) 2987 { 2988 int code; 2989 2990 switch (data_lines) { 2991 case 12: 2992 code = 0; 2993 break; 2994 case 16: 2995 code = 1; 2996 break; 2997 case 18: 2998 code = 2; 2999 break; 3000 case 24: 3001 code = 3; 3002 break; 3003 default: 3004 BUG(); 3005 return; 3006 } 3007 3008 mgr_fld_write(dispc, channel, DISPC_MGR_FLD_TFTDATALINES, code); 3009 } 3010 3011 static void dispc_mgr_set_io_pad_mode(struct dispc_device *dispc, 3012 enum dss_io_pad_mode mode) 3013 { 3014 u32 l; 3015 int gpout0, gpout1; 3016 3017 switch (mode) { 3018 case DSS_IO_PAD_MODE_RESET: 3019 gpout0 = 0; 3020 gpout1 = 0; 3021 break; 3022 case DSS_IO_PAD_MODE_RFBI: 3023 gpout0 = 1; 3024 gpout1 = 0; 3025 break; 3026 case DSS_IO_PAD_MODE_BYPASS: 3027 gpout0 = 1; 3028 gpout1 = 1; 3029 break; 3030 default: 3031 BUG(); 3032 return; 3033 } 3034 3035 l = dispc_read_reg(dispc, DISPC_CONTROL); 3036 l = FLD_MOD(l, gpout0, 15, 15); 3037 l = FLD_MOD(l, gpout1, 16, 16); 3038 dispc_write_reg(dispc, DISPC_CONTROL, l); 3039 } 3040 3041 static void dispc_mgr_enable_stallmode(struct dispc_device *dispc, 3042 enum omap_channel channel, bool enable) 3043 { 3044 mgr_fld_write(dispc, channel, DISPC_MGR_FLD_STALLMODE, enable); 3045 } 3046 3047 static void dispc_mgr_set_lcd_config(struct dispc_device *dispc, 3048 enum omap_channel channel, 3049 const struct dss_lcd_mgr_config *config) 3050 { 3051 dispc_mgr_set_io_pad_mode(dispc, config->io_pad_mode); 3052 3053 dispc_mgr_enable_stallmode(dispc, channel, config->stallmode); 3054 dispc_mgr_enable_fifohandcheck(dispc, channel, config->fifohandcheck); 3055 3056 dispc_mgr_set_clock_div(dispc, channel, &config->clock_info); 3057 3058 dispc_mgr_set_tft_data_lines(dispc, channel, config->video_port_width); 3059 3060 dispc_lcd_enable_signal_polarity(dispc, config->lcden_sig_polarity); 3061 3062 dispc_mgr_set_lcd_type_tft(dispc, channel); 3063 } 3064 3065 static bool _dispc_mgr_size_ok(struct dispc_device *dispc, 3066 u16 width, u16 height) 3067 { 3068 return width <= dispc->feat->mgr_width_max && 3069 height <= dispc->feat->mgr_height_max; 3070 } 3071 3072 static bool _dispc_lcd_timings_ok(struct dispc_device *dispc, 3073 int hsync_len, int hfp, int hbp, 3074 int vsw, int vfp, int vbp) 3075 { 3076 if (hsync_len < 1 || hsync_len > dispc->feat->sw_max || 3077 hfp < 1 || hfp > dispc->feat->hp_max || 3078 hbp < 1 || hbp > dispc->feat->hp_max || 3079 vsw < 1 || vsw > dispc->feat->sw_max || 3080 vfp < 0 || vfp > dispc->feat->vp_max || 3081 vbp < 0 || vbp > dispc->feat->vp_max) 3082 return false; 3083 return true; 3084 } 3085 3086 static bool _dispc_mgr_pclk_ok(struct dispc_device *dispc, 3087 enum omap_channel channel, 3088 unsigned long pclk) 3089 { 3090 if (dss_mgr_is_lcd(channel)) 3091 return pclk <= dispc->feat->max_lcd_pclk; 3092 else 3093 return pclk <= dispc->feat->max_tv_pclk; 3094 } 3095 3096 static int dispc_mgr_check_timings(struct dispc_device *dispc, 3097 enum omap_channel channel, 3098 const struct videomode *vm) 3099 { 3100 if (!_dispc_mgr_size_ok(dispc, vm->hactive, vm->vactive)) 3101 return MODE_BAD; 3102 3103 if (!_dispc_mgr_pclk_ok(dispc, channel, vm->pixelclock)) 3104 return MODE_BAD; 3105 3106 if (dss_mgr_is_lcd(channel)) { 3107 /* TODO: OMAP4+ supports interlace for LCD outputs */ 3108 if (vm->flags & DISPLAY_FLAGS_INTERLACED) 3109 return MODE_BAD; 3110 3111 if (!_dispc_lcd_timings_ok(dispc, vm->hsync_len, 3112 vm->hfront_porch, vm->hback_porch, 3113 vm->vsync_len, vm->vfront_porch, 3114 vm->vback_porch)) 3115 return MODE_BAD; 3116 } 3117 3118 return MODE_OK; 3119 } 3120 3121 static void _dispc_mgr_set_lcd_timings(struct dispc_device *dispc, 3122 enum omap_channel channel, 3123 const struct videomode *vm) 3124 { 3125 u32 timing_h, timing_v, l; 3126 bool onoff, rf, ipc, vs, hs, de; 3127 3128 timing_h = FLD_VAL(vm->hsync_len - 1, dispc->feat->sw_start, 0) | 3129 FLD_VAL(vm->hfront_porch - 1, dispc->feat->fp_start, 8) | 3130 FLD_VAL(vm->hback_porch - 1, dispc->feat->bp_start, 20); 3131 timing_v = FLD_VAL(vm->vsync_len - 1, dispc->feat->sw_start, 0) | 3132 FLD_VAL(vm->vfront_porch, dispc->feat->fp_start, 8) | 3133 FLD_VAL(vm->vback_porch, dispc->feat->bp_start, 20); 3134 3135 dispc_write_reg(dispc, DISPC_TIMING_H(channel), timing_h); 3136 dispc_write_reg(dispc, DISPC_TIMING_V(channel), timing_v); 3137 3138 if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH) 3139 vs = false; 3140 else 3141 vs = true; 3142 3143 if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH) 3144 hs = false; 3145 else 3146 hs = true; 3147 3148 if (vm->flags & DISPLAY_FLAGS_DE_HIGH) 3149 de = false; 3150 else 3151 de = true; 3152 3153 if (vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE) 3154 ipc = false; 3155 else 3156 ipc = true; 3157 3158 /* always use the 'rf' setting */ 3159 onoff = true; 3160 3161 if (vm->flags & DISPLAY_FLAGS_SYNC_POSEDGE) 3162 rf = true; 3163 else 3164 rf = false; 3165 3166 l = FLD_VAL(onoff, 17, 17) | 3167 FLD_VAL(rf, 16, 16) | 3168 FLD_VAL(de, 15, 15) | 3169 FLD_VAL(ipc, 14, 14) | 3170 FLD_VAL(hs, 13, 13) | 3171 FLD_VAL(vs, 12, 12); 3172 3173 /* always set ALIGN bit when available */ 3174 if (dispc->feat->supports_sync_align) 3175 l |= (1 << 18); 3176 3177 dispc_write_reg(dispc, DISPC_POL_FREQ(channel), l); 3178 3179 if (dispc->syscon_pol) { 3180 const int shifts[] = { 3181 [OMAP_DSS_CHANNEL_LCD] = 0, 3182 [OMAP_DSS_CHANNEL_LCD2] = 1, 3183 [OMAP_DSS_CHANNEL_LCD3] = 2, 3184 }; 3185 3186 u32 mask, val; 3187 3188 mask = (1 << 0) | (1 << 3) | (1 << 6); 3189 val = (rf << 0) | (ipc << 3) | (onoff << 6); 3190 3191 mask <<= 16 + shifts[channel]; 3192 val <<= 16 + shifts[channel]; 3193 3194 regmap_update_bits(dispc->syscon_pol, dispc->syscon_pol_offset, 3195 mask, val); 3196 } 3197 } 3198 3199 static int vm_flag_to_int(enum display_flags flags, enum display_flags high, 3200 enum display_flags low) 3201 { 3202 if (flags & high) 3203 return 1; 3204 if (flags & low) 3205 return -1; 3206 return 0; 3207 } 3208 3209 /* change name to mode? */ 3210 static void dispc_mgr_set_timings(struct dispc_device *dispc, 3211 enum omap_channel channel, 3212 const struct videomode *vm) 3213 { 3214 unsigned int xtot, ytot; 3215 unsigned long ht, vt; 3216 struct videomode t = *vm; 3217 3218 DSSDBG("channel %d xres %u yres %u\n", channel, t.hactive, t.vactive); 3219 3220 if (dispc_mgr_check_timings(dispc, channel, &t)) { 3221 BUG(); 3222 return; 3223 } 3224 3225 if (dss_mgr_is_lcd(channel)) { 3226 _dispc_mgr_set_lcd_timings(dispc, channel, &t); 3227 3228 xtot = t.hactive + t.hfront_porch + t.hsync_len + t.hback_porch; 3229 ytot = t.vactive + t.vfront_porch + t.vsync_len + t.vback_porch; 3230 3231 ht = vm->pixelclock / xtot; 3232 vt = vm->pixelclock / xtot / ytot; 3233 3234 DSSDBG("pck %lu\n", vm->pixelclock); 3235 DSSDBG("hsync_len %d hfp %d hbp %d vsw %d vfp %d vbp %d\n", 3236 t.hsync_len, t.hfront_porch, t.hback_porch, 3237 t.vsync_len, t.vfront_porch, t.vback_porch); 3238 DSSDBG("vsync_level %d hsync_level %d data_pclk_edge %d de_level %d sync_pclk_edge %d\n", 3239 vm_flag_to_int(t.flags, DISPLAY_FLAGS_VSYNC_HIGH, DISPLAY_FLAGS_VSYNC_LOW), 3240 vm_flag_to_int(t.flags, DISPLAY_FLAGS_HSYNC_HIGH, DISPLAY_FLAGS_HSYNC_LOW), 3241 vm_flag_to_int(t.flags, DISPLAY_FLAGS_PIXDATA_POSEDGE, DISPLAY_FLAGS_PIXDATA_NEGEDGE), 3242 vm_flag_to_int(t.flags, DISPLAY_FLAGS_DE_HIGH, DISPLAY_FLAGS_DE_LOW), 3243 vm_flag_to_int(t.flags, DISPLAY_FLAGS_SYNC_POSEDGE, DISPLAY_FLAGS_SYNC_NEGEDGE)); 3244 3245 DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt); 3246 } else { 3247 if (t.flags & DISPLAY_FLAGS_INTERLACED) 3248 t.vactive /= 2; 3249 3250 if (dispc->feat->supports_double_pixel) 3251 REG_FLD_MOD(dispc, DISPC_CONTROL, 3252 !!(t.flags & DISPLAY_FLAGS_DOUBLECLK), 3253 19, 17); 3254 } 3255 3256 dispc_mgr_set_size(dispc, channel, t.hactive, t.vactive); 3257 } 3258 3259 static void dispc_mgr_set_lcd_divisor(struct dispc_device *dispc, 3260 enum omap_channel channel, u16 lck_div, 3261 u16 pck_div) 3262 { 3263 BUG_ON(lck_div < 1); 3264 BUG_ON(pck_div < 1); 3265 3266 dispc_write_reg(dispc, DISPC_DIVISORo(channel), 3267 FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0)); 3268 3269 if (!dispc_has_feature(dispc, FEAT_CORE_CLK_DIV) && 3270 channel == OMAP_DSS_CHANNEL_LCD) 3271 dispc->core_clk_rate = dispc_fclk_rate(dispc) / lck_div; 3272 } 3273 3274 static void dispc_mgr_get_lcd_divisor(struct dispc_device *dispc, 3275 enum omap_channel channel, int *lck_div, 3276 int *pck_div) 3277 { 3278 u32 l; 3279 l = dispc_read_reg(dispc, DISPC_DIVISORo(channel)); 3280 *lck_div = FLD_GET(l, 23, 16); 3281 *pck_div = FLD_GET(l, 7, 0); 3282 } 3283 3284 static unsigned long dispc_fclk_rate(struct dispc_device *dispc) 3285 { 3286 unsigned long r; 3287 enum dss_clk_source src; 3288 3289 src = dss_get_dispc_clk_source(dispc->dss); 3290 3291 if (src == DSS_CLK_SRC_FCK) { 3292 r = dss_get_dispc_clk_rate(dispc->dss); 3293 } else { 3294 struct dss_pll *pll; 3295 unsigned int clkout_idx; 3296 3297 pll = dss_pll_find_by_src(dispc->dss, src); 3298 clkout_idx = dss_pll_get_clkout_idx_for_src(src); 3299 3300 r = pll->cinfo.clkout[clkout_idx]; 3301 } 3302 3303 return r; 3304 } 3305 3306 static unsigned long dispc_mgr_lclk_rate(struct dispc_device *dispc, 3307 enum omap_channel channel) 3308 { 3309 int lcd; 3310 unsigned long r; 3311 enum dss_clk_source src; 3312 3313 /* for TV, LCLK rate is the FCLK rate */ 3314 if (!dss_mgr_is_lcd(channel)) 3315 return dispc_fclk_rate(dispc); 3316 3317 src = dss_get_lcd_clk_source(dispc->dss, channel); 3318 3319 if (src == DSS_CLK_SRC_FCK) { 3320 r = dss_get_dispc_clk_rate(dispc->dss); 3321 } else { 3322 struct dss_pll *pll; 3323 unsigned int clkout_idx; 3324 3325 pll = dss_pll_find_by_src(dispc->dss, src); 3326 clkout_idx = dss_pll_get_clkout_idx_for_src(src); 3327 3328 r = pll->cinfo.clkout[clkout_idx]; 3329 } 3330 3331 lcd = REG_GET(dispc, DISPC_DIVISORo(channel), 23, 16); 3332 3333 return r / lcd; 3334 } 3335 3336 static unsigned long dispc_mgr_pclk_rate(struct dispc_device *dispc, 3337 enum omap_channel channel) 3338 { 3339 unsigned long r; 3340 3341 if (dss_mgr_is_lcd(channel)) { 3342 int pcd; 3343 u32 l; 3344 3345 l = dispc_read_reg(dispc, DISPC_DIVISORo(channel)); 3346 3347 pcd = FLD_GET(l, 7, 0); 3348 3349 r = dispc_mgr_lclk_rate(dispc, channel); 3350 3351 return r / pcd; 3352 } else { 3353 return dispc->tv_pclk_rate; 3354 } 3355 } 3356 3357 void dispc_set_tv_pclk(struct dispc_device *dispc, unsigned long pclk) 3358 { 3359 dispc->tv_pclk_rate = pclk; 3360 } 3361 3362 static unsigned long dispc_core_clk_rate(struct dispc_device *dispc) 3363 { 3364 return dispc->core_clk_rate; 3365 } 3366 3367 static unsigned long dispc_plane_pclk_rate(struct dispc_device *dispc, 3368 enum omap_plane_id plane) 3369 { 3370 enum omap_channel channel; 3371 3372 if (plane == OMAP_DSS_WB) 3373 return 0; 3374 3375 channel = dispc_ovl_get_channel_out(dispc, plane); 3376 3377 return dispc_mgr_pclk_rate(dispc, channel); 3378 } 3379 3380 static unsigned long dispc_plane_lclk_rate(struct dispc_device *dispc, 3381 enum omap_plane_id plane) 3382 { 3383 enum omap_channel channel; 3384 3385 if (plane == OMAP_DSS_WB) 3386 return 0; 3387 3388 channel = dispc_ovl_get_channel_out(dispc, plane); 3389 3390 return dispc_mgr_lclk_rate(dispc, channel); 3391 } 3392 3393 static void dispc_dump_clocks_channel(struct dispc_device *dispc, 3394 struct seq_file *s, 3395 enum omap_channel channel) 3396 { 3397 int lcd, pcd; 3398 enum dss_clk_source lcd_clk_src; 3399 3400 seq_printf(s, "- %s -\n", mgr_desc[channel].name); 3401 3402 lcd_clk_src = dss_get_lcd_clk_source(dispc->dss, channel); 3403 3404 seq_printf(s, "%s clk source = %s\n", mgr_desc[channel].name, 3405 dss_get_clk_source_name(lcd_clk_src)); 3406 3407 dispc_mgr_get_lcd_divisor(dispc, channel, &lcd, &pcd); 3408 3409 seq_printf(s, "lck\t\t%-16lulck div\t%u\n", 3410 dispc_mgr_lclk_rate(dispc, channel), lcd); 3411 seq_printf(s, "pck\t\t%-16lupck div\t%u\n", 3412 dispc_mgr_pclk_rate(dispc, channel), pcd); 3413 } 3414 3415 void dispc_dump_clocks(struct dispc_device *dispc, struct seq_file *s) 3416 { 3417 enum dss_clk_source dispc_clk_src; 3418 int lcd; 3419 u32 l; 3420 3421 if (dispc_runtime_get(dispc)) 3422 return; 3423 3424 seq_printf(s, "- DISPC -\n"); 3425 3426 dispc_clk_src = dss_get_dispc_clk_source(dispc->dss); 3427 seq_printf(s, "dispc fclk source = %s\n", 3428 dss_get_clk_source_name(dispc_clk_src)); 3429 3430 seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate(dispc)); 3431 3432 if (dispc_has_feature(dispc, FEAT_CORE_CLK_DIV)) { 3433 seq_printf(s, "- DISPC-CORE-CLK -\n"); 3434 l = dispc_read_reg(dispc, DISPC_DIVISOR); 3435 lcd = FLD_GET(l, 23, 16); 3436 3437 seq_printf(s, "lck\t\t%-16lulck div\t%u\n", 3438 (dispc_fclk_rate(dispc)/lcd), lcd); 3439 } 3440 3441 dispc_dump_clocks_channel(dispc, s, OMAP_DSS_CHANNEL_LCD); 3442 3443 if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) 3444 dispc_dump_clocks_channel(dispc, s, OMAP_DSS_CHANNEL_LCD2); 3445 if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) 3446 dispc_dump_clocks_channel(dispc, s, OMAP_DSS_CHANNEL_LCD3); 3447 3448 dispc_runtime_put(dispc); 3449 } 3450 3451 static int dispc_dump_regs(struct seq_file *s, void *p) 3452 { 3453 struct dispc_device *dispc = s->private; 3454 int i, j; 3455 const char *mgr_names[] = { 3456 [OMAP_DSS_CHANNEL_LCD] = "LCD", 3457 [OMAP_DSS_CHANNEL_DIGIT] = "TV", 3458 [OMAP_DSS_CHANNEL_LCD2] = "LCD2", 3459 [OMAP_DSS_CHANNEL_LCD3] = "LCD3", 3460 }; 3461 const char *ovl_names[] = { 3462 [OMAP_DSS_GFX] = "GFX", 3463 [OMAP_DSS_VIDEO1] = "VID1", 3464 [OMAP_DSS_VIDEO2] = "VID2", 3465 [OMAP_DSS_VIDEO3] = "VID3", 3466 [OMAP_DSS_WB] = "WB", 3467 }; 3468 const char **p_names; 3469 3470 #define DUMPREG(dispc, r) \ 3471 seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(dispc, r)) 3472 3473 if (dispc_runtime_get(dispc)) 3474 return 0; 3475 3476 /* DISPC common registers */ 3477 DUMPREG(dispc, DISPC_REVISION); 3478 DUMPREG(dispc, DISPC_SYSCONFIG); 3479 DUMPREG(dispc, DISPC_SYSSTATUS); 3480 DUMPREG(dispc, DISPC_IRQSTATUS); 3481 DUMPREG(dispc, DISPC_IRQENABLE); 3482 DUMPREG(dispc, DISPC_CONTROL); 3483 DUMPREG(dispc, DISPC_CONFIG); 3484 DUMPREG(dispc, DISPC_CAPABLE); 3485 DUMPREG(dispc, DISPC_LINE_STATUS); 3486 DUMPREG(dispc, DISPC_LINE_NUMBER); 3487 if (dispc_has_feature(dispc, FEAT_ALPHA_FIXED_ZORDER) || 3488 dispc_has_feature(dispc, FEAT_ALPHA_FREE_ZORDER)) 3489 DUMPREG(dispc, DISPC_GLOBAL_ALPHA); 3490 if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) { 3491 DUMPREG(dispc, DISPC_CONTROL2); 3492 DUMPREG(dispc, DISPC_CONFIG2); 3493 } 3494 if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) { 3495 DUMPREG(dispc, DISPC_CONTROL3); 3496 DUMPREG(dispc, DISPC_CONFIG3); 3497 } 3498 if (dispc_has_feature(dispc, FEAT_MFLAG)) 3499 DUMPREG(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE); 3500 3501 #undef DUMPREG 3502 3503 #define DISPC_REG(i, name) name(i) 3504 #define DUMPREG(dispc, i, r) seq_printf(s, "%s(%s)%*s %08x\n", #r, p_names[i], \ 3505 (int)(48 - strlen(#r) - strlen(p_names[i])), " ", \ 3506 dispc_read_reg(dispc, DISPC_REG(i, r))) 3507 3508 p_names = mgr_names; 3509 3510 /* DISPC channel specific registers */ 3511 for (i = 0; i < dispc_get_num_mgrs(dispc); i++) { 3512 DUMPREG(dispc, i, DISPC_DEFAULT_COLOR); 3513 DUMPREG(dispc, i, DISPC_TRANS_COLOR); 3514 DUMPREG(dispc, i, DISPC_SIZE_MGR); 3515 3516 if (i == OMAP_DSS_CHANNEL_DIGIT) 3517 continue; 3518 3519 DUMPREG(dispc, i, DISPC_TIMING_H); 3520 DUMPREG(dispc, i, DISPC_TIMING_V); 3521 DUMPREG(dispc, i, DISPC_POL_FREQ); 3522 DUMPREG(dispc, i, DISPC_DIVISORo); 3523 3524 DUMPREG(dispc, i, DISPC_DATA_CYCLE1); 3525 DUMPREG(dispc, i, DISPC_DATA_CYCLE2); 3526 DUMPREG(dispc, i, DISPC_DATA_CYCLE3); 3527 3528 if (dispc_has_feature(dispc, FEAT_CPR)) { 3529 DUMPREG(dispc, i, DISPC_CPR_COEF_R); 3530 DUMPREG(dispc, i, DISPC_CPR_COEF_G); 3531 DUMPREG(dispc, i, DISPC_CPR_COEF_B); 3532 } 3533 } 3534 3535 p_names = ovl_names; 3536 3537 for (i = 0; i < dispc_get_num_ovls(dispc); i++) { 3538 DUMPREG(dispc, i, DISPC_OVL_BA0); 3539 DUMPREG(dispc, i, DISPC_OVL_BA1); 3540 DUMPREG(dispc, i, DISPC_OVL_POSITION); 3541 DUMPREG(dispc, i, DISPC_OVL_SIZE); 3542 DUMPREG(dispc, i, DISPC_OVL_ATTRIBUTES); 3543 DUMPREG(dispc, i, DISPC_OVL_FIFO_THRESHOLD); 3544 DUMPREG(dispc, i, DISPC_OVL_FIFO_SIZE_STATUS); 3545 DUMPREG(dispc, i, DISPC_OVL_ROW_INC); 3546 DUMPREG(dispc, i, DISPC_OVL_PIXEL_INC); 3547 3548 if (dispc_has_feature(dispc, FEAT_PRELOAD)) 3549 DUMPREG(dispc, i, DISPC_OVL_PRELOAD); 3550 if (dispc_has_feature(dispc, FEAT_MFLAG)) 3551 DUMPREG(dispc, i, DISPC_OVL_MFLAG_THRESHOLD); 3552 3553 if (i == OMAP_DSS_GFX) { 3554 DUMPREG(dispc, i, DISPC_OVL_WINDOW_SKIP); 3555 DUMPREG(dispc, i, DISPC_OVL_TABLE_BA); 3556 continue; 3557 } 3558 3559 DUMPREG(dispc, i, DISPC_OVL_FIR); 3560 DUMPREG(dispc, i, DISPC_OVL_PICTURE_SIZE); 3561 DUMPREG(dispc, i, DISPC_OVL_ACCU0); 3562 DUMPREG(dispc, i, DISPC_OVL_ACCU1); 3563 if (dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) { 3564 DUMPREG(dispc, i, DISPC_OVL_BA0_UV); 3565 DUMPREG(dispc, i, DISPC_OVL_BA1_UV); 3566 DUMPREG(dispc, i, DISPC_OVL_FIR2); 3567 DUMPREG(dispc, i, DISPC_OVL_ACCU2_0); 3568 DUMPREG(dispc, i, DISPC_OVL_ACCU2_1); 3569 } 3570 if (dispc_has_feature(dispc, FEAT_ATTR2)) 3571 DUMPREG(dispc, i, DISPC_OVL_ATTRIBUTES2); 3572 } 3573 3574 if (dispc->feat->has_writeback) { 3575 i = OMAP_DSS_WB; 3576 DUMPREG(dispc, i, DISPC_OVL_BA0); 3577 DUMPREG(dispc, i, DISPC_OVL_BA1); 3578 DUMPREG(dispc, i, DISPC_OVL_SIZE); 3579 DUMPREG(dispc, i, DISPC_OVL_ATTRIBUTES); 3580 DUMPREG(dispc, i, DISPC_OVL_FIFO_THRESHOLD); 3581 DUMPREG(dispc, i, DISPC_OVL_FIFO_SIZE_STATUS); 3582 DUMPREG(dispc, i, DISPC_OVL_ROW_INC); 3583 DUMPREG(dispc, i, DISPC_OVL_PIXEL_INC); 3584 3585 if (dispc_has_feature(dispc, FEAT_MFLAG)) 3586 DUMPREG(dispc, i, DISPC_OVL_MFLAG_THRESHOLD); 3587 3588 DUMPREG(dispc, i, DISPC_OVL_FIR); 3589 DUMPREG(dispc, i, DISPC_OVL_PICTURE_SIZE); 3590 DUMPREG(dispc, i, DISPC_OVL_ACCU0); 3591 DUMPREG(dispc, i, DISPC_OVL_ACCU1); 3592 if (dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) { 3593 DUMPREG(dispc, i, DISPC_OVL_BA0_UV); 3594 DUMPREG(dispc, i, DISPC_OVL_BA1_UV); 3595 DUMPREG(dispc, i, DISPC_OVL_FIR2); 3596 DUMPREG(dispc, i, DISPC_OVL_ACCU2_0); 3597 DUMPREG(dispc, i, DISPC_OVL_ACCU2_1); 3598 } 3599 if (dispc_has_feature(dispc, FEAT_ATTR2)) 3600 DUMPREG(dispc, i, DISPC_OVL_ATTRIBUTES2); 3601 } 3602 3603 #undef DISPC_REG 3604 #undef DUMPREG 3605 3606 #define DISPC_REG(plane, name, i) name(plane, i) 3607 #define DUMPREG(dispc, plane, name, i) \ 3608 seq_printf(s, "%s_%d(%s)%*s %08x\n", #name, i, p_names[plane], \ 3609 (int)(46 - strlen(#name) - strlen(p_names[plane])), " ", \ 3610 dispc_read_reg(dispc, DISPC_REG(plane, name, i))) 3611 3612 /* Video pipeline coefficient registers */ 3613 3614 /* start from OMAP_DSS_VIDEO1 */ 3615 for (i = 1; i < dispc_get_num_ovls(dispc); i++) { 3616 for (j = 0; j < 8; j++) 3617 DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_H, j); 3618 3619 for (j = 0; j < 8; j++) 3620 DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_HV, j); 3621 3622 for (j = 0; j < 5; j++) 3623 DUMPREG(dispc, i, DISPC_OVL_CONV_COEF, j); 3624 3625 if (dispc_has_feature(dispc, FEAT_FIR_COEF_V)) { 3626 for (j = 0; j < 8; j++) 3627 DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_V, j); 3628 } 3629 3630 if (dispc_has_feature(dispc, FEAT_HANDLE_UV_SEPARATE)) { 3631 for (j = 0; j < 8; j++) 3632 DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_H2, j); 3633 3634 for (j = 0; j < 8; j++) 3635 DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_HV2, j); 3636 3637 for (j = 0; j < 8; j++) 3638 DUMPREG(dispc, i, DISPC_OVL_FIR_COEF_V2, j); 3639 } 3640 } 3641 3642 dispc_runtime_put(dispc); 3643 3644 #undef DISPC_REG 3645 #undef DUMPREG 3646 3647 return 0; 3648 } 3649 3650 /* calculate clock rates using dividers in cinfo */ 3651 int dispc_calc_clock_rates(struct dispc_device *dispc, 3652 unsigned long dispc_fclk_rate, 3653 struct dispc_clock_info *cinfo) 3654 { 3655 if (cinfo->lck_div > 255 || cinfo->lck_div == 0) 3656 return -EINVAL; 3657 if (cinfo->pck_div < 1 || cinfo->pck_div > 255) 3658 return -EINVAL; 3659 3660 cinfo->lck = dispc_fclk_rate / cinfo->lck_div; 3661 cinfo->pck = cinfo->lck / cinfo->pck_div; 3662 3663 return 0; 3664 } 3665 3666 bool dispc_div_calc(struct dispc_device *dispc, unsigned long dispc_freq, 3667 unsigned long pck_min, unsigned long pck_max, 3668 dispc_div_calc_func func, void *data) 3669 { 3670 int lckd, lckd_start, lckd_stop; 3671 int pckd, pckd_start, pckd_stop; 3672 unsigned long pck, lck; 3673 unsigned long lck_max; 3674 unsigned long pckd_hw_min, pckd_hw_max; 3675 unsigned int min_fck_per_pck; 3676 unsigned long fck; 3677 3678 #ifdef CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK 3679 min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK; 3680 #else 3681 min_fck_per_pck = 0; 3682 #endif 3683 3684 pckd_hw_min = dispc->feat->min_pcd; 3685 pckd_hw_max = 255; 3686 3687 lck_max = dss_get_max_fck_rate(dispc->dss); 3688 3689 pck_min = pck_min ? pck_min : 1; 3690 pck_max = pck_max ? pck_max : ULONG_MAX; 3691 3692 lckd_start = max(DIV_ROUND_UP(dispc_freq, lck_max), 1ul); 3693 lckd_stop = min(dispc_freq / pck_min, 255ul); 3694 3695 for (lckd = lckd_start; lckd <= lckd_stop; ++lckd) { 3696 lck = dispc_freq / lckd; 3697 3698 pckd_start = max(DIV_ROUND_UP(lck, pck_max), pckd_hw_min); 3699 pckd_stop = min(lck / pck_min, pckd_hw_max); 3700 3701 for (pckd = pckd_start; pckd <= pckd_stop; ++pckd) { 3702 pck = lck / pckd; 3703 3704 /* 3705 * For OMAP2/3 the DISPC fclk is the same as LCD's logic 3706 * clock, which means we're configuring DISPC fclk here 3707 * also. Thus we need to use the calculated lck. For 3708 * OMAP4+ the DISPC fclk is a separate clock. 3709 */ 3710 if (dispc_has_feature(dispc, FEAT_CORE_CLK_DIV)) 3711 fck = dispc_core_clk_rate(dispc); 3712 else 3713 fck = lck; 3714 3715 if (fck < pck * min_fck_per_pck) 3716 continue; 3717 3718 if (func(lckd, pckd, lck, pck, data)) 3719 return true; 3720 } 3721 } 3722 3723 return false; 3724 } 3725 3726 void dispc_mgr_set_clock_div(struct dispc_device *dispc, 3727 enum omap_channel channel, 3728 const struct dispc_clock_info *cinfo) 3729 { 3730 DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div); 3731 DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div); 3732 3733 dispc_mgr_set_lcd_divisor(dispc, channel, cinfo->lck_div, 3734 cinfo->pck_div); 3735 } 3736 3737 int dispc_mgr_get_clock_div(struct dispc_device *dispc, 3738 enum omap_channel channel, 3739 struct dispc_clock_info *cinfo) 3740 { 3741 unsigned long fck; 3742 3743 fck = dispc_fclk_rate(dispc); 3744 3745 cinfo->lck_div = REG_GET(dispc, DISPC_DIVISORo(channel), 23, 16); 3746 cinfo->pck_div = REG_GET(dispc, DISPC_DIVISORo(channel), 7, 0); 3747 3748 cinfo->lck = fck / cinfo->lck_div; 3749 cinfo->pck = cinfo->lck / cinfo->pck_div; 3750 3751 return 0; 3752 } 3753 3754 static u32 dispc_read_irqstatus(struct dispc_device *dispc) 3755 { 3756 return dispc_read_reg(dispc, DISPC_IRQSTATUS); 3757 } 3758 3759 static void dispc_clear_irqstatus(struct dispc_device *dispc, u32 mask) 3760 { 3761 dispc_write_reg(dispc, DISPC_IRQSTATUS, mask); 3762 } 3763 3764 static void dispc_write_irqenable(struct dispc_device *dispc, u32 mask) 3765 { 3766 u32 old_mask = dispc_read_reg(dispc, DISPC_IRQENABLE); 3767 3768 /* clear the irqstatus for newly enabled irqs */ 3769 dispc_clear_irqstatus(dispc, (mask ^ old_mask) & mask); 3770 3771 dispc_write_reg(dispc, DISPC_IRQENABLE, mask); 3772 3773 /* flush posted write */ 3774 dispc_read_reg(dispc, DISPC_IRQENABLE); 3775 } 3776 3777 void dispc_enable_sidle(struct dispc_device *dispc) 3778 { 3779 /* SIDLEMODE: smart idle */ 3780 REG_FLD_MOD(dispc, DISPC_SYSCONFIG, 2, 4, 3); 3781 } 3782 3783 void dispc_disable_sidle(struct dispc_device *dispc) 3784 { 3785 REG_FLD_MOD(dispc, DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */ 3786 } 3787 3788 static u32 dispc_mgr_gamma_size(struct dispc_device *dispc, 3789 enum omap_channel channel) 3790 { 3791 const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma; 3792 3793 if (!dispc->feat->has_gamma_table) 3794 return 0; 3795 3796 return gdesc->len; 3797 } 3798 3799 static void dispc_mgr_write_gamma_table(struct dispc_device *dispc, 3800 enum omap_channel channel) 3801 { 3802 const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma; 3803 u32 *table = dispc->gamma_table[channel]; 3804 unsigned int i; 3805 3806 DSSDBG("%s: channel %d\n", __func__, channel); 3807 3808 for (i = 0; i < gdesc->len; ++i) { 3809 u32 v = table[i]; 3810 3811 if (gdesc->has_index) 3812 v |= i << 24; 3813 else if (i == 0) 3814 v |= 1 << 31; 3815 3816 dispc_write_reg(dispc, gdesc->reg, v); 3817 } 3818 } 3819 3820 static void dispc_restore_gamma_tables(struct dispc_device *dispc) 3821 { 3822 DSSDBG("%s()\n", __func__); 3823 3824 if (!dispc->feat->has_gamma_table) 3825 return; 3826 3827 dispc_mgr_write_gamma_table(dispc, OMAP_DSS_CHANNEL_LCD); 3828 3829 dispc_mgr_write_gamma_table(dispc, OMAP_DSS_CHANNEL_DIGIT); 3830 3831 if (dispc_has_feature(dispc, FEAT_MGR_LCD2)) 3832 dispc_mgr_write_gamma_table(dispc, OMAP_DSS_CHANNEL_LCD2); 3833 3834 if (dispc_has_feature(dispc, FEAT_MGR_LCD3)) 3835 dispc_mgr_write_gamma_table(dispc, OMAP_DSS_CHANNEL_LCD3); 3836 } 3837 3838 static const struct drm_color_lut dispc_mgr_gamma_default_lut[] = { 3839 { .red = 0, .green = 0, .blue = 0, }, 3840 { .red = U16_MAX, .green = U16_MAX, .blue = U16_MAX, }, 3841 }; 3842 3843 static void dispc_mgr_set_gamma(struct dispc_device *dispc, 3844 enum omap_channel channel, 3845 const struct drm_color_lut *lut, 3846 unsigned int length) 3847 { 3848 const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma; 3849 u32 *table = dispc->gamma_table[channel]; 3850 uint i; 3851 3852 DSSDBG("%s: channel %d, lut len %u, hw len %u\n", __func__, 3853 channel, length, gdesc->len); 3854 3855 if (!dispc->feat->has_gamma_table) 3856 return; 3857 3858 if (lut == NULL || length < 2) { 3859 lut = dispc_mgr_gamma_default_lut; 3860 length = ARRAY_SIZE(dispc_mgr_gamma_default_lut); 3861 } 3862 3863 for (i = 0; i < length - 1; ++i) { 3864 uint first = i * (gdesc->len - 1) / (length - 1); 3865 uint last = (i + 1) * (gdesc->len - 1) / (length - 1); 3866 uint w = last - first; 3867 u16 r, g, b; 3868 uint j; 3869 3870 if (w == 0) 3871 continue; 3872 3873 for (j = 0; j <= w; j++) { 3874 r = (lut[i].red * (w - j) + lut[i+1].red * j) / w; 3875 g = (lut[i].green * (w - j) + lut[i+1].green * j) / w; 3876 b = (lut[i].blue * (w - j) + lut[i+1].blue * j) / w; 3877 3878 r >>= 16 - gdesc->bits; 3879 g >>= 16 - gdesc->bits; 3880 b >>= 16 - gdesc->bits; 3881 3882 table[first + j] = (r << (gdesc->bits * 2)) | 3883 (g << gdesc->bits) | b; 3884 } 3885 } 3886 3887 if (dispc->is_enabled) 3888 dispc_mgr_write_gamma_table(dispc, channel); 3889 } 3890 3891 static int dispc_init_gamma_tables(struct dispc_device *dispc) 3892 { 3893 int channel; 3894 3895 if (!dispc->feat->has_gamma_table) 3896 return 0; 3897 3898 for (channel = 0; channel < ARRAY_SIZE(dispc->gamma_table); channel++) { 3899 const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma; 3900 u32 *gt; 3901 3902 if (channel == OMAP_DSS_CHANNEL_LCD2 && 3903 !dispc_has_feature(dispc, FEAT_MGR_LCD2)) 3904 continue; 3905 3906 if (channel == OMAP_DSS_CHANNEL_LCD3 && 3907 !dispc_has_feature(dispc, FEAT_MGR_LCD3)) 3908 continue; 3909 3910 gt = devm_kmalloc_array(&dispc->pdev->dev, gdesc->len, 3911 sizeof(u32), GFP_KERNEL); 3912 if (!gt) 3913 return -ENOMEM; 3914 3915 dispc->gamma_table[channel] = gt; 3916 3917 dispc_mgr_set_gamma(dispc, channel, NULL, 0); 3918 } 3919 return 0; 3920 } 3921 3922 static void _omap_dispc_initial_config(struct dispc_device *dispc) 3923 { 3924 u32 l; 3925 3926 /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */ 3927 if (dispc_has_feature(dispc, FEAT_CORE_CLK_DIV)) { 3928 l = dispc_read_reg(dispc, DISPC_DIVISOR); 3929 /* Use DISPC_DIVISOR.LCD, instead of DISPC_DIVISOR1.LCD */ 3930 l = FLD_MOD(l, 1, 0, 0); 3931 l = FLD_MOD(l, 1, 23, 16); 3932 dispc_write_reg(dispc, DISPC_DIVISOR, l); 3933 3934 dispc->core_clk_rate = dispc_fclk_rate(dispc); 3935 } 3936 3937 /* Use gamma table mode, instead of palette mode */ 3938 if (dispc->feat->has_gamma_table) 3939 REG_FLD_MOD(dispc, DISPC_CONFIG, 1, 3, 3); 3940 3941 /* For older DSS versions (FEAT_FUNCGATED) this enables 3942 * func-clock auto-gating. For newer versions 3943 * (dispc->feat->has_gamma_table) this enables tv-out gamma tables. 3944 */ 3945 if (dispc_has_feature(dispc, FEAT_FUNCGATED) || 3946 dispc->feat->has_gamma_table) 3947 REG_FLD_MOD(dispc, DISPC_CONFIG, 1, 9, 9); 3948 3949 dispc_setup_color_conv_coef(dispc); 3950 3951 dispc_set_loadmode(dispc, OMAP_DSS_LOAD_FRAME_ONLY); 3952 3953 dispc_init_fifos(dispc); 3954 3955 dispc_configure_burst_sizes(dispc); 3956 3957 dispc_ovl_enable_zorder_planes(dispc); 3958 3959 if (dispc->feat->mstandby_workaround) 3960 REG_FLD_MOD(dispc, DISPC_MSTANDBY_CTRL, 1, 0, 0); 3961 3962 if (dispc_has_feature(dispc, FEAT_MFLAG)) 3963 dispc_init_mflag(dispc); 3964 } 3965 3966 static const enum dispc_feature_id omap2_dispc_features_list[] = { 3967 FEAT_LCDENABLEPOL, 3968 FEAT_LCDENABLESIGNAL, 3969 FEAT_PCKFREEENABLE, 3970 FEAT_FUNCGATED, 3971 FEAT_ROWREPEATENABLE, 3972 FEAT_RESIZECONF, 3973 }; 3974 3975 static const enum dispc_feature_id omap3_dispc_features_list[] = { 3976 FEAT_LCDENABLEPOL, 3977 FEAT_LCDENABLESIGNAL, 3978 FEAT_PCKFREEENABLE, 3979 FEAT_FUNCGATED, 3980 FEAT_LINEBUFFERSPLIT, 3981 FEAT_ROWREPEATENABLE, 3982 FEAT_RESIZECONF, 3983 FEAT_CPR, 3984 FEAT_PRELOAD, 3985 FEAT_FIR_COEF_V, 3986 FEAT_ALPHA_FIXED_ZORDER, 3987 FEAT_FIFO_MERGE, 3988 FEAT_OMAP3_DSI_FIFO_BUG, 3989 }; 3990 3991 static const enum dispc_feature_id am43xx_dispc_features_list[] = { 3992 FEAT_LCDENABLEPOL, 3993 FEAT_LCDENABLESIGNAL, 3994 FEAT_PCKFREEENABLE, 3995 FEAT_FUNCGATED, 3996 FEAT_LINEBUFFERSPLIT, 3997 FEAT_ROWREPEATENABLE, 3998 FEAT_RESIZECONF, 3999 FEAT_CPR, 4000 FEAT_PRELOAD, 4001 FEAT_FIR_COEF_V, 4002 FEAT_ALPHA_FIXED_ZORDER, 4003 FEAT_FIFO_MERGE, 4004 }; 4005 4006 static const enum dispc_feature_id omap4_dispc_features_list[] = { 4007 FEAT_MGR_LCD2, 4008 FEAT_CORE_CLK_DIV, 4009 FEAT_HANDLE_UV_SEPARATE, 4010 FEAT_ATTR2, 4011 FEAT_CPR, 4012 FEAT_PRELOAD, 4013 FEAT_FIR_COEF_V, 4014 FEAT_ALPHA_FREE_ZORDER, 4015 FEAT_FIFO_MERGE, 4016 FEAT_BURST_2D, 4017 }; 4018 4019 static const enum dispc_feature_id omap5_dispc_features_list[] = { 4020 FEAT_MGR_LCD2, 4021 FEAT_MGR_LCD3, 4022 FEAT_CORE_CLK_DIV, 4023 FEAT_HANDLE_UV_SEPARATE, 4024 FEAT_ATTR2, 4025 FEAT_CPR, 4026 FEAT_PRELOAD, 4027 FEAT_FIR_COEF_V, 4028 FEAT_ALPHA_FREE_ZORDER, 4029 FEAT_FIFO_MERGE, 4030 FEAT_BURST_2D, 4031 FEAT_MFLAG, 4032 }; 4033 4034 static const struct dss_reg_field omap2_dispc_reg_fields[] = { 4035 [FEAT_REG_FIRHINC] = { 11, 0 }, 4036 [FEAT_REG_FIRVINC] = { 27, 16 }, 4037 [FEAT_REG_FIFOLOWTHRESHOLD] = { 8, 0 }, 4038 [FEAT_REG_FIFOHIGHTHRESHOLD] = { 24, 16 }, 4039 [FEAT_REG_FIFOSIZE] = { 8, 0 }, 4040 [FEAT_REG_HORIZONTALACCU] = { 9, 0 }, 4041 [FEAT_REG_VERTICALACCU] = { 25, 16 }, 4042 }; 4043 4044 static const struct dss_reg_field omap3_dispc_reg_fields[] = { 4045 [FEAT_REG_FIRHINC] = { 12, 0 }, 4046 [FEAT_REG_FIRVINC] = { 28, 16 }, 4047 [FEAT_REG_FIFOLOWTHRESHOLD] = { 11, 0 }, 4048 [FEAT_REG_FIFOHIGHTHRESHOLD] = { 27, 16 }, 4049 [FEAT_REG_FIFOSIZE] = { 10, 0 }, 4050 [FEAT_REG_HORIZONTALACCU] = { 9, 0 }, 4051 [FEAT_REG_VERTICALACCU] = { 25, 16 }, 4052 }; 4053 4054 static const struct dss_reg_field omap4_dispc_reg_fields[] = { 4055 [FEAT_REG_FIRHINC] = { 12, 0 }, 4056 [FEAT_REG_FIRVINC] = { 28, 16 }, 4057 [FEAT_REG_FIFOLOWTHRESHOLD] = { 15, 0 }, 4058 [FEAT_REG_FIFOHIGHTHRESHOLD] = { 31, 16 }, 4059 [FEAT_REG_FIFOSIZE] = { 15, 0 }, 4060 [FEAT_REG_HORIZONTALACCU] = { 10, 0 }, 4061 [FEAT_REG_VERTICALACCU] = { 26, 16 }, 4062 }; 4063 4064 static const enum omap_overlay_caps omap2_dispc_overlay_caps[] = { 4065 /* OMAP_DSS_GFX */ 4066 OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, 4067 4068 /* OMAP_DSS_VIDEO1 */ 4069 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS | 4070 OMAP_DSS_OVL_CAP_REPLICATION, 4071 4072 /* OMAP_DSS_VIDEO2 */ 4073 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS | 4074 OMAP_DSS_OVL_CAP_REPLICATION, 4075 }; 4076 4077 static const enum omap_overlay_caps omap3430_dispc_overlay_caps[] = { 4078 /* OMAP_DSS_GFX */ 4079 OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_POS | 4080 OMAP_DSS_OVL_CAP_REPLICATION, 4081 4082 /* OMAP_DSS_VIDEO1 */ 4083 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS | 4084 OMAP_DSS_OVL_CAP_REPLICATION, 4085 4086 /* OMAP_DSS_VIDEO2 */ 4087 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | 4088 OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, 4089 }; 4090 4091 static const enum omap_overlay_caps omap3630_dispc_overlay_caps[] = { 4092 /* OMAP_DSS_GFX */ 4093 OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | 4094 OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, 4095 4096 /* OMAP_DSS_VIDEO1 */ 4097 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS | 4098 OMAP_DSS_OVL_CAP_REPLICATION, 4099 4100 /* OMAP_DSS_VIDEO2 */ 4101 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | 4102 OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_POS | 4103 OMAP_DSS_OVL_CAP_REPLICATION, 4104 }; 4105 4106 static const enum omap_overlay_caps omap4_dispc_overlay_caps[] = { 4107 /* OMAP_DSS_GFX */ 4108 OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | 4109 OMAP_DSS_OVL_CAP_ZORDER | OMAP_DSS_OVL_CAP_POS | 4110 OMAP_DSS_OVL_CAP_REPLICATION, 4111 4112 /* OMAP_DSS_VIDEO1 */ 4113 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | 4114 OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER | 4115 OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, 4116 4117 /* OMAP_DSS_VIDEO2 */ 4118 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | 4119 OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER | 4120 OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, 4121 4122 /* OMAP_DSS_VIDEO3 */ 4123 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | 4124 OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER | 4125 OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, 4126 }; 4127 4128 #define COLOR_ARRAY(arr...) (const u32[]) { arr, 0 } 4129 4130 static const u32 *omap2_dispc_supported_color_modes[] = { 4131 4132 /* OMAP_DSS_GFX */ 4133 COLOR_ARRAY( 4134 DRM_FORMAT_RGBX4444, DRM_FORMAT_RGB565, 4135 DRM_FORMAT_XRGB8888, DRM_FORMAT_RGB888), 4136 4137 /* OMAP_DSS_VIDEO1 */ 4138 COLOR_ARRAY( 4139 DRM_FORMAT_RGB565, DRM_FORMAT_XRGB8888, 4140 DRM_FORMAT_RGB888, DRM_FORMAT_YUYV, 4141 DRM_FORMAT_UYVY), 4142 4143 /* OMAP_DSS_VIDEO2 */ 4144 COLOR_ARRAY( 4145 DRM_FORMAT_RGB565, DRM_FORMAT_XRGB8888, 4146 DRM_FORMAT_RGB888, DRM_FORMAT_YUYV, 4147 DRM_FORMAT_UYVY), 4148 }; 4149 4150 static const u32 *omap3_dispc_supported_color_modes[] = { 4151 /* OMAP_DSS_GFX */ 4152 COLOR_ARRAY( 4153 DRM_FORMAT_RGBX4444, DRM_FORMAT_ARGB4444, 4154 DRM_FORMAT_RGB565, DRM_FORMAT_XRGB8888, 4155 DRM_FORMAT_RGB888, DRM_FORMAT_ARGB8888, 4156 DRM_FORMAT_RGBA8888, DRM_FORMAT_RGBX8888), 4157 4158 /* OMAP_DSS_VIDEO1 */ 4159 COLOR_ARRAY( 4160 DRM_FORMAT_XRGB8888, DRM_FORMAT_RGB888, 4161 DRM_FORMAT_RGBX4444, DRM_FORMAT_RGB565, 4162 DRM_FORMAT_YUYV, DRM_FORMAT_UYVY), 4163 4164 /* OMAP_DSS_VIDEO2 */ 4165 COLOR_ARRAY( 4166 DRM_FORMAT_RGBX4444, DRM_FORMAT_ARGB4444, 4167 DRM_FORMAT_RGB565, DRM_FORMAT_XRGB8888, 4168 DRM_FORMAT_RGB888, DRM_FORMAT_YUYV, 4169 DRM_FORMAT_UYVY, DRM_FORMAT_ARGB8888, 4170 DRM_FORMAT_RGBA8888, DRM_FORMAT_RGBX8888), 4171 }; 4172 4173 static const u32 *omap4_dispc_supported_color_modes[] = { 4174 /* OMAP_DSS_GFX */ 4175 COLOR_ARRAY( 4176 DRM_FORMAT_RGBX4444, DRM_FORMAT_ARGB4444, 4177 DRM_FORMAT_RGB565, DRM_FORMAT_XRGB8888, 4178 DRM_FORMAT_RGB888, DRM_FORMAT_ARGB8888, 4179 DRM_FORMAT_RGBA8888, DRM_FORMAT_RGBX8888, 4180 DRM_FORMAT_ARGB1555, DRM_FORMAT_XRGB4444, 4181 DRM_FORMAT_RGBA4444, DRM_FORMAT_XRGB1555), 4182 4183 /* OMAP_DSS_VIDEO1 */ 4184 COLOR_ARRAY( 4185 DRM_FORMAT_RGB565, DRM_FORMAT_RGBX4444, 4186 DRM_FORMAT_YUYV, DRM_FORMAT_ARGB1555, 4187 DRM_FORMAT_RGBA8888, DRM_FORMAT_NV12, 4188 DRM_FORMAT_RGBA4444, DRM_FORMAT_XRGB8888, 4189 DRM_FORMAT_RGB888, DRM_FORMAT_UYVY, 4190 DRM_FORMAT_ARGB4444, DRM_FORMAT_XRGB1555, 4191 DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB4444, 4192 DRM_FORMAT_RGBX8888), 4193 4194 /* OMAP_DSS_VIDEO2 */ 4195 COLOR_ARRAY( 4196 DRM_FORMAT_RGB565, DRM_FORMAT_RGBX4444, 4197 DRM_FORMAT_YUYV, DRM_FORMAT_ARGB1555, 4198 DRM_FORMAT_RGBA8888, DRM_FORMAT_NV12, 4199 DRM_FORMAT_RGBA4444, DRM_FORMAT_XRGB8888, 4200 DRM_FORMAT_RGB888, DRM_FORMAT_UYVY, 4201 DRM_FORMAT_ARGB4444, DRM_FORMAT_XRGB1555, 4202 DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB4444, 4203 DRM_FORMAT_RGBX8888), 4204 4205 /* OMAP_DSS_VIDEO3 */ 4206 COLOR_ARRAY( 4207 DRM_FORMAT_RGB565, DRM_FORMAT_RGBX4444, 4208 DRM_FORMAT_YUYV, DRM_FORMAT_ARGB1555, 4209 DRM_FORMAT_RGBA8888, DRM_FORMAT_NV12, 4210 DRM_FORMAT_RGBA4444, DRM_FORMAT_XRGB8888, 4211 DRM_FORMAT_RGB888, DRM_FORMAT_UYVY, 4212 DRM_FORMAT_ARGB4444, DRM_FORMAT_XRGB1555, 4213 DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB4444, 4214 DRM_FORMAT_RGBX8888), 4215 4216 /* OMAP_DSS_WB */ 4217 COLOR_ARRAY( 4218 DRM_FORMAT_RGB565, DRM_FORMAT_RGBX4444, 4219 DRM_FORMAT_YUYV, DRM_FORMAT_ARGB1555, 4220 DRM_FORMAT_RGBA8888, DRM_FORMAT_NV12, 4221 DRM_FORMAT_RGBA4444, DRM_FORMAT_XRGB8888, 4222 DRM_FORMAT_RGB888, DRM_FORMAT_UYVY, 4223 DRM_FORMAT_ARGB4444, DRM_FORMAT_XRGB1555, 4224 DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB4444, 4225 DRM_FORMAT_RGBX8888), 4226 }; 4227 4228 static const struct dispc_features omap24xx_dispc_feats = { 4229 .sw_start = 5, 4230 .fp_start = 15, 4231 .bp_start = 27, 4232 .sw_max = 64, 4233 .vp_max = 255, 4234 .hp_max = 256, 4235 .mgr_width_start = 10, 4236 .mgr_height_start = 26, 4237 .mgr_width_max = 2048, 4238 .mgr_height_max = 2048, 4239 .max_lcd_pclk = 66500000, 4240 .max_downscale = 2, 4241 /* 4242 * Assume the line width buffer to be 768 pixels as OMAP2 DISPC scaler 4243 * cannot scale an image width larger than 768. 4244 */ 4245 .max_line_width = 768, 4246 .min_pcd = 2, 4247 .calc_scaling = dispc_ovl_calc_scaling_24xx, 4248 .calc_core_clk = calc_core_clk_24xx, 4249 .num_fifos = 3, 4250 .features = omap2_dispc_features_list, 4251 .num_features = ARRAY_SIZE(omap2_dispc_features_list), 4252 .reg_fields = omap2_dispc_reg_fields, 4253 .num_reg_fields = ARRAY_SIZE(omap2_dispc_reg_fields), 4254 .overlay_caps = omap2_dispc_overlay_caps, 4255 .supported_color_modes = omap2_dispc_supported_color_modes, 4256 .num_mgrs = 2, 4257 .num_ovls = 3, 4258 .buffer_size_unit = 1, 4259 .burst_size_unit = 8, 4260 .no_framedone_tv = true, 4261 .set_max_preload = false, 4262 .last_pixel_inc_missing = true, 4263 }; 4264 4265 static const struct dispc_features omap34xx_rev1_0_dispc_feats = { 4266 .sw_start = 5, 4267 .fp_start = 15, 4268 .bp_start = 27, 4269 .sw_max = 64, 4270 .vp_max = 255, 4271 .hp_max = 256, 4272 .mgr_width_start = 10, 4273 .mgr_height_start = 26, 4274 .mgr_width_max = 2048, 4275 .mgr_height_max = 2048, 4276 .max_lcd_pclk = 173000000, 4277 .max_tv_pclk = 59000000, 4278 .max_downscale = 4, 4279 .max_line_width = 1024, 4280 .min_pcd = 1, 4281 .calc_scaling = dispc_ovl_calc_scaling_34xx, 4282 .calc_core_clk = calc_core_clk_34xx, 4283 .num_fifos = 3, 4284 .features = omap3_dispc_features_list, 4285 .num_features = ARRAY_SIZE(omap3_dispc_features_list), 4286 .reg_fields = omap3_dispc_reg_fields, 4287 .num_reg_fields = ARRAY_SIZE(omap3_dispc_reg_fields), 4288 .overlay_caps = omap3430_dispc_overlay_caps, 4289 .supported_color_modes = omap3_dispc_supported_color_modes, 4290 .num_mgrs = 2, 4291 .num_ovls = 3, 4292 .buffer_size_unit = 1, 4293 .burst_size_unit = 8, 4294 .no_framedone_tv = true, 4295 .set_max_preload = false, 4296 .last_pixel_inc_missing = true, 4297 }; 4298 4299 static const struct dispc_features omap34xx_rev3_0_dispc_feats = { 4300 .sw_start = 7, 4301 .fp_start = 19, 4302 .bp_start = 31, 4303 .sw_max = 256, 4304 .vp_max = 4095, 4305 .hp_max = 4096, 4306 .mgr_width_start = 10, 4307 .mgr_height_start = 26, 4308 .mgr_width_max = 2048, 4309 .mgr_height_max = 2048, 4310 .max_lcd_pclk = 173000000, 4311 .max_tv_pclk = 59000000, 4312 .max_downscale = 4, 4313 .max_line_width = 1024, 4314 .min_pcd = 1, 4315 .calc_scaling = dispc_ovl_calc_scaling_34xx, 4316 .calc_core_clk = calc_core_clk_34xx, 4317 .num_fifos = 3, 4318 .features = omap3_dispc_features_list, 4319 .num_features = ARRAY_SIZE(omap3_dispc_features_list), 4320 .reg_fields = omap3_dispc_reg_fields, 4321 .num_reg_fields = ARRAY_SIZE(omap3_dispc_reg_fields), 4322 .overlay_caps = omap3430_dispc_overlay_caps, 4323 .supported_color_modes = omap3_dispc_supported_color_modes, 4324 .num_mgrs = 2, 4325 .num_ovls = 3, 4326 .buffer_size_unit = 1, 4327 .burst_size_unit = 8, 4328 .no_framedone_tv = true, 4329 .set_max_preload = false, 4330 .last_pixel_inc_missing = true, 4331 }; 4332 4333 static const struct dispc_features omap36xx_dispc_feats = { 4334 .sw_start = 7, 4335 .fp_start = 19, 4336 .bp_start = 31, 4337 .sw_max = 256, 4338 .vp_max = 4095, 4339 .hp_max = 4096, 4340 .mgr_width_start = 10, 4341 .mgr_height_start = 26, 4342 .mgr_width_max = 2048, 4343 .mgr_height_max = 2048, 4344 .max_lcd_pclk = 173000000, 4345 .max_tv_pclk = 59000000, 4346 .max_downscale = 4, 4347 .max_line_width = 1024, 4348 .min_pcd = 1, 4349 .calc_scaling = dispc_ovl_calc_scaling_34xx, 4350 .calc_core_clk = calc_core_clk_34xx, 4351 .num_fifos = 3, 4352 .features = omap3_dispc_features_list, 4353 .num_features = ARRAY_SIZE(omap3_dispc_features_list), 4354 .reg_fields = omap3_dispc_reg_fields, 4355 .num_reg_fields = ARRAY_SIZE(omap3_dispc_reg_fields), 4356 .overlay_caps = omap3630_dispc_overlay_caps, 4357 .supported_color_modes = omap3_dispc_supported_color_modes, 4358 .num_mgrs = 2, 4359 .num_ovls = 3, 4360 .buffer_size_unit = 1, 4361 .burst_size_unit = 8, 4362 .no_framedone_tv = true, 4363 .set_max_preload = false, 4364 .last_pixel_inc_missing = true, 4365 }; 4366 4367 static const struct dispc_features am43xx_dispc_feats = { 4368 .sw_start = 7, 4369 .fp_start = 19, 4370 .bp_start = 31, 4371 .sw_max = 256, 4372 .vp_max = 4095, 4373 .hp_max = 4096, 4374 .mgr_width_start = 10, 4375 .mgr_height_start = 26, 4376 .mgr_width_max = 2048, 4377 .mgr_height_max = 2048, 4378 .max_lcd_pclk = 173000000, 4379 .max_tv_pclk = 59000000, 4380 .max_downscale = 4, 4381 .max_line_width = 1024, 4382 .min_pcd = 1, 4383 .calc_scaling = dispc_ovl_calc_scaling_34xx, 4384 .calc_core_clk = calc_core_clk_34xx, 4385 .num_fifos = 3, 4386 .features = am43xx_dispc_features_list, 4387 .num_features = ARRAY_SIZE(am43xx_dispc_features_list), 4388 .reg_fields = omap3_dispc_reg_fields, 4389 .num_reg_fields = ARRAY_SIZE(omap3_dispc_reg_fields), 4390 .overlay_caps = omap3430_dispc_overlay_caps, 4391 .supported_color_modes = omap3_dispc_supported_color_modes, 4392 .num_mgrs = 1, 4393 .num_ovls = 3, 4394 .buffer_size_unit = 1, 4395 .burst_size_unit = 8, 4396 .no_framedone_tv = true, 4397 .set_max_preload = false, 4398 .last_pixel_inc_missing = true, 4399 }; 4400 4401 static const struct dispc_features omap44xx_dispc_feats = { 4402 .sw_start = 7, 4403 .fp_start = 19, 4404 .bp_start = 31, 4405 .sw_max = 256, 4406 .vp_max = 4095, 4407 .hp_max = 4096, 4408 .mgr_width_start = 10, 4409 .mgr_height_start = 26, 4410 .mgr_width_max = 2048, 4411 .mgr_height_max = 2048, 4412 .max_lcd_pclk = 170000000, 4413 .max_tv_pclk = 185625000, 4414 .max_downscale = 4, 4415 .max_line_width = 2048, 4416 .min_pcd = 1, 4417 .calc_scaling = dispc_ovl_calc_scaling_44xx, 4418 .calc_core_clk = calc_core_clk_44xx, 4419 .num_fifos = 5, 4420 .features = omap4_dispc_features_list, 4421 .num_features = ARRAY_SIZE(omap4_dispc_features_list), 4422 .reg_fields = omap4_dispc_reg_fields, 4423 .num_reg_fields = ARRAY_SIZE(omap4_dispc_reg_fields), 4424 .overlay_caps = omap4_dispc_overlay_caps, 4425 .supported_color_modes = omap4_dispc_supported_color_modes, 4426 .num_mgrs = 3, 4427 .num_ovls = 4, 4428 .buffer_size_unit = 16, 4429 .burst_size_unit = 16, 4430 .gfx_fifo_workaround = true, 4431 .set_max_preload = true, 4432 .supports_sync_align = true, 4433 .has_writeback = true, 4434 .supports_double_pixel = true, 4435 .reverse_ilace_field_order = true, 4436 .has_gamma_table = true, 4437 .has_gamma_i734_bug = true, 4438 }; 4439 4440 static const struct dispc_features omap54xx_dispc_feats = { 4441 .sw_start = 7, 4442 .fp_start = 19, 4443 .bp_start = 31, 4444 .sw_max = 256, 4445 .vp_max = 4095, 4446 .hp_max = 4096, 4447 .mgr_width_start = 11, 4448 .mgr_height_start = 27, 4449 .mgr_width_max = 4096, 4450 .mgr_height_max = 4096, 4451 .max_lcd_pclk = 170000000, 4452 .max_tv_pclk = 186000000, 4453 .max_downscale = 4, 4454 .max_line_width = 2048, 4455 .min_pcd = 1, 4456 .calc_scaling = dispc_ovl_calc_scaling_44xx, 4457 .calc_core_clk = calc_core_clk_44xx, 4458 .num_fifos = 5, 4459 .features = omap5_dispc_features_list, 4460 .num_features = ARRAY_SIZE(omap5_dispc_features_list), 4461 .reg_fields = omap4_dispc_reg_fields, 4462 .num_reg_fields = ARRAY_SIZE(omap4_dispc_reg_fields), 4463 .overlay_caps = omap4_dispc_overlay_caps, 4464 .supported_color_modes = omap4_dispc_supported_color_modes, 4465 .num_mgrs = 4, 4466 .num_ovls = 4, 4467 .buffer_size_unit = 16, 4468 .burst_size_unit = 16, 4469 .gfx_fifo_workaround = true, 4470 .mstandby_workaround = true, 4471 .set_max_preload = true, 4472 .supports_sync_align = true, 4473 .has_writeback = true, 4474 .supports_double_pixel = true, 4475 .reverse_ilace_field_order = true, 4476 .has_gamma_table = true, 4477 .has_gamma_i734_bug = true, 4478 }; 4479 4480 static irqreturn_t dispc_irq_handler(int irq, void *arg) 4481 { 4482 struct dispc_device *dispc = arg; 4483 4484 if (!dispc->is_enabled) 4485 return IRQ_NONE; 4486 4487 return dispc->user_handler(irq, dispc->user_data); 4488 } 4489 4490 static int dispc_request_irq(struct dispc_device *dispc, irq_handler_t handler, 4491 void *dev_id) 4492 { 4493 int r; 4494 4495 if (dispc->user_handler != NULL) 4496 return -EBUSY; 4497 4498 dispc->user_handler = handler; 4499 dispc->user_data = dev_id; 4500 4501 /* ensure the dispc_irq_handler sees the values above */ 4502 smp_wmb(); 4503 4504 r = devm_request_irq(&dispc->pdev->dev, dispc->irq, dispc_irq_handler, 4505 IRQF_SHARED, "OMAP DISPC", dispc); 4506 if (r) { 4507 dispc->user_handler = NULL; 4508 dispc->user_data = NULL; 4509 } 4510 4511 return r; 4512 } 4513 4514 static void dispc_free_irq(struct dispc_device *dispc, void *dev_id) 4515 { 4516 devm_free_irq(&dispc->pdev->dev, dispc->irq, dispc); 4517 4518 dispc->user_handler = NULL; 4519 dispc->user_data = NULL; 4520 } 4521 4522 static u32 dispc_get_memory_bandwidth_limit(struct dispc_device *dispc) 4523 { 4524 u32 limit = 0; 4525 4526 /* Optional maximum memory bandwidth */ 4527 of_property_read_u32(dispc->pdev->dev.of_node, "max-memory-bandwidth", 4528 &limit); 4529 4530 return limit; 4531 } 4532 4533 /* 4534 * Workaround for errata i734 in DSS dispc 4535 * - LCD1 Gamma Correction Is Not Working When GFX Pipe Is Disabled 4536 * 4537 * For gamma tables to work on LCD1 the GFX plane has to be used at 4538 * least once after DSS HW has come out of reset. The workaround 4539 * sets up a minimal LCD setup with GFX plane and waits for one 4540 * vertical sync irq before disabling the setup and continuing with 4541 * the context restore. The physical outputs are gated during the 4542 * operation. This workaround requires that gamma table's LOADMODE 4543 * is set to 0x2 in DISPC_CONTROL1 register. 4544 * 4545 * For details see: 4546 * OMAP543x Multimedia Device Silicon Revision 2.0 Silicon Errata 4547 * Literature Number: SWPZ037E 4548 * Or some other relevant errata document for the DSS IP version. 4549 */ 4550 4551 static const struct dispc_errata_i734_data { 4552 struct videomode vm; 4553 struct omap_overlay_info ovli; 4554 struct omap_overlay_manager_info mgri; 4555 struct dss_lcd_mgr_config lcd_conf; 4556 } i734 = { 4557 .vm = { 4558 .hactive = 8, .vactive = 1, 4559 .pixelclock = 16000000, 4560 .hsync_len = 8, .hfront_porch = 4, .hback_porch = 4, 4561 .vsync_len = 1, .vfront_porch = 1, .vback_porch = 1, 4562 4563 .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW | 4564 DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_SYNC_POSEDGE | 4565 DISPLAY_FLAGS_PIXDATA_POSEDGE, 4566 }, 4567 .ovli = { 4568 .screen_width = 1, 4569 .width = 1, .height = 1, 4570 .fourcc = DRM_FORMAT_XRGB8888, 4571 .rotation = DRM_MODE_ROTATE_0, 4572 .rotation_type = OMAP_DSS_ROT_NONE, 4573 .pos_x = 0, .pos_y = 0, 4574 .out_width = 0, .out_height = 0, 4575 .global_alpha = 0xff, 4576 .pre_mult_alpha = 0, 4577 .zorder = 0, 4578 }, 4579 .mgri = { 4580 .default_color = 0, 4581 .trans_enabled = false, 4582 .partial_alpha_enabled = false, 4583 .cpr_enable = false, 4584 }, 4585 .lcd_conf = { 4586 .io_pad_mode = DSS_IO_PAD_MODE_BYPASS, 4587 .stallmode = false, 4588 .fifohandcheck = false, 4589 .clock_info = { 4590 .lck_div = 1, 4591 .pck_div = 2, 4592 }, 4593 .video_port_width = 24, 4594 .lcden_sig_polarity = 0, 4595 }, 4596 }; 4597 4598 static struct i734_buf { 4599 size_t size; 4600 dma_addr_t paddr; 4601 void *vaddr; 4602 } i734_buf; 4603 4604 static int dispc_errata_i734_wa_init(struct dispc_device *dispc) 4605 { 4606 if (!dispc->feat->has_gamma_i734_bug) 4607 return 0; 4608 4609 i734_buf.size = i734.ovli.width * i734.ovli.height * 4610 color_mode_to_bpp(i734.ovli.fourcc) / 8; 4611 4612 i734_buf.vaddr = dma_alloc_writecombine(&dispc->pdev->dev, 4613 i734_buf.size, &i734_buf.paddr, 4614 GFP_KERNEL); 4615 if (!i734_buf.vaddr) { 4616 dev_err(&dispc->pdev->dev, "%s: dma_alloc_writecombine failed\n", 4617 __func__); 4618 return -ENOMEM; 4619 } 4620 4621 return 0; 4622 } 4623 4624 static void dispc_errata_i734_wa_fini(struct dispc_device *dispc) 4625 { 4626 if (!dispc->feat->has_gamma_i734_bug) 4627 return; 4628 4629 dma_free_writecombine(&dispc->pdev->dev, i734_buf.size, i734_buf.vaddr, 4630 i734_buf.paddr); 4631 } 4632 4633 static void dispc_errata_i734_wa(struct dispc_device *dispc) 4634 { 4635 u32 framedone_irq = dispc_mgr_get_framedone_irq(dispc, 4636 OMAP_DSS_CHANNEL_LCD); 4637 struct omap_overlay_info ovli; 4638 struct dss_lcd_mgr_config lcd_conf; 4639 u32 gatestate; 4640 unsigned int count; 4641 4642 if (!dispc->feat->has_gamma_i734_bug) 4643 return; 4644 4645 gatestate = REG_GET(dispc, DISPC_CONFIG, 8, 4); 4646 4647 ovli = i734.ovli; 4648 ovli.paddr = i734_buf.paddr; 4649 lcd_conf = i734.lcd_conf; 4650 4651 /* Gate all LCD1 outputs */ 4652 REG_FLD_MOD(dispc, DISPC_CONFIG, 0x1f, 8, 4); 4653 4654 /* Setup and enable GFX plane */ 4655 dispc_ovl_setup(dispc, OMAP_DSS_GFX, &ovli, &i734.vm, false, 4656 OMAP_DSS_CHANNEL_LCD); 4657 dispc_ovl_enable(dispc, OMAP_DSS_GFX, true); 4658 4659 /* Set up and enable display manager for LCD1 */ 4660 dispc_mgr_setup(dispc, OMAP_DSS_CHANNEL_LCD, &i734.mgri); 4661 dispc_calc_clock_rates(dispc, dss_get_dispc_clk_rate(dispc->dss), 4662 &lcd_conf.clock_info); 4663 dispc_mgr_set_lcd_config(dispc, OMAP_DSS_CHANNEL_LCD, &lcd_conf); 4664 dispc_mgr_set_timings(dispc, OMAP_DSS_CHANNEL_LCD, &i734.vm); 4665 4666 dispc_clear_irqstatus(dispc, framedone_irq); 4667 4668 /* Enable and shut the channel to produce just one frame */ 4669 dispc_mgr_enable(dispc, OMAP_DSS_CHANNEL_LCD, true); 4670 dispc_mgr_enable(dispc, OMAP_DSS_CHANNEL_LCD, false); 4671 4672 /* Busy wait for framedone. We can't fiddle with irq handlers 4673 * in PM resume. Typically the loop runs less than 5 times and 4674 * waits less than a micro second. 4675 */ 4676 count = 0; 4677 while (!(dispc_read_irqstatus(dispc) & framedone_irq)) { 4678 if (count++ > 10000) { 4679 dev_err(&dispc->pdev->dev, "%s: framedone timeout\n", 4680 __func__); 4681 break; 4682 } 4683 } 4684 dispc_ovl_enable(dispc, OMAP_DSS_GFX, false); 4685 4686 /* Clear all irq bits before continuing */ 4687 dispc_clear_irqstatus(dispc, 0xffffffff); 4688 4689 /* Restore the original state to LCD1 output gates */ 4690 REG_FLD_MOD(dispc, DISPC_CONFIG, gatestate, 8, 4); 4691 } 4692 4693 static const struct dispc_ops dispc_ops = { 4694 .read_irqstatus = dispc_read_irqstatus, 4695 .clear_irqstatus = dispc_clear_irqstatus, 4696 .write_irqenable = dispc_write_irqenable, 4697 4698 .request_irq = dispc_request_irq, 4699 .free_irq = dispc_free_irq, 4700 4701 .runtime_get = dispc_runtime_get, 4702 .runtime_put = dispc_runtime_put, 4703 4704 .get_num_ovls = dispc_get_num_ovls, 4705 .get_num_mgrs = dispc_get_num_mgrs, 4706 4707 .get_memory_bandwidth_limit = dispc_get_memory_bandwidth_limit, 4708 4709 .mgr_enable = dispc_mgr_enable, 4710 .mgr_is_enabled = dispc_mgr_is_enabled, 4711 .mgr_get_vsync_irq = dispc_mgr_get_vsync_irq, 4712 .mgr_get_framedone_irq = dispc_mgr_get_framedone_irq, 4713 .mgr_get_sync_lost_irq = dispc_mgr_get_sync_lost_irq, 4714 .mgr_go_busy = dispc_mgr_go_busy, 4715 .mgr_go = dispc_mgr_go, 4716 .mgr_set_lcd_config = dispc_mgr_set_lcd_config, 4717 .mgr_check_timings = dispc_mgr_check_timings, 4718 .mgr_set_timings = dispc_mgr_set_timings, 4719 .mgr_setup = dispc_mgr_setup, 4720 .mgr_gamma_size = dispc_mgr_gamma_size, 4721 .mgr_set_gamma = dispc_mgr_set_gamma, 4722 4723 .ovl_enable = dispc_ovl_enable, 4724 .ovl_setup = dispc_ovl_setup, 4725 .ovl_get_color_modes = dispc_ovl_get_color_modes, 4726 4727 .wb_get_framedone_irq = dispc_wb_get_framedone_irq, 4728 .wb_setup = dispc_wb_setup, 4729 .has_writeback = dispc_has_writeback, 4730 .wb_go_busy = dispc_wb_go_busy, 4731 .wb_go = dispc_wb_go, 4732 }; 4733 4734 /* DISPC HW IP initialisation */ 4735 static const struct of_device_id dispc_of_match[] = { 4736 { .compatible = "ti,omap2-dispc", .data = &omap24xx_dispc_feats }, 4737 { .compatible = "ti,omap3-dispc", .data = &omap36xx_dispc_feats }, 4738 { .compatible = "ti,omap4-dispc", .data = &omap44xx_dispc_feats }, 4739 { .compatible = "ti,omap5-dispc", .data = &omap54xx_dispc_feats }, 4740 { .compatible = "ti,dra7-dispc", .data = &omap54xx_dispc_feats }, 4741 {}, 4742 }; 4743 4744 static const struct soc_device_attribute dispc_soc_devices[] = { 4745 { .machine = "OMAP3[45]*", 4746 .revision = "ES[12].?", .data = &omap34xx_rev1_0_dispc_feats }, 4747 { .machine = "OMAP3[45]*", .data = &omap34xx_rev3_0_dispc_feats }, 4748 { .machine = "AM35*", .data = &omap34xx_rev3_0_dispc_feats }, 4749 { .machine = "AM43*", .data = &am43xx_dispc_feats }, 4750 { /* sentinel */ } 4751 }; 4752 4753 static int dispc_bind(struct device *dev, struct device *master, void *data) 4754 { 4755 struct platform_device *pdev = to_platform_device(dev); 4756 const struct soc_device_attribute *soc; 4757 struct dss_device *dss = dss_get_device(master); 4758 struct dispc_device *dispc; 4759 u32 rev; 4760 int r = 0; 4761 struct resource *dispc_mem; 4762 struct device_node *np = pdev->dev.of_node; 4763 4764 dispc = kzalloc(sizeof(*dispc), GFP_KERNEL); 4765 if (!dispc) 4766 return -ENOMEM; 4767 4768 dispc->pdev = pdev; 4769 platform_set_drvdata(pdev, dispc); 4770 dispc->dss = dss; 4771 4772 spin_lock_init(&dispc->control_lock); 4773 4774 /* 4775 * The OMAP3-based models can't be told apart using the compatible 4776 * string, use SoC device matching. 4777 */ 4778 soc = soc_device_match(dispc_soc_devices); 4779 if (soc) 4780 dispc->feat = soc->data; 4781 else 4782 dispc->feat = of_match_device(dispc_of_match, &pdev->dev)->data; 4783 4784 r = dispc_errata_i734_wa_init(dispc); 4785 if (r) 4786 goto err_free; 4787 4788 dispc_mem = platform_get_resource(dispc->pdev, IORESOURCE_MEM, 0); 4789 dispc->base = devm_ioremap_resource(&pdev->dev, dispc_mem); 4790 if (IS_ERR(dispc->base)) { 4791 r = PTR_ERR(dispc->base); 4792 goto err_free; 4793 } 4794 4795 dispc->irq = platform_get_irq(dispc->pdev, 0); 4796 if (dispc->irq < 0) { 4797 DSSERR("platform_get_irq failed\n"); 4798 r = -ENODEV; 4799 goto err_free; 4800 } 4801 4802 if (np && of_property_read_bool(np, "syscon-pol")) { 4803 dispc->syscon_pol = syscon_regmap_lookup_by_phandle(np, "syscon-pol"); 4804 if (IS_ERR(dispc->syscon_pol)) { 4805 dev_err(&pdev->dev, "failed to get syscon-pol regmap\n"); 4806 r = PTR_ERR(dispc->syscon_pol); 4807 goto err_free; 4808 } 4809 4810 if (of_property_read_u32_index(np, "syscon-pol", 1, 4811 &dispc->syscon_pol_offset)) { 4812 dev_err(&pdev->dev, "failed to get syscon-pol offset\n"); 4813 r = -EINVAL; 4814 goto err_free; 4815 } 4816 } 4817 4818 r = dispc_init_gamma_tables(dispc); 4819 if (r) 4820 goto err_free; 4821 4822 pm_runtime_enable(&pdev->dev); 4823 4824 r = dispc_runtime_get(dispc); 4825 if (r) 4826 goto err_runtime_get; 4827 4828 _omap_dispc_initial_config(dispc); 4829 4830 rev = dispc_read_reg(dispc, DISPC_REVISION); 4831 dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n", 4832 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); 4833 4834 dispc_runtime_put(dispc); 4835 4836 dss->dispc = dispc; 4837 dss->dispc_ops = &dispc_ops; 4838 4839 dispc->debugfs = dss_debugfs_create_file(dss, "dispc", dispc_dump_regs, 4840 dispc); 4841 4842 return 0; 4843 4844 err_runtime_get: 4845 pm_runtime_disable(&pdev->dev); 4846 err_free: 4847 kfree(dispc); 4848 return r; 4849 } 4850 4851 static void dispc_unbind(struct device *dev, struct device *master, void *data) 4852 { 4853 struct dispc_device *dispc = dev_get_drvdata(dev); 4854 struct dss_device *dss = dispc->dss; 4855 4856 dss_debugfs_remove_file(dispc->debugfs); 4857 4858 dss->dispc = NULL; 4859 dss->dispc_ops = NULL; 4860 4861 pm_runtime_disable(dev); 4862 4863 dispc_errata_i734_wa_fini(dispc); 4864 4865 kfree(dispc); 4866 } 4867 4868 static const struct component_ops dispc_component_ops = { 4869 .bind = dispc_bind, 4870 .unbind = dispc_unbind, 4871 }; 4872 4873 static int dispc_probe(struct platform_device *pdev) 4874 { 4875 return component_add(&pdev->dev, &dispc_component_ops); 4876 } 4877 4878 static int dispc_remove(struct platform_device *pdev) 4879 { 4880 component_del(&pdev->dev, &dispc_component_ops); 4881 return 0; 4882 } 4883 4884 static int dispc_runtime_suspend(struct device *dev) 4885 { 4886 struct dispc_device *dispc = dev_get_drvdata(dev); 4887 4888 dispc->is_enabled = false; 4889 /* ensure the dispc_irq_handler sees the is_enabled value */ 4890 smp_wmb(); 4891 /* wait for current handler to finish before turning the DISPC off */ 4892 synchronize_irq(dispc->irq); 4893 4894 dispc_save_context(dispc); 4895 4896 return 0; 4897 } 4898 4899 static int dispc_runtime_resume(struct device *dev) 4900 { 4901 struct dispc_device *dispc = dev_get_drvdata(dev); 4902 4903 /* 4904 * The reset value for load mode is 0 (OMAP_DSS_LOAD_CLUT_AND_FRAME) 4905 * but we always initialize it to 2 (OMAP_DSS_LOAD_FRAME_ONLY) in 4906 * _omap_dispc_initial_config(). We can thus use it to detect if 4907 * we have lost register context. 4908 */ 4909 if (REG_GET(dispc, DISPC_CONFIG, 2, 1) != OMAP_DSS_LOAD_FRAME_ONLY) { 4910 _omap_dispc_initial_config(dispc); 4911 4912 dispc_errata_i734_wa(dispc); 4913 4914 dispc_restore_context(dispc); 4915 4916 dispc_restore_gamma_tables(dispc); 4917 } 4918 4919 dispc->is_enabled = true; 4920 /* ensure the dispc_irq_handler sees the is_enabled value */ 4921 smp_wmb(); 4922 4923 return 0; 4924 } 4925 4926 static const struct dev_pm_ops dispc_pm_ops = { 4927 .runtime_suspend = dispc_runtime_suspend, 4928 .runtime_resume = dispc_runtime_resume, 4929 }; 4930 4931 struct platform_driver omap_dispchw_driver = { 4932 .probe = dispc_probe, 4933 .remove = dispc_remove, 4934 .driver = { 4935 .name = "omapdss_dispc", 4936 .pm = &dispc_pm_ops, 4937 .of_match_table = dispc_of_match, 4938 .suppress_bind_attrs = true, 4939 }, 4940 }; 4941