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