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