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