ddp_aal.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  1. #include <linux/sched.h>
  2. #include <linux/wait.h>
  3. #include <linux/spinlock.h>
  4. #include <linux/kernel.h>
  5. #include <linux/slab.h>
  6. #include <linux/mutex.h>
  7. #include <asm/uaccess.h>
  8. #include <asm/atomic.h>
  9. #include <leds_drv.h>
  10. #include <cmdq_record.h>
  11. #include <ddp_reg.h>
  12. #include <ddp_drv.h>
  13. #include <ddp_path.h>
  14. #include <primary_display.h>
  15. #include <ddp_aal.h>
  16. #include <ddp_pwm.h>
  17. #ifdef CONFIG_MTK_CLKMGR
  18. #include <mach/mt_clkmgr.h>
  19. #else
  20. #if defined(CONFIG_ARCH_MT6755) || defined(CONFIG_ARCH_MT6797)
  21. #include <ddp_clkmgr.h>
  22. #endif
  23. #endif
  24. #if defined(CONFIG_ARCH_MT6755)
  25. /* #include "disp_lowpower.h" */
  26. /* #include "disp_helper.h" */
  27. #endif
  28. /* To enable debug log: */
  29. /* # echo aal_dbg:1 > /sys/kernel/debug/dispsys */
  30. int aal_dbg_en = 0;
  31. #define AAL_ERR(fmt, arg...) pr_err("[AAL] " fmt "\n", ##arg)
  32. #define AAL_DBG(fmt, arg...) \
  33. do { if (aal_dbg_en) pr_debug("[AAL] " fmt "\n", ##arg); } while (0)
  34. #ifdef CONFIG_MTK_AAL_SUPPORT
  35. static int disp_aal_write_init_regs(void *cmdq);
  36. #endif
  37. static int disp_aal_write_param_to_reg(cmdqRecHandle cmdq, const DISP_AAL_PARAM *param);
  38. static DECLARE_WAIT_QUEUE_HEAD(g_aal_hist_wq);
  39. static DEFINE_SPINLOCK(g_aal_hist_lock);
  40. static DISP_AAL_HIST g_aal_hist = {
  41. .serviceFlags = 0,
  42. .backlight = -1
  43. };
  44. static DISP_AAL_HIST g_aal_hist_db;
  45. static ddp_module_notify g_ddp_notify;
  46. static volatile int g_aal_hist_available;
  47. static volatile int g_aal_dirty_frame_retrieved = 1;
  48. static volatile int g_aal_is_init_regs_valid;
  49. static volatile int g_aal_backlight_notified = 1023;
  50. static volatile int g_aal_initialed;
  51. static int disp_aal_init(DISP_MODULE_ENUM module, int width, int height, void *cmdq)
  52. {
  53. #ifdef CONFIG_MTK_AAL_SUPPORT
  54. /* Enable AAL histogram, engine */
  55. DISP_REG_MASK(cmdq, DISP_AAL_CFG, 0x3 << 1, (0x3 << 1) | 0x1);
  56. disp_aal_write_init_regs(cmdq);
  57. #endif
  58. g_aal_hist_available = 0;
  59. g_aal_dirty_frame_retrieved = 1;
  60. return 0;
  61. }
  62. static void disp_aal_trigger_refresh(void)
  63. {
  64. if (g_ddp_notify != NULL)
  65. g_ddp_notify(DISP_MODULE_AAL, DISP_PATH_EVENT_TRIGGER);
  66. }
  67. static void disp_aal_set_interrupt(int enabled)
  68. {
  69. #ifdef CONFIG_MTK_AAL_SUPPORT
  70. if (enabled) {
  71. if (DISP_REG_GET(DISP_AAL_EN) == 0)
  72. AAL_DBG("[WARNING] DISP_AAL_EN not enabled!");
  73. /* Enable output frame end interrupt */
  74. DISP_CPU_REG_SET(DISP_AAL_INTEN, 0x2);
  75. AAL_DBG("Interrupt enabled");
  76. } else {
  77. if (g_aal_dirty_frame_retrieved) {
  78. DISP_CPU_REG_SET(DISP_AAL_INTEN, 0x0);
  79. AAL_DBG("Interrupt disabled");
  80. } else { /* Dirty histogram was not retrieved */
  81. /* Only if the dirty hist was retrieved, interrupt can be disabled.
  82. Continue interrupt until AALService can get the latest histogram. */
  83. }
  84. }
  85. #else
  86. AAL_ERR("AAL driver is not enabled");
  87. #endif
  88. }
  89. static void disp_aal_notify_frame_dirty(void)
  90. {
  91. #ifdef CONFIG_MTK_AAL_SUPPORT
  92. unsigned long flags;
  93. AAL_DBG("disp_aal_notify_frame_dirty()");
  94. #ifdef MTK_DISP_IDLE_LP
  95. disp_exit_idle_ex("disp_aal_notify_frame_dirty");
  96. #endif
  97. spin_lock_irqsave(&g_aal_hist_lock, flags);
  98. /* Interrupt can be disabled until dirty histogram is retrieved */
  99. g_aal_dirty_frame_retrieved = 0;
  100. spin_unlock_irqrestore(&g_aal_hist_lock, flags);
  101. disp_aal_set_interrupt(1);
  102. #endif
  103. }
  104. static int disp_aal_wait_hist(unsigned long timeout)
  105. {
  106. int ret = 0;
  107. AAL_DBG("disp_aal_wait_hist: available = %d", g_aal_hist_available);
  108. if (!g_aal_hist_available) {
  109. ret = wait_event_interruptible(g_aal_hist_wq, (g_aal_hist_available != 0));
  110. AAL_DBG("disp_aal_wait_hist: waken up, ret = %d", ret);
  111. } else {
  112. /* If g_aal_hist_available is already set, means AALService was delayed */
  113. }
  114. return ret;
  115. }
  116. void disp_aal_on_end_of_frame(void)
  117. {
  118. #ifdef CONFIG_MTK_AAL_SUPPORT
  119. unsigned int intsta;
  120. int i;
  121. unsigned long flags;
  122. intsta = DISP_REG_GET(DISP_AAL_INTSTA);
  123. AAL_DBG("disp_aal_on_end_of_frame: intsta: 0x%x", intsta);
  124. if (intsta & 0x2) { /* End of frame */
  125. if (spin_trylock_irqsave(&g_aal_hist_lock, flags)) {
  126. DISP_CPU_REG_SET(DISP_AAL_INTSTA, (intsta & ~0x3));
  127. for (i = 0; i < AAL_HIST_BIN; i++)
  128. g_aal_hist.maxHist[i] = DISP_REG_GET(DISP_AAL_STATUS_00 + (i << 2));
  129. g_aal_hist_available = 1;
  130. /* Allow to disable interrupt */
  131. g_aal_dirty_frame_retrieved = 1;
  132. spin_unlock_irqrestore(&g_aal_hist_lock, flags);
  133. if (!g_aal_is_init_regs_valid) {
  134. /*
  135. * AAL service is not running, not need per-frame wakeup.
  136. * We stop interrupt until next frame dirty.
  137. */
  138. disp_aal_set_interrupt(0);
  139. }
  140. wake_up_interruptible(&g_aal_hist_wq);
  141. } else {
  142. /*
  143. * Histogram was not be retrieved, but it's OK.
  144. * Another interrupt will come until histogram available
  145. * See: disp_aal_set_interrupt()
  146. */
  147. }
  148. }
  149. #else
  150. /*
  151. * We will not wake up AAL unless signals
  152. */
  153. #endif
  154. }
  155. void disp_aal_notify_backlight_changed(int bl_1024)
  156. {
  157. unsigned long flags;
  158. int max_backlight;
  159. unsigned int service_flags;
  160. pr_debug("disp_aal_notify_backlight_changed: %d/1023", bl_1024);
  161. #ifdef MTK_DISP_IDLE_LP
  162. disp_exit_idle_ex("disp_aal_notify_backlight_changed");
  163. #endif
  164. max_backlight = disp_pwm_get_max_backlight(DISP_PWM0);
  165. if (bl_1024 > max_backlight)
  166. bl_1024 = max_backlight;
  167. g_aal_backlight_notified = bl_1024;
  168. service_flags = 0;
  169. if (bl_1024 == 0) {
  170. backlight_brightness_set(0);
  171. /* set backlight = 0 may be not from AAL, we have to let AALService
  172. can turn on backlight on phone resumption */
  173. service_flags = AAL_SERVICE_FORCE_UPDATE;
  174. /* using CPU to set backlight = 0, */
  175. /* we have to set backlight = 0 through CMDQ again to avoid timimg issue */
  176. disp_pwm_set_force_update_flag();
  177. } else if (!g_aal_is_init_regs_valid) {
  178. /* AAL Service is not running */
  179. backlight_brightness_set(bl_1024);
  180. }
  181. spin_lock_irqsave(&g_aal_hist_lock, flags);
  182. g_aal_hist.backlight = bl_1024;
  183. g_aal_hist.serviceFlags |= service_flags;
  184. spin_unlock_irqrestore(&g_aal_hist_lock, flags);
  185. if (g_aal_is_init_regs_valid) {
  186. #if defined(CONFIG_ARCH_MT6755)
  187. /*
  188. if (disp_helper_get_option(DISP_OPT_IDLEMGR_ENTER_ULPS))
  189. primary_display_idlemgr_kick(__func__, 1);
  190. */
  191. #endif
  192. disp_aal_set_interrupt(1);
  193. disp_aal_trigger_refresh();
  194. }
  195. }
  196. static int disp_aal_copy_hist_to_user(DISP_AAL_HIST __user *hist)
  197. {
  198. unsigned long flags;
  199. int ret = -EFAULT;
  200. /* We assume only one thread will call this function */
  201. spin_lock_irqsave(&g_aal_hist_lock, flags);
  202. memcpy(&g_aal_hist_db, &g_aal_hist, sizeof(DISP_AAL_HIST));
  203. g_aal_hist.serviceFlags = 0;
  204. g_aal_hist_available = 0;
  205. spin_unlock_irqrestore(&g_aal_hist_lock, flags);
  206. if (copy_to_user(hist, &g_aal_hist_db, sizeof(DISP_AAL_HIST)) == 0)
  207. ret = 0;
  208. AAL_DBG("disp_aal_copy_hist_to_user: %d", ret);
  209. return ret;
  210. }
  211. #define CABC_GAINLMT(v0, v1, v2) (((v2) << 20) | ((v1) << 10) | (v0))
  212. #ifdef CONFIG_MTK_AAL_SUPPORT
  213. static DISP_AAL_INITREG g_aal_init_regs;
  214. #endif
  215. static DISP_AAL_PARAM g_aal_param;
  216. static int disp_aal_set_init_reg(DISP_AAL_INITREG __user *user_regs, void *cmdq)
  217. {
  218. int ret = -EFAULT;
  219. #ifdef CONFIG_MTK_AAL_SUPPORT
  220. DISP_AAL_INITREG *init_regs;
  221. init_regs = &g_aal_init_regs;
  222. ret = copy_from_user(init_regs, user_regs, sizeof(DISP_AAL_INITREG));
  223. if (ret == 0) {
  224. g_aal_is_init_regs_valid = 1;
  225. ret = disp_aal_write_init_regs(cmdq);
  226. } else {
  227. AAL_ERR("disp_aal_set_init_reg: copy_from_user() failed");
  228. }
  229. AAL_DBG("disp_aal_set_init_reg: %d", ret);
  230. #else
  231. AAL_ERR("disp_aal_set_init_reg: AAL not supported");
  232. #endif
  233. return ret;
  234. }
  235. #ifdef CONFIG_MTK_AAL_SUPPORT
  236. static int disp_aal_write_init_regs(void *cmdq)
  237. {
  238. int ret = -EFAULT;
  239. if (g_aal_is_init_regs_valid) {
  240. DISP_AAL_INITREG *init_regs = &g_aal_init_regs;
  241. int i, j;
  242. int *gain;
  243. DISP_REG_MASK(cmdq, DISP_AAL_DRE_MAPPING_00, (init_regs->dre_map_bypass << 4),
  244. 1 << 4);
  245. gain = init_regs->cabc_gainlmt;
  246. j = 0;
  247. for (i = 0; i <= 10; i++) {
  248. DISP_REG_SET(cmdq, DISP_AAL_CABC_GAINLMT_TBL(i),
  249. CABC_GAINLMT(gain[j], gain[j + 1], gain[j + 2]));
  250. j += 3;
  251. }
  252. AAL_DBG("disp_aal_write_init_regs: done");
  253. ret = 0;
  254. }
  255. return ret;
  256. }
  257. #endif
  258. int disp_aal_set_param(DISP_AAL_PARAM __user *param, void *cmdq)
  259. {
  260. int ret = -EFAULT;
  261. int backlight_value = 0;
  262. /* Not need to protect g_aal_param, since only AALService
  263. can set AAL parameters. */
  264. if (copy_from_user(&g_aal_param, param, sizeof(DISP_AAL_PARAM)) == 0) {
  265. backlight_value = g_aal_param.FinalBacklight;
  266. #ifdef CONFIG_MTK_AAL_SUPPORT
  267. /* set cabc gain zero when detect backlight setting equal to zero */
  268. if (backlight_value == 0)
  269. g_aal_param.cabc_fltgain_force = 0;
  270. #endif
  271. ret = disp_aal_write_param_to_reg(cmdq, &g_aal_param);
  272. }
  273. if (g_aal_backlight_notified == 0)
  274. backlight_value = 0;
  275. if (ret == 0)
  276. ret |= disp_pwm_set_backlight_cmdq(DISP_PWM0, backlight_value, cmdq);
  277. AAL_DBG("disp_aal_set_param(CABC = %d, DRE[0,8] = %d,%d): ret = %d",
  278. g_aal_param.cabc_fltgain_force, g_aal_param.DREGainFltStatus[0],
  279. g_aal_param.DREGainFltStatus[8], ret);
  280. backlight_brightness_set(backlight_value);
  281. disp_aal_trigger_refresh();
  282. return ret;
  283. }
  284. #define DRE_REG_2(v0, off0, v1, off1) (((v1) << (off1)) | ((v0) << (off0)))
  285. #define DRE_REG_3(v0, off0, v1, off1, v2, off2) (((v2) << (off2)) | (v1 << (off1)) | ((v0) << (off0)))
  286. static int disp_aal_write_param_to_reg(cmdqRecHandle cmdq, const DISP_AAL_PARAM *param)
  287. {
  288. int i;
  289. const int *gain;
  290. gain = param->DREGainFltStatus;
  291. DISP_REG_MASK(cmdq, DISP_AAL_DRE_FLT_FORCE(0), DRE_REG_2(gain[0], 0, gain[1], 12), ~0);
  292. DISP_REG_MASK(cmdq, DISP_AAL_DRE_FLT_FORCE(1), DRE_REG_2(gain[2], 0, gain[3], 12), ~0);
  293. DISP_REG_MASK(cmdq, DISP_AAL_DRE_FLT_FORCE(2), DRE_REG_2(gain[4], 0, gain[5], 11), ~0);
  294. DISP_REG_MASK(cmdq, DISP_AAL_DRE_FLT_FORCE(3),
  295. DRE_REG_3(gain[6], 0, gain[7], 11, gain[8], 21), ~0);
  296. DISP_REG_MASK(cmdq, DISP_AAL_DRE_FLT_FORCE(4),
  297. DRE_REG_3(gain[9], 0, gain[10], 10, gain[11], 20), ~0);
  298. DISP_REG_MASK(cmdq, DISP_AAL_DRE_FLT_FORCE(5),
  299. DRE_REG_3(gain[12], 0, gain[13], 10, gain[14], 20), ~0);
  300. DISP_REG_MASK(cmdq, DISP_AAL_DRE_FLT_FORCE(6),
  301. DRE_REG_3(gain[15], 0, gain[16], 10, gain[17], 20), ~0);
  302. DISP_REG_MASK(cmdq, DISP_AAL_DRE_FLT_FORCE(7),
  303. DRE_REG_3(gain[18], 0, gain[19], 9, gain[20], 18), ~0);
  304. DISP_REG_MASK(cmdq, DISP_AAL_DRE_FLT_FORCE(8),
  305. DRE_REG_3(gain[21], 0, gain[22], 9, gain[23], 18), ~0);
  306. DISP_REG_MASK(cmdq, DISP_AAL_DRE_FLT_FORCE(9),
  307. DRE_REG_3(gain[24], 0, gain[25], 9, gain[26], 18), ~0);
  308. DISP_REG_MASK(cmdq, DISP_AAL_DRE_FLT_FORCE(10), DRE_REG_2(gain[27], 0, gain[28], 9), ~0);
  309. DISP_REG_MASK(cmdq, DISP_AAL_CABC_00, 1 << 31, 1 << 31);
  310. DISP_REG_MASK(cmdq, DISP_AAL_CABC_02, ((1 << 26) | param->cabc_fltgain_force),
  311. ((1 << 26) | 0x3ff));
  312. gain = param->cabc_gainlmt;
  313. for (i = 0; i <= 10; i++) {
  314. DISP_REG_MASK(cmdq, DISP_AAL_CABC_GAINLMT_TBL(i),
  315. CABC_GAINLMT(gain[0], gain[1], gain[2]), ~0);
  316. gain += 3;
  317. }
  318. return 0;
  319. }
  320. static int aal_config(DISP_MODULE_ENUM module, disp_ddp_path_config *pConfig, void *cmdq)
  321. {
  322. if (pConfig->dst_dirty) {
  323. int width, height;
  324. width = pConfig->dst_w;
  325. height = pConfig->dst_h;
  326. DISP_REG_SET(cmdq, DISP_AAL_SIZE, (width << 16) | height);
  327. DISP_REG_MASK(cmdq, DISP_AAL_CFG, 0x0, 0x1); /* Disable relay mode */
  328. disp_aal_init(module, width, height, cmdq);
  329. DISP_REG_MASK(cmdq, DISP_AAL_EN, 0x1, 0x1);
  330. AAL_DBG("AAL_CFG = 0x%x, AAL_SIZE = 0x%x(%d, %d)",
  331. DISP_REG_GET(DISP_AAL_CFG), DISP_REG_GET(DISP_AAL_SIZE), width, height);
  332. }
  333. if (pConfig->ovl_dirty || pConfig->rdma_dirty)
  334. disp_aal_notify_frame_dirty();
  335. return 0;
  336. }
  337. /*****************************************************************************
  338. * AAL Backup / Restore function
  339. *****************************************************************************/
  340. struct { /* structure for backup AAL register value */
  341. unsigned int DRE_MAPPING;
  342. unsigned int DRE_FLT_FORCE[11];
  343. unsigned int CABC_00;
  344. unsigned int CABC_02;
  345. unsigned int CABC_GAINLMT[11];
  346. } g_aal_backup;
  347. static void ddp_aal_backup(void)
  348. {
  349. int i;
  350. g_aal_backup.CABC_00 = DISP_REG_GET(DISP_AAL_CABC_00);
  351. g_aal_backup.CABC_02 = DISP_REG_GET(DISP_AAL_CABC_02);
  352. for (i = 0; i <= 10; i++)
  353. g_aal_backup.CABC_GAINLMT[i] = DISP_REG_GET(DISP_AAL_CABC_GAINLMT_TBL(i));
  354. g_aal_backup.DRE_MAPPING = DISP_REG_GET(DISP_AAL_DRE_MAPPING_00);
  355. for (i = 0; i <= 10; i++)
  356. g_aal_backup.DRE_FLT_FORCE[i] = DISP_REG_GET(DISP_AAL_DRE_FLT_FORCE(i));
  357. g_aal_initialed = 1;
  358. }
  359. static void ddp_aal_restore(void *cmq_handle)
  360. {
  361. int i;
  362. if (g_aal_initialed == 1) {
  363. DISP_REG_SET(cmq_handle, DISP_AAL_CABC_00, g_aal_backup.CABC_00);
  364. DISP_REG_SET(cmq_handle, DISP_AAL_CABC_02, g_aal_backup.CABC_02);
  365. for (i = 0; i <= 10; i++)
  366. DISP_REG_SET(cmq_handle, DISP_AAL_CABC_GAINLMT_TBL(i), g_aal_backup.CABC_GAINLMT[i]);
  367. DISP_REG_SET(cmq_handle, DISP_AAL_DRE_MAPPING_00, g_aal_backup.DRE_MAPPING);
  368. for (i = 0; i <= 10; i++)
  369. DISP_REG_SET(cmq_handle, DISP_AAL_DRE_FLT_FORCE(i), g_aal_backup.DRE_FLT_FORCE[i]);
  370. }
  371. }
  372. static int aal_clock_on(DISP_MODULE_ENUM module, void *cmq_handle)
  373. {
  374. #if defined(CONFIG_ARCH_MT6755)
  375. /* aal is DCM , do nothing */
  376. #else
  377. #ifdef ENABLE_CLK_MGR
  378. #ifdef CONFIG_MTK_CLKMGR
  379. enable_clock(MT_CG_DISP0_DISP_AAL, "aal");
  380. #else
  381. ddp_clk_enable(DISP0_DISP_AAL);
  382. #endif
  383. AAL_DBG("aal_clock_on CG 0x%x", DISP_REG_GET(DISP_REG_CONFIG_MMSYS_CG_CON0));
  384. #endif
  385. #endif
  386. ddp_aal_restore(cmq_handle);
  387. return 0;
  388. }
  389. static int aal_clock_off(DISP_MODULE_ENUM module, void *cmq_handle)
  390. {
  391. ddp_aal_backup();
  392. #if defined(CONFIG_ARCH_MT6755)
  393. /* aal is DCM , do nothing */
  394. #else
  395. #ifdef ENABLE_CLK_MGR
  396. AAL_DBG("aal_clock_off");
  397. #ifdef CONFIG_MTK_CLKMGR
  398. disable_clock(MT_CG_DISP0_DISP_AAL, "aal");
  399. #else
  400. ddp_clk_disable(DISP0_DISP_AAL);
  401. #endif
  402. #endif
  403. #endif
  404. return 0;
  405. }
  406. static int aal_init(DISP_MODULE_ENUM module, void *cmq_handle)
  407. {
  408. aal_clock_on(module, cmq_handle);
  409. return 0;
  410. }
  411. static int aal_deinit(DISP_MODULE_ENUM module, void *cmq_handle)
  412. {
  413. aal_clock_off(module, cmq_handle);
  414. return 0;
  415. }
  416. static int aal_set_listener(DISP_MODULE_ENUM module, ddp_module_notify notify)
  417. {
  418. g_ddp_notify = notify;
  419. return 0;
  420. }
  421. int aal_bypass(DISP_MODULE_ENUM module, int bypass)
  422. {
  423. int relay = 0;
  424. if (bypass)
  425. relay = 1;
  426. DISP_REG_MASK(NULL, DISP_AAL_CFG, relay, 0x1);
  427. AAL_DBG("aal_bypass(bypass = %d)", bypass);
  428. return 0;
  429. }
  430. static int aal_io(DISP_MODULE_ENUM module, int msg, unsigned long arg, void *cmdq)
  431. {
  432. int ret = 0;
  433. switch (msg) {
  434. case DISP_IOCTL_AAL_EVENTCTL:
  435. {
  436. int enabled;
  437. if (copy_from_user(&enabled, (void *)arg, sizeof(enabled))) {
  438. AAL_ERR("DISP_IOCTL_AAL_EVENTCTL: copy_from_user() failed");
  439. return -EFAULT;
  440. }
  441. disp_aal_set_interrupt(enabled);
  442. if (enabled)
  443. disp_aal_trigger_refresh();
  444. break;
  445. }
  446. case DISP_IOCTL_AAL_GET_HIST:
  447. {
  448. disp_aal_wait_hist(60);
  449. if (disp_aal_copy_hist_to_user((DISP_AAL_HIST *) arg) < 0) {
  450. AAL_ERR("DISP_IOCTL_AAL_GET_HIST: copy_to_user() failed");
  451. return -EFAULT;
  452. }
  453. break;
  454. }
  455. case DISP_IOCTL_AAL_INIT_REG:
  456. {
  457. if (disp_aal_set_init_reg((DISP_AAL_INITREG *) arg, cmdq) < 0) {
  458. AAL_ERR("DISP_IOCTL_AAL_INIT_REG: failed");
  459. return -EFAULT;
  460. }
  461. break;
  462. }
  463. case DISP_IOCTL_AAL_SET_PARAM:
  464. {
  465. if (disp_aal_set_param((DISP_AAL_PARAM *) arg, cmdq) < 0) {
  466. AAL_ERR("DISP_IOCTL_AAL_SET_PARAM: failed");
  467. return -EFAULT;
  468. }
  469. break;
  470. }
  471. }
  472. return ret;
  473. }
  474. DDP_MODULE_DRIVER ddp_driver_aal = {
  475. .init = aal_init,
  476. .deinit = aal_deinit,
  477. .config = aal_config,
  478. .start = NULL,
  479. .trigger = NULL,
  480. .stop = NULL,
  481. .reset = NULL,
  482. .power_on = aal_clock_on,
  483. .power_off = aal_clock_off,
  484. .is_idle = NULL,
  485. .is_busy = NULL,
  486. .dump_info = NULL,
  487. .bypass = aal_bypass,
  488. .build_cmdq = NULL,
  489. .set_lcm_utils = NULL,
  490. .set_listener = aal_set_listener,
  491. .cmd = aal_io,
  492. };
  493. /* ---------------------------------------------------------------------- */
  494. /* Test code */
  495. /* Will not be linked in user build. */
  496. /* ---------------------------------------------------------------------- */
  497. #define AAL_TLOG(fmt, arg...) pr_debug("[AAL] " fmt "\n", ##arg)
  498. static void aal_test_en(const char *cmd)
  499. {
  500. int en = ((cmd[0] == '0') ? 0 : 1);
  501. DISP_REG_SET(NULL, DISP_AAL_EN, en);
  502. AAL_TLOG("EN = %d, read = %d", en, DISP_REG_GET(DISP_AAL_EN));
  503. }
  504. static void aal_dump_histogram(void)
  505. {
  506. unsigned long flags;
  507. DISP_AAL_HIST *hist;
  508. int i;
  509. hist = kmalloc(sizeof(DISP_AAL_HIST), GFP_KERNEL);
  510. if (hist != NULL) {
  511. spin_lock_irqsave(&g_aal_hist_lock, flags);
  512. memcpy(hist, &g_aal_hist, sizeof(DISP_AAL_HIST));
  513. spin_unlock_irqrestore(&g_aal_hist_lock, flags);
  514. for (i = 0; i + 8 < AAL_HIST_BIN; i += 8) {
  515. AAL_TLOG("Hist[%d..%d] = %6d %6d %6d %6d %6d %6d %6d %6d",
  516. i, i + 7, hist->maxHist[i], hist->maxHist[i + 1],
  517. hist->maxHist[i + 2], hist->maxHist[i + 3], hist->maxHist[i + 4],
  518. hist->maxHist[i + 5], hist->maxHist[i + 6], hist->maxHist[i + 7]);
  519. }
  520. for (; i < AAL_HIST_BIN; i++)
  521. AAL_TLOG("Hist[%d] = %6d", i, hist->maxHist[i]);
  522. kfree(hist);
  523. }
  524. }
  525. static void aal_test_ink(const char *cmd)
  526. {
  527. int en = (cmd[0] - '0');
  528. const unsigned long cabc_04 = DISP_AAL_CABC_00 + 0x4 * 4;
  529. switch (en) {
  530. case 1:
  531. DISP_REG_SET(NULL, cabc_04, (1 << 31) | (511 << 18));
  532. break;
  533. case 2:
  534. DISP_REG_SET(NULL, cabc_04, (1 << 31) | (511 << 9));
  535. break;
  536. case 3:
  537. DISP_REG_SET(NULL, cabc_04, (1 << 31) | (511 << 0));
  538. break;
  539. case 4:
  540. DISP_REG_SET(NULL, cabc_04, (1 << 31) | (511 << 18) | (511 << 9) | 511);
  541. break;
  542. default:
  543. DISP_REG_SET(NULL, cabc_04, 0);
  544. break;
  545. }
  546. disp_aal_trigger_refresh();
  547. }
  548. void aal_test(const char *cmd, char *debug_output)
  549. {
  550. debug_output[0] = '\0';
  551. AAL_TLOG("aal_test(%s)", cmd);
  552. if (strncmp(cmd, "en:", 3) == 0) {
  553. aal_test_en(cmd + 3);
  554. } else if (strncmp(cmd, "histogram", 5) == 0) {
  555. aal_dump_histogram();
  556. } else if (strncmp(cmd, "ink:", 4) == 0) {
  557. aal_test_ink(cmd + 4);
  558. } else if (strncmp(cmd, "bypass:", 7) == 0) {
  559. int bypass = (cmd[7] == '1');
  560. aal_bypass(DISP_MODULE_AAL, bypass);
  561. }
  562. }