1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (c) 2017 FriendlyARM (www.arm9.net) 4 */ 5 6#include <config.h> 7#include <common.h> 8#include <errno.h> 9#include <fdtdec.h> 10#include <fdt_support.h> 11#include <asm/io.h> 12 13#include <asm/arch/nexell.h> 14#include <asm/arch/display.h> 15#include <asm/arch/nx_gpio.h> 16 17#include "nxp-fb.h" 18 19/* 20 * param @module_index for nx_gpio APIs and will be removed 21 * after support pinctrl 22 */ 23#ifndef PAD_GPIO_A 24#define PAD_GPIO_A 0 25#endif 26 27static inline void common_gpio_init(void) 28{ 29 /* PVCLK */ 30 nx_gpio_set_fast_slew(PAD_GPIO_A, 0, 1); 31} 32 33static void s70_gpio_init(void) 34{ 35 int i; 36 37 /* PVCLK */ 38 nx_gpio_set_drive_strength(PAD_GPIO_A, 0, 1); 39 40 /* RGB24 */ 41 for (i = 1; i < 25; i++) 42 nx_gpio_set_drive_strength(PAD_GPIO_A, i, 2); 43 44 /* HS/VS/DE */ 45 for (; i < 28; i++) 46 nx_gpio_set_drive_strength(PAD_GPIO_A, i, 1); 47} 48 49static void s702_gpio_init(void) 50{ 51 int i; 52 53 common_gpio_init(); 54 55 nx_gpio_set_drive_strength(PAD_GPIO_A, 0, 2); 56 57 for (i = 1; i < 25; i++) 58 nx_gpio_set_drive_strength(PAD_GPIO_A, i, 0); 59 60 for (; i < 28; i++) 61 nx_gpio_set_drive_strength(PAD_GPIO_A, i, 1); 62} 63 64static void s430_gpio_init(void) 65{ 66 int i; 67 68 for (i = 0; i < 28; i++) 69 nx_gpio_set_drive_strength(PAD_GPIO_A, i, 1); 70} 71 72static void hd101_gpio_init(void) 73{ 74 int i; 75 76 common_gpio_init(); 77 78 nx_gpio_set_drive_strength(PAD_GPIO_A, 0, 2); 79 80 for (i = 1; i < 25; i++) 81 nx_gpio_set_drive_strength(PAD_GPIO_A, i, 1); 82 83 nx_gpio_set_drive_strength(PAD_GPIO_A, 27, 1); 84} 85 86static void hd700_gpio_init(void) 87{ 88 hd101_gpio_init(); 89} 90 91/* NXP display configs for supported LCD */ 92 93static struct nxp_lcd wxga_hd700 = { 94 .width = 800, 95 .height = 1280, 96 .p_width = 94, 97 .p_height = 151, 98 .bpp = 24, 99 .freq = 60, 100 101 .timing = { 102 .h_fp = 20, 103 .h_bp = 20, 104 .h_sw = 24, 105 .v_fp = 4, 106 .v_fpe = 1, 107 .v_bp = 4, 108 .v_bpe = 1, 109 .v_sw = 8, 110 }, 111 .polarity = { 112 .rise_vclk = 0, 113 .inv_hsync = 0, 114 .inv_vsync = 0, 115 .inv_vden = 0, 116 }, 117 .gpio_init = hd700_gpio_init, 118}; 119 120static struct nxp_lcd wvga_s70 = { 121 .width = 800, 122 .height = 480, 123 .p_width = 155, 124 .p_height = 93, 125 .bpp = 24, 126 .freq = 61, 127 128 .timing = { 129 .h_fp = 48, 130 .h_bp = 36, 131 .h_sw = 10, 132 .v_fp = 22, 133 .v_fpe = 1, 134 .v_bp = 15, 135 .v_bpe = 1, 136 .v_sw = 8, 137 }, 138 .polarity = { 139 .rise_vclk = 0, 140 .inv_hsync = 1, 141 .inv_vsync = 1, 142 .inv_vden = 0, 143 }, 144 .gpio_init = s70_gpio_init, 145}; 146 147static struct nxp_lcd wvga_s702 = { 148 .width = 800, 149 .height = 480, 150 .p_width = 155, 151 .p_height = 93, 152 .bpp = 24, 153 .freq = 61, 154 155 .timing = { 156 .h_fp = 44, 157 .h_bp = 26, 158 .h_sw = 20, 159 .v_fp = 22, 160 .v_fpe = 1, 161 .v_bp = 15, 162 .v_bpe = 1, 163 .v_sw = 8, 164 }, 165 .polarity = { 166 .rise_vclk = 1, 167 .inv_hsync = 1, 168 .inv_vsync = 1, 169 .inv_vden = 0, 170 }, 171 .gpio_init = s702_gpio_init, 172}; 173 174static struct nxp_lcd wvga_s70d = { 175 .width = 800, 176 .height = 480, 177 .p_width = 155, 178 .p_height = 93, 179 .bpp = 24, 180 .freq = 61, 181 182 .timing = { 183 .h_fp = 80, 184 .h_bp = 78, 185 .h_sw = 10, 186 .v_fp = 22, 187 .v_fpe = 1, 188 .v_bp = 24, 189 .v_bpe = 1, 190 .v_sw = 8, 191 }, 192 .polarity = { 193 .rise_vclk = 0, 194 .inv_hsync = 1, 195 .inv_vsync = 1, 196 .inv_vden = 0, 197 }, 198 .gpio_init = s702_gpio_init, 199}; 200 201static struct nxp_lcd wvga_w50 = { 202 .width = 800, 203 .height = 480, 204 .p_width = 108, 205 .p_height = 64, 206 .bpp = 24, 207 .freq = 61, 208 209 .timing = { 210 .h_fp = 40, 211 .h_bp = 40, 212 .h_sw = 48, 213 .v_fp = 20, 214 .v_fpe = 1, 215 .v_bp = 20, 216 .v_bpe = 1, 217 .v_sw = 12, 218 }, 219 .polarity = { 220 .rise_vclk = 0, 221 .inv_hsync = 1, 222 .inv_vsync = 1, 223 .inv_vden = 0, 224 }, 225 .gpio_init = s70_gpio_init, 226}; 227 228static struct nxp_lcd wvga_s430 = { 229 .width = 480, 230 .height = 800, 231 .p_width = 108, 232 .p_height = 64, 233 .bpp = 24, 234 .freq = 60, 235 236 .timing = { 237 .h_fp = 64, 238 .h_bp = 0, 239 .h_sw = 16, 240 .v_fp = 32, 241 .v_fpe = 1, 242 .v_bp = 0, 243 .v_bpe = 1, 244 .v_sw = 16, 245 }, 246 .polarity = { 247 .rise_vclk = 1, 248 .inv_hsync = 1, 249 .inv_vsync = 1, 250 .inv_vden = 0, 251 }, 252 .gpio_init = s430_gpio_init, 253}; 254 255static struct nxp_lcd wsvga_w101 = { 256 .width = 1024, 257 .height = 600, 258 .p_width = 204, 259 .p_height = 120, 260 .bpp = 24, 261 .freq = 60, 262 263 .timing = { 264 .h_fp = 40, 265 .h_bp = 40, 266 .h_sw = 200, 267 .v_fp = 8, 268 .v_fpe = 1, 269 .v_bp = 8, 270 .v_bpe = 1, 271 .v_sw = 16, 272 }, 273 .polarity = { 274 .rise_vclk = 1, 275 .inv_hsync = 1, 276 .inv_vsync = 1, 277 .inv_vden = 0, 278 }, 279}; 280 281static struct nxp_lcd wsvga_x710 = { 282 .width = 1024, 283 .height = 600, 284 .p_width = 154, 285 .p_height = 90, 286 .bpp = 24, 287 .freq = 61, 288 289 .timing = { 290 .h_fp = 84, 291 .h_bp = 84, 292 .h_sw = 88, 293 .v_fp = 10, 294 .v_fpe = 1, 295 .v_bp = 10, 296 .v_bpe = 1, 297 .v_sw = 20, 298 }, 299 .polarity = { 300 .rise_vclk = 0, 301 .inv_hsync = 1, 302 .inv_vsync = 1, 303 .inv_vden = 0, 304 }, 305 .gpio_init = hd101_gpio_init, 306}; 307 308static struct nxp_lcd xga_a97 = { 309 .width = 1024, 310 .height = 768, 311 .p_width = 200, 312 .p_height = 150, 313 .bpp = 24, 314 .freq = 61, 315 316 .timing = { 317 .h_fp = 12, 318 .h_bp = 12, 319 .h_sw = 4, 320 .v_fp = 8, 321 .v_fpe = 1, 322 .v_bp = 8, 323 .v_bpe = 1, 324 .v_sw = 4, 325 }, 326 .polarity = { 327 .rise_vclk = 0, 328 .inv_hsync = 1, 329 .inv_vsync = 1, 330 .inv_vden = 0, 331 }, 332}; 333 334static struct nxp_lcd xga_lq150 = { 335 .width = 1024, 336 .height = 768, 337 .p_width = 304, 338 .p_height = 228, 339 .bpp = 24, 340 .freq = 60, 341 342 .timing = { 343 .h_fp = 12, 344 .h_bp = 12, 345 .h_sw = 40, 346 .v_fp = 8, 347 .v_fpe = 1, 348 .v_bp = 8, 349 .v_bpe = 1, 350 .v_sw = 40, 351 }, 352 .polarity = { 353 .rise_vclk = 0, 354 .inv_hsync = 1, 355 .inv_vsync = 1, 356 .inv_vden = 0, 357 }, 358}; 359 360static struct nxp_lcd vga_l80 = { 361 .width = 640, 362 .height = 480, 363 .p_width = 160, 364 .p_height = 120, 365 .bpp = 32, 366 .freq = 60, 367 368 .timing = { 369 .h_fp = 35, 370 .h_bp = 53, 371 .h_sw = 73, 372 .v_fp = 3, 373 .v_fpe = 1, 374 .v_bp = 29, 375 .v_bpe = 1, 376 .v_sw = 6, 377 }, 378 .polarity = { 379 .rise_vclk = 0, 380 .inv_hsync = 1, 381 .inv_vsync = 1, 382 .inv_vden = 0, 383 }, 384}; 385 386static struct nxp_lcd wxga_bp101 = { 387 .width = 1280, 388 .height = 800, 389 .p_width = 218, 390 .p_height = 136, 391 .bpp = 24, 392 .freq = 60, 393 394 .timing = { 395 .h_fp = 20, 396 .h_bp = 20, 397 .h_sw = 24, 398 .v_fp = 4, 399 .v_fpe = 1, 400 .v_bp = 4, 401 .v_bpe = 1, 402 .v_sw = 8, 403 }, 404 .polarity = { 405 .rise_vclk = 1, 406 .inv_hsync = 1, 407 .inv_vsync = 1, 408 .inv_vden = 0, 409 }, 410}; 411 412static struct nxp_lcd wxga_hd101 = { 413 .width = 1280, 414 .height = 800, 415 .p_width = 218, 416 .p_height = 136, 417 .bpp = 24, 418 .freq = 60, 419 420 .timing = { 421 .h_fp = 16, 422 .h_bp = 16, 423 .h_sw = 30, 424 .v_fp = 8, 425 .v_fpe = 1, 426 .v_bp = 8, 427 .v_bpe = 1, 428 .v_sw = 12, 429 }, 430 .polarity = { 431 .rise_vclk = 1, 432 .inv_hsync = 0, 433 .inv_vsync = 0, 434 .inv_vden = 0, 435 }, 436 .gpio_init = hd101_gpio_init, 437}; 438 439static struct nxp_lcd hvga_h43 = { 440 .width = 480, 441 .height = 272, 442 .p_width = 96, 443 .p_height = 54, 444 .bpp = 32, 445 .freq = 65, 446 447 .timing = { 448 .h_fp = 5, 449 .h_bp = 40, 450 .h_sw = 2, 451 .v_fp = 8, 452 .v_fpe = 1, 453 .v_bp = 8, 454 .v_bpe = 1, 455 .v_sw = 2, 456 }, 457 .polarity = { 458 .rise_vclk = 0, 459 .inv_hsync = 1, 460 .inv_vsync = 1, 461 .inv_vden = 0, 462 }, 463}; 464 465static struct nxp_lcd hvga_p43 = { 466 .width = 480, 467 .height = 272, 468 .p_width = 96, 469 .p_height = 54, 470 .bpp = 32, 471 .freq = 65, 472 473 .timing = { 474 .h_fp = 5, 475 .h_bp = 40, 476 .h_sw = 2, 477 .v_fp = 8, 478 .v_fpe = 1, 479 .v_bp = 9, 480 .v_bpe = 1, 481 .v_sw = 2, 482 }, 483 .polarity = { 484 .rise_vclk = 1, 485 .inv_hsync = 1, 486 .inv_vsync = 1, 487 .inv_vden = 0, 488 }, 489}; 490 491static struct nxp_lcd qvga_w35 = { 492 .width = 320, 493 .height = 240, 494 .p_width = 70, 495 .p_height = 52, 496 .bpp = 16, 497 .freq = 65, 498 499 .timing = { 500 .h_fp = 4, 501 .h_bp = 70, 502 .h_sw = 4, 503 .v_fp = 4, 504 .v_fpe = 1, 505 .v_bp = 12, 506 .v_bpe = 1, 507 .v_sw = 4, 508 }, 509 .polarity = { 510 .rise_vclk = 1, 511 .inv_hsync = 0, 512 .inv_vsync = 0, 513 .inv_vden = 0, 514 }, 515}; 516 517/* HDMI */ 518static struct nxp_lcd hdmi_def = { 519 .width = 1920, 520 .height = 1080, 521 .p_width = 480, 522 .p_height = 320, 523 .bpp = 24, 524 .freq = 60, 525 526 .timing = { 527 .h_fp = 12, 528 .h_bp = 12, 529 .h_sw = 4, 530 .v_fp = 8, 531 .v_fpe = 1, 532 .v_bp = 8, 533 .v_bpe = 1, 534 .v_sw = 4, 535 }, 536 .polarity = { 537 .rise_vclk = 0, 538 .inv_hsync = 1, 539 .inv_vsync = 1, 540 .inv_vden = 0, 541 }, 542}; 543 544static struct hdmi_config { 545 char *name; 546 int width; 547 int height; 548} bd_hdmi_config[] = { 549 { "HDMI1080P60", 1920, 1080 }, 550 { "HDMI1080I60", 1920, 1080 }, 551 { "HDMI1080P30", 1920, 1080 }, 552 { "HDMI1080P50", 1920, 1080 }, 553 { "HDMI1080I50", 1920, 1080 }, 554 555 { "HDMI1080P60D", 960, 536 }, 556 { "HDMI1080I60D", 960, 536 }, 557 { "HDMI1080P30D", 960, 536 }, 558 { "HDMI1080P50D", 960, 536 }, 559 { "HDMI1080I50D", 960, 536 }, 560 561 { "HDMI720P60", 1280, 720 }, 562 { "HDMI720P60D", 640, 360 }, 563 { "HDMI720P50", 1280, 720 }, 564 { "HDMI720P50D", 640, 360 }, 565 566 { "HDMI576P16X9", 720, 576 }, 567 { "HDMI576P16X9D", 720, 576 }, 568 { "HDMI576P4X3", 720, 576 }, 569 { "HDMI576P4X3D", 720, 576 }, 570 571 { "HDMI480P16X9", 720, 480 }, 572 { "HDMI480P16X9D", 720, 480 }, 573 { "HDMI480P4X3", 720, 480 }, 574 { "HDMI480P4X3D", 720, 480 }, 575}; 576 577/* Try to guess LCD panel by kernel command line, or 578 * using *HD101* as default 579 */ 580static struct { 581 int id; 582 char *name; 583 struct nxp_lcd *lcd; 584 int dpi; 585 int ctp; 586 enum lcd_format fmt; 587} bd_lcd_config[] = { 588 { 25, "HD101", &wxga_hd101, 0, 1, LCD_RGB }, 589 { 32, "HD101B", &wxga_hd101, 0, 1, LCD_RGB }, 590 { 18, "HD700", &wxga_hd700, 213, 1, LCD_RGB }, 591 { 30, "HD702", &wxga_hd700, 213, 1, LCD_RGB }, 592 { 33, "H70", &wxga_hd700, 213, 0, LCD_VESA }, 593 { 3, "S70", &wvga_s70, 128, 1, LCD_RGB }, 594 { 36, "S701", &wvga_s70, 128, 1, LCD_RGB }, 595 { 24, "S702", &wvga_s702, 128, 3, LCD_RGB }, 596 { 26, "S70D", &wvga_s70d, 128, 0, LCD_RGB }, 597 { 14, "H43", &hvga_h43, 0, 0, LCD_RGB }, 598 { 19, "P43", &hvga_p43, 0, 0, LCD_RGB }, 599 { 8, "W35", &qvga_w35, 0, 0, LCD_RGB }, 600 { 28, "X710", &wsvga_x710, 0, 1, LCD_RGB }, 601 { 31, "S430", &wvga_s430, 180, 1, LCD_RGB }, 602 { 4, "W50", &wvga_w50, 0, 0, LCD_RGB }, 603 604 /* TODO: Testing */ 605 { 15, "W101", &wsvga_w101, 0, 1, LCD_RGB }, 606 { 5, "L80", &vga_l80, 0, 1, LCD_RGB }, 607 { -1, "A97", &xga_a97, 0, 0, LCD_RGB }, 608 { -1, "LQ150", &xga_lq150, 0, 1, LCD_RGB }, 609 { -1, "BP101", &wxga_bp101, 0, 1, LCD_RGB }, 610 /* Pls keep it at last */ 611 { 128, "HDMI", &hdmi_def, 0, 0, LCD_HDMI }, 612}; 613 614static int lcd_idx; 615 616int bd_setup_lcd_by_id(int id) 617{ 618 int i; 619 620 for (i = 0; i < ARRAY_SIZE(bd_lcd_config); i++) { 621 if (bd_lcd_config[i].id == id) { 622 lcd_idx = i; 623 break; 624 } 625 } 626 627 if (i >= ARRAY_SIZE(bd_lcd_config)) { 628 /* NOT found */ 629 return -19; 630 } 631 632 return bd_lcd_config[i].id; 633} 634 635int bd_setup_lcd_by_name(char *str) 636{ 637 char *delim; 638 int i; 639 640 delim = strchr(str, ','); 641 if (delim) 642 *delim++ = '\0'; 643 644 if (!strncasecmp("HDMI", str, 4)) { 645 struct hdmi_config *cfg = &bd_hdmi_config[0]; 646 struct nxp_lcd *lcd; 647 648 lcd_idx = ARRAY_SIZE(bd_lcd_config) - 1; 649 lcd = bd_lcd_config[lcd_idx].lcd; 650 651 for (i = 0; i < ARRAY_SIZE(bd_hdmi_config); i++, cfg++) { 652 if (!strcasecmp(cfg->name, str)) { 653 lcd->width = cfg->width; 654 lcd->height = cfg->height; 655 bd_lcd_config[lcd_idx].name = cfg->name; 656 goto __ret; 657 } 658 } 659 } 660 661 for (i = 0; i < ARRAY_SIZE(bd_lcd_config); i++) { 662 if (!strcasecmp(bd_lcd_config[i].name, str)) { 663 lcd_idx = i; 664 break; 665 } 666 } 667 668__ret: 669 return 0; 670} 671 672struct nxp_lcd *bd_get_lcd(void) 673{ 674 return bd_lcd_config[lcd_idx].lcd; 675} 676 677const char *bd_get_lcd_name(void) 678{ 679 return bd_lcd_config[lcd_idx].name; 680} 681 682enum lcd_format bd_get_lcd_format(void) 683{ 684 return bd_lcd_config[lcd_idx].fmt; 685} 686 687int bd_get_lcd_density(void) 688{ 689 return bd_lcd_config[lcd_idx].dpi; 690} 691 692#if CONFIG_IS_ENABLED(OF_CONTROL) 693int bd_fixup_lcd_fdt(void *blob, struct nxp_lcd *lcd) 694{ 695 return 0; 696} 697#endif 698