mtk_writeback.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /*
  2. * Copyright (c) 2017 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 <drm/drm_atomic_helper.h>
  15. #include <drm/drm_crtc_helper.h>
  16. #include <drm/drm_writeback.h>
  17. #include "mtk_drm_ddp.h"
  18. #include "mtk_drm_ddp_comp.h"
  19. #include "mtk_drm_drv.h"
  20. #include "mtk_drm_gem.h"
  21. #include "mtk_drm_fb.h"
  22. #include "mtk_writeback.h"
  23. #define DISP_REG_WDMA_DST_ADDR 0x0f00
  24. #define WDMA_BUFFER_SIZE(v, h) ((v) * (h)*3)
  25. static enum mtk_ddp_comp_id mtk_wb_main[] = {
  26. DDP_COMPONENT_OD, DDP_COMPONENT_WDMA0,
  27. };
  28. static enum mtk_ddp_comp_id mtk_wb_ext[] = {
  29. DDP_COMPONENT_OD1, DDP_COMPONENT_WDMA1,
  30. };
  31. static const u32 wb_output_formats[] = {
  32. DRM_FORMAT_RGB888,
  33. };
  34. static enum drm_connector_status
  35. mtk_wb_connector_detect(struct drm_connector *connector, bool force)
  36. {
  37. return connector_status_connected;
  38. }
  39. static int mtk_wb_connector_get_modes(struct drm_connector *connector)
  40. {
  41. struct drm_device *dev = connector->dev;
  42. return drm_add_modes_noedid(connector, dev->mode_config.max_width,
  43. dev->mode_config.max_height);
  44. }
  45. static enum drm_mode_status
  46. mtk_wb_connector_mode_valid(struct drm_connector *connector,
  47. struct drm_display_mode *mode)
  48. {
  49. struct drm_device *dev = connector->dev;
  50. struct drm_mode_config *mode_config = &dev->mode_config;
  51. int w = mode->hdisplay, h = mode->vdisplay;
  52. if ((w < mode_config->min_width) || (w > mode_config->max_width))
  53. return MODE_BAD_HVALUE;
  54. if ((h < mode_config->min_height) || (h > mode_config->max_height))
  55. return MODE_BAD_VVALUE;
  56. return MODE_OK;
  57. }
  58. static int mtk_wb_atomic_check(struct drm_encoder *encoder,
  59. struct drm_crtc_state *crtc_state,
  60. struct drm_connector_state *conn_state)
  61. {
  62. return 0;
  63. }
  64. static const struct drm_encoder_helper_funcs mtk_wb_encoder_helper_funcs = {
  65. .atomic_check = mtk_wb_atomic_check,
  66. };
  67. static const struct drm_connector_funcs mtk_wb_connector_funcs = {
  68. /* .dpms = drm_atomic_helper_connector_dpms, */
  69. .detect = mtk_wb_connector_detect,
  70. .fill_modes = drm_helper_probe_single_connector_modes,
  71. .destroy = drm_connector_cleanup,
  72. .reset = drm_atomic_helper_connector_reset,
  73. .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
  74. .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
  75. };
  76. static const struct drm_connector_helper_funcs mtk_wb_connector_helper_funcs = {
  77. .get_modes = mtk_wb_connector_get_modes,
  78. .mode_valid = mtk_wb_connector_mode_valid,
  79. };
  80. static struct mtk_ddp_comp *mtk_wb_find_wdma(struct mtk_drm_crtc *mtk_crtc)
  81. {
  82. struct mtk_ddp_comp *wdma = NULL;
  83. wdma = mtk_ddp_comp_find_by_id(&mtk_crtc->base, mtk_wb_main[1]);
  84. if (wdma == NULL)
  85. wdma = mtk_ddp_comp_find_by_id(&mtk_crtc->base, mtk_wb_ext[1]);
  86. return wdma;
  87. }
  88. void mtk_wb_remove_comp_from_path(struct mtk_drm_crtc *mtk_crtc)
  89. {
  90. struct mtk_ddp_comp *wdma = NULL;
  91. wdma = mtk_wb_find_wdma(mtk_crtc);
  92. if (wdma == NULL)
  93. return;
  94. drm_framebuffer_remove(wdma->fb);
  95. if (wdma->id == mtk_wb_main[1]) {
  96. mtk_ddp_remove_comp_from_path(mtk_crtc->config_regs,
  97. mtk_crtc->mmsys_reg_data,
  98. mtk_wb_main[0], mtk_wb_main[1]);
  99. } else if (wdma->id == mtk_wb_ext[1]) {
  100. mtk_ddp_remove_comp_from_path(mtk_crtc->config_regs,
  101. mtk_crtc->mmsys_reg_data,
  102. mtk_wb_ext[0], mtk_wb_ext[1]);
  103. } else {
  104. return;
  105. }
  106. }
  107. int mtk_wb_set_possible_crtcs(struct drm_device *drm_dev,
  108. struct mtk_drm_crtc *mtk_crtc,
  109. unsigned long possible_crtc)
  110. {
  111. struct drm_writeback_connector *wb_connector = &mtk_crtc->wb_connector;
  112. unsigned int *possible_crtcs = &wb_connector->encoder.possible_crtcs;
  113. *possible_crtcs = possible_crtc;
  114. if (*possible_crtcs == 0) {
  115. DRM_INFO("Failed to set wb possible_crtcs\n");
  116. return -1;
  117. }
  118. return 0;
  119. }
  120. int mtk_wb_connector_init(struct drm_device *drm_dev,
  121. struct mtk_drm_crtc *mtk_crtc)
  122. {
  123. int ret;
  124. struct drm_writeback_connector *wb_connector = &mtk_crtc->wb_connector;
  125. ret = drm_writeback_connector_init(
  126. drm_dev, wb_connector, &mtk_wb_connector_funcs,
  127. &mtk_wb_encoder_helper_funcs, wb_output_formats,
  128. (int)ARRAY_SIZE(wb_output_formats));
  129. if (ret != 0)
  130. return ret;
  131. drm_connector_helper_add(&mtk_crtc->wb_connector.base,
  132. &mtk_wb_connector_helper_funcs);
  133. return 0;
  134. }
  135. #ifdef CONFIG_MTK_DISPLAY_CMDQ
  136. void mtk_wb_atomic_commit(struct mtk_drm_crtc *mtk_crtc, unsigned int v,
  137. unsigned int h, void *cmdq_handle)
  138. #else
  139. void mtk_wb_atomic_commit(struct mtk_drm_crtc *mtk_crtc)
  140. #endif
  141. {
  142. struct mtk_ddp_comp *wdma = NULL;
  143. struct drm_writeback_connector *wb_conn = &mtk_crtc->wb_connector;
  144. struct drm_connector_state *conn_state = wb_conn->base.state;
  145. if (conn_state == NULL)
  146. return;
  147. if (conn_state->writeback_job != NULL &&
  148. conn_state->writeback_job->fb != NULL) {
  149. struct drm_framebuffer *fb = conn_state->writeback_job->fb;
  150. u32 addr;
  151. #ifdef CONFIG_MTK_DISPLAY_CMDQ
  152. #else
  153. void *cmdq_handle = NULL;
  154. #endif
  155. wdma = mtk_wb_find_wdma(mtk_crtc);
  156. if (!wdma)
  157. return;
  158. mtk_crtc->wb_enable = true;
  159. drm_writeback_queue_job(wb_conn, conn_state->writeback_job);
  160. conn_state->writeback_job = NULL;
  161. addr = (u32)mtk_fb_get_dma(fb);
  162. if (!addr)
  163. return;
  164. mtk_ddp_write(wdma, addr & 0xFFFFFFFFU, DISP_REG_WDMA_DST_ADDR,
  165. cmdq_handle);
  166. }
  167. }