mtk_ovl.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. #include <linux/delay.h>
  2. #include <linux/sched.h>
  3. #include <linux/semaphore.h>
  4. #include <linux/module.h>
  5. #include <linux/wait.h>
  6. #include <linux/kthread.h>
  7. #include <linux/mutex.h>
  8. #include "debug.h"
  9. #include "disp_drv_log.h"
  10. #include "disp_utils.h"
  11. #include "ddp_dump.h"
  12. #include "ddp_path.h"
  13. #include "ddp_drv.h"
  14. #include "ddp_ovl.h"
  15. #include "disp_session.h"
  16. #include "primary_display.h"
  17. #include "m4u.h"
  18. #include "cmdq_def.h"
  19. #include "cmdq_record.h"
  20. #include "cmdq_reg.h"
  21. #include "cmdq_core.h"
  22. #include "ddp_manager.h"
  23. #include "disp_drv_platform.h"
  24. #include "display_recorder.h"
  25. /* #include "ddp_mmp.h" */
  26. #include "mtk_ovl.h"
  27. #include "mtkfb_fence.h"
  28. #include <asm/atomic.h>
  29. static int ovl2mem_layer_num;
  30. int ovl2mem_use_m4u = 1;
  31. int ovl2mem_use_cmdq = CMDQ_ENABLE;
  32. typedef struct {
  33. int state;
  34. unsigned int session;
  35. unsigned int lcm_fps;
  36. int max_layer;
  37. int need_trigger_path;
  38. struct mutex lock;
  39. cmdqRecHandle cmdq_handle_config;
  40. cmdqRecHandle cmdq_handle_trigger;
  41. disp_path_handle dpmgr_handle;
  42. const char *mutex_locker;
  43. } ovl2mem_path_context;
  44. atomic_t g_trigger_ticket = ATOMIC_INIT(1);
  45. atomic_t g_release_ticket = ATOMIC_INIT(1);
  46. #define pgc _get_context()
  47. static ovl2mem_path_context *_get_context(void)
  48. {
  49. static int is_context_inited;
  50. static ovl2mem_path_context g_context;
  51. if (!is_context_inited) {
  52. memset((void *)&g_context, 0, sizeof(ovl2mem_path_context));
  53. is_context_inited = 1;
  54. }
  55. return &g_context;
  56. }
  57. CMDQ_SWITCH ovl2mem_cmdq_enabled(void)
  58. {
  59. return ovl2mem_use_cmdq;
  60. }
  61. static void _ovl2mem_path_lock(const char *caller)
  62. {
  63. dprec_logger_start(DPREC_LOGGER_PRIMARY_MUTEX, 0, 0);
  64. disp_sw_mutex_lock(&(pgc->lock));
  65. pgc->mutex_locker = caller;
  66. }
  67. static void _ovl2mem_path_unlock(const char *caller)
  68. {
  69. pgc->mutex_locker = NULL;
  70. disp_sw_mutex_unlock(&(pgc->lock));
  71. dprec_logger_done(DPREC_LOGGER_PRIMARY_MUTEX, 0, 0);
  72. }
  73. void ovl2mem_setlayernum(int layer_num)
  74. {
  75. ovl2mem_layer_num = layer_num;
  76. DISPERR("ovl2mem_setlayernum: %d\n", ovl2mem_layer_num);
  77. }
  78. int ovl2mem_get_info(void *info)
  79. {
  80. /* /DISPFUNC(); */
  81. disp_session_info *dispif_info = (disp_session_info *) info;
  82. memset((void *)dispif_info, 0, sizeof(disp_session_info));
  83. /* FIXME, for decouple mode, should dynamic return 4 or 8, please refer to primary_display_get_info() */
  84. dispif_info->maxLayerNum = ovl2mem_layer_num;
  85. dispif_info->displayType = DISP_IF_TYPE_DPI;
  86. dispif_info->displayMode = DISP_IF_MODE_VIDEO;
  87. dispif_info->isHwVsyncAvailable = 1;
  88. dispif_info->displayFormat = DISP_IF_FORMAT_RGB888;
  89. dispif_info->displayWidth = primary_display_get_width();
  90. dispif_info->displayHeight = primary_display_get_height();
  91. dispif_info->vsyncFPS = pgc->lcm_fps;
  92. if (dispif_info->displayWidth * dispif_info->displayHeight <= 240 * 432)
  93. dispif_info->physicalHeight = dispif_info->physicalWidth = 0;
  94. else if (dispif_info->displayWidth * dispif_info->displayHeight <= 320 * 480)
  95. dispif_info->physicalHeight = dispif_info->physicalWidth = 0;
  96. else if (dispif_info->displayWidth * dispif_info->displayHeight <= 480 * 854)
  97. dispif_info->physicalHeight = dispif_info->physicalWidth = 0;
  98. else
  99. dispif_info->physicalHeight = dispif_info->physicalWidth = 0;
  100. dispif_info->isConnected = 1;
  101. return 0;
  102. }
  103. static int _convert_disp_input_to_ovl(OVL_CONFIG_STRUCT *dst, primary_disp_input_config *src)
  104. {
  105. if (src && dst) {
  106. dst->layer = src->layer;
  107. dst->layer_en = src->layer_en;
  108. dst->source = src->buff_source;
  109. dst->fmt = src->fmt;
  110. dst->addr = src->addr;
  111. dst->vaddr = src->vaddr;
  112. dst->src_x = src->src_x;
  113. dst->src_y = src->src_y;
  114. dst->src_w = src->src_w;
  115. dst->src_h = src->src_h;
  116. dst->src_pitch = src->src_pitch;
  117. dst->dst_x = src->dst_x;
  118. dst->dst_y = src->dst_y;
  119. dst->dst_w = src->dst_w;
  120. dst->dst_h = src->dst_h;
  121. dst->keyEn = src->keyEn;
  122. dst->key = src->key;
  123. dst->aen = src->aen;
  124. dst->alpha = src->alpha;
  125. dst->sur_aen = src->sur_aen;
  126. dst->src_alpha = src->src_alpha;
  127. dst->dst_alpha = src->dst_alpha;
  128. dst->isDirty = src->isDirty;
  129. dst->buff_idx = src->buff_idx;
  130. dst->identity = src->identity;
  131. dst->connected_type = src->connected_type;
  132. dst->security = src->security;
  133. dst->yuv_range = src->yuv_range;
  134. return 0;
  135. }
  136. DISPERR("src(%p) or dst(%p) is null\n", src, dst);
  137. return -1;
  138. }
  139. static int ovl2mem_callback(unsigned int userdata)
  140. {
  141. int fence_idx = 0;
  142. int layid = 0;
  143. DISPMSG("ovl2mem_callback(%x), current tick=%d, release tick: %d\n", pgc->session,
  144. get_ovl2mem_ticket(), userdata);
  145. for (layid = 0; layid < (HW_OVERLAY_COUNT + 1); layid++) {
  146. fence_idx = mtkfb_query_idx_by_ticket(pgc->session, layid, userdata);
  147. if (fence_idx >= 0) {
  148. disp_ddp_path_config *data_config = dpmgr_path_get_last_config(pgc->dpmgr_handle);
  149. WDMA_CONFIG_STRUCT wdma_layer;
  150. wdma_layer.dstAddress = 0;
  151. if (data_config && (layid >= HW_OVERLAY_COUNT)) {
  152. wdma_layer.dstAddress = mtkfb_query_buf_mva(pgc->session, layid, fence_idx);
  153. wdma_layer.outputFormat = data_config->wdma_config.outputFormat;
  154. wdma_layer.srcWidth = data_config->wdma_config.srcWidth;
  155. wdma_layer.srcHeight = data_config->wdma_config.srcHeight;
  156. wdma_layer.dstPitch = data_config->wdma_config.dstPitch;
  157. DISPMSG("mem_seq %x-seq+ %d\n", pgc->session,
  158. mtkfb_query_frm_seq_by_addr(pgc->session, layid,
  159. wdma_layer.dstAddress));
  160. dprec_logger_frame_seq_end(pgc->session,
  161. mtkfb_query_frm_seq_by_addr(pgc->session,
  162. layid,
  163. wdma_layer.
  164. dstAddress));
  165. dprec_mmp_dump_wdma_layer(&wdma_layer, 1);
  166. }
  167. mtkfb_release_fence(pgc->session, layid, fence_idx);
  168. }
  169. }
  170. atomic_set(&g_release_ticket, userdata);
  171. return 0;
  172. }
  173. int get_ovl2mem_ticket(void)
  174. {
  175. return atomic_read(&g_trigger_ticket);
  176. }
  177. int ovl2mem_input_config(ovl2mem_in_config *input)
  178. {
  179. int ret = -1;
  180. int i = 0;
  181. disp_ddp_path_config *data_config;
  182. DISPFUNC();
  183. _ovl2mem_path_lock(__func__);
  184. /* all dirty should be cleared in dpmgr_path_get_last_config() */
  185. data_config = dpmgr_path_get_last_config(pgc->dpmgr_handle);
  186. data_config->dst_dirty = 0;
  187. data_config->ovl_dirty = 0;
  188. data_config->rdma_dirty = 0;
  189. if (pgc->state == 0) {
  190. DISPMSG("ovl2mem is already slept\n");
  191. _ovl2mem_path_unlock(__func__);
  192. return 0;
  193. }
  194. /* hope we can use only 1 input struct for input config, just set layer number */
  195. for (i = 0; i < HW_OVERLAY_COUNT; i++) {
  196. dprec_logger_start(DPREC_LOGGER_PRIMARY_CONFIG,
  197. input->layer | (input->layer_en << 16), input->addr);
  198. if (input[i].layer_en) {
  199. if (input[i].vaddr)
  200. /* / _debug_pattern(0x00000000, input[i].vaddr, input[i].dst_w, input[i].dst_h,
  201. input[i].src_pitch, 0x00000000, input[i].layer, input[i].buff_idx);
  202. */
  203. ;
  204. else
  205. /* /_debug_pattern(input[i].addr,0x00000000, input[i].dst_w, input[i].dst_h,
  206. input[i].src_pitch, 0x00000000, input[i].layer, input[i].buff_idx);
  207. */
  208. ;
  209. }
  210. /* /DISPMSG("[primary], i:%d, layer:%d, layer_en:%d, dirty:%d -0x%x\n",
  211. i, input[i].layer, input[i].layer_en, input[i].dirty, input[i].addr);
  212. */
  213. if (input[i].dirty)
  214. ret = _convert_disp_input_to_ovl(&(data_config->ovl_config[input[i].layer]),
  215. (primary_disp_input_config *)&input[i]);
  216. data_config->ovl_dirty = 1;
  217. dprec_logger_done(DPREC_LOGGER_PRIMARY_CONFIG, input->src_x, input->src_y);
  218. }
  219. if (dpmgr_path_is_busy(pgc->dpmgr_handle))
  220. dpmgr_wait_event_timeout(pgc->dpmgr_handle, DISP_PATH_EVENT_FRAME_COMPLETE, HZ / 5);
  221. ret = dpmgr_path_config(pgc->dpmgr_handle, data_config, pgc->cmdq_handle_config);
  222. _ovl2mem_path_unlock(__func__);
  223. DISPMSG("ovl2mem_input_config done\n");
  224. return ret;
  225. }
  226. int ovl2mem_output_config(disp_mem_output_config *out)
  227. {
  228. int ret = -1;
  229. disp_ddp_path_config *data_config;
  230. _ovl2mem_path_lock(__func__);
  231. /* all dirty should be cleared in dpmgr_path_get_last_config() */
  232. data_config = dpmgr_path_get_last_config(pgc->dpmgr_handle);
  233. data_config->dst_dirty = 1;
  234. data_config->dst_h = out->h;
  235. data_config->dst_w = out->w;
  236. data_config->ovl_dirty = 0;
  237. data_config->rdma_dirty = 0;
  238. data_config->wdma_dirty = 1;
  239. data_config->wdma_config.dstAddress = out->addr;
  240. data_config->wdma_config.srcHeight = out->h;
  241. data_config->wdma_config.srcWidth = out->w;
  242. data_config->wdma_config.clipX = out->x;
  243. data_config->wdma_config.clipY = out->y;
  244. data_config->wdma_config.clipHeight = out->h;
  245. data_config->wdma_config.clipWidth = out->w;
  246. data_config->wdma_config.outputFormat = out->fmt;
  247. data_config->wdma_config.dstPitch = out->pitch;
  248. data_config->wdma_config.useSpecifiedAlpha = 1;
  249. data_config->wdma_config.alpha = 0xFF;
  250. data_config->wdma_config.security = out->security;
  251. if (pgc->state == 0) {
  252. DISPMSG("ovl2mem is already slept\n");
  253. _ovl2mem_path_unlock(__func__);
  254. return 0;
  255. }
  256. if (dpmgr_path_is_busy(pgc->dpmgr_handle))
  257. dpmgr_wait_event_timeout(pgc->dpmgr_handle, DISP_PATH_EVENT_FRAME_DONE, HZ / 5);
  258. ret = dpmgr_path_config(pgc->dpmgr_handle, data_config, pgc->cmdq_handle_config);
  259. pgc->need_trigger_path = 1;
  260. _ovl2mem_path_unlock(__func__);
  261. /* /DISPMSG("ovl2mem_output_config done\n"); */
  262. return ret;
  263. }
  264. int ovl2mem_trigger(int blocking, void *callback, unsigned int userdata)
  265. {
  266. int ret = -1;
  267. int fence_idx = 0;
  268. int layid = 0;
  269. DISPFUNC();
  270. if (pgc->need_trigger_path == 0) {
  271. DISPMSG("ovl2mem_trigger do not trigger\n");
  272. if ((atomic_read(&g_trigger_ticket) - atomic_read(&g_release_ticket)) == 1) {
  273. DISPMSG("ovl2mem_trigger(%x), configue input, but does not config output!!\n", pgc->session);
  274. for (layid = 0; layid < (HW_OVERLAY_COUNT + 1); layid++) {
  275. fence_idx = mtkfb_query_idx_by_ticket(pgc->session, layid,
  276. atomic_read(&g_trigger_ticket));
  277. if (fence_idx >= 0)
  278. mtkfb_release_fence(pgc->session, layid, fence_idx);
  279. }
  280. }
  281. return ret;
  282. }
  283. _ovl2mem_path_lock(__func__);
  284. dpmgr_path_start(pgc->dpmgr_handle, ovl2mem_cmdq_enabled());
  285. dpmgr_path_trigger(pgc->dpmgr_handle, pgc->cmdq_handle_config, ovl2mem_cmdq_enabled());
  286. cmdqRecWait(pgc->cmdq_handle_config, CMDQ_EVENT_DISP_WDMA1_EOF);
  287. dpmgr_path_stop(pgc->dpmgr_handle, ovl2mem_cmdq_enabled());
  288. /* /cmdqRecDumpCommand(pgc->cmdq_handle_config); */
  289. cmdqRecFlushAsyncCallback(pgc->cmdq_handle_config, (CmdqAsyncFlushCB)ovl2mem_callback,
  290. atomic_read(&g_trigger_ticket));
  291. cmdqRecReset(pgc->cmdq_handle_config);
  292. pgc->need_trigger_path = 0;
  293. atomic_add(1, &g_trigger_ticket);
  294. _ovl2mem_path_unlock(__func__);
  295. dprec_logger_frame_seq_begin(pgc->session, mtkfb_query_frm_seq_by_addr(pgc->session, 0, 0));
  296. DISPMSG("ovl2mem_trigger ovl2mem_seq %d-seq %d\n", get_ovl2mem_ticket(),
  297. mtkfb_query_frm_seq_by_addr(pgc->session, 0, 0));
  298. return ret;
  299. }
  300. void ovl2mem_wait_done(void)
  301. {
  302. int loop_cnt = 0;
  303. if ((atomic_read(&g_trigger_ticket) - atomic_read(&g_release_ticket)) <= 1)
  304. return;
  305. DISPFUNC();
  306. while ((atomic_read(&g_trigger_ticket) - atomic_read(&g_release_ticket)) > 1) {
  307. dpmgr_wait_event_timeout(pgc->dpmgr_handle, DISP_PATH_EVENT_FRAME_COMPLETE,
  308. HZ / 30);
  309. if (loop_cnt > 5)
  310. break;
  311. loop_cnt++;
  312. }
  313. DISPMSG("ovl2mem_wait_done loop %d, trigger tick:%d, release tick:%d\n", loop_cnt,
  314. atomic_read(&g_trigger_ticket), atomic_read(&g_release_ticket));
  315. }
  316. int ovl2mem_deinit(void)
  317. {
  318. int ret = -1;
  319. DISPFUNC();
  320. _ovl2mem_path_lock(__func__);
  321. if (pgc->state == 0)
  322. goto Exit;
  323. ovl2mem_wait_done();
  324. dpmgr_path_stop(pgc->dpmgr_handle, CMDQ_DISABLE);
  325. dpmgr_path_reset(pgc->dpmgr_handle, CMDQ_DISABLE);
  326. dpmgr_path_deinit(pgc->dpmgr_handle, CMDQ_DISABLE);
  327. dpmgr_destroy_path(pgc->dpmgr_handle, NULL);
  328. cmdqRecDestroy(pgc->cmdq_handle_config);
  329. pgc->dpmgr_handle = NULL;
  330. pgc->cmdq_handle_config = NULL;
  331. pgc->state = 0;
  332. pgc->need_trigger_path = 0;
  333. atomic_set(&g_trigger_ticket, 1);
  334. atomic_set(&g_release_ticket, 1);
  335. ovl2mem_layer_num = 0;
  336. Exit:
  337. _ovl2mem_path_unlock(__func__);
  338. DISPMSG("ovl2mem_deinit done\n");
  339. return ret;
  340. }