1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) Guangzhou FriendlyARM Computer Tech. Co., Ltd.
4 * (http://www.friendlyarm.com)
10 #include <fdt_support.h>
15 #include <asm/global_data.h>
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>
23 #include <u-boot/md5.h>
25 #include <linux/stringify.h>
31 #include <env_internal.h> /* for env_save() */
32 #include <asm/mach-types.h>
34 DECLARE_GLOBAL_DATA_PTR;
37 gpio_a, gpio_b, gpio_c, gpio_d, gpio_e,
47 static inline void bd_pwm_config_gpio(int ch)
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 },
56 int gp = pwm_dev[ch].grp;
57 int io = pwm_dev[ch].bit;
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);
66 static void bd_backlight_off(void)
68 #ifdef CONFIG_S5P4418_ONEWIRE
69 onewire_set_backlight(0);
71 #elif defined(BACKLIGHT_CH)
72 bd_pwm_config_gpio(BACKLIGHT_CH);
76 static void bd_backlight_on(void)
78 #ifdef CONFIG_S5P4418_ONEWIRE
79 onewire_set_backlight(127);
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));
91 static void bd_lcd_config_gpio(void)
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);
101 nx_gpio_set_drive_strength(gpio_a, 0, 1);
104 /* DEFAULT mmc dev for eMMC boot (dwmmc.2) */
105 static int mmc_boot_dev;
107 int board_mmc_bootdev(void)
112 /* call from common/env_mmc.c */
113 int mmc_get_env_dev(void)
118 #ifdef CONFIG_DISPLAY_BOARDINFO
121 printf("Board: %s\n", get_board_name());
127 int nx_display_fixup_dp(struct nx_display_dev *dp)
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];
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;
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;
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;
156 dp->ctrl.clk_div_lv0 = clk;
157 dp->ctrl.clk_inv_lv0 = lcd->polarity.rise_vclk;
159 dp->top.screen_width = lcd->width;
160 dp->top.screen_height = lcd->height;
162 for (i = 0; i < dp->top.plane_num; i++, plane++) {
164 plane->width = lcd->width;
165 plane->height = lcd->height;
169 /* initialize display device type */
170 if (fmt == LCD_RGB) {
171 dp->dev_type = DP_DEVICE_RGBLCD;
173 } else if (fmt == LCD_HDMI) {
174 struct dp_hdmi_dev *dev = (struct dp_hdmi_dev *)dp->device;
176 dp->dev_type = DP_DEVICE_HDMI;
177 if (lcd->width == 1920 && lcd->height == 1080)
183 struct dp_lvds_dev *dev = (struct dp_lvds_dev *)dp->device;
185 dp->dev_type = DP_DEVICE_LVDS;
186 dev->lvds_format = (fmt & 0x3);
192 /* --------------------------------------------------------------------------
193 * initialize board status.
196 #define MMC_BOOT_CH0 (0)
197 #define MMC_BOOT_CH1 (1 << 3)
198 #define MMC_BOOT_CH2 (1 << 19)
200 static void bd_bootdev_init(void)
202 unsigned int rst = readl(PHY_BASEADDR_CLKPWR + SYSRSTCONFIG);
204 rst &= (1 << 19) | (1 << 3);
205 if (rst == MMC_BOOT_CH0) {
206 /* mmc dev 1 for SD boot */
211 #ifdef CONFIG_S5P4418_ONEWIRE
212 static void bd_onewire_init(void)
215 unsigned short fw_ver;
218 onewire_get_info(&lcd, &fw_ver);
222 static void bd_lcd_init(void)
228 #ifdef CONFIG_S5P4418_ONEWIRE
229 id = onewire_get_lcd_id();
230 /* -1: onwire probe failed
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");
241 printf("Panel: %s\n", bd_get_lcd_name());
249 static int mac_read_from_generic_eeprom(u8 *addr)
254 static void make_ether_addr(u8 *addr)
258 #define ETHER_MAC_TAG "ethmac"
259 memset(hash, 0, sizeof(hash));
260 memcpy(hash + 12, ETHER_MAC_TAG, sizeof(ETHER_MAC_TAG));
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);
267 md5((unsigned char *)&hash[4], 64, (unsigned char *)hash);
272 memcpy(addr, (char *)hash, 6);
273 addr[0] &= 0xfe; /* clear multicast bit */
277 static void set_ether_addr(void)
279 unsigned char mac[6];
283 if (env_get("ethaddr"))
286 ret = mac_read_from_generic_eeprom(mac);
288 make_ether_addr(mac);
290 sprintf(ethaddr, "%02x:%02x:%02x:%02x:%02x:%02x",
291 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
293 printf("MAC: [%s]\n", ethaddr);
295 env_set("ethaddr", ethaddr);
298 #ifdef CONFIG_REVISION_TAG
299 static void set_board_rev(void)
301 char info[64] = {0, };
303 snprintf(info, ARRAY_SIZE(info), "%02x", get_board_rev());
304 env_set("board_rev", info);
308 static void set_dtb_name(void)
310 char info[64] = {0, };
312 snprintf(info, ARRAY_SIZE(info),
313 "s5p4418-nanopi2-rev%02x.dtb", get_board_rev());
314 env_set("dtb_name", info);
317 static void bd_update_env(void)
319 char *lcdtype = env_get("lcdtype");
320 char *lcddpi = env_get("lcddpi");
321 char *bootargs = env_get("bootargs");
324 int rootdev = board_mmc_bootdev();
327 #define CMDLINE_LCD " lcd="
328 char cmdline[CONFIG_SYS_CBSIZE];
331 if (rootdev != CONFIG_ROOT_DEV && !env_get("firstboot")) {
332 env_set_ulong("rootdev", rootdev);
333 env_set("firstboot", "0");
338 /* Setup again as user specified LCD in env */
339 bd_setup_lcd_by_name(lcdtype);
342 name = bd_get_lcd_name();
345 n = strlen(bootargs); /* isn't 0 for NULL */
349 if ((n + strlen(name) + sizeof(CMDLINE_LCD)) > sizeof(cmdline)) {
350 printf("Error: `bootargs' is too large (%d)\n", n);
355 p = strstr(bootargs, CMDLINE_LCD);
358 p += strlen(CMDLINE_LCD);
360 strncpy(cmdline, bootargs, n);
363 /* add `lcd=NAME,NUMdpi' */
364 strncpy(cmdline + n, CMDLINE_LCD, strlen(CMDLINE_LCD));
365 n += strlen(CMDLINE_LCD);
367 strcpy(cmdline + n, name);
371 n += sprintf(cmdline + n, ",%sdpi", lcddpi);
373 int dpi = bd_get_lcd_density();
375 if (dpi > 0 && dpi < 600)
376 n += sprintf(cmdline + n, ",%ddpi", dpi);
379 /* copy remaining of bootargs */
383 strcpy(cmdline + n, p);
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);
393 /* finally, let's update uboot env & save it */
394 if (bootargs && strncmp(cmdline, bootargs, sizeof(cmdline))) {
395 env_set("bootargs", cmdline);
404 /* --------------------------------------------------------------------------
408 int board_early_init_f(void)
419 #ifdef CONFIG_S5P4418_ONEWIRE
425 bd_lcd_config_gpio();
428 if (IS_ENABLED(CONFIG_SILENT_CONSOLE))
429 gd->flags |= GD_FLG_SILENT;
434 #ifdef CONFIG_BOARD_LATE_INIT
435 int board_late_init(void)
439 #ifdef CONFIG_REVISION_TAG
446 if (IS_ENABLED(CONFIG_SILENT_CONSOLE))
447 gd->flags &= ~GD_FLG_SILENT;
456 #ifdef CONFIG_SPLASH_SOURCE
458 static struct splash_location splash_locations[] = {
461 .storage = SPLASH_STORAGE_MMC,
462 .flags = SPLASH_STORAGE_FS,
463 .devpart = __stringify(CONFIG_ROOT_DEV) ":"
464 __stringify(CONFIG_BOOT_PART),
468 int splash_screen_prepare(void)
471 char *env_cmd = env_get("load_splash");
473 debug("%s()\n", __func__);
476 err = run_command(env_cmd, 0);
479 char devpart[64] = { 0, };
480 int bootpart = env_get_ulong("bootpart", 0, CONFIG_BOOT_PART);
483 if (env_get("firstboot"))
484 rootdev = env_get_ulong("rootdev", 0, CONFIG_ROOT_DEV);
486 rootdev = board_mmc_bootdev();
488 snprintf(devpart, ARRAY_SIZE(devpart), "%d:%d", rootdev,
490 splash_locations[0].devpart = devpart;
492 err = splash_source_load(splash_locations,
493 ARRAY_SIZE(splash_locations));
499 sprintf(addr, "0x%lx", gd->fb_base);
500 env_set("fb_addr", addr);
507 /* u-boot dram initialize */
510 gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
514 /* u-boot dram board specific */
515 int dram_init_banksize(void)
517 #define SCR_USER_SIG6_READ (SCR_ALIVE_BASE + 0x0F0)
518 unsigned int reg_val = readl(SCR_USER_SIG6_READ);
520 /* set global data memory */
521 gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x00000100;
523 gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
524 gd->bd->bi_dram[0].size = CONFIG_SYS_SDRAM_SIZE;
526 /* Number of Row: 14 bits */
527 if ((reg_val >> 28) == 14)
528 gd->bd->bi_dram[0].size -= 0x20000000;
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;
538 #if defined(CONFIG_OF_BOARD_SETUP)
539 int ft_board_setup(void *blob, struct bd_info *bd)
542 unsigned int rootdev;
543 unsigned int fb_addr;
545 if (board_mmc_bootdev() > 0) {
546 rootdev = fdt_getprop_u32_default(blob, "/board", "sdidx", 2);
548 /* find or create "/chosen" node. */
549 nodeoff = fdt_find_or_add_subnode(blob, 0, "chosen");
551 fdt_setprop_u32(blob, nodeoff, "linux,rootdev",
556 fb_addr = env_get_ulong("fb_addr", 0, 0);
558 nodeoff = fdt_path_offset(blob, "/reserved-memory");
562 nodeoff = fdt_add_subnode(blob, nodeoff, "display_reserved");
566 cells[0] = cpu_to_fdt32(fb_addr);
567 cells[1] = cpu_to_fdt32(0x800000);
569 fdt_setprop(blob, nodeoff, "reg", cells,
570 sizeof(cells[0]) * 2);