exynos_fb.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2012 Samsung Electronics
  4. *
  5. * Author: InKi Dae <inki.dae@samsung.com>
  6. * Author: Donghwa Lee <dh09.lee@samsung.com>
  7. */
  8. #include <config.h>
  9. #include <common.h>
  10. #include <display.h>
  11. #include <div64.h>
  12. #include <dm.h>
  13. #include <fdtdec.h>
  14. #include <log.h>
  15. #include <linux/libfdt.h>
  16. #include <panel.h>
  17. #include <video.h>
  18. #include <video_bridge.h>
  19. #include <asm/io.h>
  20. #include <asm/arch/cpu.h>
  21. #include <asm/arch/clock.h>
  22. #include <asm/arch/clk.h>
  23. #include <asm/arch/mipi_dsim.h>
  24. #include <asm/arch/dp_info.h>
  25. #include <asm/arch/fb.h>
  26. #include <asm/arch/pinmux.h>
  27. #include <asm/arch/system.h>
  28. #include <asm/gpio.h>
  29. #include <linux/errno.h>
  30. DECLARE_GLOBAL_DATA_PTR;
  31. enum {
  32. FIMD_RGB_INTERFACE = 1,
  33. FIMD_CPU_INTERFACE = 2,
  34. };
  35. enum exynos_fb_rgb_mode_t {
  36. MODE_RGB_P = 0,
  37. MODE_BGR_P = 1,
  38. MODE_RGB_S = 2,
  39. MODE_BGR_S = 3,
  40. };
  41. struct exynos_fb_priv {
  42. ushort vl_col; /* Number of columns (i.e. 640) */
  43. ushort vl_row; /* Number of rows (i.e. 480) */
  44. ushort vl_rot; /* Rotation of Display (0, 1, 2, 3) */
  45. ushort vl_width; /* Width of display area in millimeters */
  46. ushort vl_height; /* Height of display area in millimeters */
  47. /* LCD configuration register */
  48. u_char vl_freq; /* Frequency */
  49. u_char vl_clkp; /* Clock polarity */
  50. u_char vl_oep; /* Output Enable polarity */
  51. u_char vl_hsp; /* Horizontal Sync polarity */
  52. u_char vl_vsp; /* Vertical Sync polarity */
  53. u_char vl_dp; /* Data polarity */
  54. u_char vl_bpix; /* Bits per pixel */
  55. /* Horizontal control register. Timing from data sheet */
  56. u_char vl_hspw; /* Horz sync pulse width */
  57. u_char vl_hfpd; /* Wait before of line */
  58. u_char vl_hbpd; /* Wait end of line */
  59. /* Vertical control register. */
  60. u_char vl_vspw; /* Vertical sync pulse width */
  61. u_char vl_vfpd; /* Wait before of frame */
  62. u_char vl_vbpd; /* Wait end of frame */
  63. u_char vl_cmd_allow_len; /* Wait end of frame */
  64. unsigned int win_id;
  65. unsigned int init_delay;
  66. unsigned int power_on_delay;
  67. unsigned int reset_delay;
  68. unsigned int interface_mode;
  69. unsigned int mipi_enabled;
  70. unsigned int dp_enabled;
  71. unsigned int cs_setup;
  72. unsigned int wr_setup;
  73. unsigned int wr_act;
  74. unsigned int wr_hold;
  75. unsigned int logo_on;
  76. unsigned int logo_width;
  77. unsigned int logo_height;
  78. int logo_x_offset;
  79. int logo_y_offset;
  80. unsigned long logo_addr;
  81. unsigned int rgb_mode;
  82. unsigned int resolution;
  83. /* parent clock name(MPLL, EPLL or VPLL) */
  84. unsigned int pclk_name;
  85. /* ratio value for source clock from parent clock. */
  86. unsigned int sclk_div;
  87. unsigned int dual_lcd_enabled;
  88. struct exynos_fb *reg;
  89. struct exynos_platform_mipi_dsim *dsim_platform_data_dt;
  90. };
  91. static void exynos_fimd_set_dualrgb(struct exynos_fb_priv *priv, bool enabled)
  92. {
  93. struct exynos_fb *reg = priv->reg;
  94. unsigned int cfg = 0;
  95. if (enabled) {
  96. cfg = EXYNOS_DUALRGB_BYPASS_DUAL | EXYNOS_DUALRGB_LINESPLIT |
  97. EXYNOS_DUALRGB_VDEN_EN_ENABLE;
  98. /* in case of Line Split mode, MAIN_CNT doesn't neet to set. */
  99. cfg |= EXYNOS_DUALRGB_SUB_CNT(priv->vl_col / 2) |
  100. EXYNOS_DUALRGB_MAIN_CNT(0);
  101. }
  102. writel(cfg, &reg->dualrgb);
  103. }
  104. static void exynos_fimd_set_dp_clkcon(struct exynos_fb_priv *priv,
  105. unsigned int enabled)
  106. {
  107. struct exynos_fb *reg = priv->reg;
  108. unsigned int cfg = 0;
  109. if (enabled)
  110. cfg = EXYNOS_DP_CLK_ENABLE;
  111. writel(cfg, &reg->dp_mie_clkcon);
  112. }
  113. static void exynos_fimd_set_par(struct exynos_fb_priv *priv,
  114. unsigned int win_id)
  115. {
  116. struct exynos_fb *reg = priv->reg;
  117. unsigned int cfg = 0;
  118. /* set window control */
  119. cfg = readl((unsigned int)&reg->wincon0 +
  120. EXYNOS_WINCON(win_id));
  121. cfg &= ~(EXYNOS_WINCON_BITSWP_ENABLE | EXYNOS_WINCON_BYTESWP_ENABLE |
  122. EXYNOS_WINCON_HAWSWP_ENABLE | EXYNOS_WINCON_WSWP_ENABLE |
  123. EXYNOS_WINCON_BURSTLEN_MASK | EXYNOS_WINCON_BPPMODE_MASK |
  124. EXYNOS_WINCON_INRGB_MASK | EXYNOS_WINCON_DATAPATH_MASK);
  125. /* DATAPATH is DMA */
  126. cfg |= EXYNOS_WINCON_DATAPATH_DMA;
  127. cfg |= EXYNOS_WINCON_HAWSWP_ENABLE;
  128. /* dma burst is 16 */
  129. cfg |= EXYNOS_WINCON_BURSTLEN_16WORD;
  130. switch (priv->vl_bpix) {
  131. case 4:
  132. cfg |= EXYNOS_WINCON_BPPMODE_16BPP_565;
  133. break;
  134. default:
  135. cfg |= EXYNOS_WINCON_BPPMODE_24BPP_888;
  136. break;
  137. }
  138. writel(cfg, (unsigned int)&reg->wincon0 +
  139. EXYNOS_WINCON(win_id));
  140. /* set window position to x=0, y=0*/
  141. cfg = EXYNOS_VIDOSD_LEFT_X(0) | EXYNOS_VIDOSD_TOP_Y(0);
  142. writel(cfg, (unsigned int)&reg->vidosd0a +
  143. EXYNOS_VIDOSD(win_id));
  144. cfg = EXYNOS_VIDOSD_RIGHT_X(priv->vl_col - 1) |
  145. EXYNOS_VIDOSD_BOTTOM_Y(priv->vl_row - 1) |
  146. EXYNOS_VIDOSD_RIGHT_X_E(1) |
  147. EXYNOS_VIDOSD_BOTTOM_Y_E(0);
  148. writel(cfg, (unsigned int)&reg->vidosd0b +
  149. EXYNOS_VIDOSD(win_id));
  150. /* set window size for window0*/
  151. cfg = EXYNOS_VIDOSD_SIZE(priv->vl_col * priv->vl_row);
  152. writel(cfg, (unsigned int)&reg->vidosd0c +
  153. EXYNOS_VIDOSD(win_id));
  154. }
  155. static void exynos_fimd_set_buffer_address(struct exynos_fb_priv *priv,
  156. unsigned int win_id,
  157. ulong lcd_base_addr)
  158. {
  159. struct exynos_fb *reg = priv->reg;
  160. unsigned long start_addr, end_addr;
  161. start_addr = lcd_base_addr;
  162. end_addr = start_addr + ((priv->vl_col * (VNBITS(priv->vl_bpix) / 8)) *
  163. priv->vl_row);
  164. writel(start_addr, (unsigned int)&reg->vidw00add0b0 +
  165. EXYNOS_BUFFER_OFFSET(win_id));
  166. writel(end_addr, (unsigned int)&reg->vidw00add1b0 +
  167. EXYNOS_BUFFER_OFFSET(win_id));
  168. }
  169. static void exynos_fimd_set_clock(struct exynos_fb_priv *priv)
  170. {
  171. struct exynos_fb *reg = priv->reg;
  172. unsigned int cfg = 0, div = 0, remainder, remainder_div;
  173. unsigned long pixel_clock;
  174. unsigned long long src_clock;
  175. if (priv->dual_lcd_enabled) {
  176. pixel_clock = priv->vl_freq *
  177. (priv->vl_hspw + priv->vl_hfpd +
  178. priv->vl_hbpd + priv->vl_col / 2) *
  179. (priv->vl_vspw + priv->vl_vfpd +
  180. priv->vl_vbpd + priv->vl_row);
  181. } else if (priv->interface_mode == FIMD_CPU_INTERFACE) {
  182. pixel_clock = priv->vl_freq *
  183. priv->vl_width * priv->vl_height *
  184. (priv->cs_setup + priv->wr_setup +
  185. priv->wr_act + priv->wr_hold + 1);
  186. } else {
  187. pixel_clock = priv->vl_freq *
  188. (priv->vl_hspw + priv->vl_hfpd +
  189. priv->vl_hbpd + priv->vl_col) *
  190. (priv->vl_vspw + priv->vl_vfpd +
  191. priv->vl_vbpd + priv->vl_row);
  192. }
  193. cfg = readl(&reg->vidcon0);
  194. cfg &= ~(EXYNOS_VIDCON0_CLKSEL_MASK | EXYNOS_VIDCON0_CLKVALUP_MASK |
  195. EXYNOS_VIDCON0_CLKVAL_F(0xFF) | EXYNOS_VIDCON0_VCLKEN_MASK |
  196. EXYNOS_VIDCON0_CLKDIR_MASK);
  197. cfg |= (EXYNOS_VIDCON0_CLKSEL_SCLK | EXYNOS_VIDCON0_CLKVALUP_ALWAYS |
  198. EXYNOS_VIDCON0_VCLKEN_NORMAL | EXYNOS_VIDCON0_CLKDIR_DIVIDED);
  199. src_clock = (unsigned long long) get_lcd_clk();
  200. /* get quotient and remainder. */
  201. remainder = do_div(src_clock, pixel_clock);
  202. div = src_clock;
  203. remainder *= 10;
  204. remainder_div = remainder / pixel_clock;
  205. /* round about one places of decimals. */
  206. if (remainder_div >= 5)
  207. div++;
  208. /* in case of dual lcd mode. */
  209. if (priv->dual_lcd_enabled)
  210. div--;
  211. cfg |= EXYNOS_VIDCON0_CLKVAL_F(div - 1);
  212. writel(cfg, &reg->vidcon0);
  213. }
  214. void exynos_set_trigger(struct exynos_fb_priv *priv)
  215. {
  216. struct exynos_fb *reg = priv->reg;
  217. unsigned int cfg = 0;
  218. cfg = readl(&reg->trigcon);
  219. cfg |= (EXYNOS_I80SOFT_TRIG_EN | EXYNOS_I80START_TRIG);
  220. writel(cfg, &reg->trigcon);
  221. }
  222. int exynos_is_i80_frame_done(struct exynos_fb_priv *priv)
  223. {
  224. struct exynos_fb *reg = priv->reg;
  225. unsigned int cfg = 0;
  226. int status;
  227. cfg = readl(&reg->trigcon);
  228. /* frame done func is valid only when TRIMODE[0] is set to 1. */
  229. status = (cfg & EXYNOS_I80STATUS_TRIG_DONE) ==
  230. EXYNOS_I80STATUS_TRIG_DONE;
  231. return status;
  232. }
  233. static void exynos_fimd_lcd_on(struct exynos_fb_priv *priv)
  234. {
  235. struct exynos_fb *reg = priv->reg;
  236. unsigned int cfg = 0;
  237. /* display on */
  238. cfg = readl(&reg->vidcon0);
  239. cfg |= (EXYNOS_VIDCON0_ENVID_ENABLE | EXYNOS_VIDCON0_ENVID_F_ENABLE);
  240. writel(cfg, &reg->vidcon0);
  241. }
  242. static void exynos_fimd_window_on(struct exynos_fb_priv *priv,
  243. unsigned int win_id)
  244. {
  245. struct exynos_fb *reg = priv->reg;
  246. unsigned int cfg = 0;
  247. /* enable window */
  248. cfg = readl((unsigned int)&reg->wincon0 +
  249. EXYNOS_WINCON(win_id));
  250. cfg |= EXYNOS_WINCON_ENWIN_ENABLE;
  251. writel(cfg, (unsigned int)&reg->wincon0 +
  252. EXYNOS_WINCON(win_id));
  253. cfg = readl(&reg->winshmap);
  254. cfg |= EXYNOS_WINSHMAP_CH_ENABLE(win_id);
  255. writel(cfg, &reg->winshmap);
  256. }
  257. void exynos_fimd_lcd_off(struct exynos_fb_priv *priv)
  258. {
  259. struct exynos_fb *reg = priv->reg;
  260. unsigned int cfg = 0;
  261. cfg = readl(&reg->vidcon0);
  262. cfg &= (EXYNOS_VIDCON0_ENVID_DISABLE | EXYNOS_VIDCON0_ENVID_F_DISABLE);
  263. writel(cfg, &reg->vidcon0);
  264. }
  265. void exynos_fimd_window_off(struct exynos_fb_priv *priv, unsigned int win_id)
  266. {
  267. struct exynos_fb *reg = priv->reg;
  268. unsigned int cfg = 0;
  269. cfg = readl((unsigned int)&reg->wincon0 +
  270. EXYNOS_WINCON(win_id));
  271. cfg &= EXYNOS_WINCON_ENWIN_DISABLE;
  272. writel(cfg, (unsigned int)&reg->wincon0 +
  273. EXYNOS_WINCON(win_id));
  274. cfg = readl(&reg->winshmap);
  275. cfg &= ~EXYNOS_WINSHMAP_CH_DISABLE(win_id);
  276. writel(cfg, &reg->winshmap);
  277. }
  278. /*
  279. * The reset value for FIMD SYSMMU register MMU_CTRL is 3
  280. * on Exynos5420 and newer versions.
  281. * This means FIMD SYSMMU is on by default on Exynos5420
  282. * and newer versions.
  283. * Since in u-boot we don't use SYSMMU, we should disable
  284. * those FIMD SYSMMU.
  285. * Note that there are 2 SYSMMU for FIMD: m0 and m1.
  286. * m0 handles windows 0 and 4, and m1 handles windows 1, 2 and 3.
  287. * We disable both of them here.
  288. */
  289. void exynos_fimd_disable_sysmmu(void)
  290. {
  291. u32 *sysmmufimd;
  292. unsigned int node;
  293. int node_list[2];
  294. int count;
  295. int i;
  296. count = fdtdec_find_aliases_for_id(gd->fdt_blob, "fimd",
  297. COMPAT_SAMSUNG_EXYNOS_SYSMMU, node_list, 2);
  298. for (i = 0; i < count; i++) {
  299. node = node_list[i];
  300. if (node <= 0) {
  301. debug("Can't get device node for fimd sysmmu\n");
  302. return;
  303. }
  304. sysmmufimd = (u32 *)fdtdec_get_addr(gd->fdt_blob, node, "reg");
  305. if (!sysmmufimd) {
  306. debug("Can't get base address for sysmmu fimdm0");
  307. return;
  308. }
  309. writel(0x0, sysmmufimd);
  310. }
  311. }
  312. void exynos_fimd_lcd_init(struct udevice *dev)
  313. {
  314. struct exynos_fb_priv *priv = dev_get_priv(dev);
  315. struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
  316. struct exynos_fb *reg = priv->reg;
  317. unsigned int cfg = 0, rgb_mode;
  318. unsigned int offset;
  319. unsigned int node;
  320. node = dev_of_offset(dev);
  321. if (fdtdec_get_bool(gd->fdt_blob, node, "samsung,disable-sysmmu"))
  322. exynos_fimd_disable_sysmmu();
  323. offset = exynos_fimd_get_base_offset();
  324. rgb_mode = priv->rgb_mode;
  325. if (priv->interface_mode == FIMD_RGB_INTERFACE) {
  326. cfg |= EXYNOS_VIDCON0_VIDOUT_RGB;
  327. writel(cfg, &reg->vidcon0);
  328. cfg = readl(&reg->vidcon2);
  329. cfg &= ~(EXYNOS_VIDCON2_WB_MASK |
  330. EXYNOS_VIDCON2_TVFORMATSEL_MASK |
  331. EXYNOS_VIDCON2_TVFORMATSEL_YUV_MASK);
  332. cfg |= EXYNOS_VIDCON2_WB_DISABLE;
  333. writel(cfg, &reg->vidcon2);
  334. /* set polarity */
  335. cfg = 0;
  336. if (!priv->vl_clkp)
  337. cfg |= EXYNOS_VIDCON1_IVCLK_RISING_EDGE;
  338. if (!priv->vl_hsp)
  339. cfg |= EXYNOS_VIDCON1_IHSYNC_INVERT;
  340. if (!priv->vl_vsp)
  341. cfg |= EXYNOS_VIDCON1_IVSYNC_INVERT;
  342. if (!priv->vl_dp)
  343. cfg |= EXYNOS_VIDCON1_IVDEN_INVERT;
  344. writel(cfg, (unsigned int)&reg->vidcon1 + offset);
  345. /* set timing */
  346. cfg = EXYNOS_VIDTCON0_VFPD(priv->vl_vfpd - 1);
  347. cfg |= EXYNOS_VIDTCON0_VBPD(priv->vl_vbpd - 1);
  348. cfg |= EXYNOS_VIDTCON0_VSPW(priv->vl_vspw - 1);
  349. writel(cfg, (unsigned int)&reg->vidtcon0 + offset);
  350. cfg = EXYNOS_VIDTCON1_HFPD(priv->vl_hfpd - 1);
  351. cfg |= EXYNOS_VIDTCON1_HBPD(priv->vl_hbpd - 1);
  352. cfg |= EXYNOS_VIDTCON1_HSPW(priv->vl_hspw - 1);
  353. writel(cfg, (unsigned int)&reg->vidtcon1 + offset);
  354. /* set lcd size */
  355. cfg = EXYNOS_VIDTCON2_HOZVAL(priv->vl_col - 1) |
  356. EXYNOS_VIDTCON2_LINEVAL(priv->vl_row - 1) |
  357. EXYNOS_VIDTCON2_HOZVAL_E(priv->vl_col - 1) |
  358. EXYNOS_VIDTCON2_LINEVAL_E(priv->vl_row - 1);
  359. writel(cfg, (unsigned int)&reg->vidtcon2 + offset);
  360. }
  361. /* set display mode */
  362. cfg = readl(&reg->vidcon0);
  363. cfg &= ~EXYNOS_VIDCON0_PNRMODE_MASK;
  364. cfg |= (rgb_mode << EXYNOS_VIDCON0_PNRMODE_SHIFT);
  365. writel(cfg, &reg->vidcon0);
  366. /* set par */
  367. exynos_fimd_set_par(priv, priv->win_id);
  368. /* set memory address */
  369. exynos_fimd_set_buffer_address(priv, priv->win_id, plat->base);
  370. /* set buffer size */
  371. cfg = EXYNOS_VIDADDR_PAGEWIDTH(priv->vl_col *
  372. VNBITS(priv->vl_bpix) / 8) |
  373. EXYNOS_VIDADDR_PAGEWIDTH_E(priv->vl_col *
  374. VNBITS(priv->vl_bpix) / 8) |
  375. EXYNOS_VIDADDR_OFFSIZE(0) |
  376. EXYNOS_VIDADDR_OFFSIZE_E(0);
  377. writel(cfg, (unsigned int)&reg->vidw00add2 +
  378. EXYNOS_BUFFER_SIZE(priv->win_id));
  379. /* set clock */
  380. exynos_fimd_set_clock(priv);
  381. /* set rgb mode to dual lcd. */
  382. exynos_fimd_set_dualrgb(priv, priv->dual_lcd_enabled);
  383. /* display on */
  384. exynos_fimd_lcd_on(priv);
  385. /* window on */
  386. exynos_fimd_window_on(priv, priv->win_id);
  387. exynos_fimd_set_dp_clkcon(priv, priv->dp_enabled);
  388. }
  389. unsigned long exynos_fimd_calc_fbsize(struct exynos_fb_priv *priv)
  390. {
  391. return priv->vl_col * priv->vl_row * (VNBITS(priv->vl_bpix) / 8);
  392. }
  393. int exynos_fb_ofdata_to_platdata(struct udevice *dev)
  394. {
  395. struct exynos_fb_priv *priv = dev_get_priv(dev);
  396. unsigned int node = dev_of_offset(dev);
  397. const void *blob = gd->fdt_blob;
  398. fdt_addr_t addr;
  399. addr = dev_read_addr(dev);
  400. if (addr == FDT_ADDR_T_NONE) {
  401. debug("Can't get the FIMD base address\n");
  402. return -EINVAL;
  403. }
  404. priv->reg = (struct exynos_fb *)addr;
  405. priv->vl_col = fdtdec_get_int(blob, node, "samsung,vl-col", 0);
  406. if (priv->vl_col == 0) {
  407. debug("Can't get XRES\n");
  408. return -ENXIO;
  409. }
  410. priv->vl_row = fdtdec_get_int(blob, node, "samsung,vl-row", 0);
  411. if (priv->vl_row == 0) {
  412. debug("Can't get YRES\n");
  413. return -ENXIO;
  414. }
  415. priv->vl_width = fdtdec_get_int(blob, node,
  416. "samsung,vl-width", 0);
  417. priv->vl_height = fdtdec_get_int(blob, node,
  418. "samsung,vl-height", 0);
  419. priv->vl_freq = fdtdec_get_int(blob, node, "samsung,vl-freq", 0);
  420. if (priv->vl_freq == 0) {
  421. debug("Can't get refresh rate\n");
  422. return -ENXIO;
  423. }
  424. if (fdtdec_get_bool(blob, node, "samsung,vl-clkp"))
  425. priv->vl_clkp = VIDEO_ACTIVE_LOW;
  426. if (fdtdec_get_bool(blob, node, "samsung,vl-oep"))
  427. priv->vl_oep = VIDEO_ACTIVE_LOW;
  428. if (fdtdec_get_bool(blob, node, "samsung,vl-hsp"))
  429. priv->vl_hsp = VIDEO_ACTIVE_LOW;
  430. if (fdtdec_get_bool(blob, node, "samsung,vl-vsp"))
  431. priv->vl_vsp = VIDEO_ACTIVE_LOW;
  432. if (fdtdec_get_bool(blob, node, "samsung,vl-dp"))
  433. priv->vl_dp = VIDEO_ACTIVE_LOW;
  434. priv->vl_bpix = fdtdec_get_int(blob, node, "samsung,vl-bpix", 0);
  435. if (priv->vl_bpix == 0) {
  436. debug("Can't get bits per pixel\n");
  437. return -ENXIO;
  438. }
  439. priv->vl_hspw = fdtdec_get_int(blob, node, "samsung,vl-hspw", 0);
  440. if (priv->vl_hspw == 0) {
  441. debug("Can't get hsync width\n");
  442. return -ENXIO;
  443. }
  444. priv->vl_hfpd = fdtdec_get_int(blob, node, "samsung,vl-hfpd", 0);
  445. if (priv->vl_hfpd == 0) {
  446. debug("Can't get right margin\n");
  447. return -ENXIO;
  448. }
  449. priv->vl_hbpd = (u_char)fdtdec_get_int(blob, node,
  450. "samsung,vl-hbpd", 0);
  451. if (priv->vl_hbpd == 0) {
  452. debug("Can't get left margin\n");
  453. return -ENXIO;
  454. }
  455. priv->vl_vspw = (u_char)fdtdec_get_int(blob, node,
  456. "samsung,vl-vspw", 0);
  457. if (priv->vl_vspw == 0) {
  458. debug("Can't get vsync width\n");
  459. return -ENXIO;
  460. }
  461. priv->vl_vfpd = fdtdec_get_int(blob, node,
  462. "samsung,vl-vfpd", 0);
  463. if (priv->vl_vfpd == 0) {
  464. debug("Can't get lower margin\n");
  465. return -ENXIO;
  466. }
  467. priv->vl_vbpd = fdtdec_get_int(blob, node, "samsung,vl-vbpd", 0);
  468. if (priv->vl_vbpd == 0) {
  469. debug("Can't get upper margin\n");
  470. return -ENXIO;
  471. }
  472. priv->vl_cmd_allow_len = fdtdec_get_int(blob, node,
  473. "samsung,vl-cmd-allow-len", 0);
  474. priv->win_id = fdtdec_get_int(blob, node, "samsung,winid", 0);
  475. priv->init_delay = fdtdec_get_int(blob, node,
  476. "samsung,init-delay", 0);
  477. priv->power_on_delay = fdtdec_get_int(blob, node,
  478. "samsung,power-on-delay", 0);
  479. priv->reset_delay = fdtdec_get_int(blob, node,
  480. "samsung,reset-delay", 0);
  481. priv->interface_mode = fdtdec_get_int(blob, node,
  482. "samsung,interface-mode", 0);
  483. priv->mipi_enabled = fdtdec_get_int(blob, node,
  484. "samsung,mipi-enabled", 0);
  485. priv->dp_enabled = fdtdec_get_int(blob, node,
  486. "samsung,dp-enabled", 0);
  487. priv->cs_setup = fdtdec_get_int(blob, node,
  488. "samsung,cs-setup", 0);
  489. priv->wr_setup = fdtdec_get_int(blob, node,
  490. "samsung,wr-setup", 0);
  491. priv->wr_act = fdtdec_get_int(blob, node, "samsung,wr-act", 0);
  492. priv->wr_hold = fdtdec_get_int(blob, node, "samsung,wr-hold", 0);
  493. priv->logo_on = fdtdec_get_int(blob, node, "samsung,logo-on", 0);
  494. if (priv->logo_on) {
  495. priv->logo_width = fdtdec_get_int(blob, node,
  496. "samsung,logo-width", 0);
  497. priv->logo_height = fdtdec_get_int(blob, node,
  498. "samsung,logo-height", 0);
  499. priv->logo_addr = fdtdec_get_int(blob, node,
  500. "samsung,logo-addr", 0);
  501. }
  502. priv->rgb_mode = fdtdec_get_int(blob, node,
  503. "samsung,rgb-mode", 0);
  504. priv->pclk_name = fdtdec_get_int(blob, node,
  505. "samsung,pclk-name", 0);
  506. priv->sclk_div = fdtdec_get_int(blob, node,
  507. "samsung,sclk-div", 0);
  508. priv->dual_lcd_enabled = fdtdec_get_int(blob, node,
  509. "samsung,dual-lcd-enabled", 0);
  510. return 0;
  511. }
  512. static int exynos_fb_probe(struct udevice *dev)
  513. {
  514. struct video_priv *uc_priv = dev_get_uclass_priv(dev);
  515. struct exynos_fb_priv *priv = dev_get_priv(dev);
  516. struct udevice *panel, *bridge;
  517. struct udevice *dp;
  518. int ret;
  519. debug("%s: start\n", __func__);
  520. set_system_display_ctrl();
  521. set_lcd_clk();
  522. #ifdef CONFIG_EXYNOS_MIPI_DSIM
  523. exynos_init_dsim_platform_data(&panel_info);
  524. #endif
  525. exynos_fimd_lcd_init(dev);
  526. ret = uclass_first_device(UCLASS_PANEL, &panel);
  527. if (ret) {
  528. printf("LCD panel failed to probe\n");
  529. return ret;
  530. }
  531. if (!panel) {
  532. printf("LCD panel not found\n");
  533. return -ENODEV;
  534. }
  535. ret = uclass_first_device(UCLASS_DISPLAY, &dp);
  536. if (ret) {
  537. debug("%s: Display device error %d\n", __func__, ret);
  538. return ret;
  539. }
  540. if (!dev) {
  541. debug("%s: Display device missing\n", __func__);
  542. return -ENODEV;
  543. }
  544. ret = display_enable(dp, 18, NULL);
  545. if (ret) {
  546. debug("%s: Display enable error %d\n", __func__, ret);
  547. return ret;
  548. }
  549. /* backlight / pwm */
  550. ret = panel_enable_backlight(panel);
  551. if (ret) {
  552. debug("%s: backlight error: %d\n", __func__, ret);
  553. return ret;
  554. }
  555. ret = uclass_get_device(UCLASS_VIDEO_BRIDGE, 0, &bridge);
  556. if (!ret)
  557. ret = video_bridge_set_backlight(bridge, 80);
  558. if (ret) {
  559. debug("%s: No video bridge, or no backlight on bridge\n",
  560. __func__);
  561. exynos_pinmux_config(PERIPH_ID_PWM0, 0);
  562. }
  563. uc_priv->xsize = priv->vl_col;
  564. uc_priv->ysize = priv->vl_row;
  565. uc_priv->bpix = priv->vl_bpix;
  566. /* Enable flushing after LCD writes if requested */
  567. video_set_flush_dcache(dev, true);
  568. return 0;
  569. }
  570. static int exynos_fb_bind(struct udevice *dev)
  571. {
  572. struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
  573. /* This is the maximum panel size we expect to see */
  574. plat->size = 1920 * 1080 * 2;
  575. return 0;
  576. }
  577. static const struct video_ops exynos_fb_ops = {
  578. };
  579. static const struct udevice_id exynos_fb_ids[] = {
  580. { .compatible = "samsung,exynos-fimd" },
  581. { }
  582. };
  583. U_BOOT_DRIVER(exynos_fb) = {
  584. .name = "exynos_fb",
  585. .id = UCLASS_VIDEO,
  586. .of_match = exynos_fb_ids,
  587. .ops = &exynos_fb_ops,
  588. .bind = exynos_fb_bind,
  589. .probe = exynos_fb_probe,
  590. .ofdata_to_platdata = exynos_fb_ofdata_to_platdata,
  591. .priv_auto_alloc_size = sizeof(struct exynos_fb_priv),
  592. };