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