rk_lvds.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright 2016 Rockchip Inc.
  4. */
  5. #include <common.h>
  6. #include <display.h>
  7. #include <dm.h>
  8. #include <edid.h>
  9. #include <panel.h>
  10. #include <regmap.h>
  11. #include <syscon.h>
  12. #include <asm/gpio.h>
  13. #include <asm/io.h>
  14. #include <asm/arch-rockchip/clock.h>
  15. #include <asm/arch-rockchip/lvds_rk3288.h>
  16. #include <asm/arch-rockchip/grf_rk3288.h>
  17. #include <dt-bindings/clock/rk3288-cru.h>
  18. #include <dt-bindings/video/rk3288.h>
  19. DECLARE_GLOBAL_DATA_PTR;
  20. /**
  21. * struct rk_lvds_priv - private rockchip lvds display driver info
  22. *
  23. * @reg: LVDS register address
  24. * @grf: GRF register
  25. * @panel: Panel device that is used in driver
  26. *
  27. * @output: Output mode, decided single or double channel,
  28. * LVDS or LVTLL
  29. * @format: Data format that RGB data will packing as
  30. */
  31. struct rk_lvds_priv {
  32. void __iomem *regs;
  33. struct rk3288_grf *grf;
  34. struct udevice *panel;
  35. int output;
  36. int format;
  37. };
  38. static inline void lvds_writel(struct rk_lvds_priv *lvds, u32 offset, u32 val)
  39. {
  40. writel(val, lvds->regs + offset);
  41. writel(val, lvds->regs + offset + 0x100);
  42. }
  43. int rk_lvds_enable(struct udevice *dev, int panel_bpp,
  44. const struct display_timing *edid)
  45. {
  46. struct rk_lvds_priv *priv = dev_get_priv(dev);
  47. struct display_plat *uc_plat = dev_get_uclass_platdata(dev);
  48. int ret = 0;
  49. unsigned int val = 0;
  50. ret = panel_enable_backlight(priv->panel);
  51. if (ret) {
  52. debug("%s: backlight error: %d\n", __func__, ret);
  53. return ret;
  54. }
  55. /* Select the video source */
  56. if (uc_plat->source_id)
  57. val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT |
  58. (RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16);
  59. else
  60. val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16;
  61. rk_setreg(&priv->grf->soc_con6, val);
  62. /* Select data transfer format */
  63. val = priv->format;
  64. if (priv->output == LVDS_OUTPUT_DUAL)
  65. val |= LVDS_DUAL | LVDS_CH0_EN | LVDS_CH1_EN;
  66. else if (priv->output == LVDS_OUTPUT_SINGLE)
  67. val |= LVDS_CH0_EN;
  68. else if (priv->output == LVDS_OUTPUT_RGB)
  69. val |= LVDS_TTL_EN | LVDS_CH0_EN | LVDS_CH1_EN;
  70. val |= (0xffff << 16);
  71. rk_setreg(&priv->grf->soc_con7, val);
  72. /* Enable LVDS PHY */
  73. if (priv->output == LVDS_OUTPUT_RGB) {
  74. lvds_writel(priv, RK3288_LVDS_CH0_REG0,
  75. RK3288_LVDS_CH0_REG0_TTL_EN |
  76. RK3288_LVDS_CH0_REG0_LANECK_EN |
  77. RK3288_LVDS_CH0_REG0_LANE4_EN |
  78. RK3288_LVDS_CH0_REG0_LANE3_EN |
  79. RK3288_LVDS_CH0_REG0_LANE2_EN |
  80. RK3288_LVDS_CH0_REG0_LANE1_EN |
  81. RK3288_LVDS_CH0_REG0_LANE0_EN);
  82. lvds_writel(priv, RK3288_LVDS_CH0_REG2,
  83. RK3288_LVDS_PLL_FBDIV_REG2(0x46));
  84. lvds_writel(priv, RK3288_LVDS_CH0_REG3,
  85. RK3288_LVDS_PLL_FBDIV_REG3(0x46));
  86. lvds_writel(priv, RK3288_LVDS_CH0_REG4,
  87. RK3288_LVDS_CH0_REG4_LANECK_TTL_MODE |
  88. RK3288_LVDS_CH0_REG4_LANE4_TTL_MODE |
  89. RK3288_LVDS_CH0_REG4_LANE3_TTL_MODE |
  90. RK3288_LVDS_CH0_REG4_LANE2_TTL_MODE |
  91. RK3288_LVDS_CH0_REG4_LANE1_TTL_MODE |
  92. RK3288_LVDS_CH0_REG4_LANE0_TTL_MODE);
  93. lvds_writel(priv, RK3288_LVDS_CH0_REG5,
  94. RK3288_LVDS_CH0_REG5_LANECK_TTL_DATA |
  95. RK3288_LVDS_CH0_REG5_LANE4_TTL_DATA |
  96. RK3288_LVDS_CH0_REG5_LANE3_TTL_DATA |
  97. RK3288_LVDS_CH0_REG5_LANE2_TTL_DATA |
  98. RK3288_LVDS_CH0_REG5_LANE1_TTL_DATA |
  99. RK3288_LVDS_CH0_REG5_LANE0_TTL_DATA);
  100. lvds_writel(priv, RK3288_LVDS_CH0_REGD,
  101. RK3288_LVDS_PLL_PREDIV_REGD(0x0a));
  102. lvds_writel(priv, RK3288_LVDS_CH0_REG20,
  103. RK3288_LVDS_CH0_REG20_LSB);
  104. } else {
  105. lvds_writel(priv, RK3288_LVDS_CH0_REG0,
  106. RK3288_LVDS_CH0_REG0_LVDS_EN |
  107. RK3288_LVDS_CH0_REG0_LANECK_EN |
  108. RK3288_LVDS_CH0_REG0_LANE4_EN |
  109. RK3288_LVDS_CH0_REG0_LANE3_EN |
  110. RK3288_LVDS_CH0_REG0_LANE2_EN |
  111. RK3288_LVDS_CH0_REG0_LANE1_EN |
  112. RK3288_LVDS_CH0_REG0_LANE0_EN);
  113. lvds_writel(priv, RK3288_LVDS_CH0_REG1,
  114. RK3288_LVDS_CH0_REG1_LANECK_BIAS |
  115. RK3288_LVDS_CH0_REG1_LANE4_BIAS |
  116. RK3288_LVDS_CH0_REG1_LANE3_BIAS |
  117. RK3288_LVDS_CH0_REG1_LANE2_BIAS |
  118. RK3288_LVDS_CH0_REG1_LANE1_BIAS |
  119. RK3288_LVDS_CH0_REG1_LANE0_BIAS);
  120. lvds_writel(priv, RK3288_LVDS_CH0_REG2,
  121. RK3288_LVDS_CH0_REG2_RESERVE_ON |
  122. RK3288_LVDS_CH0_REG2_LANECK_LVDS_MODE |
  123. RK3288_LVDS_CH0_REG2_LANE4_LVDS_MODE |
  124. RK3288_LVDS_CH0_REG2_LANE3_LVDS_MODE |
  125. RK3288_LVDS_CH0_REG2_LANE2_LVDS_MODE |
  126. RK3288_LVDS_CH0_REG2_LANE1_LVDS_MODE |
  127. RK3288_LVDS_CH0_REG2_LANE0_LVDS_MODE |
  128. RK3288_LVDS_PLL_FBDIV_REG2(0x46));
  129. lvds_writel(priv, RK3288_LVDS_CH0_REG3,
  130. RK3288_LVDS_PLL_FBDIV_REG3(0x46));
  131. lvds_writel(priv, RK3288_LVDS_CH0_REG4, 0x00);
  132. lvds_writel(priv, RK3288_LVDS_CH0_REG5, 0x00);
  133. lvds_writel(priv, RK3288_LVDS_CH0_REGD,
  134. RK3288_LVDS_PLL_PREDIV_REGD(0x0a));
  135. lvds_writel(priv, RK3288_LVDS_CH0_REG20,
  136. RK3288_LVDS_CH0_REG20_LSB);
  137. }
  138. /* Power on */
  139. writel(RK3288_LVDS_CFG_REGC_PLL_ENABLE,
  140. priv->regs + RK3288_LVDS_CFG_REGC);
  141. writel(RK3288_LVDS_CFG_REG21_TX_ENABLE,
  142. priv->regs + RK3288_LVDS_CFG_REG21);
  143. return 0;
  144. }
  145. int rk_lvds_read_timing(struct udevice *dev, struct display_timing *timing)
  146. {
  147. if (fdtdec_decode_display_timing
  148. (gd->fdt_blob, dev_of_offset(dev), 0, timing)) {
  149. debug("%s: Failed to decode display timing\n", __func__);
  150. return -EINVAL;
  151. }
  152. return 0;
  153. }
  154. static int rk_lvds_ofdata_to_platdata(struct udevice *dev)
  155. {
  156. struct rk_lvds_priv *priv = dev_get_priv(dev);
  157. const void *blob = gd->fdt_blob;
  158. int node = dev_of_offset(dev);
  159. int ret;
  160. priv->regs = (void *)devfdt_get_addr(dev);
  161. priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
  162. ret = fdtdec_get_int(blob, node, "rockchip,output", -1);
  163. if (ret != -1) {
  164. priv->output = ret;
  165. debug("LVDS output : %d\n", ret);
  166. } else {
  167. /* default set it as output rgb */
  168. priv->output = LVDS_OUTPUT_RGB;
  169. }
  170. ret = fdtdec_get_int(blob, node, "rockchip,data-mapping", -1);
  171. if (ret != -1) {
  172. priv->format = ret;
  173. debug("LVDS data-mapping : %d\n", ret);
  174. } else {
  175. /* default set it as format jeida */
  176. priv->format = LVDS_FORMAT_JEIDA;
  177. }
  178. ret = fdtdec_get_int(blob, node, "rockchip,data-width", -1);
  179. if (ret != -1) {
  180. debug("LVDS data-width : %d\n", ret);
  181. if (ret == 24) {
  182. priv->format |= LVDS_24BIT;
  183. } else if (ret == 18) {
  184. priv->format |= LVDS_18BIT;
  185. } else {
  186. debug("rockchip-lvds unsupport data-width[%d]\n", ret);
  187. ret = -EINVAL;
  188. return ret;
  189. }
  190. } else {
  191. priv->format |= LVDS_24BIT;
  192. }
  193. return 0;
  194. }
  195. int rk_lvds_probe(struct udevice *dev)
  196. {
  197. struct rk_lvds_priv *priv = dev_get_priv(dev);
  198. int ret;
  199. ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev, "rockchip,panel",
  200. &priv->panel);
  201. if (ret) {
  202. debug("%s: Cannot find panel for '%s' (ret=%d)\n", __func__,
  203. dev->name, ret);
  204. return ret;
  205. }
  206. return 0;
  207. }
  208. static const struct dm_display_ops lvds_rockchip_ops = {
  209. .read_timing = rk_lvds_read_timing,
  210. .enable = rk_lvds_enable,
  211. };
  212. static const struct udevice_id rockchip_lvds_ids[] = {
  213. {.compatible = "rockchip,rk3288-lvds"},
  214. {}
  215. };
  216. U_BOOT_DRIVER(lvds_rockchip) = {
  217. .name = "lvds_rockchip",
  218. .id = UCLASS_DISPLAY,
  219. .of_match = rockchip_lvds_ids,
  220. .ops = &lvds_rockchip_ops,
  221. .ofdata_to_platdata = rk_lvds_ofdata_to_platdata,
  222. .probe = rk_lvds_probe,
  223. .priv_auto_alloc_size = sizeof(struct rk_lvds_priv),
  224. };