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