ddp_irq.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. #define LOG_TAG "IRQ"
  2. #include "ddp_log.h"
  3. #include "ddp_debug.h"
  4. #include <linux/interrupt.h>
  5. #include <linux/wait.h>
  6. #include <linux/spinlock.h>
  7. #include <linux/kthread.h>
  8. #include <linux/timer.h>
  9. /* #include <mach/mt_irq.h> */
  10. #include "ddp_reg.h"
  11. #include "ddp_irq.h"
  12. #include "ddp_aal.h"
  13. #include "ddp_drv.h"
  14. #include "ddp_rdma.h"
  15. #include "ddp_rdma_ex.h"
  16. #include "primary_display.h"
  17. /* IRQ log print kthread */
  18. static struct task_struct *disp_irq_log_task;
  19. static wait_queue_head_t disp_irq_log_wq;
  20. static int disp_irq_log_module;
  21. static int irq_init;
  22. static unsigned int cnt_rdma_underflow[2];
  23. static unsigned int cnt_rdma_abnormal[2];
  24. /*static unsigned int cnt_ovl_underflow[2];*/
  25. static unsigned int cnt_wdma_underflow[2];
  26. unsigned long long rdma_start_time[RDMA_INSTANCES] = { 0 };
  27. unsigned long long rdma_end_time[RDMA_INSTANCES] = { 0 };
  28. #define DISP_MAX_IRQ_CALLBACK 10
  29. static DDP_IRQ_CALLBACK irq_module_callback_table[DISP_MODULE_NUM][DISP_MAX_IRQ_CALLBACK];
  30. static DDP_IRQ_CALLBACK irq_callback_table[DISP_MAX_IRQ_CALLBACK];
  31. atomic_t ESDCheck_byCPU = ATOMIC_INIT(0);
  32. int disp_register_irq_callback(DDP_IRQ_CALLBACK cb)
  33. {
  34. int i = 0;
  35. for (i = 0; i < DISP_MAX_IRQ_CALLBACK; i++) {
  36. if (irq_callback_table[i] == cb)
  37. break;
  38. }
  39. if (i < DISP_MAX_IRQ_CALLBACK)
  40. return 0;
  41. for (i = 0; i < DISP_MAX_IRQ_CALLBACK; i++) {
  42. if (irq_callback_table[i] == NULL)
  43. break;
  44. }
  45. if (i == DISP_MAX_IRQ_CALLBACK) {
  46. DDPERR("not enough irq callback entries for module\n");
  47. return -1;
  48. }
  49. DDPMSG("register callback on %d\n", i);
  50. irq_callback_table[i] = cb;
  51. return 0;
  52. }
  53. int disp_unregister_irq_callback(DDP_IRQ_CALLBACK cb)
  54. {
  55. int i;
  56. for (i = 0; i < DISP_MAX_IRQ_CALLBACK; i++) {
  57. if (irq_callback_table[i] == cb) {
  58. irq_callback_table[i] = NULL;
  59. break;
  60. }
  61. }
  62. if (i == DISP_MAX_IRQ_CALLBACK) {
  63. DDPERR("Try to unregister callback function %p which was not registered\n", cb);
  64. return -1;
  65. }
  66. return 0;
  67. }
  68. int disp_register_module_irq_callback(DISP_MODULE_ENUM module, DDP_IRQ_CALLBACK cb)
  69. {
  70. int i;
  71. if (module >= DISP_MODULE_NUM) {
  72. DDPERR("Register IRQ with invalid module ID. module=%d\n", module);
  73. return -1;
  74. }
  75. if (cb == NULL) {
  76. DDPERR("Register IRQ with invalid cb.\n");
  77. return -1;
  78. }
  79. for (i = 0; i < DISP_MAX_IRQ_CALLBACK; i++) {
  80. if (irq_module_callback_table[module][i] == cb)
  81. break;
  82. }
  83. if (i < DISP_MAX_IRQ_CALLBACK)
  84. return 0;/* Already registered. */
  85. for (i = 0; i < DISP_MAX_IRQ_CALLBACK; i++) {
  86. if (irq_module_callback_table[module][i] == NULL)
  87. break;
  88. }
  89. if (i == DISP_MAX_IRQ_CALLBACK) {
  90. DDPERR("No enough callback entries for module %d.\n", module);
  91. return -1;
  92. }
  93. irq_module_callback_table[module][i] = cb;
  94. return 0;
  95. }
  96. int disp_unregister_module_irq_callback(DISP_MODULE_ENUM module, DDP_IRQ_CALLBACK cb)
  97. {
  98. int i;
  99. for (i = 0; i < DISP_MAX_IRQ_CALLBACK; i++) {
  100. if (irq_module_callback_table[module][i] == cb) {
  101. irq_module_callback_table[module][i] = NULL;
  102. break;
  103. }
  104. }
  105. if (i == DISP_MAX_IRQ_CALLBACK) {
  106. DDPERR("Try to unregister callback function with was not registered. module=%d cb=%p\n", module, cb);
  107. return -1;
  108. }
  109. return 0;
  110. }
  111. void disp_invoke_irq_callbacks(DISP_MODULE_ENUM module, unsigned int param)
  112. {
  113. int i;
  114. for (i = 0; i < DISP_MAX_IRQ_CALLBACK; i++) {
  115. if (irq_callback_table[i])
  116. /* DDPERR("Invoke callback function. module=%d param=0x%X\n", module, param); */
  117. irq_callback_table[i] (module, param);
  118. if (irq_module_callback_table[module][i])
  119. /* DDPERR("Invoke module callback function. module=%d param=0x%X\n", module, param); */
  120. irq_module_callback_table[module][i] (module, param);
  121. }
  122. }
  123. /* Mark out for eliminate build warning message, because it is not used */
  124. #if 0
  125. static DISP_MODULE_ENUM find_module_by_irq(int irq)
  126. {
  127. /* should sort irq_id_to_module_table by numberic sequence */
  128. int i = 0;
  129. #define DISP_IRQ_NUM_MAX (DISP_REG_NUM)
  130. static struct irq_module_map {
  131. int irq;
  132. DISP_MODULE_ENUM module;
  133. } irq_id_to_module_table[DISP_IRQ_NUM_MAX] = {
  134. {
  135. 0, DISP_MODULE_OVL0}, {
  136. 0, DISP_MODULE_OVL1}, {
  137. 0, DISP_MODULE_RDMA0}, {
  138. 0, DISP_MODULE_RDMA1}, {
  139. 0, DISP_MODULE_WDMA0}, {
  140. 0, DISP_MODULE_COLOR0}, {
  141. 0, DISP_MODULE_CCORR}, {
  142. 0, DISP_MODULE_AAL}, {
  143. 0, DISP_MODULE_GAMMA}, {
  144. 0, DISP_MODULE_DITHER}, {
  145. 0, DISP_MODULE_UFOE}, {
  146. 0, DISP_MODULE_PWM0}, {
  147. 0, DISP_MODULE_WDMA1}, {
  148. 0, DISP_MODULE_MUTEX}, {
  149. 0, DISP_MODULE_DSI0}, {
  150. 0, DISP_MODULE_DPI},};
  151. irq_id_to_module_table[0].irq = dispsys_irq[DISP_REG_OVL0];
  152. irq_id_to_module_table[1].irq = dispsys_irq[DISP_REG_OVL1];
  153. irq_id_to_module_table[2].irq = dispsys_irq[DISP_REG_RDMA0];
  154. irq_id_to_module_table[3].irq = dispsys_irq[DISP_REG_RDMA1];
  155. irq_id_to_module_table[4].irq = dispsys_irq[DISP_REG_WDMA0];
  156. irq_id_to_module_table[5].irq = dispsys_irq[DISP_REG_COLOR];
  157. irq_id_to_module_table[6].irq = dispsys_irq[DISP_REG_CCORR];
  158. irq_id_to_module_table[7].irq = dispsys_irq[DISP_REG_AAL];
  159. irq_id_to_module_table[8].irq = dispsys_irq[DISP_REG_GAMMA];
  160. irq_id_to_module_table[9].irq = dispsys_irq[DISP_REG_DITHER];
  161. irq_id_to_module_table[10].irq = dispsys_irq[DISP_REG_UFOE];
  162. irq_id_to_module_table[11].irq = dispsys_irq[DISP_REG_PWM];
  163. irq_id_to_module_table[12].irq = dispsys_irq[DISP_REG_WDMA1];
  164. irq_id_to_module_table[13].irq = dispsys_irq[DISP_REG_MUTEX];
  165. irq_id_to_module_table[14].irq = dispsys_irq[DISP_REG_DSI0];
  166. irq_id_to_module_table[15].irq = dispsys_irq[DISP_REG_DPI0];
  167. for (i = 0; i < DISP_IRQ_NUM_MAX; i++) {
  168. if (irq_id_to_module_table[i].irq == irq) {
  169. DDPDBG("find module %d by irq %d\n", irq,
  170. irq_id_to_module_table[i].module);
  171. return irq_id_to_module_table[i].module;
  172. }
  173. }
  174. if (i == DISP_IRQ_NUM_MAX)
  175. DDPERR("can not find irq=%d in irq_id_to_module_table\n", irq);
  176. return DISP_MODULE_UNKNOWN;
  177. }
  178. #endif
  179. static char *disp_irq_module(unsigned int irq)
  180. {
  181. if (irq == dispsys_irq[DISP_REG_OVL0])
  182. return "ovl0 ";
  183. else if (irq == dispsys_irq[DISP_REG_OVL1])
  184. return "ovl1 ";
  185. else if (irq == dispsys_irq[DISP_REG_RDMA0])
  186. return "rdma0 ";
  187. else if (irq == dispsys_irq[DISP_REG_RDMA1])
  188. return "rdma1 ";
  189. else if (irq == dispsys_irq[DISP_REG_WDMA0])
  190. return "wdma0 ";
  191. else if (irq == dispsys_irq[DISP_REG_COLOR])
  192. return "color ";
  193. else if (irq == dispsys_irq[DISP_REG_CCORR])
  194. return "ccorr ";
  195. else if (irq == dispsys_irq[DISP_REG_AAL])
  196. return "aal ";
  197. else if (irq == dispsys_irq[DISP_REG_GAMMA])
  198. return "gamma ";
  199. else if (irq == dispsys_irq[DISP_REG_DITHER])
  200. return "dither";
  201. else if (irq == dispsys_irq[DISP_REG_UFOE])
  202. return "ufoe ";
  203. else if (irq == dispsys_irq[DISP_REG_PWM])
  204. return "pwm ";
  205. else if (irq == dispsys_irq[DISP_REG_WDMA1])
  206. return "wdma1 ";
  207. else if (irq == dispsys_irq[DISP_REG_MUTEX])
  208. return "mutex ";
  209. else if (irq == dispsys_irq[DISP_REG_DSI0])
  210. return "dsi0 ";
  211. else if (irq == dispsys_irq[DISP_REG_DPI0])
  212. return "dpi0 ";
  213. else
  214. return "unknown";
  215. }
  216. /* TODO: move each irq to module driver */
  217. unsigned int rdma_start_irq_cnt[RDMA_INSTANCES];
  218. unsigned int rdma_done_irq_cnt[RDMA_INSTANCES];
  219. unsigned int rdma_underflow_irq_cnt[RDMA_INSTANCES];
  220. unsigned int rdma_targetline_irq_cnt[RDMA_INSTANCES];
  221. unsigned int ovl_complete_irq_cnt[2] = { 0, 0 };
  222. unsigned int mutex_start_irq_cnt = 0;
  223. unsigned int mutex_done_irq_cnt = 0;
  224. void disp_dump_emi_status(void)
  225. {
  226. #define INFRA_BASE_PA 0x10001000
  227. #define EMI_BASE_PA 0x10203000
  228. unsigned long infra_base_va = 0;
  229. unsigned long emi_base_va = 0;
  230. unsigned int i = 0;
  231. infra_base_va = (unsigned long)ioremap_nocache(INFRA_BASE_PA, 0x200);
  232. emi_base_va = (unsigned long)ioremap_nocache(EMI_BASE_PA, 0x200);
  233. DDPMSG("dump emi status, infra_base_va=0x%lx, emi_base_va=0x%lx,\n", infra_base_va,
  234. emi_base_va);
  235. pr_debug("0x10203000: ");
  236. for (i = 0; i < 0x158; i += 4) {
  237. pr_debug("0x%x, ", *(volatile unsigned int *)(emi_base_va + i));
  238. if (i % 32 == 0 && i != 0)
  239. pr_debug("\n 0x%x: ", EMI_BASE_PA + 32 * i);
  240. }
  241. pr_debug("\n*(0x10001098)=0x%x.\n", *(volatile unsigned int *)(infra_base_va + 0x98));
  242. iounmap((void *)infra_base_va);
  243. iounmap((void *)emi_base_va);
  244. }
  245. irqreturn_t disp_irq_handler(int irq, void *dev_id)
  246. {
  247. DISP_MODULE_ENUM module = DISP_MODULE_UNKNOWN;
  248. unsigned long reg_val = 0;
  249. unsigned int index = 0;
  250. unsigned int mutexID = 0;
  251. unsigned long reg_temp_val = 0;
  252. DDPDBG("disp_irq_handler, irq=%d, module=%s\n", irq, disp_irq_module(irq));
  253. MMProfileLogEx(ddp_mmp_get_events()->DDP_IRQ, MMProfileFlagStart, irq, 0);
  254. if (irq == dispsys_irq[DISP_REG_DSI0]) {
  255. module = DISP_MODULE_DSI0;
  256. reg_val = (DISP_REG_GET(dsi_reg_va + 0xC) & 0xff);
  257. DDPIRQ("IRQ: DSI, irq=0x%x\n", (unsigned int)reg_val);
  258. if (atomic_read(&ESDCheck_byCPU) == 0) {
  259. /* rd_rdy don't clear and wait for ESD & Read LCM will clear the bit. */
  260. reg_temp_val = reg_val & 0xfffe;
  261. DISP_CPU_REG_SET(dsi_reg_va + 0xC, ~reg_temp_val);
  262. } else {
  263. DISP_CPU_REG_SET(dsi_reg_va + 0xC, ~reg_val);
  264. }
  265. MMProfileLogEx(ddp_mmp_get_events()->DSI_IRQ[0], MMProfileFlagPulse,
  266. reg_val, 0);
  267. } else if (irq == dispsys_irq[DISP_REG_OVL0] || irq == dispsys_irq[DISP_REG_OVL1]) {
  268. index = (irq == dispsys_irq[DISP_REG_OVL0]) ? 0 : 1;
  269. module = (irq == dispsys_irq[DISP_REG_OVL0]) ? DISP_MODULE_OVL0 : DISP_MODULE_OVL1;
  270. reg_val = DISP_REG_GET(DISP_REG_OVL_INTSTA + index * DISP_OVL_INDEX_OFFSET);
  271. if (reg_val & (1 << 1)) {
  272. unsigned int i = 0;
  273. DDPIRQ("IRQ: OVL%d frame done!\n", index);
  274. ovl_complete_irq_cnt[index]++;
  275. /* update OVL addr */
  276. if (index == 0) {
  277. for (i = 0; i < 4; i++) {
  278. if (DISP_REG_GET(DISP_REG_OVL_SRC_CON) & (0x1 << i))
  279. MMProfileLogEx(ddp_mmp_get_events()->layer[i],
  280. MMProfileFlagPulse, DISP_REG_GET
  281. (DISP_REG_OVL_L0_ADDR + i * 0x20), 0);
  282. }
  283. }
  284. if (index == 1) {
  285. for (i = 0; i < 4; i++) {
  286. if (DISP_REG_GET(DISP_REG_OVL_SRC_CON + DISP_OVL_INDEX_OFFSET) & (0x1 << i))
  287. MMProfileLogEx(ddp_mmp_get_events()->ovl1_layer[i],
  288. MMProfileFlagPulse, DISP_REG_GET
  289. (DISP_REG_OVL_L0_ADDR +
  290. DISP_OVL_INDEX_OFFSET + i * 0x20), 0);
  291. }
  292. }
  293. }
  294. if (reg_val & (1 << 2)) {
  295. /* DDPERR("IRQ: OVL%d frame underrun! cnt=%d\n",index, cnt_ovl_underflow[index]++); */
  296. /* disp_irq_log_module |= 1<<module; */
  297. }
  298. if (reg_val & (1 << 3))
  299. DDPIRQ("IRQ: OVL%d sw reset done\n", index);
  300. if (reg_val & (1 << 4))
  301. DDPIRQ("IRQ: OVL%d hw reset done\n", index);
  302. if (reg_val & (1 << 5))
  303. DDPERR("IRQ: OVL%d-L0 not complete until EOF!\n", index);
  304. /* disp_irq_log_module |= 1<<module; */
  305. if (reg_val & (1 << 6)) {
  306. DDPERR("IRQ: OVL%d-L1 not complete until EOF!\n", index);
  307. /* disp_irq_log_module |= 1<<module; */
  308. }
  309. if (reg_val & (1 << 7)) {
  310. DDPERR("IRQ: OVL%d-L2 not complete until EOF!\n", index);
  311. /* disp_irq_log_module |= 1<<module; */
  312. }
  313. if (reg_val & (1 << 8)) {
  314. DDPERR("IRQ: OVL%d-L3 not complete until EOF!\n", index);
  315. /* disp_irq_log_module |= 1<<module; */
  316. }
  317. if (reg_val & (1 << 9)) {
  318. /* DDPERR("IRQ: OVL%d-L0 fifo underflow!\n",index); */
  319. /* disp_irq_log_module |= 1<<module; */
  320. }
  321. if (reg_val & (1 << 10)) {
  322. /* DDPERR("IRQ: OVL%d-L1 fifo underflow!\n",index); */
  323. /* disp_irq_log_module |= 1<<module; */
  324. }
  325. if (reg_val & (1 << 11)) {
  326. /* DDPERR("IRQ: OVL%d-L2 fifo underflow!\n",index); */
  327. /* disp_irq_log_module |= 1<<module; */
  328. }
  329. if (reg_val & (1 << 12)) {
  330. /* DDPERR("IRQ: OVL%d-L3 fifo underflow!\n",index); */
  331. /* disp_irq_log_module |= 1<<module; */
  332. }
  333. /* clear intr */
  334. if (reg_val & (0xf << 5)) {
  335. ddp_dump_analysis(DISP_MODULE_CONFIG);
  336. if (index == 0) {
  337. #if defined(OVL_CASCADE_SUPPORT)
  338. ddp_dump_analysis(DISP_MODULE_OVL1);
  339. #endif
  340. ddp_dump_analysis(DISP_MODULE_OVL0);
  341. ddp_dump_analysis(DISP_MODULE_COLOR0);
  342. ddp_dump_analysis(DISP_MODULE_AAL);
  343. ddp_dump_analysis(DISP_MODULE_RDMA0);
  344. } else {
  345. ddp_dump_analysis(DISP_MODULE_OVL1);
  346. ddp_dump_analysis(DISP_MODULE_RDMA1);
  347. ddp_dump_reg(DISP_MODULE_CONFIG);
  348. }
  349. }
  350. DISP_CPU_REG_SET(DISP_REG_OVL_INTSTA + index * DISP_OVL_INDEX_OFFSET,
  351. ~reg_val);
  352. MMProfileLogEx(ddp_mmp_get_events()->OVL_IRQ[index], MMProfileFlagPulse,
  353. reg_val, 0);
  354. if (reg_val & 0x1e0)
  355. MMProfileLogEx(ddp_mmp_get_events()->ddp_abnormal_irq,
  356. MMProfileFlagPulse, (index << 16) | reg_val, module);
  357. } else if (irq == dispsys_irq[DISP_REG_WDMA0] || irq == dispsys_irq[DISP_REG_WDMA1]) {
  358. index = (irq == dispsys_irq[DISP_REG_WDMA0]) ? 0 : 1;
  359. module =
  360. (irq ==
  361. dispsys_irq[DISP_REG_WDMA0]) ? DISP_MODULE_WDMA0 : DISP_MODULE_WDMA1;
  362. reg_val =
  363. DISP_REG_GET(DISP_REG_WDMA_INTSTA + index * DISP_WDMA_INDEX_OFFSET);
  364. if (reg_val & (1 << 0))
  365. DDPIRQ("IRQ: WDMA%d frame done!\n", index);
  366. if (reg_val & (1 << 1)) {
  367. DDPERR("IRQ: WDMA%d underrun! cnt=%d\n", index,
  368. cnt_wdma_underflow[index]++);
  369. disp_irq_log_module |= 1 << module;
  370. }
  371. /* clear intr */
  372. DISP_CPU_REG_SET(DISP_REG_WDMA_INTSTA + index * DISP_WDMA_INDEX_OFFSET,
  373. ~reg_val);
  374. MMProfileLogEx(ddp_mmp_get_events()->WDMA_IRQ[index], MMProfileFlagPulse,
  375. reg_val, DISP_REG_GET(DISP_REG_WDMA_CLIP_SIZE));
  376. if (reg_val & 0x2)
  377. MMProfileLogEx(ddp_mmp_get_events()->ddp_abnormal_irq, MMProfileFlagPulse,
  378. (cnt_wdma_underflow[index] << 24) | (index << 16) | reg_val, module);
  379. } else if (irq == dispsys_irq[DISP_REG_RDMA0] || irq == dispsys_irq[DISP_REG_RDMA1]) {
  380. if (dispsys_irq[DISP_REG_RDMA0] == irq) {
  381. index = 0;
  382. module = DISP_MODULE_RDMA0;
  383. } else if (dispsys_irq[DISP_REG_RDMA1] == irq) {
  384. index = 1;
  385. module = DISP_MODULE_RDMA1;
  386. }
  387. reg_val = DISP_REG_GET(DISP_REG_RDMA_INT_STATUS + index * DISP_RDMA_INDEX_OFFSET);
  388. if (reg_val & (1 << 0))
  389. DDPIRQ("IRQ: RDMA%d reg update done!\n", index);
  390. if (reg_val & (1 << 1)) {
  391. MMProfileLogEx(ddp_mmp_get_events()->SCREEN_UPDATE[index],
  392. MMProfileFlagStart, reg_val,
  393. DISP_REG_GET(DISP_REG_RDMA_MEM_START_ADDR));
  394. rdma_start_time[index] = sched_clock();
  395. DDPIRQ("IRQ: RDMA%d frame start!\n", index);
  396. rdma_start_irq_cnt[index]++;
  397. /* rdma start/end irq should equal, else need reset ovl */
  398. if (gResetRDMAEnable == 1 && is_hwc_enabled == 1 && index == 0 &&
  399. primary_display_is_video_mode() == 1 &&
  400. rdma_start_irq_cnt[0] > rdma_done_irq_cnt[0] + 3) {
  401. ovl_reset(DISP_MODULE_OVL0, NULL);
  402. if (ovl_get_status() != DDP_OVL1_STATUS_SUB)
  403. ovl_reset(DISP_MODULE_OVL1, NULL);
  404. rdma_done_irq_cnt[0] = rdma_start_irq_cnt[0];
  405. DDPERR("warning: reset ovl!\n");
  406. }
  407. }
  408. if (reg_val & (1 << 2)) {
  409. MMProfileLogEx(ddp_mmp_get_events()->SCREEN_UPDATE[index],
  410. MMProfileFlagEnd, reg_val, 0);
  411. rdma_end_time[index] = sched_clock();
  412. DDPIRQ("IRQ: RDMA%d frame done!\n", index);
  413. /* rdma_done_irq_cnt[index] ++; */
  414. rdma_done_irq_cnt[index] = rdma_start_irq_cnt[index];
  415. }
  416. if (reg_val & (1 << 3)) {
  417. DDPERR("IRQ: RDMA%d abnormal! cnt=%d\n", index,
  418. cnt_rdma_abnormal[index]++);
  419. disp_irq_log_module |= 1 << module;
  420. }
  421. if (reg_val & (1 << 4)) {
  422. DDPMSG("rdma%d, pix(%d,%d,%d,%d)\n",
  423. index,
  424. DISP_REG_GET(DISP_REG_RDMA_IN_P_CNT +
  425. DISP_RDMA_INDEX_OFFSET * index),
  426. DISP_REG_GET(DISP_REG_RDMA_IN_LINE_CNT +
  427. DISP_RDMA_INDEX_OFFSET * index),
  428. DISP_REG_GET(DISP_REG_RDMA_OUT_P_CNT +
  429. DISP_RDMA_INDEX_OFFSET * index),
  430. DISP_REG_GET(DISP_REG_RDMA_OUT_LINE_CNT +
  431. DISP_RDMA_INDEX_OFFSET * index));
  432. DDPERR("IRQ: RDMA%d underflow! cnt=%d\n", index,
  433. cnt_rdma_underflow[index]++);
  434. disp_irq_log_module |= 1 << module;
  435. rdma_underflow_irq_cnt[index]++;
  436. }
  437. if (reg_val & (1 << 5)) {
  438. DDPIRQ("IRQ: RDMA%d target line!\n", index);
  439. rdma_targetline_irq_cnt[index]++;
  440. }
  441. /* clear intr */
  442. DISP_CPU_REG_SET(DISP_REG_RDMA_INT_STATUS + index * DISP_RDMA_INDEX_OFFSET,
  443. ~reg_val);
  444. MMProfileLogEx(ddp_mmp_get_events()->RDMA_IRQ[index], MMProfileFlagPulse,
  445. reg_val, 0);
  446. if (reg_val & 0x18) {
  447. MMProfileLogEx(ddp_mmp_get_events()->ddp_abnormal_irq,
  448. MMProfileFlagPulse,
  449. (rdma_underflow_irq_cnt[index] << 24) | (index << 16)
  450. | reg_val, module);
  451. }
  452. } else if (irq == dispsys_irq[DISP_REG_COLOR]) {
  453. ;
  454. } else if (irq == dispsys_irq[DISP_REG_MUTEX]) {
  455. /* mutex0: perimary disp */
  456. /* mutex1: sub disp */
  457. /* mutex2: aal */
  458. module = DISP_MODULE_MUTEX;
  459. reg_val = DISP_REG_GET(DISP_REG_CONFIG_MUTEX_INTSTA) & 0x7C1F;
  460. for (mutexID = 0; mutexID < 5; mutexID++) {
  461. if (reg_val & (0x1 << mutexID)) {
  462. DDPIRQ("IRQ: mutex%d sof!\n", mutexID);
  463. mutex_start_irq_cnt++;
  464. MMProfileLogEx(ddp_mmp_get_events()->MUTEX_IRQ[mutexID],
  465. MMProfileFlagPulse, reg_val, 0);
  466. }
  467. if (reg_val & (0x1 << (mutexID + DISP_MUTEX_TOTAL))) {
  468. DDPIRQ("IRQ: mutex%d eof!\n", mutexID);
  469. mutex_done_irq_cnt++;
  470. MMProfileLogEx(ddp_mmp_get_events()->MUTEX_IRQ[mutexID],
  471. MMProfileFlagPulse, reg_val, 1);
  472. }
  473. }
  474. DISP_CPU_REG_SET(DISP_REG_CONFIG_MUTEX_INTSTA, ~reg_val);
  475. } else if (irq == dispsys_irq[DISP_REG_AAL]) {
  476. module = DISP_MODULE_AAL;
  477. reg_val = DISP_REG_GET(DISP_AAL_INTSTA);
  478. disp_aal_on_end_of_frame();
  479. } else if (irq == dispsys_irq[DISP_REG_CONFIG]) {/* MMSYS error intr */
  480. reg_val = DISP_REG_GET(DISP_REG_CONFIG_MMSYS_INTSTA) & 0x7;
  481. if (reg_val & (1 << 0))
  482. DDPERR("MMSYS to MFG APB TX Error, MMSYS clock off but MFG clock on!\n");
  483. if (reg_val & (1 << 1))
  484. DDPERR("MMSYS to MJC APB TX Error, MMSYS clock off but MJC clock on!\n");
  485. if (reg_val & (1 << 2))
  486. DDPERR("PWM APB TX Error!\n");
  487. DISP_CPU_REG_SET(DISP_REG_CONFIG_MMSYS_INTSTA, ~reg_val);
  488. } else {
  489. module = DISP_MODULE_UNKNOWN;
  490. reg_val = 0;
  491. DDPERR("invalid irq=%d\n ", irq);
  492. }
  493. disp_invoke_irq_callbacks(module, reg_val);
  494. if (disp_irq_log_module != 0)
  495. wake_up_interruptible(&disp_irq_log_wq);
  496. MMProfileLogEx(ddp_mmp_get_events()->DDP_IRQ, MMProfileFlagEnd, irq, reg_val);
  497. return IRQ_HANDLED;
  498. }
  499. /* extern smi_dumpDebugMsg(void); */
  500. static int disp_irq_log_kthread_func(void *data)
  501. {
  502. unsigned int i = 0;
  503. while (1) {
  504. wait_event_interruptible(disp_irq_log_wq, disp_irq_log_module);
  505. DDPMSG("disp_irq_log_kthread_func dump intr register: disp_irq_log_module=%d\n",
  506. disp_irq_log_module);
  507. if ((disp_irq_log_module & (1 << DISP_MODULE_UNKNOWN)) != 0) {
  508. primary_display_reset_ovl_by_cmdq(disp_irq_log_module & 0x1);
  509. /* DDPAEE("dump disp info\n"); */
  510. primary_display_diagnose();
  511. } else if ((disp_irq_log_module & (1 << DISP_MODULE_RDMA0)) != 0) {
  512. ddp_dump_analysis(DISP_MODULE_CONFIG);
  513. ddp_dump_analysis(DISP_MODULE_RDMA0);
  514. ddp_dump_analysis(DISP_MODULE_OVL0);
  515. #if defined(OVL_CASCADE_SUPPORT)
  516. ddp_dump_analysis(DISP_MODULE_OVL1);
  517. #endif
  518. /* dump ultra/preultra related regs */
  519. DDPMSG("wdma_con1(2c)=0x%x, wdma_con2(0x38)=0x%x,\n",
  520. DISP_REG_GET(DISP_REG_WDMA_BUF_CON1),
  521. DISP_REG_GET(DISP_REG_WDMA_BUF_CON2));
  522. DDPMSG("rdma_gmc0(30)=0x%x, rdma_gmc1(38)=0x%x, fifo_con(40)=0x%x\n",
  523. DISP_REG_GET(DISP_REG_RDMA_MEM_GMC_SETTING_0),
  524. DISP_REG_GET(DISP_REG_RDMA_MEM_GMC_SETTING_1),
  525. DISP_REG_GET(DISP_REG_RDMA_FIFO_CON));
  526. DDPMSG("ovl0_gmc: 0x%x, 0x%x, 0x%x, 0x%x\n",
  527. DISP_REG_GET(DISP_REG_OVL_RDMA0_MEM_GMC_SETTING),
  528. DISP_REG_GET(DISP_REG_OVL_RDMA1_MEM_GMC_SETTING),
  529. DISP_REG_GET(DISP_REG_OVL_RDMA2_MEM_GMC_SETTING),
  530. DISP_REG_GET(DISP_REG_OVL_RDMA3_MEM_GMC_SETTING));
  531. #if defined(OVL_CASCADE_SUPPORT)
  532. DDPMSG("ovl1_gmc: 0x%x, 0x%x, 0x%x, 0x%x\n",
  533. DISP_REG_GET(DISP_REG_OVL_RDMA0_MEM_GMC_SETTING +
  534. DISP_OVL_INDEX_OFFSET),
  535. DISP_REG_GET(DISP_REG_OVL_RDMA1_MEM_GMC_SETTING +
  536. DISP_OVL_INDEX_OFFSET),
  537. DISP_REG_GET(DISP_REG_OVL_RDMA2_MEM_GMC_SETTING +
  538. DISP_OVL_INDEX_OFFSET),
  539. DISP_REG_GET(DISP_REG_OVL_RDMA3_MEM_GMC_SETTING +
  540. DISP_OVL_INDEX_OFFSET));
  541. #endif
  542. /* dump smi regs */
  543. /* smi_dumpDebugMsg(); */
  544. } else {
  545. for (i = 0; i < DISP_MODULE_NUM; i++) {
  546. if ((disp_irq_log_module & (1 << i)) != 0)
  547. ddp_dump_reg(i);
  548. }
  549. }
  550. disp_irq_log_module = 0;
  551. }
  552. return 0;
  553. }
  554. void disp_register_dev_irq(unsigned int irq_num, char *device_name)
  555. {
  556. if (request_irq(irq_num, (irq_handler_t) disp_irq_handler,
  557. IRQF_TRIGGER_LOW, device_name, NULL))
  558. DDPERR("ddp register irq %u failed on device %s\n", irq_num, device_name);
  559. }
  560. int disp_init_irq(void)
  561. {
  562. if (irq_init)
  563. return 0;
  564. irq_init = 1;
  565. DDPPRINT("disp_init_irq\n");
  566. #if 0 /* irq mapped in DT probe() */
  567. static char *device_name = "mtk_disp";
  568. /* Register IRQ */
  569. disp_register_dev_irq(DISP_OVL0_IRQ_BIT_ID, "DISP_OVL0");
  570. disp_register_dev_irq(DISP_OVL1_IRQ_BIT_ID, "DISP_OVL1");
  571. disp_register_dev_irq(DISP_RDMA0_IRQ_BIT_ID, "DISP_RDMA0");
  572. disp_register_dev_irq(DISP_RDMA1_IRQ_BIT_ID, "DISP_RDMA1");
  573. disp_register_dev_irq(DISP_RDMA2_IRQ_BIT_ID, "DISP_RDMA2");
  574. disp_register_dev_irq(DISP_WDMA0_IRQ_BIT_ID, "DISP_WDMA0");
  575. disp_register_dev_irq(DISP_WDMA1_IRQ_BIT_ID, "DISP_WDMA1");
  576. disp_register_dev_irq(DSI0_IRQ_BIT_ID, "DISP_DSI0");
  577. /* disp_register_dev_irq(DISP_COLOR0_IRQ_BIT_ID ,device_name); */
  578. /* disp_register_dev_irq(DISP_COLOR1_IRQ_BIT_ID ,device_name); */
  579. /* disp_register_dev_irq(DISP_GAMMA_IRQ_BIT_ID ,device_name ); */
  580. /* disp_register_dev_irq(DISP_UFOE_IRQ_BIT_ID ,device_name); */
  581. disp_register_dev_irq(MM_MUTEX_IRQ_BIT_ID, "DISP_MUTEX");
  582. disp_register_dev_irq(DISP_AAL_IRQ_BIT_ID, "DISP_AAL");
  583. #endif
  584. /* create irq log thread */
  585. init_waitqueue_head(&disp_irq_log_wq);
  586. disp_irq_log_task = kthread_create(disp_irq_log_kthread_func, NULL, "ddp_irq_log_kthread");
  587. if (IS_ERR(disp_irq_log_task))
  588. DDPERR(" can not create disp_irq_log_task kthread\n");
  589. wake_up_process(disp_irq_log_task);
  590. return 0;
  591. }