blob: 4dff32e10d6b7c0582ee0a0496b5b806b7e5f2c1 [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 Glassd0da0052024-08-21 10:18:58 -060014#include <video.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060015#include <asm/global_data.h>
Stefan Boschb4bb31d2020-07-10 19:07:37 +020016#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 */
Tom Rini66faa432022-12-04 10:03:26 -050083 s5p_pwm_init(BACKLIGHT_CH,
Stefan Boschb4bb31d2020-07-10 19:07:37 +020084 BACKLIGHT_DIV, BACKLIGHT_INV);
Tom Rini66faa432022-12-04 10:03:26 -050085 s5p_pwm_config(BACKLIGHT_CH,
Stefan Boschb4bb31d2020-07-10 19:07:37 +020086 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
Raymond Maoc35e1a42024-10-03 14:50:17 -0700267 md5_wd((unsigned char *)&hash[4], 64, (unsigned char *)hash,
268 MD5_DEF_CHUNK_SZ);
Stefan Boschb4bb31d2020-07-10 19:07:37 +0200269
270 hash[0] ^= hash[2];
271 hash[1] ^= hash[3];
272
273 memcpy(addr, (char *)hash, 6);
274 addr[0] &= 0xfe; /* clear multicast bit */
275 addr[0] |= 0x02;
276}
277
278static void set_ether_addr(void)
279{
280 unsigned char mac[6];
281 char ethaddr[20];
282 int ret;
283
284 if (env_get("ethaddr"))
285 return;
286
287 ret = mac_read_from_generic_eeprom(mac);
288 if (ret < 0)
289 make_ether_addr(mac);
290
291 sprintf(ethaddr, "%02x:%02x:%02x:%02x:%02x:%02x",
292 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
293 if (!ret)
294 printf("MAC: [%s]\n", ethaddr);
295
296 env_set("ethaddr", ethaddr);
297}
298
Tom Rini4cc38852021-08-30 09:16:30 -0400299#ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
Stefan Boschb4bb31d2020-07-10 19:07:37 +0200300static void set_board_rev(void)
301{
302 char info[64] = {0, };
303
Tom Rini4cc38852021-08-30 09:16:30 -0400304 snprintf(info, ARRAY_SIZE(info), "%02x", get_board_revision());
Stefan Boschb4bb31d2020-07-10 19:07:37 +0200305 env_set("board_rev", info);
306}
307#endif
308
309static void set_dtb_name(void)
310{
311 char info[64] = {0, };
312
313 snprintf(info, ARRAY_SIZE(info),
Tom Rini4cc38852021-08-30 09:16:30 -0400314 "s5p4418-nanopi2-rev%02x.dtb", get_board_revision());
Stefan Boschb4bb31d2020-07-10 19:07:37 +0200315 env_set("dtb_name", info);
316}
317
318static void bd_update_env(void)
319{
320 char *lcdtype = env_get("lcdtype");
321 char *lcddpi = env_get("lcddpi");
322 char *bootargs = env_get("bootargs");
323 const char *name;
324 char *p = NULL;
325 int rootdev = board_mmc_bootdev();
326 int need_save = 0;
327
328#define CMDLINE_LCD " lcd="
329 char cmdline[CONFIG_SYS_CBSIZE];
330 int n = 1;
331
332 if (rootdev != CONFIG_ROOT_DEV && !env_get("firstboot")) {
333 env_set_ulong("rootdev", rootdev);
334 env_set("firstboot", "0");
335 need_save = 1;
336 }
337
338 if (lcdtype) {
339 /* Setup again as user specified LCD in env */
340 bd_setup_lcd_by_name(lcdtype);
341 }
342
343 name = bd_get_lcd_name();
344
345 if (bootargs)
346 n = strlen(bootargs); /* isn't 0 for NULL */
347 else
348 cmdline[0] = '\0';
349
350 if ((n + strlen(name) + sizeof(CMDLINE_LCD)) > sizeof(cmdline)) {
351 printf("Error: `bootargs' is too large (%d)\n", n);
352 goto __exit;
353 }
354
355 if (bootargs) {
356 p = strstr(bootargs, CMDLINE_LCD);
357 if (p) {
358 n = (p - bootargs);
359 p += strlen(CMDLINE_LCD);
360 }
361 strncpy(cmdline, bootargs, n);
362 }
363
364 /* add `lcd=NAME,NUMdpi' */
365 strncpy(cmdline + n, CMDLINE_LCD, strlen(CMDLINE_LCD));
366 n += strlen(CMDLINE_LCD);
367
368 strcpy(cmdline + n, name);
369 n += strlen(name);
370
371 if (lcddpi) {
372 n += sprintf(cmdline + n, ",%sdpi", lcddpi);
373 } else {
374 int dpi = bd_get_lcd_density();
375
376 if (dpi > 0 && dpi < 600)
377 n += sprintf(cmdline + n, ",%ddpi", dpi);
378 }
379
380 /* copy remaining of bootargs */
381 if (p) {
382 p = strstr(p, " ");
383 if (p) {
384 strcpy(cmdline + n, p);
385 n += strlen(p);
386 }
387 }
388
389 /* append `bootdev=2' */
390#define CMDLINE_BDEV " bootdev="
391 if (rootdev > 0 && !strstr(cmdline, CMDLINE_BDEV))
392 n += sprintf(cmdline + n, "%s2", CMDLINE_BDEV);
393
394 /* finally, let's update uboot env & save it */
395 if (bootargs && strncmp(cmdline, bootargs, sizeof(cmdline))) {
396 env_set("bootargs", cmdline);
397 need_save = 1;
398 }
399
400__exit:
401 if (need_save)
402 env_save();
403}
404
405/* --------------------------------------------------------------------------
406 * call from u-boot
407 */
408
409int board_early_init_f(void)
410{
411 return 0;
412}
413
414int board_init(void)
415{
416 bd_hwrev_init();
417 bd_base_rev_init();
418
419 bd_bootdev_init();
420#ifdef CONFIG_S5P4418_ONEWIRE
421 bd_onewire_init();
422#endif
423
424 bd_backlight_off();
425
426 bd_lcd_config_gpio();
427 bd_lcd_init();
428
429 if (IS_ENABLED(CONFIG_SILENT_CONSOLE))
430 gd->flags |= GD_FLG_SILENT;
431
432 return 0;
433}
434
435#ifdef CONFIG_BOARD_LATE_INIT
436int board_late_init(void)
437{
438 bd_update_env();
439
Tom Rini4cc38852021-08-30 09:16:30 -0400440#ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
Stefan Boschb4bb31d2020-07-10 19:07:37 +0200441 set_board_rev();
442#endif
443 set_dtb_name();
444
445 set_ether_addr();
446
447 if (IS_ENABLED(CONFIG_SILENT_CONSOLE))
448 gd->flags &= ~GD_FLG_SILENT;
449
450 bd_backlight_on();
451 printf("\n");
452
453 return 0;
454}
455#endif
456
457#ifdef CONFIG_SPLASH_SOURCE
458#include <splash.h>
459static struct splash_location splash_locations[] = {
460 {
461 .name = "mmc_fs",
462 .storage = SPLASH_STORAGE_MMC,
463 .flags = SPLASH_STORAGE_FS,
464 .devpart = __stringify(CONFIG_ROOT_DEV) ":"
465 __stringify(CONFIG_BOOT_PART),
466 },
467};
468
469int splash_screen_prepare(void)
470{
471 int err;
472 char *env_cmd = env_get("load_splash");
473
474 debug("%s()\n", __func__);
475
476 if (env_cmd) {
477 err = run_command(env_cmd, 0);
478
479 } else {
480 char devpart[64] = { 0, };
481 int bootpart = env_get_ulong("bootpart", 0, CONFIG_BOOT_PART);
482 int rootdev;
483
484 if (env_get("firstboot"))
485 rootdev = env_get_ulong("rootdev", 0, CONFIG_ROOT_DEV);
486 else
487 rootdev = board_mmc_bootdev();
488
489 snprintf(devpart, ARRAY_SIZE(devpart), "%d:%d", rootdev,
490 bootpart);
491 splash_locations[0].devpart = devpart;
492
493 err = splash_source_load(splash_locations,
494 ARRAY_SIZE(splash_locations));
495 }
496
Simon Glassd0da0052024-08-21 10:18:58 -0600497 if (!err)
498 env_set_hex("fb_addr", video_get_fb());
Stefan Boschb4bb31d2020-07-10 19:07:37 +0200499
500 return err;
501}
502#endif
503
504/* u-boot dram initialize */
505int dram_init(void)
506{
Tom Rinibb4dd962022-11-16 13:10:37 -0500507 gd->ram_size = CFG_SYS_SDRAM_SIZE;
Stefan Boschb4bb31d2020-07-10 19:07:37 +0200508 return 0;
509}
510
511/* u-boot dram board specific */
512int dram_init_banksize(void)
513{
514#define SCR_USER_SIG6_READ (SCR_ALIVE_BASE + 0x0F0)
515 unsigned int reg_val = readl(SCR_USER_SIG6_READ);
516
517 /* set global data memory */
Tom Rinibb4dd962022-11-16 13:10:37 -0500518 gd->bd->bi_boot_params = CFG_SYS_SDRAM_BASE + 0x00000100;
Stefan Boschb4bb31d2020-07-10 19:07:37 +0200519
Tom Rinibb4dd962022-11-16 13:10:37 -0500520 gd->bd->bi_dram[0].start = CFG_SYS_SDRAM_BASE;
521 gd->bd->bi_dram[0].size = CFG_SYS_SDRAM_SIZE;
Stefan Boschb4bb31d2020-07-10 19:07:37 +0200522
523 /* Number of Row: 14 bits */
524 if ((reg_val >> 28) == 14)
525 gd->bd->bi_dram[0].size -= 0x20000000;
526
527 /* Number of Memory Chips */
528 if ((reg_val & 0x3) > 1) {
529 gd->bd->bi_dram[1].start = 0x80000000;
530 gd->bd->bi_dram[1].size = 0x40000000;
531 }
532 return 0;
533}
534
535#if defined(CONFIG_OF_BOARD_SETUP)
536int ft_board_setup(void *blob, struct bd_info *bd)
537{
538 int nodeoff;
539 unsigned int rootdev;
540 unsigned int fb_addr;
541
542 if (board_mmc_bootdev() > 0) {
543 rootdev = fdt_getprop_u32_default(blob, "/board", "sdidx", 2);
544 if (rootdev) {
545 /* find or create "/chosen" node. */
546 nodeoff = fdt_find_or_add_subnode(blob, 0, "chosen");
547 if (nodeoff >= 0)
548 fdt_setprop_u32(blob, nodeoff, "linux,rootdev",
549 rootdev);
550 }
551 }
552
553 fb_addr = env_get_ulong("fb_addr", 0, 0);
554 if (fb_addr) {
555 nodeoff = fdt_path_offset(blob, "/reserved-memory");
556 if (nodeoff < 0)
557 return nodeoff;
558
559 nodeoff = fdt_add_subnode(blob, nodeoff, "display_reserved");
560 if (nodeoff >= 0) {
561 fdt32_t cells[2];
562
563 cells[0] = cpu_to_fdt32(fb_addr);
564 cells[1] = cpu_to_fdt32(0x800000);
565
566 fdt_setprop(blob, nodeoff, "reg", cells,
567 sizeof(cells[0]) * 2);
568 }
569 }
570
571 return 0;
572}
573#endif