tilcdc-panel.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * OMAP panel support
  4. *
  5. * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
  6. */
  7. #include <common.h>
  8. #include <backlight.h>
  9. #include <clk.h>
  10. #include <display.h>
  11. #include <dm.h>
  12. #include <dm/device_compat.h>
  13. #include <log.h>
  14. #include <panel.h>
  15. #include <asm/gpio.h>
  16. #include <linux/err.h>
  17. #include "tilcdc.h"
  18. struct tilcdc_panel_priv {
  19. struct tilcdc_panel_info info;
  20. struct display_timing timing;
  21. struct udevice *backlight;
  22. struct gpio_desc enable;
  23. };
  24. static int tilcdc_panel_enable_backlight(struct udevice *dev)
  25. {
  26. struct tilcdc_panel_priv *priv = dev_get_priv(dev);
  27. if (dm_gpio_is_valid(&priv->enable))
  28. dm_gpio_set_value(&priv->enable, 1);
  29. if (priv->backlight)
  30. return backlight_enable(priv->backlight);
  31. return 0;
  32. }
  33. static int tilcdc_panel_set_backlight(struct udevice *dev, int percent)
  34. {
  35. struct tilcdc_panel_priv *priv = dev_get_priv(dev);
  36. if (dm_gpio_is_valid(&priv->enable))
  37. dm_gpio_set_value(&priv->enable, 1);
  38. if (priv->backlight)
  39. return backlight_set_brightness(priv->backlight, percent);
  40. return 0;
  41. }
  42. int tilcdc_panel_get_display_info(struct udevice *dev,
  43. struct tilcdc_panel_info *info)
  44. {
  45. struct tilcdc_panel_priv *priv = dev_get_priv(dev);
  46. memcpy(info, &priv->info, sizeof(*info));
  47. return 0;
  48. }
  49. static int tilcdc_panel_get_display_timing(struct udevice *dev,
  50. struct display_timing *timing)
  51. {
  52. struct tilcdc_panel_priv *priv = dev_get_priv(dev);
  53. memcpy(timing, &priv->timing, sizeof(*timing));
  54. return 0;
  55. }
  56. static int tilcdc_panel_remove(struct udevice *dev)
  57. {
  58. struct tilcdc_panel_priv *priv = dev_get_priv(dev);
  59. if (dm_gpio_is_valid(&priv->enable))
  60. dm_gpio_free(dev, &priv->enable);
  61. return 0;
  62. }
  63. static int tilcdc_panel_probe(struct udevice *dev)
  64. {
  65. struct tilcdc_panel_priv *priv = dev_get_priv(dev);
  66. int err;
  67. err = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
  68. "backlight", &priv->backlight);
  69. if (err)
  70. dev_warn(dev, "failed to get backlight\n");
  71. err = gpio_request_by_name(dev, "enable-gpios", 0, &priv->enable,
  72. GPIOD_IS_OUT);
  73. if (err) {
  74. dev_warn(dev, "failed to get enable GPIO\n");
  75. if (err != -ENOENT)
  76. return err;
  77. }
  78. return 0;
  79. }
  80. static int tilcdc_panel_of_to_plat(struct udevice *dev)
  81. {
  82. struct tilcdc_panel_priv *priv = dev_get_priv(dev);
  83. ofnode node;
  84. int err;
  85. err = ofnode_decode_display_timing(dev_ofnode(dev), 0, &priv->timing);
  86. if (err) {
  87. dev_err(dev, "failed to get display timing\n");
  88. return err;
  89. }
  90. node = dev_read_subnode(dev, "panel-info");
  91. if (!ofnode_valid(node)) {
  92. dev_err(dev, "missing 'panel-info' node\n");
  93. return -ENXIO;
  94. }
  95. err |= ofnode_read_u32(node, "ac-bias", &priv->info.ac_bias);
  96. err |= ofnode_read_u32(node, "ac-bias-intrpt",
  97. &priv->info.ac_bias_intrpt);
  98. err |= ofnode_read_u32(node, "dma-burst-sz", &priv->info.dma_burst_sz);
  99. err |= ofnode_read_u32(node, "bpp", &priv->info.bpp);
  100. err |= ofnode_read_u32(node, "fdd", &priv->info.fdd);
  101. err |= ofnode_read_u32(node, "sync-edge", &priv->info.sync_edge);
  102. err |= ofnode_read_u32(node, "sync-ctrl", &priv->info.sync_ctrl);
  103. err |= ofnode_read_u32(node, "raster-order", &priv->info.raster_order);
  104. err |= ofnode_read_u32(node, "fifo-th", &priv->info.fifo_th);
  105. if (err) {
  106. dev_err(dev, "failed to get panel info\n");
  107. return err;
  108. }
  109. /* optional */
  110. priv->info.tft_alt_mode = ofnode_read_bool(node, "tft-alt-mode");
  111. priv->info.invert_pxl_clk = ofnode_read_bool(node, "invert-pxl-clk");
  112. dev_dbg(dev, "LCD: %dx%d, bpp=%d, clk=%d Hz\n",
  113. priv->timing.hactive.typ, priv->timing.vactive.typ,
  114. priv->info.bpp, priv->timing.pixelclock.typ);
  115. dev_dbg(dev, " hbp=%d, hfp=%d, hsw=%d\n",
  116. priv->timing.hback_porch.typ, priv->timing.hfront_porch.typ,
  117. priv->timing.hsync_len.typ);
  118. dev_dbg(dev, " vbp=%d, vfp=%d, vsw=%d\n",
  119. priv->timing.vback_porch.typ, priv->timing.vfront_porch.typ,
  120. priv->timing.vsync_len.typ);
  121. return 0;
  122. }
  123. static const struct panel_ops tilcdc_panel_ops = {
  124. .enable_backlight = tilcdc_panel_enable_backlight,
  125. .set_backlight = tilcdc_panel_set_backlight,
  126. .get_display_timing = tilcdc_panel_get_display_timing,
  127. };
  128. static const struct udevice_id tilcdc_panel_ids[] = {
  129. {.compatible = "ti,tilcdc,panel"},
  130. {}
  131. };
  132. U_BOOT_DRIVER(tilcdc_panel) = {
  133. .name = "tilcdc_panel",
  134. .id = UCLASS_PANEL,
  135. .of_match = tilcdc_panel_ids,
  136. .ops = &tilcdc_panel_ops,
  137. .of_to_plat = tilcdc_panel_of_to_plat,
  138. .probe = tilcdc_panel_probe,
  139. .remove = tilcdc_panel_remove,
  140. .priv_auto = sizeof(struct tilcdc_panel_priv),
  141. };