1 /* 2 * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <common.h> 8 #include <boot_rkimg.h> 9 #include <asm/io.h> 10 #include <dm/device.h> 11 #include <linux/dw_hdmi.h> 12 #include <linux/hdmi.h> 13 #include <linux/media-bus-format.h> 14 #include "rockchip_display.h" 15 #include "rockchip_crtc.h" 16 #include "rockchip_connector.h" 17 #include "dw_hdmi.h" 18 #include "rockchip_dw_hdmi.h" 19 20 #define HDMI_SEL_LCDC(x, bit) ((((x) & 1) << bit) | (1 << (16 + bit))) 21 #define RK3288_GRF_SOC_CON6 0x025C 22 #define RK3288_HDMI_LCDC_SEL BIT(4) 23 #define RK3399_GRF_SOC_CON20 0x6250 24 #define RK3399_HDMI_LCDC_SEL BIT(6) 25 26 #define RK3228_IO_3V_DOMAIN ((7 << 4) | (7 << (4 + 16))) 27 #define RK3328_IO_3V_DOMAIN (7 << (9 + 16)) 28 #define RK3328_IO_5V_DOMAIN ((7 << 9) | (3 << (9 + 16))) 29 #define RK3328_IO_CTRL_BY_HDMI ((1 << 13) | (1 << (13 + 16))) 30 #define RK3328_IO_DDC_IN_MSK ((3 << 10) | (3 << (10 + 16))) 31 #define RK3228_IO_DDC_IN_MSK ((3 << 13) | (3 << (13 + 16))) 32 #define RK3228_GRF_SOC_CON2 0x0408 33 #define RK3228_GRF_SOC_CON6 0x0418 34 #define RK3328_GRF_SOC_CON2 0x0408 35 #define RK3328_GRF_SOC_CON3 0x040c 36 #define RK3328_GRF_SOC_CON4 0x0410 37 38 #define DRM_BASE_MODE(c, hd, hss, hse, ht, vd, vss, vse, vt, vs, f) \ 39 .clock = (c), \ 40 .hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \ 41 .htotal = (ht), .vdisplay = (vd), \ 42 .vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \ 43 .vscan = (vs), .flags = (f) 44 45 static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { 46 { 47 30666000, { 48 { 0x00b3, 0x0000 }, 49 { 0x2153, 0x0000 }, 50 { 0x40f3, 0x0000 }, 51 }, 52 }, { 53 36800000, { 54 { 0x00b3, 0x0000 }, 55 { 0x2153, 0x0000 }, 56 { 0x40a2, 0x0001 }, 57 }, 58 }, { 59 46000000, { 60 { 0x00b3, 0x0000 }, 61 { 0x2142, 0x0001 }, 62 { 0x40a2, 0x0001 }, 63 }, 64 }, { 65 61333000, { 66 { 0x0072, 0x0001 }, 67 { 0x2142, 0x0001 }, 68 { 0x40a2, 0x0001 }, 69 }, 70 }, { 71 73600000, { 72 { 0x0072, 0x0001 }, 73 { 0x2142, 0x0001 }, 74 { 0x4061, 0x0002 }, 75 }, 76 }, { 77 92000000, { 78 { 0x0072, 0x0001 }, 79 { 0x2145, 0x0002 }, 80 { 0x4061, 0x0002 }, 81 }, 82 }, { 83 122666000, { 84 { 0x0051, 0x0002 }, 85 { 0x2145, 0x0002 }, 86 { 0x4061, 0x0002 }, 87 }, 88 }, { 89 147200000, { 90 { 0x0051, 0x0002 }, 91 { 0x2145, 0x0002 }, 92 { 0x4064, 0x0003 }, 93 }, 94 }, { 95 184000000, { 96 { 0x0051, 0x0002 }, 97 { 0x214c, 0x0003 }, 98 { 0x4064, 0x0003 }, 99 }, 100 }, { 101 226666000, { 102 { 0x0040, 0x0003 }, 103 { 0x214c, 0x0003 }, 104 { 0x4064, 0x0003 }, 105 }, 106 }, { 107 272000000, { 108 { 0x0040, 0x0003 }, 109 { 0x214c, 0x0003 }, 110 { 0x5a64, 0x0003 }, 111 }, 112 }, { 113 340000000, { 114 { 0x0040, 0x0003 }, 115 { 0x3b4c, 0x0003 }, 116 { 0x5a64, 0x0003 }, 117 }, 118 }, { 119 600000000, { 120 { 0x1a40, 0x0003 }, 121 { 0x3b4c, 0x0003 }, 122 { 0x5a64, 0x0003 }, 123 }, 124 }, { 125 ~0UL, { 126 { 0x0000, 0x0000 }, 127 { 0x0000, 0x0000 }, 128 { 0x0000, 0x0000 }, 129 }, 130 } 131 }; 132 133 static const struct dw_hdmi_mpll_config rockchip_mpll_cfg_420[] = { 134 { 135 30666000, { 136 { 0x00b7, 0x0000 }, 137 { 0x2157, 0x0000 }, 138 { 0x40f7, 0x0000 }, 139 }, 140 }, { 141 92000000, { 142 { 0x00b7, 0x0000 }, 143 { 0x2143, 0x0001 }, 144 { 0x40a3, 0x0001 }, 145 }, 146 }, { 147 184000000, { 148 { 0x0073, 0x0001 }, 149 { 0x2146, 0x0002 }, 150 { 0x4062, 0x0002 }, 151 }, 152 }, { 153 340000000, { 154 { 0x0052, 0x0003 }, 155 { 0x214d, 0x0003 }, 156 { 0x4065, 0x0003 }, 157 }, 158 }, { 159 600000000, { 160 { 0x0041, 0x0003 }, 161 { 0x3b4d, 0x0003 }, 162 { 0x5a65, 0x0003 }, 163 }, 164 }, { 165 ~0UL, { 166 { 0x0000, 0x0000 }, 167 { 0x0000, 0x0000 }, 168 { 0x0000, 0x0000 }, 169 }, 170 } 171 }; 172 173 static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = { 174 /* pixelclk bpp8 bpp10 bpp12 */ 175 { 176 600000000, { 0x0000, 0x0000, 0x0000 }, 177 }, { 178 ~0UL, { 0x0000, 0x0000, 0x0000}, 179 } 180 }; 181 182 static const struct dw_hdmi_phy_config rockchip_phy_config[] = { 183 /*pixelclk symbol term vlev*/ 184 { 74250000, 0x8009, 0x0004, 0x0272}, 185 { 165000000, 0x802b, 0x0004, 0x0209}, 186 { 297000000, 0x8039, 0x0005, 0x028d}, 187 { 594000000, 0x8039, 0x0000, 0x019d}, 188 { ~0UL, 0x0000, 0x0000, 0x0000} 189 }; 190 191 static const struct base_drm_display_mode resolution_white[] = { 192 /* 0. vic:2 - 720x480@60Hz */ 193 { DRM_BASE_MODE(27000, 720, 736, 194 798, 858, 480, 489, 495, 525, 0, 195 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), 196 .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, 197 /* 1. vic:3 - 720x480@60Hz */ 198 { DRM_BASE_MODE(27000, 720, 736, 199 798, 858, 480, 489, 495, 525, 0, 200 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), 201 .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, 202 /* 2. vic:4 - 1280x720@60Hz */ 203 { DRM_BASE_MODE(74250, 1280, 1390, 204 1430, 1650, 720, 725, 730, 750, 0, 205 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), 206 .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, 207 /* 3. vic:5 - 1920x1080i@60Hz */ 208 { DRM_BASE_MODE(74250, 1920, 2008, 209 2052, 2200, 1080, 1084, 1094, 1125, 0, 210 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | 211 DRM_MODE_FLAG_INTERLACE), 212 .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, 213 /* 4. vic:6 - 720(1440)x480i@60Hz */ 214 { DRM_BASE_MODE(13500, 720, 739, 215 801, 858, 480, 488, 494, 525, 0, 216 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | 217 DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), 218 .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, 219 /* 5. vic:16 - 1920x1080@60Hz */ 220 { DRM_BASE_MODE(148500, 1920, 2008, 221 2052, 2200, 1080, 1084, 1089, 1125, 0, 222 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), 223 .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, 224 /* 6. vic:17 - 720x576@50Hz */ 225 { DRM_BASE_MODE(27000, 720, 732, 226 796, 864, 576, 581, 586, 625, 0, 227 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), 228 .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, 229 /* 7. vic:18 - 720x576@50Hz */ 230 { DRM_BASE_MODE(27000, 720, 732, 231 796, 864, 576, 581, 586, 625, 0, 232 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), 233 .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, 234 /* 8. vic:19 - 1280x720@50Hz */ 235 { DRM_BASE_MODE(74250, 1280, 1720, 236 1760, 1980, 720, 725, 730, 750, 0, 237 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), 238 .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, 239 /* 9. vic:20 - 1920x1080i@50Hz */ 240 { DRM_BASE_MODE(74250, 1920, 2448, 241 2492, 2640, 1080, 1084, 1094, 1125, 0, 242 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | 243 DRM_MODE_FLAG_INTERLACE), 244 .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, 245 /* 10. vic:21 - 720(1440)x576i@50Hz */ 246 { DRM_BASE_MODE(13500, 720, 732, 247 795, 864, 576, 580, 586, 625, 0, 248 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | 249 DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), 250 .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, 251 /* 11. vic:31 - 1920x1080@50Hz */ 252 { DRM_BASE_MODE(148500, 1920, 2448, 253 2492, 2640, 1080, 1084, 1089, 1125, 0, 254 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), 255 .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, 256 /* 12. vic:32 - 1920x1080@24Hz */ 257 { DRM_BASE_MODE(74250, 1920, 2558, 258 2602, 2750, 1080, 1084, 1089, 1125, 0, 259 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), 260 .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, 261 /* 13. vic:33 - 1920x1080@25Hz */ 262 { DRM_BASE_MODE(74250, 1920, 2448, 263 2492, 2640, 1080, 1084, 1089, 1125, 0, 264 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), 265 .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, 266 /* 14. vic:34 - 1920x1080@30Hz */ 267 { DRM_BASE_MODE(74250, 1920, 2008, 268 2052, 2200, 1080, 1084, 1089, 1125, 0, 269 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), 270 .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, 271 /* 15. vic:39 - 1920x1080i@50Hz */ 272 { DRM_BASE_MODE(72000, 1920, 1952, 273 2120, 2304, 1080, 1126, 1136, 1250, 0, 274 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC | 275 DRM_MODE_FLAG_INTERLACE), 276 .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, 277 /* 16. vic:60 - 1280x720@24Hz */ 278 { DRM_BASE_MODE(59400, 1280, 3040, 279 3080, 3300, 720, 725, 730, 750, 0, 280 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), 281 .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, 282 /* 17. vic:61 - 1280x720@25Hz */ 283 { DRM_BASE_MODE(74250, 1280, 3700, 284 3740, 3960, 720, 725, 730, 750, 0, 285 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), 286 .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, 287 /* 18. vic:62 - 1280x720@30Hz */ 288 { DRM_BASE_MODE(74250, 1280, 3040, 289 3080, 3300, 720, 725, 730, 750, 0, 290 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), 291 .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, 292 /* 19. vic:93 - 3840x2160p@24Hz 16:9 */ 293 { DRM_BASE_MODE(297000, 3840, 5116, 294 5204, 5500, 2160, 2168, 2178, 2250, 0, 295 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), 296 .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, 297 /* 20. vic:94 - 3840x2160p@25Hz 16:9 */ 298 { DRM_BASE_MODE(297000, 3840, 4896, 299 4984, 5280, 2160, 2168, 2178, 2250, 0, 300 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), 301 .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, 302 /* 21. vic:95 - 3840x2160p@30Hz 16:9 */ 303 { DRM_BASE_MODE(297000, 3840, 4016, 304 4104, 4400, 2160, 2168, 2178, 2250, 0, 305 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), 306 .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, 307 /* 22. vic:96 - 3840x2160p@50Hz 16:9 */ 308 { DRM_BASE_MODE(594000, 3840, 4896, 309 4984, 5280, 2160, 2168, 2178, 2250, 0, 310 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), 311 .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, 312 /* 23. vic:97 - 3840x2160p@60Hz 16:9 */ 313 { DRM_BASE_MODE(594000, 3840, 4016, 314 4104, 4400, 2160, 2168, 2178, 2250, 0, 315 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), 316 .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, 317 /* 24. vic:98 - 4096x2160p@24Hz 256:135 */ 318 { DRM_BASE_MODE(297000, 4096, 5116, 319 5204, 5500, 2160, 2168, 2178, 2250, 0, 320 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), 321 .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, }, 322 /* 25. vic:99 - 4096x2160p@25Hz 256:135 */ 323 { DRM_BASE_MODE(297000, 4096, 5064, 324 5152, 5280, 2160, 2168, 2178, 2250, 0, 325 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), 326 .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, }, 327 /* 26. vic:100 - 4096x2160p@30Hz 256:135 */ 328 { DRM_BASE_MODE(297000, 4096, 4184, 329 4272, 4400, 2160, 2168, 2178, 2250, 0, 330 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), 331 .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, }, 332 /* 27. vic:101 - 4096x2160p@50Hz 256:135 */ 333 { DRM_BASE_MODE(594000, 4096, 5064, 334 5152, 5280, 2160, 2168, 2178, 2250, 0, 335 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), 336 .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, }, 337 /* 28. vic:102 - 4096x2160p@60Hz 256:135 */ 338 { DRM_BASE_MODE(594000, 4096, 4184, 339 4272, 4400, 2160, 2168, 2178, 2250, 0, 340 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), 341 .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, }, 342 }; 343 344 static bool drm_mode_equal(const struct base_drm_display_mode *mode1, 345 const struct drm_display_mode *mode2) 346 { 347 unsigned int flags_mask = 348 DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_PHSYNC | 349 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC | 350 DRM_MODE_FLAG_NVSYNC; 351 352 if (mode1->clock == mode2->clock && 353 mode1->hdisplay == mode2->hdisplay && 354 mode1->hsync_start == mode2->hsync_start && 355 mode1->hsync_end == mode2->hsync_end && 356 mode1->htotal == mode2->htotal && 357 mode1->vdisplay == mode2->vdisplay && 358 mode1->vsync_start == mode2->vsync_start && 359 mode1->vsync_end == mode2->vsync_end && 360 mode1->vtotal == mode2->vtotal && 361 (mode1->flags & flags_mask) == (mode2->flags & flags_mask)) { 362 return true; 363 } 364 365 return false; 366 } 367 368 /** 369 * drm_mode_sort - sort mode list 370 * @edid_data: modes structures to sort 371 * 372 * Sort @edid_data by favorability, moving good modes to the head of the list. 373 */ 374 void drm_mode_sort(struct hdmi_edid_data *edid_data) 375 { 376 struct drm_display_mode *a, *b; 377 struct drm_display_mode c; 378 int diff, i, j; 379 380 for (i = 0; i < (edid_data->modes - 1); i++) { 381 a = &edid_data->mode_buf[i]; 382 for (j = i + 1; j < edid_data->modes; j++) { 383 b = &edid_data->mode_buf[j]; 384 diff = ((b->type & DRM_MODE_TYPE_PREFERRED) != 0) - 385 ((a->type & DRM_MODE_TYPE_PREFERRED) != 0); 386 if (diff) { 387 if (diff > 0) { 388 c = *a; 389 *a = *b; 390 *b = c; 391 } 392 continue; 393 } 394 395 diff = b->hdisplay * b->vdisplay 396 - a->hdisplay * a->vdisplay; 397 if (diff) { 398 if (diff > 0) { 399 c = *a; 400 *a = *b; 401 *b = c; 402 } 403 continue; 404 } 405 406 diff = b->vrefresh - a->vrefresh; 407 if (diff) { 408 if (diff > 0) { 409 c = *a; 410 *a = *b; 411 *b = c; 412 } 413 continue; 414 } 415 416 diff = b->clock - a->clock; 417 if (diff > 0) { 418 c = *a; 419 *a = *b; 420 *b = c; 421 } 422 } 423 } 424 edid_data->preferred_mode = &edid_data->mode_buf[0]; 425 } 426 427 /** 428 * drm_mode_prune_invalid - remove invalid modes from mode list 429 * @edid_data: structure store mode list 430 * Returns: 431 * Number of valid modes. 432 */ 433 int drm_mode_prune_invalid(struct hdmi_edid_data *edid_data) 434 { 435 int i, j; 436 int num = edid_data->modes; 437 int len = sizeof(struct drm_display_mode); 438 struct drm_display_mode *mode_buf = edid_data->mode_buf; 439 440 for (i = 0; i < num; i++) { 441 if (mode_buf[i].invalid) { 442 /* If mode is invalid, delete it. */ 443 for (j = i; j < num - 1; j++) 444 memcpy(&mode_buf[j], &mode_buf[j + 1], len); 445 446 num--; 447 i--; 448 } 449 } 450 /* Clear redundant modes of mode_buf. */ 451 memset(&mode_buf[num], 0, len * (edid_data->modes - num)); 452 453 edid_data->modes = num; 454 return num; 455 } 456 457 /** 458 * drm_rk_filter_whitelist - mark modes out of white list from mode list 459 * @edid_data: structure store mode list 460 */ 461 void drm_rk_filter_whitelist(struct hdmi_edid_data *edid_data) 462 { 463 int i, j, white_len; 464 465 if (sizeof(resolution_white)) { 466 white_len = sizeof(resolution_white) / 467 sizeof(resolution_white[0]); 468 for (i = 0; i < edid_data->modes; i++) { 469 for (j = 0; j < white_len; j++) { 470 if (drm_mode_equal(&resolution_white[j], 471 &edid_data->mode_buf[i])) 472 break; 473 } 474 475 if (j == white_len) 476 edid_data->mode_buf[i].invalid = true; 477 } 478 } 479 } 480 481 void drm_rk_select_mode(struct hdmi_edid_data *edid_data, 482 struct base_screen_info *screen_info) 483 { 484 int i; 485 const struct base_drm_display_mode *base_mode; 486 487 if (!screen_info) { 488 /* define init resolution here */ 489 } else { 490 base_mode = &screen_info->mode; 491 for (i = 0; i < edid_data->modes; i++) { 492 if (drm_mode_equal(base_mode, 493 &edid_data->mode_buf[i])) { 494 edid_data->preferred_mode = 495 &edid_data->mode_buf[i]; 496 break; 497 } 498 } 499 } 500 } 501 502 static unsigned int drm_rk_select_color(struct hdmi_edid_data *edid_data, 503 struct base_screen_info *screen_info, 504 enum dw_hdmi_devtype dev_type) 505 { 506 struct drm_display_info *info = &edid_data->display_info; 507 struct drm_display_mode *mode = edid_data->preferred_mode; 508 int max_tmds_clock = info->max_tmds_clock; 509 bool support_dc = false; 510 bool mode_420 = drm_mode_is_420(info, mode); 511 unsigned int color_depth = 8; 512 unsigned int base_color = DRM_HDMI_OUTPUT_YCBCR444; 513 unsigned int color_format = DRM_HDMI_OUTPUT_DEFAULT_RGB; 514 unsigned long tmdsclock, pixclock = mode->clock; 515 516 if (screen_info) 517 base_color = screen_info->format; 518 519 switch (base_color) { 520 case DRM_HDMI_OUTPUT_YCBCR_HQ: 521 if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) 522 color_format = DRM_HDMI_OUTPUT_YCBCR444; 523 else if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) 524 color_format = DRM_HDMI_OUTPUT_YCBCR422; 525 else if (mode_420) 526 color_format = DRM_HDMI_OUTPUT_YCBCR420; 527 break; 528 case DRM_HDMI_OUTPUT_YCBCR_LQ: 529 if (mode_420) 530 color_format = DRM_HDMI_OUTPUT_YCBCR420; 531 else if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) 532 color_format = DRM_HDMI_OUTPUT_YCBCR422; 533 else if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) 534 color_format = DRM_HDMI_OUTPUT_YCBCR444; 535 break; 536 case DRM_HDMI_OUTPUT_YCBCR420: 537 if (mode_420) 538 color_format = DRM_HDMI_OUTPUT_YCBCR420; 539 break; 540 case DRM_HDMI_OUTPUT_YCBCR422: 541 if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) 542 color_format = DRM_HDMI_OUTPUT_YCBCR422; 543 break; 544 case DRM_HDMI_OUTPUT_YCBCR444: 545 if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) 546 color_format = DRM_HDMI_OUTPUT_YCBCR444; 547 break; 548 case DRM_HDMI_OUTPUT_DEFAULT_RGB: 549 default: 550 break; 551 } 552 553 if (color_format == DRM_HDMI_OUTPUT_DEFAULT_RGB && 554 info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30) 555 support_dc = true; 556 if (color_format == DRM_HDMI_OUTPUT_YCBCR444 && 557 (info->edid_hdmi_dc_modes & 558 (DRM_EDID_HDMI_DC_Y444 | DRM_EDID_HDMI_DC_30))) 559 support_dc = true; 560 if (color_format == DRM_HDMI_OUTPUT_YCBCR422) 561 support_dc = true; 562 if (color_format == DRM_HDMI_OUTPUT_YCBCR420 && 563 info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30) 564 support_dc = true; 565 566 if (mode->flags & DRM_MODE_FLAG_DBLCLK) 567 pixclock *= 2; 568 569 if (screen_info && screen_info->depth == 10) 570 color_depth = screen_info->depth; 571 572 if (color_format == DRM_HDMI_OUTPUT_YCBCR422 || color_depth == 8) 573 tmdsclock = pixclock; 574 else 575 tmdsclock = pixclock * color_depth / 8; 576 577 if (color_format == DRM_HDMI_OUTPUT_YCBCR420) 578 tmdsclock /= 2; 579 580 if (!max_tmds_clock) 581 max_tmds_clock = 340000; 582 583 switch (dev_type) { 584 case RK3368_HDMI: 585 max_tmds_clock = min(max_tmds_clock, 340000); 586 break; 587 case RK3328_HDMI: 588 case RK3228_HDMI: 589 max_tmds_clock = min(max_tmds_clock, 371250); 590 break; 591 default: 592 max_tmds_clock = min(max_tmds_clock, 594000); 593 break; 594 } 595 596 if (tmdsclock > max_tmds_clock) { 597 if (max_tmds_clock >= 594000) { 598 color_depth = 8; 599 } else if (max_tmds_clock > 340000) { 600 if (drm_mode_is_420(info, mode)) 601 color_format = DRM_HDMI_OUTPUT_YCBCR420; 602 } else { 603 color_depth = 8; 604 if (drm_mode_is_420(info, mode)) 605 color_format = DRM_HDMI_OUTPUT_YCBCR420; 606 } 607 } 608 609 if (color_depth > 8 && support_dc) { 610 if (dev_type == RK3288_HDMI) 611 return MEDIA_BUS_FMT_RGB101010_1X30; 612 switch (color_format) { 613 case DRM_HDMI_OUTPUT_YCBCR444: 614 return MEDIA_BUS_FMT_YUV10_1X30; 615 case DRM_HDMI_OUTPUT_YCBCR422: 616 return MEDIA_BUS_FMT_UYVY10_1X20; 617 case DRM_HDMI_OUTPUT_YCBCR420: 618 return MEDIA_BUS_FMT_UYYVYY10_0_5X30; 619 default: 620 return MEDIA_BUS_FMT_RGB101010_1X30; 621 } 622 } else { 623 if (dev_type == RK3288_HDMI) 624 return MEDIA_BUS_FMT_RGB888_1X24; 625 switch (color_format) { 626 case DRM_HDMI_OUTPUT_YCBCR444: 627 return MEDIA_BUS_FMT_YUV8_1X24; 628 case DRM_HDMI_OUTPUT_YCBCR422: 629 return MEDIA_BUS_FMT_UYVY8_1X16; 630 case DRM_HDMI_OUTPUT_YCBCR420: 631 return MEDIA_BUS_FMT_UYYVYY8_0_5X24; 632 default: 633 return MEDIA_BUS_FMT_RGB888_1X24; 634 } 635 } 636 } 637 638 void drm_rk_selete_output(struct hdmi_edid_data *edid_data, 639 unsigned int *bus_format, 640 struct overscan *overscan, 641 enum dw_hdmi_devtype dev_type) 642 { 643 int ret, i, screen_size; 644 struct base_disp_info base_parameter; 645 const struct base_overscan *scan; 646 struct base_screen_info *screen_info = NULL; 647 int max_scan = 100; 648 int min_scan = 51; 649 struct blk_desc *dev_desc; 650 disk_partition_t part_info; 651 char baseparameter_buf[8 * RK_BLK_SIZE] __aligned(ARCH_DMA_MINALIGN); 652 653 overscan->left_margin = max_scan; 654 overscan->right_margin = max_scan; 655 overscan->top_margin = max_scan; 656 overscan->bottom_margin = max_scan; 657 658 if (dev_type == RK3288_HDMI) 659 *bus_format = MEDIA_BUS_FMT_RGB888_1X24; 660 else 661 *bus_format = MEDIA_BUS_FMT_YUV8_1X24; 662 663 dev_desc = rockchip_get_bootdev(); 664 if (!dev_desc) { 665 printf("%s: Could not find device\n", __func__); 666 return; 667 } 668 669 if (part_get_info_by_name(dev_desc, "baseparameter", &part_info) < 0) { 670 printf("Could not find baseparameter partition\n"); 671 return; 672 } 673 674 ret = blk_dread(dev_desc, part_info.start, 1, 675 (void *)baseparameter_buf); 676 if (ret < 0) { 677 printf("read baseparameter failed\n"); 678 return; 679 } 680 681 memcpy(&base_parameter, baseparameter_buf, sizeof(base_parameter)); 682 scan = &base_parameter.scan; 683 684 if (scan->leftscale < min_scan && scan->leftscale > 0) 685 overscan->left_margin = min_scan; 686 else if (scan->leftscale < max_scan && scan->leftscale > 0) 687 overscan->left_margin = scan->leftscale; 688 689 if (scan->rightscale < min_scan && scan->rightscale > 0) 690 overscan->right_margin = min_scan; 691 else if (scan->rightscale < max_scan && scan->rightscale > 0) 692 overscan->right_margin = scan->rightscale; 693 694 if (scan->topscale < min_scan && scan->topscale > 0) 695 overscan->top_margin = min_scan; 696 else if (scan->topscale < max_scan && scan->topscale > 0) 697 overscan->top_margin = scan->topscale; 698 699 if (scan->bottomscale < min_scan && scan->bottomscale > 0) 700 overscan->bottom_margin = min_scan; 701 else if (scan->bottomscale < max_scan && scan->bottomscale > 0) 702 overscan->bottom_margin = scan->bottomscale; 703 704 screen_size = sizeof(base_parameter.screen_list) / 705 sizeof(base_parameter.screen_list[0]); 706 707 for (i = 0; i < screen_size; i++) { 708 if (base_parameter.screen_list[i].type == 709 DRM_MODE_CONNECTOR_HDMIA) { 710 screen_info = &base_parameter.screen_list[i]; 711 break; 712 } 713 } 714 715 if (screen_info) 716 printf("base_parameter.mode:%dx%d\n", 717 screen_info->mode.hdisplay, 718 screen_info->mode.vdisplay); 719 drm_rk_select_mode(edid_data, screen_info); 720 721 *bus_format = drm_rk_select_color(edid_data, screen_info, 722 dev_type); 723 } 724 725 void inno_dw_hdmi_set_domain(void *grf, int status) 726 { 727 if (status) 728 writel(RK3328_IO_5V_DOMAIN, grf + RK3328_GRF_SOC_CON4); 729 else 730 writel(RK3328_IO_3V_DOMAIN, grf + RK3328_GRF_SOC_CON4); 731 } 732 733 void dw_hdmi_set_iomux(void *grf, int dev_type) 734 { 735 switch (dev_type) { 736 case RK3328_HDMI: 737 writel(RK3328_IO_DDC_IN_MSK, grf + RK3328_GRF_SOC_CON2); 738 writel(RK3328_IO_CTRL_BY_HDMI, grf + RK3328_GRF_SOC_CON3); 739 break; 740 case RK3228_HDMI: 741 writel(RK3228_IO_3V_DOMAIN, grf + RK3228_GRF_SOC_CON6); 742 writel(RK3228_IO_DDC_IN_MSK, grf + RK3228_GRF_SOC_CON2); 743 break; 744 default: 745 break; 746 } 747 } 748 749 static const struct dw_hdmi_phy_ops inno_dw_hdmi_phy_ops = { 750 .init = inno_dw_hdmi_phy_init, 751 .disable = inno_dw_hdmi_phy_disable, 752 .read_hpd = inno_dw_hdmi_phy_read_hpd, 753 .mode_valid = inno_dw_hdmi_mode_valid, 754 }; 755 756 static const struct rockchip_connector_funcs rockchip_dw_hdmi_funcs = { 757 .init = rockchip_dw_hdmi_init, 758 .deinit = rockchip_dw_hdmi_deinit, 759 .prepare = rockchip_dw_hdmi_prepare, 760 .enable = rockchip_dw_hdmi_enable, 761 .disable = rockchip_dw_hdmi_disable, 762 .get_timing = rockchip_dw_hdmi_get_timing, 763 .detect = rockchip_dw_hdmi_detect, 764 .get_edid = rockchip_dw_hdmi_get_edid, 765 }; 766 767 const struct dw_hdmi_plat_data rk3288_hdmi_drv_data = { 768 .vop_sel_bit = 4, 769 .grf_vop_sel_reg = RK3288_GRF_SOC_CON6, 770 .mpll_cfg = rockchip_mpll_cfg, 771 .cur_ctr = rockchip_cur_ctr, 772 .phy_config = rockchip_phy_config, 773 .dev_type = RK3288_HDMI, 774 }; 775 776 const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = { 777 .vop_sel_bit = 0, 778 .grf_vop_sel_reg = 0, 779 .phy_ops = &inno_dw_hdmi_phy_ops, 780 .phy_name = "inno_dw_hdmi_phy2", 781 .dev_type = RK3328_HDMI, 782 }; 783 784 const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = { 785 .vop_sel_bit = 0, 786 .grf_vop_sel_reg = 0, 787 .phy_ops = &inno_dw_hdmi_phy_ops, 788 .phy_name = "inno_dw_hdmi_phy", 789 .dev_type = RK3228_HDMI, 790 }; 791 792 const struct dw_hdmi_plat_data rk3368_hdmi_drv_data = { 793 .mpll_cfg = rockchip_mpll_cfg, 794 .cur_ctr = rockchip_cur_ctr, 795 .phy_config = rockchip_phy_config, 796 .mpll_cfg_420 = rockchip_mpll_cfg_420, 797 .dev_type = RK3368_HDMI, 798 }; 799 800 const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = { 801 .vop_sel_bit = 6, 802 .grf_vop_sel_reg = RK3399_GRF_SOC_CON20, 803 .mpll_cfg = rockchip_mpll_cfg, 804 .cur_ctr = rockchip_cur_ctr, 805 .phy_config = rockchip_phy_config, 806 .mpll_cfg_420 = rockchip_mpll_cfg_420, 807 .dev_type = RK3399_HDMI, 808 }; 809 810 static int rockchip_dw_hdmi_probe(struct udevice *dev) 811 { 812 return 0; 813 } 814 815 static const struct rockchip_connector rk3399_dw_hdmi_data = { 816 .funcs = &rockchip_dw_hdmi_funcs, 817 .data = &rk3399_hdmi_drv_data, 818 }; 819 820 static const struct rockchip_connector rk3368_dw_hdmi_data = { 821 .funcs = &rockchip_dw_hdmi_funcs, 822 .data = &rk3368_hdmi_drv_data, 823 }; 824 825 static const struct rockchip_connector rk3288_dw_hdmi_data = { 826 .funcs = &rockchip_dw_hdmi_funcs, 827 .data = &rk3288_hdmi_drv_data, 828 }; 829 830 static const struct rockchip_connector rk3328_dw_hdmi_data = { 831 .funcs = &rockchip_dw_hdmi_funcs, 832 .data = &rk3328_hdmi_drv_data, 833 }; 834 835 static const struct rockchip_connector rk3228_dw_hdmi_data = { 836 .funcs = &rockchip_dw_hdmi_funcs, 837 .data = &rk3228_hdmi_drv_data, 838 }; 839 840 static const struct udevice_id rockchip_dw_hdmi_ids[] = { 841 { 842 .compatible = "rockchip,rk3399-dw-hdmi", 843 .data = (ulong)&rk3399_dw_hdmi_data, 844 }, { 845 .compatible = "rockchip,rk3368-dw-hdmi", 846 .data = (ulong)&rk3368_dw_hdmi_data, 847 }, { 848 .compatible = "rockchip,rk3288-dw-hdmi", 849 .data = (ulong)&rk3288_dw_hdmi_data, 850 }, { 851 .compatible = "rockchip,rk3328-dw-hdmi", 852 .data = (ulong)&rk3328_dw_hdmi_data, 853 }, { 854 .compatible = "rockchip,rk3128-inno-hdmi", 855 .data = (ulong)&rk3228_dw_hdmi_data, 856 }, { 857 .compatible = "rockchip,rk3228-dw-hdmi", 858 .data = (ulong)&rk3228_dw_hdmi_data, 859 }, {} 860 }; 861 862 U_BOOT_DRIVER(rockchip_dw_hdmi) = { 863 .name = "rockchip_dw_hdmi", 864 .id = UCLASS_DISPLAY, 865 .of_match = rockchip_dw_hdmi_ids, 866 .probe = rockchip_dw_hdmi_probe, 867 }; 868