rk3288_mipi.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd
  4. * Author: Eric Gao <eric.gao@rock-chips.com>
  5. */
  6. #include <common.h>
  7. #include <clk.h>
  8. #include <display.h>
  9. #include <dm.h>
  10. #include <log.h>
  11. #include <panel.h>
  12. #include <regmap.h>
  13. #include "rk_mipi.h"
  14. #include <syscon.h>
  15. #include <asm/gpio.h>
  16. #include <asm/io.h>
  17. #include <dm/uclass-internal.h>
  18. #include <linux/err.h>
  19. #include <linux/kernel.h>
  20. #include <asm/arch-rockchip/clock.h>
  21. #include <asm/arch-rockchip/cru.h>
  22. #include <asm/arch-rockchip/grf_rk3288.h>
  23. #include <asm/arch-rockchip/hardware.h>
  24. #include <asm/arch-rockchip/rockchip_mipi_dsi.h>
  25. #define MHz 1000000
  26. /* Select mipi dsi source, big or little vop */
  27. static int rk_mipi_dsi_source_select(struct udevice *dev)
  28. {
  29. struct rk_mipi_priv *priv = dev_get_priv(dev);
  30. struct rk3288_grf *grf = priv->grf;
  31. struct display_plat *disp_uc_plat = dev_get_uclass_platdata(dev);
  32. /* Select the video source */
  33. switch (disp_uc_plat->source_id) {
  34. case VOP_B:
  35. rk_clrsetreg(&grf->soc_con6, RK3288_DSI0_LCDC_SEL_MASK,
  36. RK3288_DSI0_LCDC_SEL_BIG
  37. << RK3288_DSI0_LCDC_SEL_SHIFT);
  38. break;
  39. case VOP_L:
  40. rk_clrsetreg(&grf->soc_con6, RK3288_DSI0_LCDC_SEL_MASK,
  41. RK3288_DSI0_LCDC_SEL_LIT
  42. << RK3288_DSI0_LCDC_SEL_SHIFT);
  43. break;
  44. default:
  45. debug("%s: Invalid VOP id\n", __func__);
  46. return -EINVAL;
  47. }
  48. return 0;
  49. }
  50. /* Setup mipi dphy working mode */
  51. static void rk_mipi_dphy_mode_set(struct udevice *dev)
  52. {
  53. struct rk_mipi_priv *priv = dev_get_priv(dev);
  54. struct rk3288_grf *grf = priv->grf;
  55. int val;
  56. /* Set Controller as TX mode */
  57. val = RK3288_DPHY_TX0_RXMODE_DIS << RK3288_DPHY_TX0_RXMODE_SHIFT;
  58. rk_clrsetreg(&grf->soc_con8, RK3288_DPHY_TX0_RXMODE_MASK, val);
  59. /* Exit tx stop mode */
  60. val |= RK3288_DPHY_TX0_TXSTOPMODE_EN
  61. << RK3288_DPHY_TX0_TXSTOPMODE_SHIFT;
  62. rk_clrsetreg(&grf->soc_con8,
  63. RK3288_DPHY_TX0_TXSTOPMODE_MASK, val);
  64. /* Disable turnequest */
  65. val |= RK3288_DPHY_TX0_TURNREQUEST_EN
  66. << RK3288_DPHY_TX0_TURNREQUEST_SHIFT;
  67. rk_clrsetreg(&grf->soc_con8,
  68. RK3288_DPHY_TX0_TURNREQUEST_MASK, val);
  69. }
  70. /*
  71. * This function is called by rk_display_init() using rk_mipi_dsi_enable() and
  72. * rk_mipi_phy_enable() to initialize mipi controller and dphy. If success,
  73. * enable backlight.
  74. */
  75. static int rk_mipi_enable(struct udevice *dev, int panel_bpp,
  76. const struct display_timing *timing)
  77. {
  78. int ret;
  79. struct rk_mipi_priv *priv = dev_get_priv(dev);
  80. /* Fill the mipi controller parameter */
  81. priv->ref_clk = 24 * MHz;
  82. priv->sys_clk = priv->ref_clk;
  83. priv->pix_clk = timing->pixelclock.typ;
  84. priv->phy_clk = priv->pix_clk * 6;
  85. priv->txbyte_clk = priv->phy_clk / 8;
  86. priv->txesc_clk = 20 * MHz;
  87. /* Select vop port, big or little */
  88. rk_mipi_dsi_source_select(dev);
  89. /* Set mipi dphy work mode */
  90. rk_mipi_dphy_mode_set(dev);
  91. /* Config and enable mipi dsi according to timing */
  92. ret = rk_mipi_dsi_enable(dev, timing);
  93. if (ret) {
  94. debug("%s: rk_mipi_dsi_enable() failed (err=%d)\n",
  95. __func__, ret);
  96. return ret;
  97. }
  98. /* Config and enable mipi phy */
  99. ret = rk_mipi_phy_enable(dev);
  100. if (ret) {
  101. debug("%s: rk_mipi_phy_enable() failed (err=%d)\n",
  102. __func__, ret);
  103. return ret;
  104. }
  105. /* Enable backlight */
  106. ret = panel_enable_backlight(priv->panel);
  107. if (ret) {
  108. debug("%s: panel_enable_backlight() failed (err=%d)\n",
  109. __func__, ret);
  110. return ret;
  111. }
  112. return 0;
  113. }
  114. static int rk_mipi_ofdata_to_platdata(struct udevice *dev)
  115. {
  116. struct rk_mipi_priv *priv = dev_get_priv(dev);
  117. priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
  118. if (IS_ERR_OR_NULL(priv->grf)) {
  119. debug("%s: Get syscon grf failed (ret=%p)\n",
  120. __func__, priv->grf);
  121. return -ENXIO;
  122. }
  123. priv->regs = dev_read_addr(dev);
  124. if (priv->regs == FDT_ADDR_T_NONE) {
  125. debug("%s: Get MIPI dsi address failed (ret=%lu)\n", __func__,
  126. priv->regs);
  127. return -ENXIO;
  128. }
  129. return 0;
  130. }
  131. /*
  132. * Probe function: check panel existence and readingit's timing. Then config
  133. * mipi dsi controller and enable it according to the timing parameter.
  134. */
  135. static int rk_mipi_probe(struct udevice *dev)
  136. {
  137. int ret;
  138. struct rk_mipi_priv *priv = dev_get_priv(dev);
  139. ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev, "rockchip,panel",
  140. &priv->panel);
  141. if (ret) {
  142. debug("%s: Can not find panel (err=%d)\n", __func__, ret);
  143. return ret;
  144. }
  145. return 0;
  146. }
  147. static const struct dm_display_ops rk_mipi_dsi_ops = {
  148. .read_timing = rk_mipi_read_timing,
  149. .enable = rk_mipi_enable,
  150. };
  151. static const struct udevice_id rk_mipi_dsi_ids[] = {
  152. { .compatible = "rockchip,rk3288_mipi_dsi" },
  153. { }
  154. };
  155. U_BOOT_DRIVER(rk_mipi_dsi) = {
  156. .name = "rk_mipi_dsi",
  157. .id = UCLASS_DISPLAY,
  158. .of_match = rk_mipi_dsi_ids,
  159. .ofdata_to_platdata = rk_mipi_ofdata_to_platdata,
  160. .probe = rk_mipi_probe,
  161. .ops = &rk_mipi_dsi_ops,
  162. .priv_auto_alloc_size = sizeof(struct rk_mipi_priv),
  163. };