arm: Disable ATAGs support
[platform/kernel/u-boot.git] / board / friendlyarm / nanopi2 / board.c
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
34 DECLARE_GLOBAL_DATA_PTR;
35
36 enum gpio_group {
37         gpio_a, gpio_b, gpio_c, gpio_d, gpio_e,
38 };
39
40 #ifdef CONFIG_PWM_NX
41 struct pwm_device {
42         int grp;
43         int bit;
44         int io_fn;
45 };
46
47 static 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
66 static 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
76 static 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
91 static 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) */
105 static int mmc_boot_dev;
106
107 int board_mmc_bootdev(void)
108 {
109         return mmc_boot_dev;
110 }
111
112 /* call from common/env_mmc.c */
113 int mmc_get_env_dev(void)
114 {
115         return mmc_boot_dev;
116 }
117
118 #ifdef CONFIG_DISPLAY_BOARDINFO
119 int checkboard(void)
120 {
121         printf("Board: %s\n", get_board_name());
122
123         return 0;
124 }
125 #endif
126
127 int 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
200 static 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
212 static 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
222 static 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
249 static int mac_read_from_generic_eeprom(u8 *addr)
250 {
251         return -1;
252 }
253
254 static 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
277 static 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
299 static 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
308 static 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
317 static 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
408 int board_early_init_f(void)
409 {
410         return 0;
411 }
412
413 int 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
435 int 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>
458 static 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
468 int 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 */
508 int dram_init(void)
509 {
510         gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
511         return 0;
512 }
513
514 /* u-boot dram board specific */
515 int 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)
539 int 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