rk3288_hdmi.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH
  4. */
  5. #include <common.h>
  6. #include <clk.h>
  7. #include <display.h>
  8. #include <dm.h>
  9. #include <dw_hdmi.h>
  10. #include <edid.h>
  11. #include <log.h>
  12. #include <malloc.h>
  13. #include <regmap.h>
  14. #include <syscon.h>
  15. #include <asm/gpio.h>
  16. #include <asm/io.h>
  17. #include <asm/arch-rockchip/clock.h>
  18. #include <asm/arch-rockchip/hardware.h>
  19. #include <asm/arch-rockchip/grf_rk3288.h>
  20. #include <power/regulator.h>
  21. #include "rk_hdmi.h"
  22. static int rk3288_hdmi_enable(struct udevice *dev, int panel_bpp,
  23. const struct display_timing *edid)
  24. {
  25. struct rk_hdmi_priv *priv = dev_get_priv(dev);
  26. struct display_plat *uc_plat = dev_get_uclass_platdata(dev);
  27. int vop_id = uc_plat->source_id;
  28. struct rk3288_grf *grf = priv->grf;
  29. /* hdmi source select hdmi controller */
  30. rk_setreg(&grf->soc_con6, 1 << 15);
  31. /* hdmi data from vop id */
  32. rk_clrsetreg(&grf->soc_con6, 1 << 4, (vop_id == 1) ? (1 << 4) : 0);
  33. return dw_hdmi_enable(&priv->hdmi, edid);
  34. }
  35. static int rk3288_hdmi_ofdata_to_platdata(struct udevice *dev)
  36. {
  37. struct rk_hdmi_priv *priv = dev_get_priv(dev);
  38. struct dw_hdmi *hdmi = &priv->hdmi;
  39. hdmi->i2c_clk_high = 0x7a;
  40. hdmi->i2c_clk_low = 0x8d;
  41. /*
  42. * TODO(sjg@chromium.org): The above values don't work - these
  43. * ones work better, but generate lots of errors in the data.
  44. */
  45. hdmi->i2c_clk_high = 0x0d;
  46. hdmi->i2c_clk_low = 0x0d;
  47. return rk_hdmi_ofdata_to_platdata(dev);
  48. }
  49. static int rk3288_clk_config(struct udevice *dev)
  50. {
  51. struct display_plat *uc_plat = dev_get_uclass_platdata(dev);
  52. struct clk clk;
  53. int ret;
  54. /*
  55. * Configure the maximum clock to permit whatever resolution the
  56. * monitor wants
  57. */
  58. ret = clk_get_by_index(uc_plat->src_dev, 0, &clk);
  59. if (ret >= 0) {
  60. ret = clk_set_rate(&clk, 384000000);
  61. clk_free(&clk);
  62. }
  63. if (ret < 0) {
  64. debug("%s: Failed to set clock in source device '%s': ret=%d\n",
  65. __func__, uc_plat->src_dev->name, ret);
  66. return ret;
  67. }
  68. return 0;
  69. }
  70. static const char * const rk3288_regulator_names[] = {
  71. "vcc50_hdmi"
  72. };
  73. static int rk3288_hdmi_probe(struct udevice *dev)
  74. {
  75. /* Enable VOP clock for RK3288 */
  76. rk3288_clk_config(dev);
  77. /* Enable regulators required for HDMI */
  78. rk_hdmi_probe_regulators(dev, rk3288_regulator_names,
  79. ARRAY_SIZE(rk3288_regulator_names));
  80. return rk_hdmi_probe(dev);
  81. }
  82. static const struct dm_display_ops rk3288_hdmi_ops = {
  83. .read_edid = rk_hdmi_read_edid,
  84. .enable = rk3288_hdmi_enable,
  85. };
  86. static const struct udevice_id rk3288_hdmi_ids[] = {
  87. { .compatible = "rockchip,rk3288-dw-hdmi" },
  88. { }
  89. };
  90. U_BOOT_DRIVER(rk3288_hdmi_rockchip) = {
  91. .name = "rk3288_hdmi_rockchip",
  92. .id = UCLASS_DISPLAY,
  93. .of_match = rk3288_hdmi_ids,
  94. .ops = &rk3288_hdmi_ops,
  95. .ofdata_to_platdata = rk3288_hdmi_ofdata_to_platdata,
  96. .probe = rk3288_hdmi_probe,
  97. .priv_auto_alloc_size = sizeof(struct rk_hdmi_priv),
  98. };