extd_multi_control.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. #include <linux/kthread.h>
  2. /*#include <linux/rtpm_prio.h>*/
  3. #include "extd_multi_control.h"
  4. #include "disp_drv_platform.h"
  5. #include "external_display.h"
  6. #include "extd_platform.h"
  7. #include "extd_log.h"
  8. #include "mtk_ovl.h"
  9. static const struct EXTD_DRIVER *extd_driver[DEV_MAX_NUM-1];
  10. static struct SWITCH_MODE_INFO_STRUCT path_info;
  11. struct task_struct *disp_switch_mode_task = NULL;
  12. wait_queue_head_t switch_mode_wq;
  13. atomic_t switch_mode_event = ATOMIC_INIT(0);
  14. static int extd_create_path(enum EXT_DISP_PATH_MODE mode, unsigned int session)
  15. {
  16. int ret = 0;
  17. MULTI_COTRL_LOG("extd_create_path session:%08x, mode:%d", session, mode);
  18. ext_disp_path_set_mode(mode, session);
  19. ret = ext_disp_init(NULL, session);
  20. return ret;
  21. }
  22. /*
  23. static int extd_recompute_bg(int src_w, int src_h, unsigned int session)
  24. {
  25. int ret = 0;
  26. int device_id = (session & 0x0FF) - 1;
  27. if (device_id == DEV_MHL && extd_driver[DEV_MHL]->ioctl)
  28. ret = extd_driver[DEV_MHL]->ioctl(RECOMPUTE_BG_CMD, src_w, src_h, NULL);
  29. else if (device_id == DEV_EINK && extd_driver[DEV_EINK]->ioctl)
  30. ret = extd_driver[DEV_EINK]->ioctl(RECOMPUTE_BG_CMD, src_w, src_h, NULL);
  31. return ret;
  32. }
  33. */
  34. static int extd_get_device_type(unsigned int session)
  35. {
  36. int ret = 0;
  37. int device_id = (session & 0x0FF) - 1;
  38. if (device_id == DEV_MHL && extd_driver[DEV_MHL]->ioctl) {
  39. /*for mhl device*/
  40. ret = extd_driver[DEV_MHL]->ioctl(GET_DEV_TYPE_CMD, 0, 0, NULL);
  41. } else if (device_id == DEV_EINK && extd_driver[DEV_EINK]->ioctl) {
  42. /*for eink device*/
  43. ret = extd_driver[DEV_EINK]->ioctl(GET_DEV_TYPE_CMD, 0, 0, NULL);
  44. }
  45. MULTI_COTRL_LOG("device type is:%d\n", ret);
  46. return ret;
  47. }
  48. static void extd_set_layer_num(int layer_num, unsigned int session)
  49. {
  50. int device_id = (session & 0x0FF) - 1;
  51. if (device_id == DEV_MHL && extd_driver[DEV_MHL]->ioctl) {
  52. /*for mhl device*/
  53. extd_driver[DEV_MHL]->ioctl(SET_LAYER_NUM_CMD, layer_num, 0, NULL);
  54. } else if (device_id == DEV_EINK && extd_driver[DEV_EINK]->ioctl) {
  55. /*for eink device*/
  56. extd_driver[DEV_EINK]->ioctl(SET_LAYER_NUM_CMD, layer_num, 0, NULL);
  57. }
  58. }
  59. static int create_external_display_path(unsigned int session, int mode)
  60. {
  61. int ret = 0;
  62. int extd_type = DISP_IF_MHL;
  63. MULTI_COTRL_LOG("create_external_display_path session:%08x, mode:%d\n", session, mode);
  64. if (DISP_SESSION_TYPE(session) == DISP_SESSION_MEMORY && EXTD_OVERLAY_CNT > 0) {
  65. if (mode < DISP_SESSION_DIRECT_LINK_MIRROR_MODE
  66. && (path_info.old_mode[DEV_WFD] >= DISP_SESSION_DIRECT_LINK_MIRROR_MODE
  67. || path_info.old_session[DEV_WFD] != DISP_SESSION_MEMORY)) {
  68. if (ext_disp_wait_ovl_available(0) > 0) {
  69. ovl2mem_init(session);
  70. ovl2mem_setlayernum(4);
  71. } else {
  72. MULTI_COTRL_ERR("mhl path: OVL1 can not be split out!\n");
  73. ret = -1;
  74. }
  75. } else if (mode >= DISP_SESSION_DIRECT_LINK_MIRROR_MODE
  76. && path_info.old_session[DEV_WFD] == DISP_SESSION_MEMORY
  77. && path_info.old_mode[DEV_WFD] < DISP_SESSION_DIRECT_LINK_MIRROR_MODE) {
  78. ovl2mem_deinit();
  79. ovl2mem_setlayernum(0);
  80. ext_disp_path_change(EXTD_OVL_IDLE_REQ, session);
  81. }
  82. } else if (DISP_SESSION_TYPE(session) == DISP_SESSION_EXTERNAL) {
  83. int device_id = DISP_SESSION_DEV(session) - 1;
  84. extd_type = extd_get_device_type(session);
  85. if (path_info.old_session[device_id] == DISP_SESSION_EXTERNAL) {
  86. if (EXTD_OVERLAY_CNT < 1) {
  87. /*external display has no OVL to use, so no actions for mode switch */
  88. MULTI_COTRL_ERR("external display has no OVL to use, so no actions for mode switch\n");
  89. return ret;
  90. }
  91. }
  92. if (extd_type != DISP_IF_EPD && (mode < DISP_SESSION_DIRECT_LINK_MIRROR_MODE
  93. || extd_type == DISP_IF_HDMI_SMARTBOOK)) {
  94. if (ext_disp_wait_ovl_available(0) > 0) {
  95. if (path_info.old_session[device_id] == DISP_SESSION_EXTERNAL
  96. && extd_type != DISP_IF_HDMI_SMARTBOOK) {
  97. /*insert OVL to external dispaly path*/
  98. ext_disp_path_change(EXTD_OVL_INSERT_REQ, session);
  99. } else {
  100. /*create external display path with OVL*/
  101. extd_create_path(EXTD_DIRECT_LINK_MODE, session);
  102. }
  103. extd_set_layer_num(4, session);
  104. } else {
  105. MULTI_COTRL_ERR("mhl path: OVL1 can not be split out!\n");
  106. extd_create_path(EXTD_RDMA_DPI_MODE, session);
  107. extd_set_layer_num(1, session);
  108. }
  109. } else {
  110. if (path_info.old_session[device_id] == DISP_SESSION_EXTERNAL) {
  111. ext_disp_path_change(EXTD_OVL_REMOVE_REQ, session);
  112. extd_set_layer_num(1, session);
  113. } else {
  114. extd_create_path(EXTD_RDMA_DPI_MODE, session);
  115. extd_set_layer_num(1, session);
  116. }
  117. }
  118. } else if (DISP_SESSION_TYPE(session) == DISP_SESSION_MEMORY && EXTD_OVERLAY_CNT == 0) {
  119. MULTI_COTRL_ERR("memory session and ovl time sharing!\n");
  120. ovl2mem_setlayernum(4);
  121. }
  122. return ret;
  123. }
  124. static void destroy_external_display_path(unsigned int session, int mode)
  125. {
  126. int device_id = 0;
  127. MULTI_COTRL_LOG("destroy_external_display_path session:%08x\n", session);
  128. if (DISP_SESSION_TYPE(session) == DISP_SESSION_MEMORY) {
  129. /*virtual device id*/
  130. device_id = DISP_SESSION_DEV(session);
  131. } else {
  132. /*external device id*/
  133. device_id = DISP_SESSION_DEV(session) - 1;
  134. }
  135. if ((path_info.old_session[device_id] == DISP_SESSION_PRIMARY)
  136. || (path_info.old_session[device_id] == DISP_SESSION_MEMORY
  137. && path_info.old_mode[device_id] >= DISP_SESSION_DIRECT_LINK_MIRROR_MODE)) {
  138. /*discard for memory session in mirror mode*/
  139. MULTI_COTRL_LOG("no need destroy path for session:0x%08x, mode:%d\n", path_info.old_session[device_id],
  140. path_info.old_mode[device_id]);
  141. return;
  142. }
  143. if (path_info.old_session[device_id] == DISP_SESSION_EXTERNAL) {
  144. ext_disp_deinit(session);
  145. extd_set_layer_num(0, session);
  146. ext_disp_path_change(EXTD_OVL_IDLE_REQ, session);
  147. } else if (path_info.old_session[device_id] == DISP_SESSION_MEMORY && EXTD_OVERLAY_CNT > 0) {
  148. ovl2mem_deinit();
  149. ovl2mem_setlayernum(0);
  150. ext_disp_path_change(EXTD_OVL_IDLE_REQ, session);
  151. }
  152. }
  153. static int disp_switch_mode_kthread(void *data)
  154. {
  155. int ret = 0;
  156. struct sched_param param = { .sched_priority = 94 }; /*RTPM_PRIO_SCRN_UPDATE*/
  157. sched_setscheduler(current, SCHED_RR, &param);
  158. MULTI_COTRL_LOG("disp_switch_mode_kthread in!\n");
  159. for (;;) {
  160. wait_event_interruptible(switch_mode_wq, atomic_read(&switch_mode_event));
  161. atomic_set(&switch_mode_event, 0);
  162. MULTI_COTRL_LOG("switch mode, create or change path, mode:%d, session:0x%x\n",
  163. path_info.cur_mode, path_info.ext_sid);
  164. ret = create_external_display_path(path_info.ext_sid, path_info.cur_mode);
  165. if (ret == 0) {
  166. path_info.old_session[path_info.switching] = DISP_SESSION_TYPE(path_info.ext_sid);
  167. path_info.old_mode[path_info.switching] = path_info.cur_mode;
  168. }
  169. path_info.switching = DEV_MAX_NUM;
  170. path_info.ext_sid = 0;
  171. if (kthread_should_stop()) {
  172. /*thread exit*/
  173. break;
  174. }
  175. }
  176. return 0;
  177. }
  178. #ifndef OVL_CASCADE_SUPPORT
  179. static int path_change_without_cascade(DISP_MODE mode, unsigned int session_id, unsigned int device_id)
  180. {
  181. int ret = -1;
  182. unsigned int session = 0;
  183. /*MULTI_COTRL_FUNC();*/
  184. /*destroy external display path*/
  185. if (session_id == 0 && path_info.old_session[device_id] != DISP_SESSION_PRIMARY) {
  186. if (device_id == DEV_WFD) {
  187. /*make memory session for WFD*/
  188. session = MAKE_DISP_SESSION(DISP_SESSION_MEMORY, device_id);
  189. } else {
  190. /*make external session*/
  191. session = MAKE_DISP_SESSION(DISP_SESSION_EXTERNAL, device_id + 1);
  192. }
  193. destroy_external_display_path(session, DISP_SESSION_DIRECT_LINK_MODE);
  194. path_info.old_session[device_id] = DISP_SESSION_PRIMARY;
  195. path_info.old_mode[device_id] = DISP_SESSION_DIRECT_LINK_MODE;
  196. path_info.switching = DEV_MAX_NUM;
  197. return 1;
  198. }
  199. /*create path or change path*/
  200. if ((session_id > 0 && path_info.old_session[device_id] == DISP_SESSION_PRIMARY)
  201. || (mode != path_info.old_mode[device_id] && path_info.old_session[device_id] != DISP_SESSION_PRIMARY)) {
  202. ret = create_external_display_path(session_id, mode);
  203. if (ret == 0) {
  204. path_info.old_session[device_id] = DISP_SESSION_TYPE(session_id);
  205. path_info.old_mode[device_id] = mode;
  206. }
  207. path_info.switching = DEV_MAX_NUM;
  208. return 1;
  209. }
  210. return 0;
  211. }
  212. #else
  213. static int path_change_with_cascade(DISP_MODE mode, unsigned int session_id, unsigned int device_id)
  214. {
  215. int disp_type = 0;
  216. unsigned int session = 0;
  217. /*MULTI_COTRL_FUNC();*/
  218. /*destroy external display path*/
  219. if (session_id == 0 && path_info.old_session[device_id] != DISP_SESSION_PRIMARY) {
  220. if (device_id == DEV_WFD) {
  221. /*make memory session for WFD*/
  222. session = MAKE_DISP_SESSION(DISP_SESSION_MEMORY, device_id);
  223. } else {
  224. /*make external session*/
  225. session = MAKE_DISP_SESSION(DISP_SESSION_EXTERNAL, device_id + 1);
  226. }
  227. destroy_external_display_path(session, DISP_SESSION_DIRECT_LINK_MODE);
  228. path_info.old_session[device_id] = DISP_SESSION_PRIMARY;
  229. path_info.old_mode[device_id] = DISP_SESSION_DIRECT_LINK_MODE;
  230. path_info.switching = DEV_MAX_NUM;
  231. path_info.ext_sid = 0;
  232. return 1;
  233. }
  234. /*create path or change path*/
  235. if ((session_id > 0 && path_info.old_session[device_id] == DISP_SESSION_PRIMARY)
  236. || (mode != path_info.old_mode[device_id] && path_info.old_session[device_id] != DISP_SESSION_PRIMARY)) {
  237. /* the case will use OVL */
  238. disp_type = extd_get_device_type(session_id);
  239. if (disp_type != DISP_IF_EPD
  240. && (mode < DISP_SESSION_DIRECT_LINK_MIRROR_MODE || disp_type == DISP_IF_HDMI_SMARTBOOK)) {
  241. /*request OVL*/
  242. ext_disp_path_change(EXTD_OVL_REQUSTING_REQ, session_id);
  243. }
  244. /*workaroud for HWC, get layers and set input layers not match*/
  245. if (path_info.old_session[device_id] == DISP_SESSION_EXTERNAL
  246. && mode >= DISP_SESSION_DIRECT_LINK_MIRROR_MODE) {
  247. /*1 layer cab be used, it is to say that the path is RDMA-DPI*/
  248. extd_set_layer_num(1, session_id);
  249. }
  250. MULTI_COTRL_LOG("path_change_with_cascade, wake up\n");
  251. path_info.cur_mode = mode;
  252. path_info.ext_sid = session_id;
  253. path_info.switching = device_id;
  254. atomic_set(&switch_mode_event, 1);
  255. wake_up_interruptible(&switch_mode_wq);
  256. return 1;
  257. }
  258. return 0;
  259. }
  260. #endif
  261. void external_display_control_init(void)
  262. {
  263. int i = 0;
  264. MULTI_COTRL_FUNC();
  265. memset(&path_info, 0, sizeof(struct SWITCH_MODE_INFO_STRUCT));
  266. path_info.switching = DEV_MAX_NUM;
  267. for (i = 0; i < DEV_MAX_NUM; i++) {
  268. path_info.old_mode[i] = DISP_SESSION_DIRECT_LINK_MODE;
  269. path_info.old_session[i] = DISP_SESSION_PRIMARY;
  270. }
  271. extd_driver[DEV_MHL] = EXTD_HDMI_Driver();
  272. extd_driver[DEV_EINK] = EXTD_EPD_Driver();
  273. init_waitqueue_head(&switch_mode_wq);
  274. disp_switch_mode_task = kthread_create(disp_switch_mode_kthread, NULL, "disp_switch_mode_kthread");
  275. wake_up_process(disp_switch_mode_task);
  276. ext_disp_probe();
  277. }
  278. int external_display_config_input(disp_session_input_config *input, int idx, unsigned int session)
  279. {
  280. int ret = 0;
  281. if (ext_disp_path_get_mode(session) == EXTD_RDMA_DPI_MODE) {
  282. /*recompule background*/
  283. /*extd_recompute_bg(input->src_w, input->src_h, session);*/
  284. }
  285. ret = ext_disp_config_input_multiple(input, idx, session);
  286. return ret;
  287. }
  288. int external_display_trigger(EXTD_TRIGGER_MODE trigger, unsigned int session)
  289. {
  290. int ret = 0;
  291. enum EXTD_OVL_REQ_STATUS ovl_status = EXTD_OVL_NO_REQ;
  292. if (trigger == TRIGGER_RESUME) {
  293. ext_disp_resume(session);
  294. if (DISP_SESSION_TYPE(session) == DISP_SESSION_EXTERNAL && DISP_SESSION_DEV(session) == DEV_EINK+1) {
  295. if (extd_driver[DEV_EINK]->power_enable) {
  296. /*1 for power on, 0 for power off*/
  297. extd_driver[DEV_EINK]->power_enable(1);
  298. }
  299. }
  300. }
  301. ret = ext_disp_trigger(0, NULL, 0, session);
  302. if (trigger == TRIGGER_SUSPEND) {
  303. ext_disp_suspend_trigger(NULL, 0, session);
  304. if (DISP_SESSION_TYPE(session) == DISP_SESSION_EXTERNAL && DISP_SESSION_DEV(session) == DEV_EINK+1) {
  305. if (extd_driver[DEV_EINK]->power_enable) {
  306. /*1 for power on, 0 for power off*/
  307. extd_driver[DEV_EINK]->power_enable(0);
  308. }
  309. }
  310. }
  311. ovl_status = ext_disp_get_ovl_req_status(session);
  312. if (ovl_status == EXTD_OVL_REMOVING) {
  313. /*the new buffer configured, ovl can be removed*/
  314. ext_disp_path_change(EXTD_OVL_REMOVED, session);
  315. } else if (ovl_status == EXTD_OVL_INSERT_REQ) {
  316. /*the new buffer configured, ovl already is inserted in the path*/
  317. ext_disp_path_change(EXTD_OVL_INSERTED, session);
  318. }
  319. return ret;
  320. }
  321. int external_display_wait_for_vsync(void *config, unsigned int session)
  322. {
  323. int ret = 0;
  324. ret = ext_disp_wait_for_vsync(config, session);
  325. return ret;
  326. }
  327. int external_display_get_info(void *info, unsigned int session)
  328. {
  329. int ret = 0;
  330. int device_id = (session & 0x0FF) - 1;
  331. if (device_id == DEV_MHL && extd_driver[DEV_MHL]->get_dev_info) {
  332. /*get device info for MHL*/
  333. ret = extd_driver[DEV_MHL]->get_dev_info(SF_GET_INFO, info);
  334. } else if (device_id == DEV_EINK && extd_driver[DEV_EINK]->get_dev_info) {
  335. /*get device info for EINK*/
  336. ret = extd_driver[DEV_EINK]->get_dev_info(SF_GET_INFO, info);
  337. }
  338. return ret;
  339. }
  340. int external_display_switch_mode(DISP_MODE mode, unsigned int *session_created, unsigned int session)
  341. {
  342. int i = 0;
  343. int j = 0;
  344. int ret = -1;
  345. int switching = 0;
  346. int session_id[DEV_MAX_NUM] = {0};
  347. if (session_created == NULL) {
  348. /*error,no session can be compared*/
  349. return ret;
  350. }
  351. if (path_info.switching < DEV_MAX_NUM) {
  352. /*mode is switching, return directly*/
  353. return ret;
  354. }
  355. path_info.switching = DEV_MAX_NUM - 1;
  356. for (i = 0; i < MAX_SESSION_COUNT; i++) {
  357. if (session_created[i] == MAKE_DISP_SESSION(DISP_SESSION_EXTERNAL, DEV_MHL+1)) {
  358. /*it has MHL session*/
  359. session_id[DEV_MHL] = session_created[i];
  360. }
  361. if (session_created[i] == MAKE_DISP_SESSION(DISP_SESSION_EXTERNAL, DEV_EINK+1)) {
  362. /*it has EINK session*/
  363. session_id[DEV_EINK] = session_created[i];
  364. }
  365. if (session_created[i] == MAKE_DISP_SESSION(DISP_SESSION_MEMORY, DEV_WFD)) {
  366. /*it has WFD session*/
  367. session_id[DEV_WFD] = session_created[i];
  368. }
  369. }
  370. for (j = 0; j < DEV_MAX_NUM; j++) {
  371. #ifndef OVL_CASCADE_SUPPORT
  372. switching = path_change_without_cascade(mode, session_id[j], j);
  373. #else
  374. switching = path_change_with_cascade(mode, session_id[j], j);
  375. #endif
  376. if (switching == 1) {
  377. /*session switching one by one*/
  378. break;
  379. }
  380. }
  381. path_info.switching = (switching == 0) ? DEV_MAX_NUM : path_info.switching;
  382. return 0;
  383. }