uboot/board/friendlyarm/nanopi2/board.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) Guangzhou FriendlyARM Computer Tech. Co., Ltd.
   4 * (http://www.friendlyarm.com)
   5 */
   6
   7#include <config.h>
   8#include <common.h>
   9#include <command.h>
  10#include <fdt_support.h>
  11#include <log.h>
  12#ifdef CONFIG_PWM_NX
  13#include <pwm.h>
  14#endif
  15#include <asm/global_data.h>
  16#include <asm/io.h>
  17
  18#include <asm/arch/nexell.h>
  19#include <asm/arch/nx_gpio.h>
  20#include <asm/arch/display.h>
  21#include <asm/arch/display_dev.h>
  22
  23#include <u-boot/md5.h>
  24
  25#include <linux/stringify.h>
  26
  27#include "hwrev.h"
  28#include "onewire.h"
  29#include "nxp-fb.h"
  30
  31#include <env_internal.h>       /* for env_save() */
  32#include <asm/mach-types.h>
  33
  34DECLARE_GLOBAL_DATA_PTR;
  35
  36enum gpio_group {
  37        gpio_a, gpio_b, gpio_c, gpio_d, gpio_e,
  38};
  39
  40#ifdef CONFIG_PWM_NX
  41struct pwm_device {
  42        int grp;
  43        int bit;
  44        int io_fn;
  45};
  46
  47static inline void bd_pwm_config_gpio(int ch)
  48{
  49        struct pwm_device pwm_dev[] = {
  50                [0] = { .grp = gpio_d, .bit = 1,  .io_fn = 0 },
  51                [1] = { .grp = gpio_c, .bit = 13, .io_fn = 1 },
  52                [2] = { .grp = gpio_c, .bit = 14, .io_fn = 1 },
  53                [3] = { .grp = gpio_d, .bit = 0,  .io_fn = 0 },
  54        };
  55
  56        int gp = pwm_dev[ch].grp;
  57        int io = pwm_dev[ch].bit;
  58
  59        /* pwm backlight OFF: HIGH, ON: LOW */
  60        nx_gpio_set_pad_function(gp, io, pwm_dev[ch].io_fn);
  61        nx_gpio_set_output_value(gp, io, 1);
  62        nx_gpio_set_output_enable(gp, io, 1);
  63}
  64#endif
  65
  66static void bd_backlight_off(void)
  67{
  68#ifdef CONFIG_S5P4418_ONEWIRE
  69        onewire_set_backlight(0);
  70
  71#elif defined(BACKLIGHT_CH)
  72        bd_pwm_config_gpio(BACKLIGHT_CH);
  73#endif
  74}
  75
  76static void bd_backlight_on(void)
  77{
  78#ifdef CONFIG_S5P4418_ONEWIRE
  79        onewire_set_backlight(127);
  80
  81#elif defined(BACKLIGHT_CH)
  82        /* pwm backlight ON: HIGH, ON: LOW */
  83        pwm_init(BACKLIGHT_CH,
  84                 BACKLIGHT_DIV, BACKLIGHT_INV);
  85        pwm_config(BACKLIGHT_CH,
  86                   TO_DUTY_NS(BACKLIGHT_DUTY, BACKLIGHT_HZ),
  87                   TO_PERIOD_NS(BACKLIGHT_HZ));
  88#endif
  89}
  90
  91static void bd_lcd_config_gpio(void)
  92{
  93        int i;
  94
  95        for (i = 0; i < 28; i++) {
  96                nx_gpio_set_pad_function(gpio_a, i, 1);
  97                nx_gpio_set_drive_strength(gpio_a, i, 0);
  98                nx_gpio_set_pull_mode(gpio_a, i, 2);
  99        }
 100
 101        nx_gpio_set_drive_strength(gpio_a, 0, 1);
 102}
 103
 104/* DEFAULT mmc dev for eMMC boot (dwmmc.2) */
 105static int mmc_boot_dev;
 106
 107int board_mmc_bootdev(void)
 108{
 109        return mmc_boot_dev;
 110}
 111
 112/* call from common/env_mmc.c */
 113int mmc_get_env_dev(void)
 114{
 115        return mmc_boot_dev;
 116}
 117
 118#ifdef CONFIG_DISPLAY_BOARDINFO
 119int checkboard(void)
 120{
 121        printf("Board: %s\n", get_board_name());
 122
 123        return 0;
 124}
 125#endif
 126
 127int nx_display_fixup_dp(struct nx_display_dev *dp)
 128{
 129        struct nxp_lcd *lcd = bd_get_lcd();
 130        enum lcd_format fmt = bd_get_lcd_format();
 131        struct nxp_lcd_timing *timing = &lcd->timing;
 132        struct dp_sync_info *sync = &dp->sync;
 133        struct dp_plane_info *plane = &dp->planes[0];
 134        int i;
 135        u32 clk = 800000000;
 136        u32 div;
 137
 138        sync->h_active_len = lcd->width;
 139        sync->h_sync_width = timing->h_sw;
 140        sync->h_back_porch = timing->h_bp;
 141        sync->h_front_porch = timing->h_fp;
 142        sync->h_sync_invert = !lcd->polarity.inv_hsync;
 143
 144        sync->v_active_len = lcd->height;
 145        sync->v_sync_width = timing->v_sw;
 146        sync->v_back_porch = timing->v_bp;
 147        sync->v_front_porch = timing->v_fp;
 148        sync->v_sync_invert = !lcd->polarity.inv_vsync;
 149
 150        /* calculates pixel clock */
 151        div  = timing->h_sw + timing->h_bp + timing->h_fp + lcd->width;
 152        div *= timing->v_sw + timing->v_bp + timing->v_fp + lcd->height;
 153        div *= lcd->freq ? : 60;
 154        clk /= div;
 155
 156        dp->ctrl.clk_div_lv0 = clk;
 157        dp->ctrl.clk_inv_lv0 = lcd->polarity.rise_vclk;
 158
 159        dp->top.screen_width = lcd->width;
 160        dp->top.screen_height = lcd->height;
 161
 162        for (i = 0; i < dp->top.plane_num; i++, plane++) {
 163                if (plane->enable) {
 164                        plane->width = lcd->width;
 165                        plane->height = lcd->height;
 166                }
 167        }
 168
 169        /* initialize display device type */
 170        if (fmt == LCD_RGB) {
 171                dp->dev_type = DP_DEVICE_RGBLCD;
 172
 173        } else if (fmt == LCD_HDMI) {
 174                struct dp_hdmi_dev *dev = (struct dp_hdmi_dev *)dp->device;
 175
 176                dp->dev_type = DP_DEVICE_HDMI;
 177                if (lcd->width == 1920 && lcd->height == 1080)
 178                        dev->preset = 1;
 179                else
 180                        dev->preset = 0;
 181
 182        } else {
 183                struct dp_lvds_dev *dev = (struct dp_lvds_dev *)dp->device;
 184
 185                dp->dev_type = DP_DEVICE_LVDS;
 186                dev->lvds_format = (fmt & 0x3);
 187        }
 188
 189        return 0;
 190}
 191
 192/* --------------------------------------------------------------------------
 193 * initialize board status.
 194 */
 195
 196#define MMC_BOOT_CH0            (0)
 197#define MMC_BOOT_CH1            (1 <<  3)
 198#define MMC_BOOT_CH2            (1 << 19)
 199
 200static void bd_bootdev_init(void)
 201{
 202        unsigned int rst = readl(PHY_BASEADDR_CLKPWR + SYSRSTCONFIG);
 203
 204        rst &= (1 << 19) | (1 << 3);
 205        if (rst == MMC_BOOT_CH0) {
 206                /* mmc dev 1 for SD boot */
 207                mmc_boot_dev = 1;
 208        }
 209}
 210
 211#ifdef CONFIG_S5P4418_ONEWIRE
 212static void bd_onewire_init(void)
 213{
 214        unsigned char lcd;
 215        unsigned short fw_ver;
 216
 217        onewire_init();
 218        onewire_get_info(&lcd, &fw_ver);
 219}
 220#endif
 221
 222static void bd_lcd_init(void)
 223{
 224        struct nxp_lcd *cfg;
 225        int id = -1;
 226        int ret;
 227
 228#ifdef CONFIG_S5P4418_ONEWIRE
 229        id = onewire_get_lcd_id();
 230        /* -1: onwire probe failed
 231         *  0: bad
 232         * >0: identified
 233         */
 234#endif
 235        ret = bd_setup_lcd_by_id(id);
 236        if (id <= 0 || ret != id) {
 237                printf("Panel: N/A (%d)\n", id);
 238                bd_setup_lcd_by_name("HDMI720P60");
 239
 240        } else {
 241                printf("Panel: %s\n", bd_get_lcd_name());
 242
 243                cfg = bd_get_lcd();
 244                if (cfg->gpio_init)
 245                        cfg->gpio_init();
 246        }
 247}
 248
 249static int mac_read_from_generic_eeprom(u8 *addr)
 250{
 251        return -1;
 252}
 253
 254static void make_ether_addr(u8 *addr)
 255{
 256        u32 hash[20];
 257
 258#define ETHER_MAC_TAG  "ethmac"
 259        memset(hash, 0, sizeof(hash));
 260        memcpy(hash + 12, ETHER_MAC_TAG, sizeof(ETHER_MAC_TAG));
 261
 262        hash[4] = readl(PHY_BASEADDR_ECID + 0x00);
 263        hash[5] = readl(PHY_BASEADDR_ECID + 0x04);
 264        hash[6] = readl(PHY_BASEADDR_ECID + 0x08);
 265        hash[7] = readl(PHY_BASEADDR_ECID + 0x0c);
 266
 267        md5((unsigned char *)&hash[4], 64, (unsigned char *)hash);
 268
 269        hash[0] ^= hash[2];
 270        hash[1] ^= hash[3];
 271
 272        memcpy(addr, (char *)hash, 6);
 273        addr[0] &= 0xfe;        /* clear multicast bit */
 274        addr[0] |= 0x02;
 275}
 276
 277static void set_ether_addr(void)
 278{
 279        unsigned char mac[6];
 280        char ethaddr[20];
 281        int ret;
 282
 283        if (env_get("ethaddr"))
 284                return;
 285
 286        ret = mac_read_from_generic_eeprom(mac);
 287        if (ret < 0)
 288                make_ether_addr(mac);
 289
 290        sprintf(ethaddr, "%02x:%02x:%02x:%02x:%02x:%02x",
 291                mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
 292        if (!ret)
 293                printf("MAC:  [%s]\n", ethaddr);
 294
 295        env_set("ethaddr", ethaddr);
 296}
 297
 298#ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
 299static void set_board_rev(void)
 300{
 301        char info[64] = {0, };
 302
 303        snprintf(info, ARRAY_SIZE(info), "%02x", get_board_revision());
 304        env_set("board_rev", info);
 305}
 306#endif
 307
 308static void set_dtb_name(void)
 309{
 310        char info[64] = {0, };
 311
 312        snprintf(info, ARRAY_SIZE(info),
 313                 "s5p4418-nanopi2-rev%02x.dtb", get_board_revision());
 314        env_set("dtb_name", info);
 315}
 316
 317static void bd_update_env(void)
 318{
 319        char *lcdtype = env_get("lcdtype");
 320        char *lcddpi = env_get("lcddpi");
 321        char *bootargs = env_get("bootargs");
 322        const char *name;
 323        char *p = NULL;
 324        int rootdev = board_mmc_bootdev();
 325        int need_save = 0;
 326
 327#define CMDLINE_LCD             " lcd="
 328        char cmdline[CONFIG_SYS_CBSIZE];
 329        int n = 1;
 330
 331        if (rootdev != CONFIG_ROOT_DEV && !env_get("firstboot")) {
 332                env_set_ulong("rootdev", rootdev);
 333                env_set("firstboot", "0");
 334                need_save = 1;
 335        }
 336
 337        if (lcdtype) {
 338                /* Setup again as user specified LCD in env */
 339                bd_setup_lcd_by_name(lcdtype);
 340        }
 341
 342        name = bd_get_lcd_name();
 343
 344        if (bootargs)
 345                n = strlen(bootargs);   /* isn't 0 for NULL */
 346        else
 347                cmdline[0] = '\0';
 348
 349        if ((n + strlen(name) + sizeof(CMDLINE_LCD)) > sizeof(cmdline)) {
 350                printf("Error: `bootargs' is too large (%d)\n", n);
 351                goto __exit;
 352        }
 353
 354        if (bootargs) {
 355                p = strstr(bootargs, CMDLINE_LCD);
 356                if (p) {
 357                        n = (p - bootargs);
 358                        p += strlen(CMDLINE_LCD);
 359                }
 360                strncpy(cmdline, bootargs, n);
 361        }
 362
 363        /* add `lcd=NAME,NUMdpi' */
 364        strncpy(cmdline + n, CMDLINE_LCD, strlen(CMDLINE_LCD));
 365        n += strlen(CMDLINE_LCD);
 366
 367        strcpy(cmdline + n, name);
 368        n += strlen(name);
 369
 370        if (lcddpi) {
 371                n += sprintf(cmdline + n, ",%sdpi", lcddpi);
 372        } else {
 373                int dpi = bd_get_lcd_density();
 374
 375                if (dpi > 0 && dpi < 600)
 376                        n += sprintf(cmdline + n, ",%ddpi", dpi);
 377        }
 378
 379        /* copy remaining of bootargs */
 380        if (p) {
 381                p = strstr(p, " ");
 382                if (p) {
 383                        strcpy(cmdline + n, p);
 384                        n += strlen(p);
 385                }
 386        }
 387
 388        /* append `bootdev=2' */
 389#define CMDLINE_BDEV    " bootdev="
 390        if (rootdev > 0 && !strstr(cmdline, CMDLINE_BDEV))
 391                n += sprintf(cmdline + n, "%s2", CMDLINE_BDEV);
 392
 393        /* finally, let's update uboot env & save it */
 394        if (bootargs && strncmp(cmdline, bootargs, sizeof(cmdline))) {
 395                env_set("bootargs", cmdline);
 396                need_save = 1;
 397        }
 398
 399__exit:
 400        if (need_save)
 401                env_save();
 402}
 403
 404/* --------------------------------------------------------------------------
 405 * call from u-boot
 406 */
 407
 408int board_early_init_f(void)
 409{
 410        return 0;
 411}
 412
 413int board_init(void)
 414{
 415        bd_hwrev_init();
 416        bd_base_rev_init();
 417
 418        bd_bootdev_init();
 419#ifdef CONFIG_S5P4418_ONEWIRE
 420        bd_onewire_init();
 421#endif
 422
 423        bd_backlight_off();
 424
 425        bd_lcd_config_gpio();
 426        bd_lcd_init();
 427
 428        if (IS_ENABLED(CONFIG_SILENT_CONSOLE))
 429                gd->flags |= GD_FLG_SILENT;
 430
 431        return 0;
 432}
 433
 434#ifdef CONFIG_BOARD_LATE_INIT
 435int board_late_init(void)
 436{
 437        bd_update_env();
 438
 439#ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
 440        set_board_rev();
 441#endif
 442        set_dtb_name();
 443
 444        set_ether_addr();
 445
 446        if (IS_ENABLED(CONFIG_SILENT_CONSOLE))
 447                gd->flags &= ~GD_FLG_SILENT;
 448
 449        bd_backlight_on();
 450        printf("\n");
 451
 452        return 0;
 453}
 454#endif
 455
 456#ifdef CONFIG_SPLASH_SOURCE
 457#include <splash.h>
 458static struct splash_location splash_locations[] = {
 459        {
 460        .name = "mmc_fs",
 461        .storage = SPLASH_STORAGE_MMC,
 462        .flags = SPLASH_STORAGE_FS,
 463        .devpart = __stringify(CONFIG_ROOT_DEV) ":"
 464                   __stringify(CONFIG_BOOT_PART),
 465        },
 466};
 467
 468int splash_screen_prepare(void)
 469{
 470        int err;
 471        char *env_cmd = env_get("load_splash");
 472
 473        debug("%s()\n", __func__);
 474
 475        if (env_cmd) {
 476                err = run_command(env_cmd, 0);
 477
 478        } else {
 479                char devpart[64] = { 0, };
 480                int bootpart = env_get_ulong("bootpart", 0, CONFIG_BOOT_PART);
 481                int rootdev;
 482
 483                if (env_get("firstboot"))
 484                        rootdev = env_get_ulong("rootdev", 0, CONFIG_ROOT_DEV);
 485                else
 486                        rootdev = board_mmc_bootdev();
 487
 488                snprintf(devpart, ARRAY_SIZE(devpart), "%d:%d", rootdev,
 489                         bootpart);
 490                splash_locations[0].devpart = devpart;
 491
 492                err = splash_source_load(splash_locations,
 493                                         ARRAY_SIZE(splash_locations));
 494        }
 495
 496        if (!err) {
 497                char addr[64];
 498
 499                sprintf(addr, "0x%lx", gd->fb_base);
 500                env_set("fb_addr", addr);
 501        }
 502
 503        return err;
 504}
 505#endif
 506
 507/* u-boot dram initialize */
 508int dram_init(void)
 509{
 510        gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
 511        return 0;
 512}
 513
 514/* u-boot dram board specific */
 515int dram_init_banksize(void)
 516{
 517#define SCR_USER_SIG6_READ              (SCR_ALIVE_BASE + 0x0F0)
 518        unsigned int reg_val = readl(SCR_USER_SIG6_READ);
 519
 520        /* set global data memory */
 521        gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x00000100;
 522
 523        gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
 524        gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
 525
 526        /* Number of Row: 14 bits */
 527        if ((reg_val >> 28) == 14)
 528                gd->bd->bi_dram[0].size -= 0x20000000;
 529
 530        /* Number of Memory Chips */
 531        if ((reg_val & 0x3) > 1) {
 532                gd->bd->bi_dram[1].start = 0x80000000;
 533                gd->bd->bi_dram[1].size  = 0x40000000;
 534        }
 535        return 0;
 536}
 537
 538#if defined(CONFIG_OF_BOARD_SETUP)
 539int ft_board_setup(void *blob, struct bd_info *bd)
 540{
 541        int nodeoff;
 542        unsigned int rootdev;
 543        unsigned int fb_addr;
 544
 545        if (board_mmc_bootdev() > 0) {
 546                rootdev = fdt_getprop_u32_default(blob, "/board", "sdidx", 2);
 547                if (rootdev) {
 548                        /* find or create "/chosen" node. */
 549                        nodeoff = fdt_find_or_add_subnode(blob, 0, "chosen");
 550                        if (nodeoff >= 0)
 551                                fdt_setprop_u32(blob, nodeoff, "linux,rootdev",
 552                                                rootdev);
 553                }
 554        }
 555
 556        fb_addr = env_get_ulong("fb_addr", 0, 0);
 557        if (fb_addr) {
 558                nodeoff = fdt_path_offset(blob, "/reserved-memory");
 559                if (nodeoff < 0)
 560                        return nodeoff;
 561
 562                nodeoff = fdt_add_subnode(blob, nodeoff, "display_reserved");
 563                if (nodeoff >= 0) {
 564                        fdt32_t cells[2];
 565
 566                        cells[0] = cpu_to_fdt32(fb_addr);
 567                        cells[1] = cpu_to_fdt32(0x800000);
 568
 569                        fdt_setprop(blob, nodeoff, "reg", cells,
 570                                    sizeof(cells[0]) * 2);
 571                }
 572        }
 573
 574        return 0;
 575}
 576#endif
 577