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