mtk_disp_rdma.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. /*
  2. * Copyright (c) 2015 MediaTek Inc.
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License version 2 as
  6. * published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. */
  13. #include <drm/drmP.h>
  14. #include <linux/clk.h>
  15. #include <linux/component.h>
  16. #include <linux/of_device.h>
  17. #include <linux/of_irq.h>
  18. #include <linux/platform_device.h>
  19. #include "mtk_drm_crtc.h"
  20. #include "mtk_drm_ddp_comp.h"
  21. #define DISP_REG_RDMA_INT_ENABLE 0x0000
  22. #define DISP_REG_RDMA_INT_STATUS 0x0004
  23. #define RDMA_TARGET_LINE_INT BIT(5)
  24. #define RDMA_FIFO_UNDERFLOW_INT BIT(4)
  25. #define RDMA_EOF_ABNORMAL_INT BIT(3)
  26. #define RDMA_FRAME_END_INT BIT(2)
  27. #define RDMA_FRAME_START_INT BIT(1)
  28. #define RDMA_REG_UPDATE_INT BIT(0)
  29. #define DISP_REG_RDMA_GLOBAL_CON 0x0010
  30. #define RDMA_ENGINE_EN BIT(0)
  31. #define DISP_REG_RDMA_SIZE_CON_0 0x0014
  32. #define DISP_REG_RDMA_SIZE_CON_1 0x0018
  33. #define DISP_REG_RDMA_TARGET_LINE 0x001c
  34. #define DISP_REG_RDMA_FIFO_CON 0x0040
  35. #define RDMA_FIFO_UNDERFLOW_EN BIT(31)
  36. #define RDMA_FIFO_PSEUDO_SIZE(bytes) (((bytes) / 16) << 16)
  37. #define RDMA_OUTPUT_VALID_FIFO_THRESHOLD(bytes) ((bytes) / 16)
  38. #define RDMA_FIFO_SIZE(rdma) ((rdma)->data->fifo_size)
  39. struct mtk_disp_rdma_data {
  40. unsigned int fifo_size;
  41. };
  42. /**
  43. * struct mtk_disp_rdma - DISP_RDMA driver structure
  44. * @ddp_comp - structure containing type enum and hardware resources
  45. * @crtc - associated crtc to report irq events to
  46. */
  47. struct mtk_disp_rdma {
  48. struct mtk_ddp_comp ddp_comp;
  49. struct drm_crtc *crtc;
  50. const struct mtk_disp_rdma_data *data;
  51. };
  52. static inline struct mtk_disp_rdma *comp_to_rdma(struct mtk_ddp_comp *comp)
  53. {
  54. return container_of(comp, struct mtk_disp_rdma, ddp_comp);
  55. }
  56. static irqreturn_t mtk_disp_rdma_irq_handler(int irq, void *dev_id)
  57. {
  58. struct mtk_disp_rdma *priv = dev_id;
  59. struct mtk_ddp_comp *rdma = &priv->ddp_comp;
  60. /* Clear frame completion interrupt */
  61. writel(0x0, rdma->regs + DISP_REG_RDMA_INT_STATUS);
  62. if (!priv->crtc)
  63. return IRQ_NONE;
  64. mtk_crtc_ddp_irq(priv->crtc, rdma);
  65. return IRQ_HANDLED;
  66. }
  67. static void rdma_update_bits(struct mtk_ddp_comp *comp, unsigned int reg,
  68. unsigned int mask, unsigned int val)
  69. {
  70. unsigned int tmp = readl(comp->regs + reg);
  71. tmp = (tmp & ~mask) | (val & mask);
  72. writel(tmp, comp->regs + reg);
  73. }
  74. static void mtk_rdma_enable_vblank(struct mtk_ddp_comp *comp,
  75. struct drm_crtc *crtc)
  76. {
  77. struct mtk_disp_rdma *rdma = comp_to_rdma(comp);
  78. rdma->crtc = crtc;
  79. rdma_update_bits(comp, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT,
  80. RDMA_FRAME_END_INT);
  81. }
  82. static void mtk_rdma_disable_vblank(struct mtk_ddp_comp *comp)
  83. {
  84. struct mtk_disp_rdma *rdma = comp_to_rdma(comp);
  85. rdma->crtc = NULL;
  86. rdma_update_bits(comp, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT, 0);
  87. }
  88. static void mtk_rdma_start(struct mtk_ddp_comp *comp)
  89. {
  90. rdma_update_bits(comp, DISP_REG_RDMA_GLOBAL_CON, RDMA_ENGINE_EN,
  91. RDMA_ENGINE_EN);
  92. }
  93. static void mtk_rdma_stop(struct mtk_ddp_comp *comp)
  94. {
  95. rdma_update_bits(comp, DISP_REG_RDMA_GLOBAL_CON, RDMA_ENGINE_EN, 0);
  96. }
  97. static void mtk_rdma_config(struct mtk_ddp_comp *comp, unsigned int width,
  98. unsigned int height, unsigned int vrefresh,
  99. unsigned int bpc)
  100. {
  101. unsigned int threshold;
  102. unsigned int reg;
  103. struct mtk_disp_rdma *rdma = comp_to_rdma(comp);
  104. rdma_update_bits(comp, DISP_REG_RDMA_SIZE_CON_0, 0xfff, width);
  105. rdma_update_bits(comp, DISP_REG_RDMA_SIZE_CON_1, 0xfffff, height);
  106. /*
  107. * Enable FIFO underflow since DSI and DPI can't be blocked.
  108. * Keep the FIFO pseudo size reset default of 8 KiB. Set the
  109. * output threshold to 6 microseconds with 7/6 overhead to
  110. * account for blanking, and with a pixel depth of 4 bytes:
  111. */
  112. threshold = width * height * vrefresh * 4 * 7 / 1000000;
  113. reg = RDMA_FIFO_UNDERFLOW_EN |
  114. RDMA_FIFO_PSEUDO_SIZE(RDMA_FIFO_SIZE(rdma)) |
  115. RDMA_OUTPUT_VALID_FIFO_THRESHOLD(threshold);
  116. writel(reg, comp->regs + DISP_REG_RDMA_FIFO_CON);
  117. }
  118. static const struct mtk_ddp_comp_funcs mtk_disp_rdma_funcs = {
  119. .config = mtk_rdma_config,
  120. .start = mtk_rdma_start,
  121. .stop = mtk_rdma_stop,
  122. .enable_vblank = mtk_rdma_enable_vblank,
  123. .disable_vblank = mtk_rdma_disable_vblank,
  124. };
  125. static int mtk_disp_rdma_bind(struct device *dev, struct device *master,
  126. void *data)
  127. {
  128. struct mtk_disp_rdma *priv = dev_get_drvdata(dev);
  129. struct drm_device *drm_dev = data;
  130. int ret;
  131. ret = mtk_ddp_comp_register(drm_dev, &priv->ddp_comp);
  132. if (ret < 0) {
  133. dev_err(dev, "Failed to register component %pOF: %d\n",
  134. dev->of_node, ret);
  135. return ret;
  136. }
  137. return 0;
  138. }
  139. static void mtk_disp_rdma_unbind(struct device *dev, struct device *master,
  140. void *data)
  141. {
  142. struct mtk_disp_rdma *priv = dev_get_drvdata(dev);
  143. struct drm_device *drm_dev = data;
  144. mtk_ddp_comp_unregister(drm_dev, &priv->ddp_comp);
  145. }
  146. static const struct component_ops mtk_disp_rdma_component_ops = {
  147. .bind = mtk_disp_rdma_bind,
  148. .unbind = mtk_disp_rdma_unbind,
  149. };
  150. static int mtk_disp_rdma_probe(struct platform_device *pdev)
  151. {
  152. struct device *dev = &pdev->dev;
  153. struct mtk_disp_rdma *priv;
  154. int comp_id;
  155. int irq;
  156. int ret;
  157. priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  158. if (!priv)
  159. return -ENOMEM;
  160. irq = platform_get_irq(pdev, 0);
  161. if (irq < 0)
  162. return irq;
  163. comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DISP_RDMA);
  164. if (comp_id < 0) {
  165. dev_err(dev, "Failed to identify by alias: %d\n", comp_id);
  166. return comp_id;
  167. }
  168. ret = mtk_ddp_comp_init(dev, dev->of_node, &priv->ddp_comp, comp_id,
  169. &mtk_disp_rdma_funcs);
  170. if (ret) {
  171. dev_err(dev, "Failed to initialize component: %d\n", ret);
  172. return ret;
  173. }
  174. /* Disable and clear pending interrupts */
  175. writel(0x0, priv->ddp_comp.regs + DISP_REG_RDMA_INT_ENABLE);
  176. writel(0x0, priv->ddp_comp.regs + DISP_REG_RDMA_INT_STATUS);
  177. ret = devm_request_irq(dev, irq, mtk_disp_rdma_irq_handler,
  178. IRQF_TRIGGER_NONE, dev_name(dev), priv);
  179. if (ret < 0) {
  180. dev_err(dev, "Failed to request irq %d: %d\n", irq, ret);
  181. return ret;
  182. }
  183. priv->data = of_device_get_match_data(dev);
  184. platform_set_drvdata(pdev, priv);
  185. ret = component_add(dev, &mtk_disp_rdma_component_ops);
  186. if (ret)
  187. dev_err(dev, "Failed to add component: %d\n", ret);
  188. return ret;
  189. }
  190. static int mtk_disp_rdma_remove(struct platform_device *pdev)
  191. {
  192. component_del(&pdev->dev, &mtk_disp_rdma_component_ops);
  193. return 0;
  194. }
  195. static const struct mtk_disp_rdma_data mt2701_rdma_driver_data = {
  196. .fifo_size = SZ_4K,
  197. };
  198. static const struct mtk_disp_rdma_data mt8173_rdma_driver_data = {
  199. .fifo_size = SZ_8K,
  200. };
  201. static const struct of_device_id mtk_disp_rdma_driver_dt_match[] = {
  202. { .compatible = "mediatek,mt2701-disp-rdma",
  203. .data = &mt2701_rdma_driver_data},
  204. { .compatible = "mediatek,mt8173-disp-rdma",
  205. .data = &mt8173_rdma_driver_data},
  206. {},
  207. };
  208. MODULE_DEVICE_TABLE(of, mtk_disp_rdma_driver_dt_match);
  209. struct platform_driver mtk_disp_rdma_driver = {
  210. .probe = mtk_disp_rdma_probe,
  211. .remove = mtk_disp_rdma_remove,
  212. .driver = {
  213. .name = "mediatek-disp-rdma",
  214. .owner = THIS_MODULE,
  215. .of_match_table = mtk_disp_rdma_driver_dt_match,
  216. },
  217. };