1 /* 2 * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <asm/unaligned.h> 8 #include <config.h> 9 #include <common.h> 10 #include <errno.h> 11 #include <libfdt.h> 12 #include <fdtdec.h> 13 #include <fdt_support.h> 14 #include <linux/list.h> 15 #include <linux/compat.h> 16 #include <linux/media-bus-format.h> 17 #include <malloc.h> 18 #include <video.h> 19 #include <dm/device.h> 20 #include <dm/uclass-internal.h> 21 22 #include "bmp_helper.h" 23 #include "rockchip_display.h" 24 #include "rockchip_crtc.h" 25 #include "rockchip_connector.h" 26 #include "rockchip_phy.h" 27 #include "rockchip_panel.h" 28 29 DECLARE_GLOBAL_DATA_PTR; 30 static LIST_HEAD(rockchip_display_list); 31 static LIST_HEAD(logo_cache_list); 32 33 #define DRM_ROCKCHIP_FB_WIDTH 1920 34 #define DRM_ROCKCHIP_FB_HEIGHT 1080 35 36 #define MEMORY_POOL_SIZE 32 * 1024 * 1024 37 static unsigned long memory_start; 38 static unsigned long memory_end; 39 40 #ifdef CONFIG_RK_PWM_BL 41 extern int rk_pwm_bl_config(int brightness); 42 #endif 43 44 struct bmp_header *get_bmp_header(const char *bmp_name) 45 { 46 printf("%s %d TODO\n", __func__, __LINE__); 47 } 48 49 int load_bmp_content(const char *logo, void *bmp, int size) 50 { 51 printf("%s %d TODO\n", __func__, __LINE__); 52 } 53 54 static void init_display_buffer(void) 55 { 56 memory_start = gd->fb_base; 57 memory_end = memory_start; 58 } 59 60 static void *get_display_buffer(int size) 61 { 62 unsigned long roundup_memory = roundup(memory_end, PAGE_SIZE); 63 void *buf; 64 65 if (roundup_memory + size > memory_start + MEMORY_POOL_SIZE) { 66 printf("failed to alloc %dbyte memory to display\n", size); 67 return NULL; 68 } 69 buf = (void *)roundup_memory; 70 71 memory_end = roundup_memory + size; 72 73 return buf; 74 } 75 76 static unsigned long get_display_size(void) 77 { 78 return memory_end - memory_start; 79 } 80 81 static bool can_direct_logo(int bpp) 82 { 83 return bpp == 24 || bpp == 32; 84 } 85 86 static int get_panel_node(struct display_state *state, int conn_node) 87 { 88 const void *blob = state->blob; 89 int panel, ports, port, ep, remote, ph, nodedepth; 90 91 panel = fdt_subnode_offset(blob, conn_node, "panel"); 92 if (panel > 0) 93 return panel; 94 95 ports = fdt_subnode_offset(blob, conn_node, "ports"); 96 if (ports < 0) 97 return -ENODEV; 98 99 fdt_for_each_subnode(port, blob, ports) { 100 fdt_for_each_subnode(ep, blob, port) { 101 ph = fdt_getprop_u32_default_node(blob, ep, 0, 102 "remote-endpoint", 0); 103 if (!ph) 104 continue; 105 106 remote = fdt_node_offset_by_phandle(blob, ph); 107 108 nodedepth = fdt_node_depth(blob, remote); 109 if (nodedepth < 2) 110 continue; 111 112 panel = fdt_supernode_atdepth_offset(blob, remote, 113 nodedepth - 2, 114 NULL); 115 break; 116 } 117 } 118 119 return panel; 120 } 121 122 static int connector_phy_init(struct display_state *state) 123 { 124 struct connector_state *conn_state = &state->conn_state; 125 int conn_node = conn_state->node; 126 const void *blob = state->blob; 127 const struct rockchip_phy *phy; 128 int phy_node, phandle; 129 130 phandle = fdt_getprop_u32_default_node(blob, conn_node, 0, 131 "phys", -1); 132 if (phandle < 0) 133 return 0; 134 135 phy_node = fdt_node_offset_by_phandle(blob, phandle); 136 if (phy_node < 0) { 137 printf("failed to find phy node\n"); 138 return phy_node; 139 } 140 141 phy = rockchip_get_phy(blob, phy_node); 142 if (!phy) { 143 printf("failed to find phy driver\n"); 144 return 0; 145 } 146 147 conn_state->phy_node = phy_node; 148 149 if (!phy->funcs || !phy->funcs->init || 150 phy->funcs->init(state)) { 151 printf("failed to init phy driver\n"); 152 return -EINVAL; 153 } 154 155 conn_state->phy = phy; 156 return 0; 157 } 158 159 static int connector_panel_init(struct display_state *state) 160 { 161 struct connector_state *conn_state = &state->conn_state; 162 struct panel_state *panel_state = &state->panel_state; 163 struct udevice *dev; 164 const void *blob = state->blob; 165 int conn_node = conn_state->node; 166 const struct rockchip_panel *panel; 167 int panel_node, dsp_lut_node; 168 int ret, len; 169 170 panel_node = get_panel_node(state, conn_node); 171 if (panel_node < 0) { 172 printf("failed to find panel node\n"); 173 return -ENODEV; 174 } 175 176 if (!fdt_device_is_available(blob, panel_node)) { 177 printf("panel is disabled\n"); 178 return -ENODEV; 179 } 180 181 dm_scan_fdt_dev(conn_state->dev); 182 183 panel_state->node = panel_node; 184 185 ret = uclass_find_device_by_of_offset(UCLASS_PANEL, panel_node, &dev); 186 if (ret) { 187 printf("Warn: %s: can't find panel driver\n", 188 fdt_get_name(blob, panel_node, NULL)); 189 return -ENODEV; 190 } 191 panel = (const struct rockchip_panel *)dev_get_driver_data(dev); 192 if (!panel) { 193 printf("failed to find panel driver\n"); 194 return 0; 195 } 196 197 panel_state->dev = dev; 198 panel_state->panel = panel; 199 200 ret = rockchip_panel_init(state); 201 if (ret) { 202 printf("failed to init panel driver\n"); 203 return ret; 204 } 205 206 dsp_lut_node = fdt_subnode_offset(blob, panel_node, "dsp-lut"); 207 fdt_getprop(blob, dsp_lut_node, "gamma-lut", &len); 208 if (len > 0) { 209 conn_state->gamma.size = len / sizeof(u32); 210 conn_state->gamma.lut = malloc(len); 211 if (!conn_state->gamma.lut) { 212 printf("malloc gamma lut failed\n"); 213 return -ENOMEM; 214 } 215 if (fdtdec_get_int_array(blob, dsp_lut_node, "gamma-lut", 216 conn_state->gamma.lut, 217 conn_state->gamma.size)) { 218 printf("Cannot decode gamma_lut\n"); 219 conn_state->gamma.lut = NULL; 220 return -EINVAL; 221 } 222 panel_state->dsp_lut_node = dsp_lut_node; 223 } 224 225 return 0; 226 } 227 228 int drm_mode_vrefresh(const struct drm_display_mode *mode) 229 { 230 int refresh = 0; 231 unsigned int calc_val; 232 233 if (mode->vrefresh > 0) { 234 refresh = mode->vrefresh; 235 } else if (mode->htotal > 0 && mode->vtotal > 0) { 236 int vtotal; 237 238 vtotal = mode->vtotal; 239 /* work out vrefresh the value will be x1000 */ 240 calc_val = (mode->clock * 1000); 241 calc_val /= mode->htotal; 242 refresh = (calc_val + vtotal / 2) / vtotal; 243 244 if (mode->flags & DRM_MODE_FLAG_INTERLACE) 245 refresh *= 2; 246 if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 247 refresh /= 2; 248 if (mode->vscan > 1) 249 refresh /= mode->vscan; 250 } 251 return refresh; 252 } 253 254 static int display_get_timing_from_dts(int panel, const void *blob, 255 struct drm_display_mode *mode) 256 { 257 int timing, phandle, native_mode; 258 int hactive, vactive, pixelclock; 259 int hfront_porch, hback_porch, hsync_len; 260 int vfront_porch, vback_porch, vsync_len; 261 int val, flags = 0; 262 263 timing = fdt_subnode_offset(blob, panel, "display-timings"); 264 if (timing < 0) 265 return -ENODEV; 266 267 native_mode = fdt_subnode_offset(blob, timing, "timing"); 268 if (native_mode < 0) { 269 phandle = fdt_getprop_u32_default_node(blob, timing, 0, 270 "native-mode", -1); 271 native_mode = fdt_node_offset_by_phandle_node(blob, timing, phandle); 272 if (native_mode <= 0) { 273 printf("failed to get display timings from DT\n"); 274 return -ENXIO; 275 } 276 } 277 278 #define FDT_GET_INT(val, name) \ 279 val = fdtdec_get_int(blob, native_mode, name, -1); \ 280 if (val < 0) { \ 281 printf("Can't get %s\n", name); \ 282 return -ENXIO; \ 283 } 284 285 FDT_GET_INT(hactive, "hactive"); 286 FDT_GET_INT(vactive, "vactive"); 287 FDT_GET_INT(pixelclock, "clock-frequency"); 288 FDT_GET_INT(hsync_len, "hsync-len"); 289 FDT_GET_INT(hfront_porch, "hfront-porch"); 290 FDT_GET_INT(hback_porch, "hback-porch"); 291 FDT_GET_INT(vsync_len, "vsync-len"); 292 FDT_GET_INT(vfront_porch, "vfront-porch"); 293 FDT_GET_INT(vback_porch, "vback-porch"); 294 FDT_GET_INT(val, "hsync-active"); 295 flags |= val ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC; 296 FDT_GET_INT(val, "vsync-active"); 297 flags |= val ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC; 298 299 mode->hdisplay = hactive; 300 mode->hsync_start = mode->hdisplay + hfront_porch; 301 mode->hsync_end = mode->hsync_start + hsync_len; 302 mode->htotal = mode->hsync_end + hback_porch; 303 304 mode->vdisplay = vactive; 305 mode->vsync_start = mode->vdisplay + vfront_porch; 306 mode->vsync_end = mode->vsync_start + vsync_len; 307 mode->vtotal = mode->vsync_end + vback_porch; 308 309 mode->clock = pixelclock / 1000; 310 mode->flags = flags; 311 312 return 0; 313 } 314 315 static int display_get_timing(struct display_state *state) 316 { 317 struct connector_state *conn_state = &state->conn_state; 318 const struct rockchip_connector *conn = conn_state->connector; 319 const struct rockchip_connector_funcs *conn_funcs = conn->funcs; 320 struct drm_display_mode *mode = &conn_state->mode; 321 const struct drm_display_mode *m; 322 const void *blob = state->blob; 323 int conn_node = conn_state->node; 324 int panel; 325 326 panel = get_panel_node(state, conn_node); 327 if (panel < 0) { 328 printf("failed to find panel node\n"); 329 return -ENODEV; 330 } 331 332 if (!display_get_timing_from_dts(panel, blob, mode)) { 333 printf("Using display timing dts\n"); 334 goto done; 335 } 336 337 m = rockchip_get_display_mode_from_panel(state); 338 if (m) { 339 printf("Using display timing from compatible panel driver\n"); 340 memcpy(mode, m, sizeof(*m)); 341 goto done; 342 } 343 344 rockchip_panel_prepare(state); 345 346 if (conn_funcs->get_edid && !conn_funcs->get_edid(state)) { 347 int panel_bits_per_colourp; 348 349 if (!edid_get_drm_mode((void *)&conn_state->edid, 350 sizeof(conn_state->edid), mode, 351 &panel_bits_per_colourp)) { 352 printf("Using display timing from edid\n"); 353 edid_print_info((void *)&conn_state->edid); 354 goto done; 355 } 356 } 357 358 printf("failed to find display timing\n"); 359 return -ENODEV; 360 done: 361 printf("Detailed mode clock %u kHz, flags[%x]\n" 362 " H: %04d %04d %04d %04d\n" 363 " V: %04d %04d %04d %04d\n" 364 "bus_format: %x\n", 365 mode->clock, mode->flags, 366 mode->hdisplay, mode->hsync_start, 367 mode->hsync_end, mode->htotal, 368 mode->vdisplay, mode->vsync_start, 369 mode->vsync_end, mode->vtotal, 370 conn_state->bus_format); 371 372 return 0; 373 } 374 375 static int display_init(struct display_state *state) 376 { 377 struct connector_state *conn_state = &state->conn_state; 378 const struct rockchip_connector *conn = conn_state->connector; 379 const struct rockchip_connector_funcs *conn_funcs = conn->funcs; 380 struct crtc_state *crtc_state = &state->crtc_state; 381 const struct rockchip_crtc *crtc = crtc_state->crtc; 382 const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs; 383 int ret = 0; 384 385 if (state->is_init) 386 return 0; 387 388 if (!conn_funcs || !crtc_funcs) { 389 printf("failed to find connector or crtc functions\n"); 390 return -ENXIO; 391 } 392 393 if (conn_funcs->init) { 394 ret = conn_funcs->init(state); 395 if (ret) 396 goto deinit_panel; 397 } 398 /* 399 * support hotplug, but not connect; 400 */ 401 if (conn_funcs->detect) { 402 ret = conn_funcs->detect(state); 403 if (!ret) 404 goto deinit; 405 } 406 407 if (conn_funcs->get_timing) { 408 ret = conn_funcs->get_timing(state); 409 if (ret) 410 goto deinit; 411 } else { 412 ret = display_get_timing(state); 413 if (ret) 414 goto deinit; 415 } 416 417 if (crtc_funcs->init) { 418 ret = crtc_funcs->init(state); 419 if (ret) 420 goto deinit; 421 } 422 423 state->is_init = 1; 424 425 return 0; 426 427 deinit: 428 if (conn_funcs->deinit) 429 conn_funcs->deinit(state); 430 deinit_panel: 431 rockchip_panel_deinit(state); 432 return ret; 433 } 434 435 static int display_set_plane(struct display_state *state) 436 { 437 struct crtc_state *crtc_state = &state->crtc_state; 438 const struct rockchip_crtc *crtc = crtc_state->crtc; 439 const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs; 440 int ret; 441 442 if (!state->is_init) 443 return -EINVAL; 444 445 if (crtc_funcs->set_plane) { 446 ret = crtc_funcs->set_plane(state); 447 if (ret) 448 return ret; 449 } 450 451 return 0; 452 } 453 454 static int display_enable(struct display_state *state) 455 { 456 struct connector_state *conn_state = &state->conn_state; 457 const struct rockchip_connector *conn = conn_state->connector; 458 const struct rockchip_connector_funcs *conn_funcs = conn->funcs; 459 struct crtc_state *crtc_state = &state->crtc_state; 460 const struct rockchip_crtc *crtc = crtc_state->crtc; 461 const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs; 462 int ret = 0; 463 464 display_init(state); 465 466 if (!state->is_init) 467 return -EINVAL; 468 469 if (state->is_enable) 470 return 0; 471 472 if (crtc_funcs->prepare) { 473 ret = crtc_funcs->prepare(state); 474 if (ret) 475 return ret; 476 } 477 478 if (conn_funcs->prepare) { 479 ret = conn_funcs->prepare(state); 480 if (ret) 481 goto unprepare_crtc; 482 } 483 484 rockchip_panel_prepare(state); 485 486 if (crtc_funcs->enable) { 487 ret = crtc_funcs->enable(state); 488 if (ret) 489 goto unprepare_conn; 490 } 491 492 if (conn_funcs->enable) { 493 ret = conn_funcs->enable(state); 494 if (ret) 495 goto disable_crtc; 496 } 497 498 rockchip_panel_enable(state); 499 500 state->is_enable = true; 501 502 return 0; 503 unprepare_crtc: 504 if (crtc_funcs->unprepare) 505 crtc_funcs->unprepare(state); 506 unprepare_conn: 507 if (conn_funcs->unprepare) 508 conn_funcs->unprepare(state); 509 disable_crtc: 510 if (crtc_funcs->disable) 511 crtc_funcs->disable(state); 512 return ret; 513 } 514 515 static int display_disable(struct display_state *state) 516 { 517 struct connector_state *conn_state = &state->conn_state; 518 const struct rockchip_connector *conn = conn_state->connector; 519 const struct rockchip_connector_funcs *conn_funcs = conn->funcs; 520 struct crtc_state *crtc_state = &state->crtc_state; 521 const struct rockchip_crtc *crtc = crtc_state->crtc; 522 const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs; 523 524 if (!state->is_init) 525 return 0; 526 527 if (!state->is_enable) 528 return 0; 529 530 rockchip_panel_disable(state); 531 532 if (crtc_funcs->disable) 533 crtc_funcs->disable(state); 534 535 if (conn_funcs->disable) 536 conn_funcs->disable(state); 537 538 rockchip_panel_unprepare(state); 539 540 if (conn_funcs->unprepare) 541 conn_funcs->unprepare(state); 542 543 state->is_enable = 0; 544 state->is_init = 0; 545 546 return 0; 547 } 548 549 static int display_logo(struct display_state *state) 550 { 551 struct crtc_state *crtc_state = &state->crtc_state; 552 struct connector_state *conn_state = &state->conn_state; 553 struct logo_info *logo = &state->logo; 554 int hdisplay, vdisplay; 555 556 display_init(state); 557 if (!state->is_init) 558 return -ENODEV; 559 560 switch (logo->bpp) { 561 case 16: 562 crtc_state->format = ROCKCHIP_FMT_RGB565; 563 break; 564 case 24: 565 crtc_state->format = ROCKCHIP_FMT_RGB888; 566 break; 567 case 32: 568 crtc_state->format = ROCKCHIP_FMT_ARGB8888; 569 break; 570 default: 571 printf("can't support bmp bits[%d]\n", logo->bpp); 572 return -EINVAL; 573 } 574 crtc_state->rb_swap = logo->bpp != 32; 575 hdisplay = conn_state->mode.hdisplay; 576 vdisplay = conn_state->mode.vdisplay; 577 crtc_state->src_w = logo->width; 578 crtc_state->src_h = logo->height; 579 crtc_state->src_x = 0; 580 crtc_state->src_y = 0; 581 crtc_state->ymirror = logo->ymirror; 582 583 crtc_state->dma_addr = logo->mem + logo->offset; 584 crtc_state->xvir = ALIGN(crtc_state->src_w * logo->bpp, 32) >> 5; 585 586 if (logo->mode == ROCKCHIP_DISPLAY_FULLSCREEN) { 587 crtc_state->crtc_x = 0; 588 crtc_state->crtc_y = 0; 589 crtc_state->crtc_w = hdisplay; 590 crtc_state->crtc_h = vdisplay; 591 } else { 592 if (crtc_state->src_w >= hdisplay) { 593 crtc_state->crtc_x = 0; 594 crtc_state->crtc_w = hdisplay; 595 } else { 596 crtc_state->crtc_x = (hdisplay - crtc_state->src_w) / 2; 597 crtc_state->crtc_w = crtc_state->src_w; 598 } 599 600 if (crtc_state->src_h >= vdisplay) { 601 crtc_state->crtc_y = 0; 602 crtc_state->crtc_h = vdisplay; 603 } else { 604 crtc_state->crtc_y = (vdisplay - crtc_state->src_h) / 2; 605 crtc_state->crtc_h = crtc_state->src_h; 606 } 607 } 608 609 display_set_plane(state); 610 display_enable(state); 611 612 return 0; 613 } 614 615 static int get_crtc_id(const void *blob, int connect) 616 { 617 int phandle, remote; 618 int val; 619 620 phandle = fdt_getprop_u32_default_node(blob, connect, 0, 621 "remote-endpoint", -1); 622 if (phandle < 0) 623 goto err; 624 remote = fdt_node_offset_by_phandle(blob, phandle); 625 626 val = fdtdec_get_int(blob, remote, "reg", -1); 627 if (val < 0) 628 goto err; 629 630 return val; 631 err: 632 printf("Can't get crtc id, default set to id = 0\n"); 633 return 0; 634 } 635 636 static int find_crtc_node(const void *blob, int node) 637 { 638 int nodedepth = fdt_node_depth(blob, node); 639 640 if (nodedepth < 2) 641 return -EINVAL; 642 643 return fdt_supernode_atdepth_offset(blob, node, 644 nodedepth - 2, NULL); 645 } 646 647 static int find_connector_node(const void *blob, int node) 648 { 649 int phandle, remote; 650 int nodedepth; 651 652 phandle = fdt_getprop_u32_default_node(blob, node, 0, 653 "remote-endpoint", -1); 654 remote = fdt_node_offset_by_phandle(blob, phandle); 655 nodedepth = fdt_node_depth(blob, remote); 656 657 return fdt_supernode_atdepth_offset(blob, remote, 658 nodedepth - 3, NULL); 659 } 660 661 struct rockchip_logo_cache *find_or_alloc_logo_cache(const char *bmp) 662 { 663 struct rockchip_logo_cache *tmp, *logo_cache = NULL; 664 665 list_for_each_entry(tmp, &logo_cache_list, head) { 666 if (!strcmp(tmp->name, bmp)) { 667 logo_cache = tmp; 668 break; 669 } 670 } 671 672 if (!logo_cache) { 673 logo_cache = malloc(sizeof(*logo_cache)); 674 if (!logo_cache) { 675 printf("failed to alloc memory for logo cache\n"); 676 return NULL; 677 } 678 memset(logo_cache, 0, sizeof(*logo_cache)); 679 strcpy(logo_cache->name, bmp); 680 INIT_LIST_HEAD(&logo_cache->head); 681 list_add_tail(&logo_cache->head, &logo_cache_list); 682 } 683 684 return logo_cache; 685 } 686 687 static int load_bmp_logo(struct logo_info *logo, const char *bmp_name) 688 { 689 struct rockchip_logo_cache *logo_cache; 690 struct bmp_header *header; 691 void *dst = NULL, *pdst; 692 int size; 693 694 if (!logo || !bmp_name) 695 return -EINVAL; 696 logo_cache = find_or_alloc_logo_cache(bmp_name); 697 if (!logo_cache) 698 return -ENOMEM; 699 700 if (logo_cache->logo.mem) { 701 memcpy(logo, &logo_cache->logo, sizeof(*logo)); 702 return 0; 703 } 704 705 header = get_bmp_header(bmp_name); 706 if (!header) 707 return -EINVAL; 708 709 logo->bpp = get_unaligned_le16(&header->bit_count); 710 logo->width = get_unaligned_le32(&header->width); 711 logo->height = get_unaligned_le32(&header->height); 712 size = get_unaligned_le32(&header->file_size); 713 if (!can_direct_logo(logo->bpp)) { 714 if (size > MEMORY_POOL_SIZE) { 715 printf("failed to use boot buf as temp bmp buffer\n"); 716 return -ENOMEM; 717 } 718 pdst = (void *)gd->video_top; 719 720 } else { 721 pdst = get_display_buffer(size); 722 dst = pdst; 723 } 724 725 if (load_bmp_content(bmp_name, pdst, size)) { 726 printf("failed to load bmp %s\n", bmp_name); 727 return 0; 728 } 729 730 if (!can_direct_logo(logo->bpp)) { 731 int dst_size; 732 /* 733 * TODO: force use 16bpp if bpp less than 16; 734 */ 735 logo->bpp = (logo->bpp <= 16) ? 16 : logo->bpp; 736 dst_size = logo->width * logo->height * logo->bpp >> 3; 737 738 dst = get_display_buffer(dst_size); 739 if (!dst) 740 return -ENOMEM; 741 if (bmpdecoder(pdst, dst, logo->bpp)) { 742 printf("failed to decode bmp %s\n", bmp_name); 743 return 0; 744 } 745 logo->offset = 0; 746 logo->ymirror = 0; 747 } else { 748 logo->offset = get_unaligned_le32(&header->data_offset); 749 logo->ymirror = 1; 750 } 751 logo->mem = (u32)(unsigned long)dst; 752 753 memcpy(&logo_cache->logo, logo, sizeof(*logo)); 754 755 return 0; 756 } 757 758 void rockchip_show_fbbase(ulong fbbase) 759 { 760 struct display_state *s; 761 762 list_for_each_entry(s, &rockchip_display_list, head) { 763 s->logo.mode = ROCKCHIP_DISPLAY_FULLSCREEN; 764 s->logo.mem = fbbase; 765 s->logo.width = DRM_ROCKCHIP_FB_WIDTH; 766 s->logo.height = DRM_ROCKCHIP_FB_HEIGHT; 767 s->logo.bpp = 32; 768 s->logo.ymirror = 0; 769 770 display_logo(s); 771 } 772 } 773 774 void rockchip_show_bmp(const char *bmp) 775 { 776 struct display_state *s; 777 778 if (!bmp) { 779 list_for_each_entry(s, &rockchip_display_list, head) 780 display_disable(s); 781 return; 782 } 783 784 list_for_each_entry(s, &rockchip_display_list, head) { 785 s->logo.mode = s->charge_logo_mode; 786 if (load_bmp_logo(&s->logo, bmp)) 787 continue; 788 display_logo(s); 789 } 790 } 791 792 void rockchip_show_logo(void) 793 { 794 struct display_state *s; 795 796 list_for_each_entry(s, &rockchip_display_list, head) { 797 s->logo.mode = s->logo_mode; 798 if (load_bmp_logo(&s->logo, s->ulogo_name)) 799 printf("failed to display uboot logo\n"); 800 else 801 display_logo(s); 802 if (load_bmp_logo(&s->logo, s->klogo_name)) 803 printf("failed to display kernel logo\n"); 804 } 805 } 806 807 extern const struct rockchip_connector rk3399_mipi_dsi_data; 808 static int rockchip_display_probe(struct udevice *dev) 809 { 810 struct video_priv *uc_priv = dev_get_uclass_priv(dev); 811 struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); 812 const void *blob = gd->fdt_blob; 813 int route, child, phandle, connect, crtc_node, conn_node; 814 struct udevice *crtc_dev, *conn_dev; 815 const struct rockchip_crtc *crtc; 816 const struct rockchip_connector *conn; 817 struct display_state *s; 818 const char *name; 819 int ret; 820 821 /* Before relocation we don't need to do anything */ 822 if (!(gd->flags & GD_FLG_RELOC)) 823 return 0; 824 825 route = fdt_path_offset(blob, "/display-subsystem/route"); 826 if (route < 0) { 827 printf("Can't find display display route node\n"); 828 return -ENODEV; 829 } 830 831 if (!fdt_device_is_available(blob, route)) 832 return -ENODEV; 833 834 init_display_buffer(); 835 836 fdt_for_each_subnode(child, blob, route) { 837 if (!fdt_device_is_available(blob, child)) 838 continue; 839 840 phandle = fdt_getprop_u32_default_node(blob, child, 0, 841 "connect", -1); 842 if (phandle < 0) { 843 printf("Warn: %s: can't find connect node's handle\n", 844 fdt_get_name(blob, child, NULL)); 845 continue; 846 } 847 848 connect = fdt_node_offset_by_phandle(blob, phandle); 849 if (connect < 0) { 850 printf("Warn: %s: can't find connect node\n", 851 fdt_get_name(blob, child, NULL)); 852 continue; 853 } 854 855 crtc_node = find_crtc_node(blob, connect); 856 if (!fdt_device_is_available(blob, crtc_node)) { 857 printf("Warn: %s: crtc node is not available\n", 858 fdt_get_name(blob, child, NULL)); 859 continue; 860 } 861 ret = uclass_find_device_by_of_offset(UCLASS_VIDEO_CRTC, crtc_node, &crtc_dev); 862 if (ret) { 863 printf("Warn: %s: can't find crtc driver\n", 864 fdt_get_name(blob, child, NULL)); 865 continue; 866 } 867 868 crtc = (const struct rockchip_crtc *)dev_get_driver_data(crtc_dev); 869 870 conn_node = find_connector_node(blob, connect); 871 if (!fdt_device_is_available(blob, conn_node)) { 872 printf("Warn: %s: connector node is not available\n", 873 fdt_get_name(blob, child, NULL)); 874 continue; 875 } 876 ret = uclass_find_device_by_of_offset(UCLASS_DISPLAY, conn_node, &conn_dev); 877 if (ret) { 878 printf("Warn: %s: can't find connector driver\n", 879 fdt_get_name(blob, child, NULL)); 880 continue; 881 } 882 conn = (const struct rockchip_connector *)dev_get_driver_data(conn_dev); 883 884 s = malloc(sizeof(*s)); 885 if (!s) 886 goto err_free; 887 888 memset(s, 0, sizeof(*s)); 889 890 INIT_LIST_HEAD(&s->head); 891 s->klogo_name = fdt_stringlist_get(blob, child, "logo,kernel", 0, NULL); 892 name = fdt_stringlist_get(blob, child, "logo,mode", 0, NULL); 893 if (!strcmp(name, "fullscreen")) 894 s->logo_mode = ROCKCHIP_DISPLAY_FULLSCREEN; 895 else 896 s->logo_mode = ROCKCHIP_DISPLAY_CENTER; 897 name = fdt_stringlist_get(blob, child, "charge_logo,mode", 0, NULL); 898 if (!strcmp(name, "fullscreen")) 899 s->charge_logo_mode = ROCKCHIP_DISPLAY_FULLSCREEN; 900 else 901 s->charge_logo_mode = ROCKCHIP_DISPLAY_CENTER; 902 903 s->blob = blob; 904 s->conn_state.node = conn_node; 905 s->conn_state.dev = conn_dev; 906 s->conn_state.connector = conn; 907 s->crtc_state.node = crtc_node; 908 s->crtc_state.dev = crtc_dev; 909 s->crtc_state.crtc = crtc; 910 s->crtc_state.crtc_id = get_crtc_id(blob, connect); 911 s->node = child; 912 913 connector_phy_init(s); 914 connector_panel_init(s); 915 list_add_tail(&s->head, &rockchip_display_list); 916 } 917 918 uc_priv->xsize = DRM_ROCKCHIP_FB_WIDTH; 919 uc_priv->ysize = DRM_ROCKCHIP_FB_HEIGHT; 920 uc_priv->bpix = VIDEO_BPP32; 921 922 rockchip_show_fbbase(plat->base); 923 video_set_flush_dcache(dev, true); 924 925 return 0; 926 927 err_free: 928 list_for_each_entry(s, &rockchip_display_list, head) { 929 list_del(&s->head); 930 free(s); 931 } 932 return -ENODEV; 933 } 934 #if 0 935 void rockchip_display_fixup(void *blob) 936 { 937 const struct rockchip_connector_funcs *conn_funcs; 938 const struct rockchip_crtc_funcs *crtc_funcs; 939 const struct rockchip_connector *conn; 940 const struct rockchip_crtc *crtc; 941 struct display_state *s; 942 u32 offset; 943 int node; 944 char path[100]; 945 int ret; 946 947 if (!get_display_size()) 948 return; 949 950 node = fdt_update_reserved_memory(blob, "rockchip,drm-logo", 951 (u64)memory_start, 952 (u64)get_display_size()); 953 if (node < 0) { 954 printf("failed to add drm-loader-logo memory\n"); 955 return; 956 } 957 958 list_for_each_entry(s, &rockchip_display_list, head) { 959 conn = s->conn_state.connector; 960 if (!conn) 961 continue; 962 conn_funcs = conn->funcs; 963 if (!conn_funcs) { 964 printf("failed to get exist connector\n"); 965 continue; 966 } 967 968 crtc = s->crtc_state.crtc; 969 if (!crtc) 970 continue; 971 972 crtc_funcs = crtc->funcs; 973 if (!crtc_funcs) { 974 printf("failed to get exist crtc\n"); 975 continue; 976 } 977 978 if (crtc_funcs->fixup_dts) 979 crtc_funcs->fixup_dts(s, blob); 980 981 if (conn_funcs->fixup_dts) 982 conn_funcs->fixup_dts(s, blob); 983 984 ret = fdt_get_path(s->blob, s->node, path, sizeof(path)); 985 if (ret < 0) { 986 printf("failed to get route path[%s], ret=%d\n", 987 path, ret); 988 continue; 989 } 990 991 #define FDT_SET_U32(name, val) \ 992 do_fixup_by_path_u32(blob, path, name, val, 1); 993 994 offset = s->logo.offset + s->logo.mem - memory_start; 995 FDT_SET_U32("logo,offset", offset); 996 FDT_SET_U32("logo,width", s->logo.width); 997 FDT_SET_U32("logo,height", s->logo.height); 998 FDT_SET_U32("logo,bpp", s->logo.bpp); 999 FDT_SET_U32("logo,ymirror", s->logo.ymirror); 1000 FDT_SET_U32("video,hdisplay", s->conn_state.mode.hdisplay); 1001 FDT_SET_U32("video,vdisplay", s->conn_state.mode.vdisplay); 1002 FDT_SET_U32("video,vrefresh", 1003 drm_mode_vrefresh(&s->conn_state.mode)); 1004 #undef FDT_SET_U32 1005 } 1006 } 1007 #endif 1008 1009 int rockchip_display_bind(struct udevice *dev) 1010 { 1011 struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); 1012 1013 plat->size = 4 * DRM_ROCKCHIP_FB_WIDTH * DRM_ROCKCHIP_FB_HEIGHT; 1014 1015 return 0; 1016 } 1017 1018 static const struct udevice_id rockchip_display_ids[] = { 1019 { .compatible = "rockchip,display-subsystem" }, 1020 { } 1021 }; 1022 1023 U_BOOT_DRIVER(rockchip_display) = { 1024 .name = "rockchip_display", 1025 .id = UCLASS_VIDEO, 1026 .of_match = rockchip_display_ids, 1027 .bind = rockchip_display_bind, 1028 .probe = rockchip_display_probe, 1029 }; 1030