board.c 11 KB

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