board.c 11 KB

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