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