mtk_disp_merge.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  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 <linux/pm_runtime.h>
  20. #include <linux/soc/mediatek/mtk-cmdq.h>
  21. #include "mtk_drm_crtc.h"
  22. #include "mtk_drm_ddp_comp.h"
  23. #include "mtk_dump.h"
  24. #include "mtk_rect.h"
  25. #include "mtk_drm_drv.h"
  26. #define DISP_REG_MERGE_CTRL (0x000)
  27. #define FLD_MERGE_EN REG_FLD_MSB_LSB(0, 0)
  28. #define FLD_MERGE_RST REG_FLD_MSB_LSB(4, 4)
  29. #define FLD_MERGE_LR_SWAP REG_FLD_MSB_LSB(8, 8)
  30. #define FLD_MERGE_DCM_DIS REG_FLD_MSB_LSB(12, 12)
  31. #define DISP_REG_MERGE_WIDTH (0x004)
  32. #define FLD_IN_WIDHT_L REG_FLD_MSB_LSB(15, 0)
  33. #define FLD_IN_WIDHT_R REG_FLD_MSB_LSB(31, 16)
  34. #define DISP_REG_MERGE_HEIGHT (0x008)
  35. #define FLD_IN_HEIGHT REG_FLD_MSB_LSB(15, 0)
  36. #define DISP_REG_MERGE_SHADOW_CRTL (0x00C)
  37. #define DISP_REG_MERGE_DGB0 (0x010)
  38. #define FLD_PIXEL_CNT REG_FLD_MSB_LSB(15, 0)
  39. #define FLD_MERGE_STATE REG_FLD_MSB_LSB(17, 16)
  40. #define DISP_REG_MERGE_DGB1 (0x014)
  41. #define FLD_LINE_CNT REG_FLD_MSB_LSB(15, 0)
  42. struct mtk_merge_config_struct {
  43. unsigned short width_right;
  44. unsigned short width_left;
  45. unsigned int height;
  46. };
  47. struct mtk_disp_merge {
  48. struct mtk_ddp_comp ddp_comp;
  49. struct drm_crtc *crtc;
  50. };
  51. static inline struct mtk_disp_merge *comp_to_merge(struct mtk_ddp_comp *comp)
  52. {
  53. return container_of(comp, struct mtk_disp_merge, ddp_comp);
  54. }
  55. static void mtk_merge_start(struct mtk_ddp_comp *comp, struct cmdq_pkt *handle)
  56. {
  57. int ret;
  58. ret = pm_runtime_get_sync(comp->dev);
  59. if (ret < 0)
  60. DRM_ERROR("Failed to enable power domain: %d\n", ret);
  61. DDPMSG("%s\n", __func__);
  62. cmdq_pkt_write(handle, comp->cmdq_base,
  63. comp->regs_pa + DISP_REG_MERGE_CTRL, 0x1, ~0);
  64. }
  65. static void mtk_merge_stop(struct mtk_ddp_comp *comp, struct cmdq_pkt *handle)
  66. {
  67. int ret;
  68. DDPMSG("%s\n", __func__);
  69. ret = pm_runtime_put(comp->dev);
  70. if (ret < 0)
  71. DRM_ERROR("Failed to disable power domain: %d\n", ret);
  72. cmdq_pkt_write(handle, comp->cmdq_base,
  73. comp->regs_pa + DISP_REG_MERGE_CTRL, 0x0, ~0);
  74. }
  75. static int mtk_merge_check_params(struct mtk_merge_config_struct *merge_config)
  76. {
  77. if (!merge_config->height || !merge_config->width_left
  78. || !merge_config->width_right) {
  79. DDPPR_ERR("%s:merge input width l(%u) w(%u) h(%u)\n",
  80. __func__, merge_config->width_left,
  81. merge_config->width_right, merge_config->height);
  82. return -EINVAL;
  83. }
  84. DDPMSG("%s:merge input width l(%u) r(%u) height(%u)\n",
  85. __func__, merge_config->width_left,
  86. merge_config->width_right, merge_config->height);
  87. return 0;
  88. }
  89. static void mtk_merge_config(struct mtk_ddp_comp *comp,
  90. struct mtk_ddp_config *cfg,
  91. struct cmdq_pkt *handle)
  92. {
  93. struct mtk_merge_config_struct merge_config;
  94. merge_config.height = cfg->h;
  95. merge_config.width_left = cfg->w / 2;
  96. merge_config.width_right = cfg->w / 2;
  97. mtk_merge_check_params(&merge_config);
  98. DDPMSG("%s\n", __func__);
  99. cmdq_pkt_write(handle, comp->cmdq_base,
  100. comp->regs_pa + DISP_REG_MERGE_WIDTH,
  101. merge_config.width_left | (merge_config.width_right << 16),
  102. ~0);
  103. cmdq_pkt_write(handle, comp->cmdq_base,
  104. comp->regs_pa + DISP_REG_MERGE_HEIGHT,
  105. merge_config.height, ~0);
  106. }
  107. void mtk_merge_dump(struct mtk_ddp_comp *comp)
  108. {
  109. void __iomem *baddr = comp->regs;
  110. int i = 0;
  111. DDPDUMP("== DISP %s REGS ==\n", mtk_dump_comp_str(comp));
  112. for (i = 0; i < 1; i++) {
  113. DDPDUMP("0x%03X: 0x%08x 0x%08x 0x%08x 0x%08x\n", i * 0x10,
  114. readl(baddr + i * 0x10), readl(baddr + i * 0x10 + 0x4),
  115. readl(baddr + i * 0x10 + 0x8),
  116. readl(baddr + i * 0x10 + 0xC));
  117. }
  118. DDPDUMP("0x010: 0x%08x 0x%08x;\n", readl(baddr + 0x10),
  119. readl(baddr + 0x14));
  120. }
  121. int mtk_merge_analysis(struct mtk_ddp_comp *comp)
  122. {
  123. void __iomem *baddr = comp->regs;
  124. u32 width = 0;
  125. u32 height = 0;
  126. u32 enable = 0;
  127. u32 dbg0 = 0;
  128. u32 dbg1 = 0;
  129. const int len = 100;
  130. char msg[len];
  131. int n = 0;
  132. enable = readl(baddr + DISP_REG_MERGE_CTRL);
  133. width = readl(baddr + DISP_REG_MERGE_WIDTH);
  134. height = readl(baddr + DISP_REG_MERGE_HEIGHT);
  135. dbg0 = readl(baddr + DISP_REG_MERGE_DGB0);
  136. dbg1 = readl(baddr + DISP_REG_MERGE_DGB1);
  137. DDPDUMP("== DISP %s ANALYSIS ==\n", mtk_dump_comp_str(comp));
  138. n = snprintf(msg, len,
  139. "en:%d,swap:%d,dcm_dis:%d,width_L:%d,width_R:%d,h:%d,pix_cnt:%d,line_cnt:%d\n",
  140. REG_FLD_VAL_GET(FLD_MERGE_EN, enable),
  141. REG_FLD_VAL_GET(FLD_MERGE_LR_SWAP, enable),
  142. REG_FLD_VAL_GET(FLD_MERGE_DCM_DIS, enable),
  143. REG_FLD_VAL_GET(FLD_IN_WIDHT_L, width),
  144. REG_FLD_VAL_GET(FLD_IN_WIDHT_R, width),
  145. REG_FLD_VAL_GET(FLD_IN_HEIGHT, height),
  146. REG_FLD_VAL_GET(FLD_PIXEL_CNT, dbg0),
  147. REG_FLD_VAL_GET(FLD_MERGE_STATE, dbg0),
  148. REG_FLD_VAL_GET(FLD_LINE_CNT, dbg1));
  149. DDPDUMP("%s", msg);
  150. return 0;
  151. }
  152. static void mtk_merge_prepare(struct mtk_ddp_comp *comp)
  153. {
  154. mtk_ddp_comp_clk_prepare(comp);
  155. }
  156. static void mtk_merge_unprepare(struct mtk_ddp_comp *comp)
  157. {
  158. mtk_ddp_comp_clk_unprepare(comp);
  159. }
  160. static const struct mtk_ddp_comp_funcs mtk_disp_merge_funcs = {
  161. .start = mtk_merge_start,
  162. .stop = mtk_merge_stop,
  163. .config = mtk_merge_config,
  164. .prepare = mtk_merge_prepare,
  165. .unprepare = mtk_merge_unprepare,
  166. };
  167. static int mtk_disp_merge_bind(struct device *dev, struct device *master,
  168. void *data)
  169. {
  170. struct mtk_disp_merge *priv = dev_get_drvdata(dev);
  171. struct drm_device *drm_dev = data;
  172. //struct mtk_drm_private *private = drm_dev->dev_private;
  173. int ret;
  174. pr_info("%s\n", __func__);
  175. ret = mtk_ddp_comp_register(drm_dev, &priv->ddp_comp);
  176. if (ret < 0) {
  177. dev_err(dev, "Failed to register component %s: %d\n",
  178. dev->of_node->full_name, ret);
  179. return ret;
  180. }
  181. pr_info("%s end\n", __func__);
  182. return 0;
  183. }
  184. static void mtk_disp_merge_unbind(struct device *dev, struct device *master,
  185. void *data)
  186. {
  187. struct mtk_disp_merge *priv = dev_get_drvdata(dev);
  188. struct drm_device *drm_dev = data;
  189. mtk_ddp_comp_unregister(drm_dev, &priv->ddp_comp);
  190. }
  191. static const struct component_ops mtk_disp_merge_component_ops = {
  192. .bind = mtk_disp_merge_bind, .unbind = mtk_disp_merge_unbind,
  193. };
  194. static int mtk_disp_merge_probe(struct platform_device *pdev)
  195. {
  196. struct device *dev = &pdev->dev;
  197. struct mtk_disp_merge *priv;
  198. enum mtk_ddp_comp_id comp_id;
  199. int ret;
  200. pr_info("%s+\n", __func__);
  201. priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  202. if (!priv)
  203. return -ENOMEM;
  204. comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DISP_MERGE);
  205. if ((int)comp_id < 0) {
  206. dev_err(dev, "Failed to identify by alias: %d\n", comp_id);
  207. return comp_id;
  208. }
  209. ret = mtk_ddp_comp_init(dev, dev->of_node, &priv->ddp_comp, comp_id,
  210. &mtk_disp_merge_funcs);
  211. if (ret) {
  212. dev_err(dev, "Failed to initialize component: %d\n", ret);
  213. return ret;
  214. }
  215. //priv->data = of_device_get_match_data(dev);
  216. platform_set_drvdata(pdev, priv);
  217. pm_runtime_enable(dev);
  218. ret = component_add(dev, &mtk_disp_merge_component_ops);
  219. if (ret != 0) {
  220. dev_err(dev, "Failed to add component: %d\n", ret);
  221. pm_runtime_disable(dev);
  222. }
  223. pr_info("%s-\n", __func__);
  224. return ret;
  225. }
  226. static int mtk_disp_merge_remove(struct platform_device *pdev)
  227. {
  228. component_del(&pdev->dev, &mtk_disp_merge_component_ops);
  229. pm_runtime_disable(&pdev->dev);
  230. return 0;
  231. }
  232. static const struct of_device_id mtk_disp_merge_driver_dt_match[] = {
  233. {.compatible = "mediatek,mt6779-disp-merge", },
  234. {.compatible = "mediatek,mt6885-disp-merge", },
  235. {},
  236. };
  237. MODULE_DEVICE_TABLE(of, mtk_disp_merge_driver_dt_match);
  238. struct platform_driver mtk_disp_merge_driver = {
  239. .probe = mtk_disp_merge_probe,
  240. .remove = mtk_disp_merge_remove,
  241. .driver = {
  242. .name = "mediatek-disp-merge",
  243. .owner = THIS_MODULE,
  244. .of_match_table = mtk_disp_merge_driver_dt_match,
  245. },
  246. };