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->picture_aspect_ratio == mode2->picture_aspect_ratio && 362 (mode1->flags & flags_mask) == (mode2->flags & flags_mask)) { 363 return true; 364 } 365 366 return false; 367 } 368 369 /** 370 * drm_mode_sort - sort mode list 371 * @edid_data: modes structures to sort 372 * 373 * Sort @edid_data by favorability, moving good modes to the head of the list. 374 */ 375 void drm_mode_sort(struct hdmi_edid_data *edid_data) 376 { 377 struct drm_display_mode *a, *b; 378 struct drm_display_mode c; 379 int diff, i, j; 380 381 for (i = 0; i < (edid_data->modes - 1); i++) { 382 a = &edid_data->mode_buf[i]; 383 for (j = i + 1; j < edid_data->modes; j++) { 384 b = &edid_data->mode_buf[j]; 385 diff = ((b->type & DRM_MODE_TYPE_PREFERRED) != 0) - 386 ((a->type & DRM_MODE_TYPE_PREFERRED) != 0); 387 if (diff) { 388 if (diff > 0) { 389 c = *a; 390 *a = *b; 391 *b = c; 392 } 393 continue; 394 } 395 396 diff = b->hdisplay * b->vdisplay 397 - a->hdisplay * a->vdisplay; 398 if (diff) { 399 if (diff > 0) { 400 c = *a; 401 *a = *b; 402 *b = c; 403 } 404 continue; 405 } 406 407 diff = b->vrefresh - a->vrefresh; 408 if (diff) { 409 if (diff > 0) { 410 c = *a; 411 *a = *b; 412 *b = c; 413 } 414 continue; 415 } 416 417 diff = b->clock - a->clock; 418 if (diff > 0) { 419 c = *a; 420 *a = *b; 421 *b = c; 422 } 423 } 424 } 425 edid_data->preferred_mode = &edid_data->mode_buf[0]; 426 } 427 428 /** 429 * drm_mode_prune_invalid - remove invalid modes from mode list 430 * @edid_data: structure store mode list 431 * Returns: 432 * Number of valid modes. 433 */ 434 int drm_mode_prune_invalid(struct hdmi_edid_data *edid_data) 435 { 436 int i, j; 437 int num = edid_data->modes; 438 int len = sizeof(struct drm_display_mode); 439 struct drm_display_mode *mode_buf = edid_data->mode_buf; 440 441 for (i = 0; i < num; i++) { 442 if (mode_buf[i].invalid) { 443 /* If mode is invalid, delete it. */ 444 for (j = i; j < num - 1; j++) 445 memcpy(&mode_buf[j], &mode_buf[j + 1], len); 446 447 num--; 448 i--; 449 } 450 } 451 /* Clear redundant modes of mode_buf. */ 452 memset(&mode_buf[num], 0, len * (edid_data->modes - num)); 453 454 edid_data->modes = num; 455 return num; 456 } 457 458 /** 459 * drm_rk_filter_whitelist - mark modes out of white list from mode list 460 * @edid_data: structure store mode list 461 */ 462 void drm_rk_filter_whitelist(struct hdmi_edid_data *edid_data) 463 { 464 int i, j, white_len; 465 466 if (sizeof(resolution_white)) { 467 white_len = sizeof(resolution_white) / 468 sizeof(resolution_white[0]); 469 for (i = 0; i < edid_data->modes; i++) { 470 for (j = 0; j < white_len; j++) { 471 if (drm_mode_equal(&resolution_white[j], 472 &edid_data->mode_buf[i])) 473 break; 474 } 475 476 if (j == white_len) 477 edid_data->mode_buf[i].invalid = true; 478 } 479 } 480 } 481 482 void drm_rk_select_mode(struct hdmi_edid_data *edid_data, 483 struct base_screen_info *screen_info) 484 { 485 int i; 486 const struct base_drm_display_mode *base_mode; 487 488 if (!screen_info) { 489 /* define init resolution here */ 490 } else { 491 base_mode = &screen_info->mode; 492 for (i = 0; i < edid_data->modes; i++) { 493 if (drm_mode_equal(base_mode, 494 &edid_data->mode_buf[i])) { 495 edid_data->preferred_mode = 496 &edid_data->mode_buf[i]; 497 break; 498 } 499 } 500 } 501 } 502 503 static unsigned int drm_rk_select_color(struct hdmi_edid_data *edid_data, 504 struct base_screen_info *screen_info, 505 enum dw_hdmi_devtype dev_type) 506 { 507 struct drm_display_info *info = &edid_data->display_info; 508 struct drm_display_mode *mode = edid_data->preferred_mode; 509 int max_tmds_clock = info->max_tmds_clock; 510 bool support_dc = false; 511 bool mode_420 = drm_mode_is_420(info, mode); 512 unsigned int color_depth = 8; 513 unsigned int base_color = DRM_HDMI_OUTPUT_YCBCR444; 514 unsigned int color_format = DRM_HDMI_OUTPUT_DEFAULT_RGB; 515 unsigned long tmdsclock, pixclock = mode->clock; 516 517 if (screen_info) 518 base_color = screen_info->format; 519 520 switch (base_color) { 521 case DRM_HDMI_OUTPUT_YCBCR_HQ: 522 if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) 523 color_format = DRM_HDMI_OUTPUT_YCBCR444; 524 else if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) 525 color_format = DRM_HDMI_OUTPUT_YCBCR422; 526 else if (mode_420) 527 color_format = DRM_HDMI_OUTPUT_YCBCR420; 528 break; 529 case DRM_HDMI_OUTPUT_YCBCR_LQ: 530 if (mode_420) 531 color_format = DRM_HDMI_OUTPUT_YCBCR420; 532 else if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) 533 color_format = DRM_HDMI_OUTPUT_YCBCR422; 534 else if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) 535 color_format = DRM_HDMI_OUTPUT_YCBCR444; 536 break; 537 case DRM_HDMI_OUTPUT_YCBCR420: 538 if (mode_420) 539 color_format = DRM_HDMI_OUTPUT_YCBCR420; 540 break; 541 case DRM_HDMI_OUTPUT_YCBCR422: 542 if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) 543 color_format = DRM_HDMI_OUTPUT_YCBCR422; 544 break; 545 case DRM_HDMI_OUTPUT_YCBCR444: 546 if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) 547 color_format = DRM_HDMI_OUTPUT_YCBCR444; 548 break; 549 case DRM_HDMI_OUTPUT_DEFAULT_RGB: 550 default: 551 break; 552 } 553 554 if (color_format == DRM_HDMI_OUTPUT_DEFAULT_RGB && 555 info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30) 556 support_dc = true; 557 if (color_format == DRM_HDMI_OUTPUT_YCBCR444 && 558 (info->edid_hdmi_dc_modes & 559 (DRM_EDID_HDMI_DC_Y444 | DRM_EDID_HDMI_DC_30))) 560 support_dc = true; 561 if (color_format == DRM_HDMI_OUTPUT_YCBCR422) 562 support_dc = true; 563 if (color_format == DRM_HDMI_OUTPUT_YCBCR420 && 564 info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30) 565 support_dc = true; 566 567 if (mode->flags & DRM_MODE_FLAG_DBLCLK) 568 pixclock *= 2; 569 570 if (screen_info && screen_info->depth == 10) 571 color_depth = screen_info->depth; 572 573 if (color_format == DRM_HDMI_OUTPUT_YCBCR422 || color_depth == 8) 574 tmdsclock = pixclock; 575 else 576 tmdsclock = pixclock * color_depth / 8; 577 578 if (color_format == DRM_HDMI_OUTPUT_YCBCR420) 579 tmdsclock /= 2; 580 581 if (!max_tmds_clock) 582 max_tmds_clock = 340000; 583 584 switch (dev_type) { 585 case RK3368_HDMI: 586 max_tmds_clock = min(max_tmds_clock, 340000); 587 break; 588 case RK3328_HDMI: 589 case RK3228_HDMI: 590 max_tmds_clock = min(max_tmds_clock, 371250); 591 break; 592 default: 593 max_tmds_clock = min(max_tmds_clock, 594000); 594 break; 595 } 596 597 if (tmdsclock > max_tmds_clock) { 598 if (max_tmds_clock >= 594000) { 599 color_depth = 8; 600 } else if (max_tmds_clock > 340000) { 601 if (drm_mode_is_420(info, mode)) 602 color_format = DRM_HDMI_OUTPUT_YCBCR420; 603 } else { 604 color_depth = 8; 605 if (drm_mode_is_420(info, mode)) 606 color_format = DRM_HDMI_OUTPUT_YCBCR420; 607 } 608 } 609 610 if (color_depth > 8 && support_dc) { 611 if (dev_type == RK3288_HDMI) 612 return MEDIA_BUS_FMT_RGB101010_1X30; 613 switch (color_format) { 614 case DRM_HDMI_OUTPUT_YCBCR444: 615 return MEDIA_BUS_FMT_YUV10_1X30; 616 case DRM_HDMI_OUTPUT_YCBCR422: 617 return MEDIA_BUS_FMT_UYVY10_1X20; 618 case DRM_HDMI_OUTPUT_YCBCR420: 619 return MEDIA_BUS_FMT_UYYVYY10_0_5X30; 620 default: 621 return MEDIA_BUS_FMT_RGB101010_1X30; 622 } 623 } else { 624 if (dev_type == RK3288_HDMI) 625 return MEDIA_BUS_FMT_RGB888_1X24; 626 switch (color_format) { 627 case DRM_HDMI_OUTPUT_YCBCR444: 628 return MEDIA_BUS_FMT_YUV8_1X24; 629 case DRM_HDMI_OUTPUT_YCBCR422: 630 return MEDIA_BUS_FMT_UYVY8_1X16; 631 case DRM_HDMI_OUTPUT_YCBCR420: 632 return MEDIA_BUS_FMT_UYYVYY8_0_5X24; 633 default: 634 return MEDIA_BUS_FMT_RGB888_1X24; 635 } 636 } 637 } 638 639 void drm_rk_selete_output(struct hdmi_edid_data *edid_data, 640 unsigned int *bus_format, 641 struct overscan *overscan, 642 enum dw_hdmi_devtype dev_type) 643 { 644 int ret, i, screen_size; 645 struct base_disp_info base_parameter; 646 const struct base_overscan *scan; 647 struct base_screen_info *screen_info = NULL; 648 int max_scan = 100; 649 int min_scan = 51; 650 struct blk_desc *dev_desc; 651 disk_partition_t part_info; 652 char baseparameter_buf[8 * RK_BLK_SIZE] __aligned(ARCH_DMA_MINALIGN); 653 654 overscan->left_margin = max_scan; 655 overscan->right_margin = max_scan; 656 overscan->top_margin = max_scan; 657 overscan->bottom_margin = max_scan; 658 659 if (dev_type == RK3288_HDMI) 660 *bus_format = MEDIA_BUS_FMT_RGB888_1X24; 661 else 662 *bus_format = MEDIA_BUS_FMT_YUV8_1X24; 663 664 dev_desc = rockchip_get_bootdev(); 665 if (!dev_desc) { 666 printf("%s: Could not find device\n", __func__); 667 return; 668 } 669 670 if (part_get_info_by_name(dev_desc, "baseparameter", &part_info) < 0) { 671 printf("Could not find baseparameter partition\n"); 672 return; 673 } 674 675 ret = blk_dread(dev_desc, part_info.start, 1, 676 (void *)baseparameter_buf); 677 if (ret < 0) { 678 printf("read baseparameter failed\n"); 679 return; 680 } 681 682 memcpy(&base_parameter, baseparameter_buf, sizeof(base_parameter)); 683 scan = &base_parameter.scan; 684 685 if (scan->leftscale < min_scan && scan->leftscale > 0) 686 overscan->left_margin = min_scan; 687 else if (scan->leftscale < max_scan && scan->leftscale > 0) 688 overscan->left_margin = scan->leftscale; 689 690 if (scan->rightscale < min_scan && scan->rightscale > 0) 691 overscan->right_margin = min_scan; 692 else if (scan->rightscale < max_scan && scan->rightscale > 0) 693 overscan->right_margin = scan->rightscale; 694 695 if (scan->topscale < min_scan && scan->topscale > 0) 696 overscan->top_margin = min_scan; 697 else if (scan->topscale < max_scan && scan->topscale > 0) 698 overscan->top_margin = scan->topscale; 699 700 if (scan->bottomscale < min_scan && scan->bottomscale > 0) 701 overscan->bottom_margin = min_scan; 702 else if (scan->bottomscale < max_scan && scan->bottomscale > 0) 703 overscan->bottom_margin = scan->bottomscale; 704 705 screen_size = sizeof(base_parameter.screen_list) / 706 sizeof(base_parameter.screen_list[0]); 707 708 for (i = 0; i < screen_size; i++) { 709 if (base_parameter.screen_list[i].type == 710 DRM_MODE_CONNECTOR_HDMIA) { 711 screen_info = &base_parameter.screen_list[i]; 712 screen_info->mode.picture_aspect_ratio = 713 (screen_info->mode.flags & DRM_MODE_FLAG_PIC_AR_MASK) >> 19; 714 break; 715 } 716 } 717 718 if (screen_info) 719 printf("base_parameter.mode:%dx%d\n", 720 screen_info->mode.hdisplay, 721 screen_info->mode.vdisplay); 722 drm_rk_select_mode(edid_data, screen_info); 723 724 *bus_format = drm_rk_select_color(edid_data, screen_info, 725 dev_type); 726 } 727 728 void inno_dw_hdmi_set_domain(void *grf, int status) 729 { 730 if (status) 731 writel(RK3328_IO_5V_DOMAIN, grf + RK3328_GRF_SOC_CON4); 732 else 733 writel(RK3328_IO_3V_DOMAIN, grf + RK3328_GRF_SOC_CON4); 734 } 735 736 void dw_hdmi_set_iomux(void *grf, int dev_type) 737 { 738 switch (dev_type) { 739 case RK3328_HDMI: 740 writel(RK3328_IO_DDC_IN_MSK, grf + RK3328_GRF_SOC_CON2); 741 writel(RK3328_IO_CTRL_BY_HDMI, grf + RK3328_GRF_SOC_CON3); 742 break; 743 case RK3228_HDMI: 744 writel(RK3228_IO_3V_DOMAIN, grf + RK3228_GRF_SOC_CON6); 745 writel(RK3228_IO_DDC_IN_MSK, grf + RK3228_GRF_SOC_CON2); 746 break; 747 default: 748 break; 749 } 750 } 751 752 static const struct dw_hdmi_phy_ops inno_dw_hdmi_phy_ops = { 753 .init = inno_dw_hdmi_phy_init, 754 .disable = inno_dw_hdmi_phy_disable, 755 .read_hpd = inno_dw_hdmi_phy_read_hpd, 756 .mode_valid = inno_dw_hdmi_mode_valid, 757 }; 758 759 static const struct rockchip_connector_funcs rockchip_dw_hdmi_funcs = { 760 .init = rockchip_dw_hdmi_init, 761 .deinit = rockchip_dw_hdmi_deinit, 762 .prepare = rockchip_dw_hdmi_prepare, 763 .enable = rockchip_dw_hdmi_enable, 764 .disable = rockchip_dw_hdmi_disable, 765 .get_timing = rockchip_dw_hdmi_get_timing, 766 .detect = rockchip_dw_hdmi_detect, 767 .get_edid = rockchip_dw_hdmi_get_edid, 768 }; 769 770 const struct dw_hdmi_plat_data rk3288_hdmi_drv_data = { 771 .vop_sel_bit = 4, 772 .grf_vop_sel_reg = RK3288_GRF_SOC_CON6, 773 .mpll_cfg = rockchip_mpll_cfg, 774 .cur_ctr = rockchip_cur_ctr, 775 .phy_config = rockchip_phy_config, 776 .dev_type = RK3288_HDMI, 777 }; 778 779 const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = { 780 .vop_sel_bit = 0, 781 .grf_vop_sel_reg = 0, 782 .phy_ops = &inno_dw_hdmi_phy_ops, 783 .phy_name = "inno_dw_hdmi_phy2", 784 .dev_type = RK3328_HDMI, 785 }; 786 787 const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = { 788 .vop_sel_bit = 0, 789 .grf_vop_sel_reg = 0, 790 .phy_ops = &inno_dw_hdmi_phy_ops, 791 .phy_name = "inno_dw_hdmi_phy", 792 .dev_type = RK3228_HDMI, 793 }; 794 795 const struct dw_hdmi_plat_data rk3368_hdmi_drv_data = { 796 .mpll_cfg = rockchip_mpll_cfg, 797 .cur_ctr = rockchip_cur_ctr, 798 .phy_config = rockchip_phy_config, 799 .mpll_cfg_420 = rockchip_mpll_cfg_420, 800 .dev_type = RK3368_HDMI, 801 }; 802 803 const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = { 804 .vop_sel_bit = 6, 805 .grf_vop_sel_reg = RK3399_GRF_SOC_CON20, 806 .mpll_cfg = rockchip_mpll_cfg, 807 .cur_ctr = rockchip_cur_ctr, 808 .phy_config = rockchip_phy_config, 809 .mpll_cfg_420 = rockchip_mpll_cfg_420, 810 .dev_type = RK3399_HDMI, 811 }; 812 813 static int rockchip_dw_hdmi_probe(struct udevice *dev) 814 { 815 return 0; 816 } 817 818 static const struct rockchip_connector rk3399_dw_hdmi_data = { 819 .funcs = &rockchip_dw_hdmi_funcs, 820 .data = &rk3399_hdmi_drv_data, 821 }; 822 823 static const struct rockchip_connector rk3368_dw_hdmi_data = { 824 .funcs = &rockchip_dw_hdmi_funcs, 825 .data = &rk3368_hdmi_drv_data, 826 }; 827 828 static const struct rockchip_connector rk3288_dw_hdmi_data = { 829 .funcs = &rockchip_dw_hdmi_funcs, 830 .data = &rk3288_hdmi_drv_data, 831 }; 832 833 static const struct rockchip_connector rk3328_dw_hdmi_data = { 834 .funcs = &rockchip_dw_hdmi_funcs, 835 .data = &rk3328_hdmi_drv_data, 836 }; 837 838 static const struct rockchip_connector rk3228_dw_hdmi_data = { 839 .funcs = &rockchip_dw_hdmi_funcs, 840 .data = &rk3228_hdmi_drv_data, 841 }; 842 843 static const struct udevice_id rockchip_dw_hdmi_ids[] = { 844 { 845 .compatible = "rockchip,rk3399-dw-hdmi", 846 .data = (ulong)&rk3399_dw_hdmi_data, 847 }, { 848 .compatible = "rockchip,rk3368-dw-hdmi", 849 .data = (ulong)&rk3368_dw_hdmi_data, 850 }, { 851 .compatible = "rockchip,rk3288-dw-hdmi", 852 .data = (ulong)&rk3288_dw_hdmi_data, 853 }, { 854 .compatible = "rockchip,rk3328-dw-hdmi", 855 .data = (ulong)&rk3328_dw_hdmi_data, 856 }, { 857 .compatible = "rockchip,rk3128-inno-hdmi", 858 .data = (ulong)&rk3228_dw_hdmi_data, 859 }, { 860 .compatible = "rockchip,rk3228-dw-hdmi", 861 .data = (ulong)&rk3228_dw_hdmi_data, 862 }, {} 863 }; 864 865 U_BOOT_DRIVER(rockchip_dw_hdmi) = { 866 .name = "rockchip_dw_hdmi", 867 .id = UCLASS_DISPLAY, 868 .of_match = rockchip_dw_hdmi_ids, 869 .probe = rockchip_dw_hdmi_probe, 870 }; 871