ddp_od.c 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360
  1. #include <linux/gfp.h>
  2. #include <linux/types.h>
  3. #include <linux/string.h> /* for test cases */
  4. #include <asm/cacheflush.h>
  5. #include <linux/slab.h>
  6. #include <linux/dma-mapping.h>
  7. #include <asm/uaccess.h>
  8. #include <asm/bitops.h>
  9. #include <linux/time.h>
  10. #include <linux/delay.h>
  11. #include <linux/sched.h>
  12. #include <linux/module.h>
  13. #include <linux/kthread.h>
  14. /* #include <mach/mt_spm_idle.h> */
  15. #ifdef CONFIG_MTK_CLKMGR
  16. #include <mach/mt_clkmgr.h>
  17. #else
  18. #include <ddp_clkmgr.h>
  19. #endif
  20. #include <m4u.h>
  21. #include <ddp_drv.h>
  22. #include <ddp_reg.h>
  23. #include <ddp_debug.h>
  24. #include <ddp_log.h>
  25. #include <lcm_drv.h>
  26. #include <ddp_dither.h>
  27. #include <ddp_od.h>
  28. #include "ddp_od_reg.h"
  29. #include "ddp_od_table.h"
  30. #define OD_ALLOW_DEFAULT_TABLE
  31. /* #define OD_LINEAR_TABLE_IF_NONE */
  32. /* compression ratio */
  33. #define OD_MANUAL_CPR 58 /* 38 */
  34. #define OD_HSYNC_WIDTH 100
  35. #define OD_LINESIZE_BUFFER 8
  36. /* Additional space after the given memory to avoid unexpected memory corruption */
  37. /* In the experiments, OD hardware overflew 240 bytes */
  38. #define OD_ADDITIONAL_BUFFER 256
  39. #define OD_GUARD_PATTERN 0x16881688
  40. #define OD_GUARD_PATTERN_SIZE 4
  41. #define OD_REG_SET_FIELD(cmdq, reg, val, field) DISP_REG_SET_FIELD(cmdq, field, (unsigned long)(reg), val)
  42. #define OD_REG_GET(reg32) DISP_REG_GET((unsigned long)(reg32))
  43. #define OD_REG_SET(handle, reg32, val) DISP_REG_SET(handle, (unsigned long)(reg32), val)
  44. #define ABS(a) ((a > 0) ? a : -a)
  45. /* debug macro */
  46. #define ODERR(fmt, arg...) pr_err("[OD] " fmt "\n", ##arg)
  47. #define ODNOTICE(fmt, arg...) pr_warn("[OD] " fmt "\n", ##arg)
  48. /* ioctl */
  49. typedef enum {
  50. OD_CTL_READ_REG,
  51. OD_CTL_WRITE_REG,
  52. OD_CTL_ENABLE_DEMO_MODE,
  53. OD_CTL_RUN_TEST,
  54. OD_CTL_WRITE_TABLE,
  55. OD_CTL_CMD_NUM,
  56. OD_CTL_ENABLE
  57. } DISP_OD_CMD_TYPE;
  58. typedef enum {
  59. OD_CTL_ENABLE_OFF,
  60. OD_CTL_ENABLE_ON
  61. } DISP_OD_ENABLE_STAGE;
  62. enum {
  63. OD_RED,
  64. OD_GREEN,
  65. OD_BLUE,
  66. OD_ALL
  67. };
  68. enum {
  69. OD_TABLE_17,
  70. OD_TABLE_33
  71. };
  72. static void od_dbg_dump(void);
  73. struct OD_BUFFER_STRUCT {
  74. unsigned int size;
  75. unsigned long pa;
  76. void *va;
  77. } g_od_buf;
  78. enum OD_DBG_LEVEL {
  79. OD_DBG_ALWAYS = 0,
  80. OD_DBG_VERBOSE,
  81. OD_DBG_DEBUG
  82. };
  83. static int od_debug_level = -1;
  84. #define ODDBG(level, fmt, arg...) \
  85. do { \
  86. if (od_debug_level >= (level)) \
  87. pr_debug("[OD] " fmt "\n", ##arg); \
  88. } while (0)
  89. static int g_od_is_demo_mode;
  90. enum OD_DEBUG_MODE {
  91. DEBUG_MODE_NONE = 0,
  92. DEBUG_MODE_INK,
  93. DEBUG_MODE_INK_OSD
  94. };
  95. static enum OD_DEBUG_MODE g_od_debug_mode = DEBUG_MODE_NONE;
  96. static int g_od_is_enabled; /* OD is disabled by default */
  97. enum OD_DISABLED_BIT_FLAGS {
  98. DISABLED_BY_HWC = 0,
  99. DISABLED_BY_MHL
  100. };
  101. static volatile unsigned long g_od_force_disabled; /* Initialized to 0 */
  102. enum OD_DEBUG_ENABLE_ENUM {
  103. DEBUG_ENABLE_NORMAL = 0,
  104. DEBUG_ENABLE_ALWAYS,
  105. DEBUG_ENABLE_NEVER
  106. };
  107. static enum OD_DEBUG_ENABLE_ENUM g_od_debug_enable = DEBUG_ENABLE_NORMAL;
  108. static volatile struct {
  109. unsigned int frame;
  110. unsigned int rdma_error;
  111. unsigned int rdma_normal;
  112. } g_od_debug_cnt = { 0 };
  113. static ddp_module_notify g_od_ddp_notify;
  114. static void _od_reg_init(void *cmdq)
  115. {
  116. DISP_REG_SET(cmdq, OD_REG00, 0x82040201);
  117. DISP_REG_SET(cmdq, OD_REG01, 0x00070E01 & 0x000000ff);
  118. DISP_REG_SET(cmdq, OD_REG02, 0x00000400);
  119. DISP_REG_SET(cmdq, OD_REG03, 0x00E0FF04);
  120. DISP_REG_SET(cmdq, OD_REG30, 0x00010026); /* set cr rate ==0x42 */
  121. DISP_REG_SET(cmdq, OD_REG33, 0x00021000 & 0x003fffff);
  122. DISP_REG_SET(cmdq, OD_REG34, 0x0674A0E6);
  123. DISP_REG_SET(cmdq, OD_REG35, 0x000622E0); /* 0x00051170 */
  124. DISP_REG_SET(cmdq, OD_REG36, 0xE0849C40); /* DET8B_POS=4 */
  125. DISP_REG_SET(cmdq, OD_REG37, 0x05CFDE08); /* 0x04E6D998 */
  126. DISP_REG_SET(cmdq, OD_REG38, 0x011F1013); /* line size=0xf8 | (0x37 << 13) */
  127. DISP_REG_SET(cmdq, OD_REG39, 0x00200000 & 0x00ff0000); /* dram_crc_cnt=0x20 */
  128. DISP_REG_SET(cmdq, OD_REG40, 0x20000610); /* enable GM */
  129. DISP_REG_SET(cmdq, OD_REG41, 0x001E02D0);
  130. DISP_REG_SET(cmdq, OD_REG42, 0x00327C7C);
  131. DISP_REG_SET(cmdq, OD_REG43, 0x00180000); /* disable film mode detection */
  132. DISP_REG_SET(cmdq, OD_REG44, 0x006400C8);
  133. DISP_REG_SET(cmdq, OD_REG45, 0x00210032 & 0xfffffffc); /* pcid_alig_sel=1 */
  134. DISP_REG_SET(cmdq, OD_REG46, 0x4E00023F);
  135. DISP_REG_SET(cmdq, OD_REG47, 0xC306B16A); /* pre_bw=3 */
  136. DISP_REG_SET(cmdq, OD_REG48, 0x10240408); /* ???00210408??? */
  137. DISP_REG_SET(cmdq, OD_REG49, 0xC5C00000 & 0xC7C00000);
  138. DISP_REG_SET(cmdq, OD_REG51, 0x21A1B800);/* dump burst */
  139. DISP_REG_SET(cmdq, OD_REG52, 0x60000044 & 0xe00000ff);/* DUMP_WFF_FULL_CONF=3 */
  140. DISP_REG_SET(cmdq, OD_REG53, 0x2FFF3E00);
  141. DISP_REG_SET(cmdq, OD_REG54, 0x80039000); /* new 3x3 */
  142. DISP_REG_SET(cmdq, OD_REG57, 0x352835CA); /* skip color thr */
  143. DISP_REG_SET(cmdq, OD_REG62, 0x00014438); /* pattern gen */
  144. DISP_REG_SET(cmdq, OD_REG63, 0x27800898);
  145. DISP_REG_SET(cmdq, OD_REG64, 0x00438465);
  146. DISP_REG_SET(cmdq, OD_REG65, 0x01180001);
  147. DISP_REG_SET(cmdq, OD_REG66, 0x0002D000);
  148. DISP_REG_SET(cmdq, OD_REG67, 0x3FFFFFFF);
  149. DISP_REG_SET(cmdq, OD_REG68, 0x00000000);
  150. DISP_REG_SET(cmdq, OD_REG69, 0x000200C0);
  151. }
  152. static void od_refresh_screen(void)
  153. {
  154. if (g_od_ddp_notify != NULL)
  155. g_od_ddp_notify(DISP_MODULE_OD, DISP_PATH_EVENT_TRIGGER);
  156. }
  157. void od_debug_reg(void)
  158. {
  159. ODDBG(OD_DBG_ALWAYS, "==DISP OD REGS==\n");
  160. ODDBG(OD_DBG_ALWAYS, "OD:0x000=0x%08x,0x004=0x%08x,0x008=0x%08x,0x00c=0x%08x\n",
  161. OD_REG_GET(DISP_REG_OD_EN),
  162. OD_REG_GET(DISP_REG_OD_RESET),
  163. OD_REG_GET(DISP_REG_OD_INTEN),
  164. OD_REG_GET(DISP_REG_OD_INTSTA));
  165. ODDBG(OD_DBG_ALWAYS, "OD:0x010=0x%08x,0x020=0x%08x,0x024=0x%08x,0x028=0x%08x\n",
  166. OD_REG_GET(DISP_REG_OD_STATUS),
  167. OD_REG_GET(DISP_REG_OD_CFG),
  168. OD_REG_GET(DISP_REG_OD_INPUT_COUNT),
  169. OD_REG_GET(DISP_REG_OD_OUTPUT_COUNT));
  170. ODDBG(OD_DBG_ALWAYS, "OD:0x02c=0x%08x,0x030=0x%08x,0x040=0x%08x,0x044=0x%08x\n",
  171. OD_REG_GET(DISP_REG_OD_CHKSUM),
  172. OD_REG_GET(DISP_REG_OD_SIZE),
  173. OD_REG_GET(DISP_REG_OD_HSYNC_WIDTH),
  174. OD_REG_GET(DISP_REG_OD_VSYNC_WIDTH));
  175. ODDBG(OD_DBG_ALWAYS, "OD:0x048=0x%08x,0x0C0=0x%08x\n",
  176. OD_REG_GET(DISP_REG_OD_MISC),
  177. OD_REG_GET(DISP_REG_OD_DUMMY_REG));
  178. ODDBG(OD_DBG_ALWAYS, "OD:0x684=0x%08x,0x688=0x%08x,0x68c=0x%08x,0x690=0x%08x\n",
  179. OD_REG_GET(DISPSYS_OD_BASE + 0x684),
  180. OD_REG_GET(DISPSYS_OD_BASE + 0x688),
  181. OD_REG_GET(DISPSYS_OD_BASE + 0x68c),
  182. OD_REG_GET(DISPSYS_OD_BASE + 0x690));
  183. ODDBG(OD_DBG_ALWAYS, "OD:0x694=0x%08x,0x698=0x%08x,0x700=0x%08x,0x704=0x%08x\n",
  184. OD_REG_GET(DISPSYS_OD_BASE + 0x694),
  185. OD_REG_GET(DISPSYS_OD_BASE + 0x698),
  186. OD_REG_GET(DISPSYS_OD_BASE + 0x700),
  187. OD_REG_GET(DISPSYS_OD_BASE + 0x704));
  188. ODDBG(OD_DBG_ALWAYS, "OD:0x708=0x%08x,0x778=0x%08x,0x78c=0x%08x,0x790=0x%08x\n",
  189. OD_REG_GET(DISPSYS_OD_BASE + 0x708),
  190. OD_REG_GET(DISPSYS_OD_BASE + 0x778),
  191. OD_REG_GET(DISPSYS_OD_BASE + 0x78c),
  192. OD_REG_GET(DISPSYS_OD_BASE + 0x790));
  193. ODDBG(OD_DBG_ALWAYS, "OD:0x7a0=0x%08x,0x7dc=0x%08x,0x7e8=0x%08x\n",
  194. OD_REG_GET(DISPSYS_OD_BASE + 0x7a0),
  195. OD_REG_GET(DISPSYS_OD_BASE + 0x7dc),
  196. OD_REG_GET(DISPSYS_OD_BASE + 0x7e8));
  197. }
  198. /* NOTE: OD is not really enabled here until _disp_od_start() is called */
  199. void _disp_od_core_enabled(void *cmdq, int enabled)
  200. {
  201. #if defined(CONFIG_MTK_OD_SUPPORT)
  202. od_debug_reg();
  203. /* dram and bypass setting */
  204. /* We will set ODT_MAX_RATIO to valid value to enable OD */
  205. OD_REG_SET_FIELD(cmdq, OD_REG37, 0x0, ODT_MAX_RATIO);
  206. OD_REG_SET_FIELD(cmdq, OD_REG02, 0, ODT_BYPASS);
  207. OD_REG_SET_FIELD(cmdq, OD_REG71, 1, RG_WDRAM_HOLD_EN);
  208. OD_REG_SET_FIELD(cmdq, OD_REG72, 1, RG_RDRAM_HOLD_EN);
  209. OD_REG_SET_FIELD(cmdq, OD_REG39, 0, WDRAM_DIS);
  210. OD_REG_SET_FIELD(cmdq, OD_REG39, 0, RDRAM_DIS);
  211. if (enabled == 1) {
  212. DISP_REG_MASK(cmdq, OD_REG00, 0, (1 << 31)); /* bypass_all = 0 */
  213. DISP_REG_MASK(cmdq, OD_REG00, 1, 1); /* EN = 1 */
  214. DISP_REG_MASK(cmdq, DISP_REG_OD_CFG, 1<<1, 0x2); /* core en */
  215. } else {
  216. DISP_REG_MASK(cmdq, OD_REG00, 1, (1 << 31)); /* bypass_all = 1 */
  217. DISP_REG_MASK(cmdq, OD_REG00, 0, 1); /* EN = 0 */
  218. DISP_REG_MASK(cmdq, DISP_REG_OD_CFG, 0<<1, 0x2); /* core disable */
  219. }
  220. ODDBG(OD_DBG_ALWAYS, "_disp_od_core_enabled value=%d\n", enabled);
  221. #else
  222. ODDBG(OD_DBG_ALWAYS, "_disp_od_core_enabled: CONFIG_MTK_OD_SUPPORT is not set");
  223. #endif
  224. od_refresh_screen();
  225. }
  226. void _disp_od_start(void *cmdq)
  227. {
  228. #if defined(CONFIG_MTK_OD_SUPPORT)
  229. /* set max OD strength after bypass n frame */
  230. OD_REG_SET_FIELD(cmdq, OD_REG37, 0xf, ODT_MAX_RATIO);
  231. ODDBG(OD_DBG_ALWAYS, "_disp_od_start(%d)", g_od_is_enabled);
  232. od_refresh_screen();
  233. #endif
  234. }
  235. void disp_od_irq_handler(void)
  236. {
  237. #if defined(CONFIG_MTK_OD_SUPPORT)
  238. unsigned int od_istra = DISP_REG_GET(DISP_REG_OD_INTSTA);
  239. /* clear interrupt flag if "1" */
  240. DISP_REG_SET(NULL, DISP_REG_OD_INTSTA, (od_istra & ~0x1ff));
  241. /* detect certain interrupt for action */
  242. if ((od_istra & 0x2) != 0) {/* check OD output frame end interrupt */
  243. g_od_debug_cnt.frame++;
  244. }
  245. #endif
  246. DISP_REG_SET(NULL, DISP_REG_OD_INTSTA, 0);
  247. }
  248. int disp_rdma_notify(unsigned int reg)
  249. {
  250. #if defined(CONFIG_MTK_OD_SUPPORT)
  251. if ((reg & (1 << 4)) != 0)
  252. g_od_debug_cnt.rdma_error++;
  253. else if ((reg & (1 << 1)) != 0)
  254. g_od_debug_cnt.rdma_normal++;
  255. #endif
  256. return 0;
  257. }
  258. int disp_od_update_status(void *cmdq) /* Linked from primary_display.c */
  259. {
  260. /* Do nothing */
  261. return 0;
  262. }
  263. static void _od_set_dram_buffer_addr(void *cmdq, int manual_comp, int image_width, int image_height)
  264. {
  265. u32 u4ODDramSize;
  266. u32 u4Linesize;
  267. u32 od_buf_pa_32;
  268. static int is_inited;
  269. /* set line size : ( h active/4* manual CR )/128 ==>linesize = (h active * manual CR)/512*/
  270. u4Linesize = ((image_width * manual_comp) >> 9) + OD_LINESIZE_BUFFER;
  271. u4ODDramSize = u4Linesize * (image_height / 2) * 16;
  272. if (!is_inited) {
  273. void *va;
  274. dma_addr_t dma_addr;
  275. va = dma_alloc_coherent(disp_get_device(), u4ODDramSize + OD_ADDITIONAL_BUFFER + OD_GUARD_PATTERN_SIZE,
  276. &dma_addr, GFP_KERNEL);
  277. if (va == NULL) {
  278. ODDBG(OD_DBG_ALWAYS, "OD: MEM NOT ENOUGH %d", u4Linesize);
  279. BUG();
  280. }
  281. ODDBG(OD_DBG_ALWAYS, "OD: pa %08lx size %d order %d va %lx\n",
  282. (unsigned long)(dma_addr), u4ODDramSize, get_order(u4ODDramSize), (unsigned long)va);
  283. is_inited = 1;
  284. g_od_buf.size = u4ODDramSize;
  285. g_od_buf.pa = (unsigned long)dma_addr;
  286. g_od_buf.va = va;
  287. /* set guard pattern */
  288. *((u32 *)((unsigned long)va + u4ODDramSize)) = OD_GUARD_PATTERN;
  289. *((u32 *)((unsigned long)va + u4ODDramSize + OD_ADDITIONAL_BUFFER)) = OD_GUARD_PATTERN;
  290. }
  291. od_buf_pa_32 = (u32)g_od_buf.pa;
  292. OD_REG_SET_FIELD(cmdq, OD_REG06, (od_buf_pa_32 >> 4), RG_BASE_ADR);
  293. OD_REG_SET_FIELD(cmdq, OD_REG56, ((od_buf_pa_32 + u4ODDramSize) >> 4), DRAM_UPBOUND);
  294. OD_REG_SET_FIELD(cmdq, OD_REG56, 1, DRAM_PROT);
  295. }
  296. static void _od_set_frame_protect_init(void *cmdq, int image_width, int image_height)
  297. {
  298. OD_REG_SET_FIELD(cmdq, OD_REG08, image_width, OD_H_ACTIVE);
  299. OD_REG_SET_FIELD(cmdq, OD_REG32, image_width, OD_DE_WIDTH);
  300. OD_REG_SET_FIELD(cmdq, OD_REG08, image_height, OD_V_ACTIVE);
  301. OD_REG_SET_FIELD(cmdq, OD_REG53, 0x0BFB, FRAME_ERR_CON); /* don't care v blank */
  302. OD_REG_SET_FIELD(cmdq, OD_REG09, 0x01E, RG_H_BLANK); /* h_blank = htotal - h_active */
  303. OD_REG_SET_FIELD(cmdq, OD_REG09, 0x0A, RG_H_OFFSET); /* tolerrance */
  304. OD_REG_SET_FIELD(cmdq, OD_REG10, 0xFFF, RG_H_BLANK_MAX);
  305. OD_REG_SET_FIELD(cmdq, OD_REG10, 0x3FFFF, RG_V_BLANK_MAX); /* pixel-based counter */
  306. OD_REG_SET_FIELD(cmdq, OD_REG11, 0xB000, RG_V_BLANK); /* v_blank = vtotal - v_active */
  307. OD_REG_SET_FIELD(cmdq, OD_REG11, 2, RG_FRAME_SET);
  308. }
  309. static void _od_set_param(void *cmdq, int manual_comp, int image_width, int image_height)
  310. {
  311. u32 u4GMV_width;
  312. u32 u4Linesize;
  313. /* set gmv detection width */
  314. u4GMV_width = image_width / 6;
  315. OD_REG_SET_FIELD(cmdq, OD_REG40, (u4GMV_width*1)>>4, GM_R0_CENTER);
  316. OD_REG_SET_FIELD(cmdq, OD_REG40, (u4GMV_width*2)>>4, GM_R1_CENTER);
  317. OD_REG_SET_FIELD(cmdq, OD_REG41, (u4GMV_width*3)>>4, GM_R2_CENTER);
  318. OD_REG_SET_FIELD(cmdq, OD_REG41, (u4GMV_width*4)>>4, GM_R3_CENTER);
  319. OD_REG_SET_FIELD(cmdq, OD_REG42, (u4GMV_width*5)>>4, GM_R4_CENTER);
  320. OD_REG_SET_FIELD(cmdq, OD_REG43, 12 >> 2 , GM_V_ST);
  321. OD_REG_SET_FIELD(cmdq, OD_REG43, (image_height-12)>>2 , GM_V_END);
  322. OD_REG_SET_FIELD(cmdq, OD_REG42, (100*image_height)/1080 , GM_LGMIN_DIFF);
  323. OD_REG_SET_FIELD(cmdq, OD_REG44, (400*image_height)/1080 , GM_LMIN_THR);
  324. OD_REG_SET_FIELD(cmdq, OD_REG44, (200*image_height)/1080 , GM_GMIN_THR);
  325. /* set compression ratio */
  326. OD_REG_SET_FIELD(cmdq, OD_REG30, manual_comp, MANU_CPR);
  327. /* set line size */
  328. /* linesize = ( h active/4* manual CR )/128 ==>linesize = (h active * manual CR)/512 */
  329. u4Linesize = ((image_width * manual_comp) >> 9) + 2;
  330. OD_REG_SET_FIELD(cmdq, OD_REG47, 3, PRE_BW); /* vIO32WriteFldAlign(OD_REG47, 3, PRE_BW); */
  331. OD_REG_SET_FIELD(cmdq, OD_REG34, 0xF, ODT_SB_TH0);
  332. OD_REG_SET_FIELD(cmdq, OD_REG34, 0x10, ODT_SB_TH1);
  333. OD_REG_SET_FIELD(cmdq, OD_REG34, 0x11, ODT_SB_TH2);
  334. OD_REG_SET_FIELD(cmdq, OD_REG34, 0x12, ODT_SB_TH3);
  335. OD_REG_SET_FIELD(cmdq, OD_REG47, 0x13, ODT_SB_TH4);
  336. OD_REG_SET_FIELD(cmdq, OD_REG47, 0x14, ODT_SB_TH5);
  337. OD_REG_SET_FIELD(cmdq, OD_REG47, 0x15, ODT_SB_TH6);
  338. OD_REG_SET_FIELD(cmdq, OD_REG47, 0x16, ODT_SB_TH7);
  339. OD_REG_SET_FIELD(cmdq, OD_REG38, u4Linesize, LINE_SIZE);
  340. /* use 64 burst length */
  341. OD_REG_SET_FIELD(cmdq, OD_REG38, 3, WR_BURST_LEN);
  342. OD_REG_SET_FIELD(cmdq, OD_REG38, 3, RD_BURST_LEN);
  343. /*set auto 8bit parameters */
  344. if (image_width > 1900) {
  345. OD_REG_SET_FIELD(cmdq, OD_REG35, (140000 << 0), DET8B_DC_NUM);
  346. OD_REG_SET_FIELD(cmdq, OD_REG36, (40000 << 18), DET8B_BTC_NUM);
  347. OD_REG_SET_FIELD(cmdq, OD_REG37, (1900000>>4) , DET8B_BIT_MGN);
  348. } else {
  349. OD_REG_SET_FIELD(cmdq, OD_REG35, 70000, DET8B_DC_NUM);
  350. OD_REG_SET_FIELD(cmdq, OD_REG36, 20000, DET8B_BTC_NUM);
  351. OD_REG_SET_FIELD(cmdq, OD_REG37, (950000>>4), DET8B_BIT_MGN);
  352. }
  353. /* set auto Y5 mode thr */
  354. OD_REG_SET_FIELD(cmdq, OD_REG46, 0x4E00, AUTO_Y5_NUM);
  355. OD_REG_SET_FIELD(cmdq, OD_REG53, 0x4E00, AUTO_Y5_NUM_1);
  356. /* set OD threshold */
  357. OD_REG_SET_FIELD(cmdq, OD_REG01, 10, MOTION_THR);
  358. OD_REG_SET_FIELD(cmdq, OD_REG48, 8, ODT_INDIFF_TH);
  359. OD_REG_SET_FIELD(cmdq, OD_REG02, 1, FBT_BYPASS);
  360. /* set dump param */
  361. OD_REG_SET_FIELD(cmdq, OD_REG51, 0, DUMP_STLINE);
  362. OD_REG_SET_FIELD(cmdq, OD_REG51, (image_height-1), DUMP_ENDLINE);
  363. /* set compression param */
  364. OD_REG_SET_FIELD(cmdq, OD_REG77, 0xfc, RC_U_RATIO);
  365. OD_REG_SET_FIELD(cmdq, OD_REG78, 0xfc, RC_U_RATIO_FIRST2);
  366. OD_REG_SET_FIELD(cmdq, OD_REG77, 0x68, RC_L_RATIO);
  367. OD_REG_SET_FIELD(cmdq, OD_REG78, 0x68, RC_L_RATIO_FIRST2);
  368. OD_REG_SET_FIELD(cmdq, OD_REG76, 0x3, CHG_Q_FREQ);
  369. OD_REG_SET_FIELD(cmdq, OD_REG76, 0x2, CURR_Q_UV);
  370. OD_REG_SET_FIELD(cmdq, OD_REG76, 0x2, CURR_Q_BYPASS);
  371. OD_REG_SET_FIELD(cmdq, OD_REG77, 0x8, IP_SAD_TH);
  372. OD_REG_SET_FIELD(cmdq, OD_REG71, 40, RG_WR_HIGH);
  373. OD_REG_SET_FIELD(cmdq, OD_REG71, 40, RG_WR_PRE_HIGH);
  374. OD_REG_SET_FIELD(cmdq, OD_REG71, 1, RG_WRULTRA_EN);
  375. OD_REG_SET_FIELD(cmdq, OD_REG71, 40, RG_WR_LOW);
  376. OD_REG_SET_FIELD(cmdq, OD_REG71, 40, RG_WR_PRELOW);
  377. OD_REG_SET_FIELD(cmdq, OD_REG71, 1, RG_WGPREULTRA_EN);
  378. OD_REG_SET_FIELD(cmdq, OD_REG71, 1, RG_WDRAM_HOLD_EN);
  379. OD_REG_SET_FIELD(cmdq, OD_REG71, 1, RG_WDRAM_LEN_X8);
  380. OD_REG_SET_FIELD(cmdq, OD_REG72, 40, RG_RD_HIGH);
  381. OD_REG_SET_FIELD(cmdq, OD_REG72, 40, RG_RD_PRE_HIGH);
  382. OD_REG_SET_FIELD(cmdq, OD_REG72, 1, RG_RDULTRA_EN);
  383. OD_REG_SET_FIELD(cmdq, OD_REG72, 40, RG_RD_LOW);
  384. OD_REG_SET_FIELD(cmdq, OD_REG72, 40, RG_RD_PRELOW);
  385. OD_REG_SET_FIELD(cmdq, OD_REG72, 1, RG_RGPREULTRA_EN);
  386. OD_REG_SET_FIELD(cmdq, OD_REG72, 1, RG_RDRAM_HOLD_EN);
  387. OD_REG_SET_FIELD(cmdq, OD_REG72, 1, RG_RDRAM_LEN_X8);
  388. }
  389. static void _od_write_table(void *cmdq, u8 TableSel, u8 ColorSel, const u8 *pTable, int table_inverse)
  390. {
  391. u32 i, u4TblSize;
  392. u32 u1ODBypass = DISP_REG_GET(OD_REG02) & (1 << 9) ? 1 : 0;
  393. u32 u1FBBypass = DISP_REG_GET(OD_REG02) & (1 << 10) ? 1 : 0;
  394. u32 u1PCIDBypass = DISP_REG_GET(OD_REG02) & (1 << 21) ? 1 : 0;
  395. if (ColorSel > 3)
  396. return;
  397. /* disable OD_START */
  398. DISP_REG_SET(cmdq, OD_REG12, 0);
  399. OD_REG_SET_FIELD(cmdq, OD_REG02, 1, ODT_BYPASS);
  400. OD_REG_SET_FIELD(cmdq, OD_REG02, 1, FBT_BYPASS);
  401. OD_REG_SET_FIELD(cmdq, OD_REG45, 0, OD_PCID_EN);
  402. OD_REG_SET_FIELD(cmdq, OD_REG45, 1, OD_PCID_BYPASS);
  403. OD_REG_SET_FIELD(cmdq, OD_REG04, 1, TABLE_ONLY_W_ADR_INC);
  404. OD_REG_SET_FIELD(cmdq, OD_REG04, 0, ADDR_YX);
  405. OD_REG_SET_FIELD(cmdq, OD_REG04, 0x3, TABLE_RW_SEL_OD_BGR);
  406. if (ColorSel == 3)
  407. OD_REG_SET_FIELD(cmdq, OD_REG04, 7, TABLE_RW_SEL_OD_BGR);
  408. else
  409. OD_REG_SET_FIELD(cmdq, OD_REG04, (1 << ColorSel), TABLE_RW_SEL_OD_BGR);
  410. switch (TableSel) {
  411. case OD_TABLE_33:
  412. u4TblSize = OD_TBL_M_SIZE;
  413. OD_REG_SET_FIELD(cmdq, OD_REG32, 0, OD_IDX_41);
  414. OD_REG_SET_FIELD(cmdq, OD_REG32, 0, OD_IDX_17);
  415. break;
  416. case OD_TABLE_17:
  417. u4TblSize = OD_TBL_S_SIZE;
  418. OD_REG_SET_FIELD(cmdq, OD_REG32, 0, OD_IDX_41);
  419. OD_REG_SET_FIELD(cmdq, OD_REG32, 1, OD_IDX_17);
  420. break;
  421. default:
  422. return;
  423. }
  424. for (i = 0; i < u4TblSize; i++) {
  425. if (table_inverse) {
  426. u8 value = ABS(255 - *(pTable+i));
  427. DISP_REG_SET(cmdq, OD_REG05, value);
  428. } else {
  429. DISP_REG_SET(cmdq, OD_REG05, *(pTable+i));
  430. }
  431. }
  432. DISP_REG_SET(cmdq, OD_REG04, 0);
  433. OD_REG_SET_FIELD(cmdq, OD_REG02, u1ODBypass, ODT_BYPASS);
  434. OD_REG_SET_FIELD(cmdq, OD_REG02, u1FBBypass, FBT_BYPASS);
  435. OD_REG_SET_FIELD(cmdq, OD_REG45, (!u1PCIDBypass), OD_PCID_EN);
  436. OD_REG_SET_FIELD(cmdq, OD_REG45, (u1PCIDBypass), OD_PCID_BYPASS);
  437. }
  438. static u8 _od_read_table(void *cmdq, u8 TableSel, u8 ColorSel, const u8 *pTable, int table_inverse)
  439. {
  440. u32 i, u4TblVal, u4TblSize, u4ErrCnt = 0;
  441. u32 mask;
  442. u32 u1ODBypass = DISP_REG_GET(OD_REG02) & (1 << 9) ? 1 : 0;
  443. u32 u1FBBypass = DISP_REG_GET(OD_REG02) & (1 << 10) ? 1 : 0;
  444. u32 u1PCIDBypass = DISP_REG_GET(OD_REG02) & (1 << 21) ? 1 : 0;
  445. if (ColorSel > 2)
  446. return 1;
  447. OD_REG_SET_FIELD(cmdq, OD_REG02, u1ODBypass, ODT_BYPASS);
  448. OD_REG_SET_FIELD(cmdq, OD_REG02, u1FBBypass, FBT_BYPASS);
  449. OD_REG_SET_FIELD(cmdq, OD_REG04, 0, TABLE_ONLY_W_ADR_INC);
  450. OD_REG_SET_FIELD(cmdq, OD_REG04, 0, ADDR_YX);
  451. mask = ~(0x7 << 19);
  452. OD_REG_SET_FIELD(cmdq, OD_REG04, 7, TABLE_RW_SEL_OD_BGR);
  453. switch (TableSel) {
  454. case OD_TABLE_33:
  455. u4TblSize = OD_TBL_M_SIZE;
  456. OD_REG_SET_FIELD(cmdq, OD_REG32, 0, OD_IDX_41);
  457. OD_REG_SET_FIELD(cmdq, OD_REG32, 0, OD_IDX_17);
  458. break;
  459. case OD_TABLE_17:
  460. u4TblSize = OD_TBL_S_SIZE;
  461. OD_REG_SET_FIELD(cmdq, OD_REG32, 0, OD_IDX_41);
  462. OD_REG_SET_FIELD(cmdq, OD_REG32, 1, OD_IDX_17);
  463. break;
  464. default:
  465. return 0;
  466. }
  467. for (i = 0; i < u4TblSize; i++) {
  468. u4TblVal = DISP_REG_GET(OD_REG05);
  469. if (table_inverse) {
  470. u8 value = ABS(255 - *(pTable+i));
  471. if (value != u4TblVal)
  472. u4ErrCnt++;
  473. } else {
  474. if (*(pTable+i) != u4TblVal) {
  475. ODDBG(OD_DBG_ALWAYS, "OD %d TBL %d %d != %d\n", ColorSel, i, *(pTable+i), u4TblVal);
  476. u4ErrCnt++;
  477. }
  478. }
  479. }
  480. DISP_REG_SET(cmdq, OD_REG04, 0);
  481. OD_REG_SET_FIELD(cmdq, OD_REG02, u1ODBypass, ODT_BYPASS);
  482. OD_REG_SET_FIELD(cmdq, OD_REG02, u1FBBypass, FBT_BYPASS);
  483. OD_REG_SET_FIELD(cmdq, OD_REG45, !u1PCIDBypass, OD_PCID_EN);
  484. OD_REG_SET_FIELD(cmdq, OD_REG45, u1PCIDBypass, OD_PCID_BYPASS);
  485. return u4ErrCnt;
  486. }
  487. static void _od_set_table(void *cmdq, int tableSelect, const u8 *od_table, int table_inverse)
  488. {
  489. /* Write OD table */
  490. if (OD_TABLE_17 == tableSelect) {
  491. _od_write_table(cmdq, OD_TABLE_17, OD_ALL, od_table, table_inverse);
  492. /* Check OD table */
  493. /*
  494. #ifndef DEF_CMDQ
  495. _od_read_table(OD_TABLE_17, OD_RED, OD_Table_17x17, table_inverse);
  496. _od_read_table(OD_TABLE_17, OD_GREEN, OD_Table_17x17, table_inverse);
  497. _od_read_table(OD_TABLE_17, OD_BLUE, OD_Table_17x17, table_inverse);
  498. #endif
  499. */
  500. DISP_REG_SET(cmdq, OD_REG02, (1 << 10));
  501. OD_REG_SET_FIELD(cmdq, OD_REG45, 1, OD_PCID_BYPASS);
  502. OD_REG_SET_FIELD(cmdq, OD_REG45, 0, OD_PCID_EN);
  503. DISP_REG_SET(cmdq, OD_REG12, 1 << 0);
  504. } else if (OD_TABLE_33 == tableSelect) {
  505. _od_write_table(cmdq, OD_TABLE_33, OD_ALL, od_table, table_inverse);
  506. /* Check OD table */
  507. /*
  508. #ifndef DEF_CMDQ
  509. _od_read_table(OD_TABLE_33, OD_RED, OD_Table_33x33, table_inverse);
  510. _od_read_table(OD_TABLE_33, OD_GREEN, OD_Table_33x33, table_inverse);
  511. _od_read_table(OD_TABLE_33, OD_BLUE, OD_Table_33x33, table_inverse);
  512. #endif
  513. */
  514. DISP_REG_SET(cmdq, OD_REG02, (1 << 10));
  515. OD_REG_SET_FIELD(cmdq, OD_REG45, 1, OD_PCID_BYPASS);
  516. OD_REG_SET_FIELD(cmdq, OD_REG45, 0, OD_PCID_EN);
  517. DISP_REG_SET(cmdq, OD_REG12, 1 << 0);
  518. } else {
  519. ODDBG(OD_DBG_ALWAYS, "Error OD table\n");
  520. BUG();
  521. }
  522. }
  523. static void od_dbg_dump(void)
  524. {
  525. ODDBG(OD_DBG_ALWAYS, "OD EN %d INPUT %d %d\n", DISP_REG_GET(DISP_REG_OD_EN),
  526. DISP_REG_GET(DISP_REG_OD_INPUT_COUNT) >> 16, DISP_REG_GET(DISP_REG_OD_INPUT_COUNT) & 0xFFFF);
  527. ODDBG(OD_DBG_ALWAYS, "STA 0x%08x\n", DISP_REG_GET(OD_STA00));
  528. ODDBG(OD_DBG_ALWAYS, "REG49 0x%08x\n", DISP_REG_GET(OD_REG49));
  529. }
  530. void disp_config_od(unsigned int width, unsigned int height, void *cmdq, unsigned int od_table_size, void *od_table)
  531. {
  532. int manual_cpr = OD_MANUAL_CPR;
  533. int od_table_select = 0;
  534. ODDBG(OD_DBG_ALWAYS, "OD conf start %lx %x %lx\n", (unsigned long)cmdq, od_table_size, (unsigned long)od_table);
  535. switch (od_table_size) {
  536. case 17*17:
  537. od_table_select = OD_TABLE_17;
  538. break;
  539. case 33*33:
  540. od_table_select = OD_TABLE_33;
  541. break;
  542. /* default linear table */
  543. default:
  544. od_table_select = OD_TABLE_17;
  545. od_table = (void *)OD_Table_dummy_17x17;
  546. break;
  547. }
  548. if (od_table == NULL) {
  549. ODDBG(OD_DBG_ALWAYS, "LCM NULL OD table\n");
  550. BUG();
  551. }
  552. DISP_REG_SET(cmdq, DISP_REG_OD_EN, 1);
  553. DISP_REG_SET(cmdq, DISP_REG_OD_SIZE, (width << 16) | height);
  554. DISP_REG_SET(cmdq, DISP_REG_OD_HSYNC_WIDTH, OD_HSYNC_WIDTH);
  555. DISP_REG_SET(cmdq, DISP_REG_OD_VSYNC_WIDTH, (OD_HSYNC_WIDTH << 16) | (width * 3 / 2));
  556. _od_reg_init(cmdq);
  557. _od_set_dram_buffer_addr(cmdq, manual_cpr, width, height);
  558. _od_set_frame_protect_init(cmdq, width, height);
  559. /* OD on/off align to vsync */
  560. DISP_REG_SET(cmdq, OD_REG53, DISP_REG_GET(OD_REG53) | (1 << 30));
  561. /* _od_set_param(38, width, height); */
  562. _od_set_param(cmdq, manual_cpr, width, height);
  563. DISP_REG_SET(cmdq, OD_REG53, 0x6BFB7E00);
  564. DISP_REG_SET(cmdq, DISP_REG_OD_MISC, 1); /* [1]:can access OD table; [0]:can't access OD table */
  565. /* _od_set_table(OD_TABLE_17, 0); /// default use 17x17 table */
  566. _od_set_table(cmdq, od_table_select, od_table, 0);
  567. DISP_REG_SET(cmdq, DISP_REG_OD_MISC, 0); /* [1]:can access OD table; [0]:can't access OD table */
  568. /* modified ALBUF2_DLY OD_REG01 */
  569. /* OD_REG_SET_FIELD(cmdq, OD_REG01, (0xD), ALBUF2_DLY); // 1080w */
  570. OD_REG_SET_FIELD(cmdq, OD_REG01, (0xE), ALBUF2_DLY); /* 720w */
  571. /* disable hold for debug */
  572. /*
  573. OD_REG_SET_FIELD(cmdq, OD_REG71, 0, RG_WDRAM_HOLD_EN);
  574. OD_REG_SET_FIELD(cmdq, OD_REG72, 0, RG_RDRAM_HOLD_EN);
  575. */
  576. /* enable debug OSD for status reg */
  577. /* OD_REG_SET_FIELD(cmdq, OD_REG46, 1, OD_OSD_SEL); */
  578. /* lower hold threshold */
  579. /*
  580. OD_REG_SET_FIELD(cmdq, OD_REG73, 0, RG_WDRAM_HOLD_THR);
  581. OD_REG_SET_FIELD(cmdq, OD_REG73, 0, RG_RDRAM_HOLD_THR);
  582. */
  583. /* restore demo mode for suspend / resume */
  584. if (g_od_is_demo_mode)
  585. OD_REG_SET_FIELD(cmdq, OD_REG02, 1, DEMO_MODE);
  586. OD_REG_SET_FIELD(cmdq, OD_REG00, 0, BYPASS_ALL);
  587. /* GO OD. relay = 0, od_core_en = 1, DITHER_EN = 1 */
  588. /* Dynamic turn on from ioctl */
  589. DISP_REG_SET(cmdq, DISP_REG_OD_CFG, 2);
  590. /* clear crc error first */
  591. OD_REG_SET_FIELD(cmdq, OD_REG38, 1, DRAM_CRC_CLR);
  592. if (od_debug_level >= OD_DBG_DEBUG)
  593. od_dbg_dump();
  594. ODDBG(OD_DBG_ALWAYS, "OD inited W %d H %d\n", width, height);
  595. DISP_REG_MASK(cmdq, DISP_REG_OD_INTEN, 0x43, 0xff);
  596. /* workaround for debug (OSD+INK) */
  597. if (g_od_debug_mode == DEBUG_MODE_INK) {
  598. OD_REG_SET_FIELD(cmdq, OD_REG46, 1, OD_OSD_SEL);
  599. DISP_REG_MASK(cmdq, OD_REG03, 0, 0x1);
  600. } else if (g_od_debug_mode == DEBUG_MODE_INK_OSD) {
  601. OD_REG_SET_FIELD(cmdq, OD_REG46, 1, OD_OSD_SEL);
  602. DISP_REG_MASK(cmdq, OD_REG03, (0x33 << 24) | (0xaa << 16) | (0x55 << 8) | 1, 0xffffff01);
  603. } else {
  604. OD_REG_SET_FIELD(cmdq, OD_REG46, 0, OD_OSD_SEL);
  605. DISP_REG_MASK(cmdq, OD_REG03, 0, 0x1);
  606. }
  607. }
  608. int disp_od_get_enabled(void)
  609. {
  610. return g_od_is_enabled;
  611. }
  612. void disp_od_mhl_force(int allow_enabled)
  613. {
  614. ODDBG(OD_DBG_ALWAYS, "disp_od_mhl_force(allow = %d)\n", allow_enabled);
  615. if (!allow_enabled)
  616. set_bit(DISABLED_BY_MHL, &g_od_force_disabled);
  617. else
  618. clear_bit(DISABLED_BY_MHL, &g_od_force_disabled);
  619. }
  620. void disp_od_hwc_force(int allow_enabled)
  621. {
  622. ODDBG(OD_DBG_ALWAYS, "disp_od_hwc_force(allow = %d)\n", allow_enabled);
  623. if (!allow_enabled)
  624. set_bit(DISABLED_BY_HWC, &g_od_force_disabled);
  625. else
  626. clear_bit(DISABLED_BY_HWC, &g_od_force_disabled);
  627. }
  628. void disp_od_set_enabled(void *cmdq, int enabled)
  629. {
  630. #if defined(CONFIG_MTK_OD_SUPPORT)
  631. if (g_od_debug_enable == DEBUG_ENABLE_NORMAL) {
  632. if (!enabled || g_od_force_disabled != 0)
  633. g_od_is_enabled = 0;
  634. else
  635. g_od_is_enabled = 1;
  636. } else if (g_od_debug_enable == DEBUG_ENABLE_ALWAYS)
  637. g_od_is_enabled = 1;
  638. else
  639. g_od_is_enabled = 0;
  640. ODDBG(OD_DBG_ALWAYS, "disp_od_set_enabled=%d (in:%d)(force_disabled:0x%lx)\n",
  641. g_od_is_enabled, enabled, g_od_force_disabled);
  642. #endif
  643. }
  644. /*
  645. * Must be called after the 3rd frame after disp_od_set_enabled(1)
  646. * to enable OD function
  647. */
  648. void disp_od_start_read(void *cmdq)
  649. {
  650. #if defined(CONFIG_MTK_OD_SUPPORT)
  651. OD_REG_SET_FIELD(cmdq, OD_REG37, 0xf, ODT_MAX_RATIO);
  652. ODDBG(OD_DBG_ALWAYS, "disp_od_start_read(): enabled = %d\n", g_od_is_enabled);
  653. #endif
  654. }
  655. static int disp_od_ioctl_ctlcmd(DISP_MODULE_ENUM module, int msg, unsigned long arg, void *cmdq)
  656. {
  657. DISP_OD_CMD cmd;
  658. if (copy_from_user((void *)&cmd, (void *)arg, sizeof(DISP_OD_CMD)))
  659. return -EFAULT;
  660. ODDBG(OD_DBG_ALWAYS, "OD ioctl cmdq %lx\n", (unsigned long)cmdq);
  661. switch (cmd.type) {
  662. case OD_CTL_ENABLE: /* on/off OD */
  663. if (cmd.param0 == OD_CTL_ENABLE_OFF) {
  664. disp_od_hwc_force(0);
  665. disp_od_set_enabled(cmdq, 0);
  666. } else if (cmd.param0 == OD_CTL_ENABLE_ON) {
  667. disp_od_hwc_force(1);
  668. disp_od_set_enabled(cmdq, 1);
  669. } else {
  670. ODDBG(OD_DBG_ALWAYS, "unknown enable type command\n");
  671. }
  672. break;
  673. case OD_CTL_READ_REG: /* read reg */
  674. if (cmd.param0 < 0x1000) { /* deny OOB access */
  675. cmd.ret = OD_REG_GET(cmd.param0 + OD_BASE);
  676. } else {
  677. cmd.ret = 0;
  678. }
  679. break;
  680. case OD_CTL_WRITE_REG: /* write reg */
  681. if (cmd.param0 < 0x1000) { /* deny OOB access */
  682. DISP_REG_SET(cmdq, (unsigned long)(cmd.param0 + OD_BASE), cmd.param1);
  683. cmd.ret = OD_REG_GET(cmd.param0 + OD_BASE);
  684. } else {
  685. cmd.ret = 0;
  686. }
  687. break;
  688. /* enable split screen OD demo mode for miravision */
  689. case OD_CTL_ENABLE_DEMO_MODE:
  690. {
  691. switch (cmd.param0) {
  692. /* demo mode */
  693. case 0:
  694. case 1:
  695. {
  696. int enable = cmd.param0 ? 1 : 0;
  697. OD_REG_SET_FIELD(cmdq, OD_REG02, enable, DEMO_MODE);
  698. ODDBG(OD_DBG_ALWAYS, "OD demo %d\n", enable);
  699. /* save demo mode flag for suspend/resume */
  700. g_od_is_demo_mode = enable;
  701. break;
  702. }
  703. /* enable ink */
  704. case 2: /* off */
  705. case 3: /* on */
  706. OD_REG_SET_FIELD(cmdq, OD_REG03, (cmd.param0 - 2), ODT_INK_EN);
  707. break;
  708. /* eanble debug OSD */
  709. case 4: /* off */
  710. case 5: /* on */
  711. OD_REG_SET_FIELD(cmdq, OD_REG46, (cmd.param0 - 4), OD_OSD_SEL);
  712. break;
  713. default:
  714. break;
  715. }
  716. }
  717. break;
  718. /* write od table */
  719. case OD_CTL_WRITE_TABLE:
  720. return -EFAULT;
  721. default:
  722. break;
  723. }
  724. if (copy_to_user((void *)arg, (void *)&cmd, sizeof(DISP_OD_CMD)))
  725. return -EFAULT;
  726. return 0;
  727. }
  728. static int disp_od_ioctl(DISP_MODULE_ENUM module, int msg, unsigned long arg, void *cmdq)
  729. {
  730. switch (msg) {
  731. case DISP_IOCTL_OD_CTL:
  732. return disp_od_ioctl_ctlcmd(module, msg, arg, cmdq);
  733. default:
  734. return -EFAULT;
  735. }
  736. return 0;
  737. }
  738. static void ddp_bypass_od(unsigned int width, unsigned int height, void *handle)
  739. {
  740. ODNOTICE("ddp_bypass_od");
  741. DISP_REG_SET(handle, DISP_REG_OD_SIZE, (width << 16) | height);
  742. /* do not use OD relay mode (dither will be bypassed) od_core_en = 0 */
  743. DISP_REG_SET(handle, DISP_REG_OD_CFG, 0);
  744. DISP_REG_SET(handle, DISP_REG_OD_EN, 0x1);
  745. }
  746. static int od_config_od(DISP_MODULE_ENUM module, disp_ddp_path_config *pConfig, void *cmdq)
  747. {
  748. #if defined(CONFIG_MTK_OD_SUPPORT)
  749. const LCM_PARAMS *lcm_param = &(pConfig->dispif_config);
  750. #endif
  751. if (pConfig->dst_dirty) {
  752. #if defined(CONFIG_MTK_OD_SUPPORT)
  753. M4U_PORT_STRUCT m4u_port;
  754. unsigned int od_table_size = lcm_param->od_table_size;
  755. void *od_table = lcm_param->od_table;
  756. m4u_port.ePortID = M4U_PORT_DISP_OD_R;
  757. m4u_port.Virtuality = 0;
  758. m4u_port.Security = 0;
  759. m4u_port.domain = 0;
  760. m4u_port.Distance = 1;
  761. m4u_port.Direction = 0;
  762. m4u_config_port(&m4u_port);
  763. m4u_port.ePortID = M4U_PORT_DISP_OD_W;
  764. m4u_config_port(&m4u_port);
  765. if (od_table != NULL)
  766. ODDBG(OD_DBG_ALWAYS, "od_config_od: LCD OD table\n");
  767. #if defined(OD_ALLOW_DEFAULT_TABLE)
  768. if (od_table == NULL) {
  769. od_table_size = 33 * 33;
  770. od_table = (void *)OD_Table_33x33;
  771. }
  772. #endif
  773. #if defined(OD_LINEAR_TABLE_IF_NONE)
  774. if (od_table == NULL) {
  775. od_table_size = 17 * 17;
  776. od_table = (void *)OD_Table_dummy_17x17;
  777. }
  778. #endif
  779. if (od_table != NULL) {
  780. /* spm_enable_sodi(0); */
  781. disp_config_od(pConfig->dst_w, pConfig->dst_h, cmdq, od_table_size, od_table);
  782. #if 0
  783. /* For debug */
  784. DISP_REG_MASK(cmdq, DISP_REG_OD_INTEN, (1<<6)|(1<<3)|(1<<2), (1<<6)|(1<<3)|(1<<2));
  785. #endif
  786. } else {
  787. ddp_bypass_od(pConfig->dst_w, pConfig->dst_h, cmdq);
  788. }
  789. #else /* Not support OD */
  790. ddp_bypass_od(pConfig->dst_w, pConfig->dst_h, cmdq);
  791. #endif
  792. }
  793. #if defined(CONFIG_MTK_OD_SUPPORT)
  794. if (!pConfig->dst_dirty &&
  795. (lcm_param->type == LCM_TYPE_DSI) && (lcm_param->dsi.mode == CMD_MODE)) {
  796. if (pConfig->ovl_dirty || pConfig->rdma_dirty)
  797. od_refresh_screen();
  798. }
  799. #endif
  800. return 0;
  801. }
  802. static int od_clock_on(DISP_MODULE_ENUM module, void *handle)
  803. {
  804. #ifdef ENABLE_CLK_MGR
  805. #ifdef CONFIG_MTK_CLKMGR
  806. enable_clock(MT_CG_DISP0_DISP_OD, "od");
  807. DDPMSG("od_clock on CG 0x%x\n", DISP_REG_GET(DISP_REG_CONFIG_MMSYS_CG_CON0));
  808. #else
  809. ddp_clk_enable(DISP0_DISP_OD);
  810. #endif
  811. #endif
  812. return 0;
  813. }
  814. static int od_clock_off(DISP_MODULE_ENUM module, void *handle)
  815. {
  816. #ifdef ENABLE_CLK_MGR
  817. #ifdef CONFIG_MTK_CLKMGR
  818. disable_clock(MT_CG_DISP0_DISP_OD , "od");
  819. DDPMSG("od_clock off CG 0x%x\n", DISP_REG_GET(DISP_REG_CONFIG_MMSYS_CG_CON0));
  820. #else
  821. ddp_clk_disable(DISP0_DISP_OD);
  822. #endif
  823. #endif
  824. return 0;
  825. }
  826. /* for SODI to check OD is enabled or not, this will be called when screen is on and disp clock is enabled */
  827. int disp_od_is_enabled(void)
  828. {
  829. return (DISP_REG_GET(DISP_REG_OD_CFG) & (1 << 1)) ? 1 : 0;
  830. }
  831. static int od_set_listener(DISP_MODULE_ENUM module, ddp_module_notify notify)
  832. {
  833. g_od_ddp_notify = notify;
  834. return 0;
  835. }
  836. /* OD driver module */
  837. DDP_MODULE_DRIVER ddp_driver_od = {
  838. .init = od_clock_on,
  839. .deinit = od_clock_off,
  840. .config = od_config_od,
  841. .start = NULL,
  842. .trigger = NULL,
  843. .stop = NULL,
  844. .reset = NULL,
  845. .power_on = od_clock_on,
  846. .power_off = od_clock_off,
  847. .is_idle = NULL,
  848. .is_busy = NULL,
  849. .dump_info = NULL,
  850. .bypass = NULL,
  851. .build_cmdq = NULL,
  852. .set_lcm_utils = NULL,
  853. .cmd = disp_od_ioctl,
  854. .set_listener = od_set_listener
  855. };
  856. /* ----------------------------------------------------------------------
  857. // Test code
  858. // Following is only for OD functional test, not normal code
  859. // Will not be linked into user build.
  860. // --------------------------------------------------------------------*/
  861. #define OD_TLOG(fmt, arg...) pr_warn("[OD] " fmt "\n", ##arg)
  862. /*
  863. * A replacement of obsolete simple_strtoul(). The user must be restricted
  864. * and the usage must be reviewed carefully to avoid potential security issue.
  865. */
  866. static unsigned long od_simple_strtoul(char *next, char **new_next, int base)
  867. {
  868. char buffer[20];
  869. int i;
  870. unsigned long value;
  871. for (i = 0; i < sizeof(buffer) - 1; i++) {
  872. char ch = next[i];
  873. if ((ch == 'x') || ('0' <= ch && ch <= '9') ||
  874. ('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F')) {
  875. buffer[i] = ch;
  876. } else {
  877. buffer[i] = '\0';
  878. break;
  879. }
  880. }
  881. buffer[sizeof(buffer) - 1] = '\0';
  882. *new_next = &(next[i]);
  883. if (kstrtoul(buffer, base, &value) == 0)
  884. return value;
  885. return 0;
  886. }
  887. static int od_parse_triple(const char *cmd, unsigned long *offset, unsigned int *value, unsigned int *mask)
  888. {
  889. int count = 0;
  890. char *next = (char *)cmd;
  891. *value = 0;
  892. *mask = 0;
  893. *offset = (unsigned long)od_simple_strtoul(next, &next, 0);
  894. if (*offset > 0x1000UL || (*offset & 0x3UL) != 0) {
  895. *offset = 0UL;
  896. return 0;
  897. }
  898. count++;
  899. if (*next != ',')
  900. return count;
  901. next++;
  902. *value = (unsigned int)od_simple_strtoul(next, &next, 0);
  903. count++;
  904. if (*next != ',')
  905. return count;
  906. next++;
  907. *mask = (unsigned int)od_simple_strtoul(next, &next, 0);
  908. count++;
  909. return count;
  910. }
  911. static void od_dump_reg(const char *reg_list)
  912. {
  913. unsigned long offset;
  914. unsigned int value;
  915. char *next = (char *)reg_list;
  916. OD_TLOG("OD reg base = %lx", (unsigned long)(OD_BASE));
  917. while (1) {
  918. offset = (unsigned long)od_simple_strtoul(next, &next, 0);
  919. if (offset < 0x1000UL && (offset & 0x3UL) == 0) {
  920. value = DISP_REG_GET(OD_BASE + offset);
  921. OD_TLOG("[+0x%03lx] = 0x%08x(%d)", offset, value, value);
  922. }
  923. if (next[0] != ',')
  924. break;
  925. next++;
  926. }
  927. }
  928. static void od_test_slow_mode(void)
  929. {
  930. #if 0
  931. msleep(30);
  932. /* SLOW */
  933. WDMASlowMode(DISP_MODULE_WDMA0, 1, 4, 0xff, 0x7, NULL); /* time period between two write request is 0xff */
  934. ODDBG(OD_DBG_ALWAYS, "OD SLOW\n");
  935. msleep(2000);
  936. ODDBG(OD_DBG_ALWAYS, "OD OK\n");
  937. WDMASlowMode(DISP_MODULE_WDMA0, 0, 0, 0, 0x7, NULL);
  938. #endif
  939. }
  940. static void od_verify_boundary(void)
  941. {
  942. int guard1, guard2;
  943. guard1 = (*((u32 *)((unsigned long)g_od_buf.va + g_od_buf.size)) == OD_GUARD_PATTERN);
  944. guard2 = (*((u32 *)((unsigned long)g_od_buf.va + g_od_buf.size + OD_ADDITIONAL_BUFFER)) == OD_GUARD_PATTERN);
  945. OD_TLOG("od_verify_boundary(): guard 1 = %d, guard 2 = %d", guard1, guard2);
  946. }
  947. static void od_dump_all(void)
  948. {
  949. static const unsigned short od_addr_all[] = {
  950. 0x0000, 0x0004, 0x0008, 0x000c, 0x0010, 0x0020, 0x0024, 0x0028, 0x002c, 0x0030,
  951. 0x0040, 0x0044, 0x0048, 0x00c0, 0x0100, 0x0108, 0x010c, 0x0200, 0x0208, 0x020c,
  952. 0x0500, 0x0504, 0x0508, 0x050c, 0x0510, 0x0540, 0x0544, 0x0548, 0x0580, 0x0584,
  953. 0x0588, 0x05c0, 0x05c4, 0x05c8, 0x05cc, 0x05d0, 0x05d4, 0x05d8, 0x05dc, 0x05e0,
  954. 0x05e4, 0x05e8, 0x05ec, 0x05f0, 0x05f8, 0x05fc, 0x0680, 0x0684, 0x0688, 0x068c,
  955. 0x0690, 0x0694, 0x0698, 0x06c0, 0x06c4, 0x06c8, 0x06cc, 0x06d0, 0x06d4, 0x06d8,
  956. 0x06dc, 0x06e0, 0x06e4, 0x06e8, 0x06ec, 0x0700, 0x0704, 0x0708, 0x070c, 0x0710,
  957. 0x0714, 0x0718, 0x071c, 0x0720, 0x0724, 0x0728, 0x072c, 0x0730, 0x0734, 0x0738,
  958. 0x073c, 0x0740, 0x0744, 0x0748, 0x074c, 0x0750, 0x0754, 0x0758, 0x075c, 0x0760,
  959. 0x0764, 0x0768, 0x076c, 0x0770, 0x0774, 0x0778, 0x077c, 0x0788, 0x078c, 0x0790,
  960. 0x0794, 0x0798, 0x079c, 0x07a0, 0x07a4, 0x07a8, 0x07ac, 0x07b0, 0x07b4, 0x07b8,
  961. 0x07bc, 0x07c0, 0x07c4, 0x07c8, 0x07cc, 0x07d0, 0x07d4, 0x07d8, 0x07dc, 0x07e0,
  962. 0x07e4, 0x07e8, 0x07ec
  963. };
  964. int i;
  965. unsigned int value, offset;
  966. OD_TLOG("OD reg base = %lx", (unsigned long)(OD_BASE));
  967. for (i = 0; i < sizeof(od_addr_all) / sizeof(od_addr_all[0]); i++) {
  968. offset = od_addr_all[i];
  969. value = DISP_REG_GET((unsigned long)(OD_BASE + offset));
  970. OD_TLOG("[+0x%03x] = 0x%08x(%d)", offset, value, value);
  971. }
  972. }
  973. static void od_test_stress_table(void *cmdq)
  974. {
  975. int i;
  976. ODDBG(OD_DBG_ALWAYS, "OD TEST -- STRESS TABLE START\n");
  977. DISP_REG_SET(cmdq, DISP_REG_OD_MISC, 1); /* [1]:can access OD table; [0]:can't access OD table */
  978. /* read/write table for 100 times, 17x17 and 33x33 50 times each */
  979. for (i = 0; i < 50; i++) {
  980. /* test 17 table */
  981. _od_set_table(cmdq, OD_TABLE_17, OD_Table_17x17, 0);
  982. _od_read_table(cmdq, OD_TABLE_17, 0, OD_Table_17x17, 0);
  983. _od_read_table(cmdq, OD_TABLE_17, 1, OD_Table_17x17, 0);
  984. _od_read_table(cmdq, OD_TABLE_17, 2, OD_Table_17x17, 0);
  985. /* test 33 table */
  986. _od_set_table(cmdq, OD_TABLE_33, OD_Table_33x33, 0); /* default use 17x17 table */
  987. _od_read_table(cmdq, OD_TABLE_33, 0, OD_Table_33x33, 0);
  988. _od_read_table(cmdq, OD_TABLE_33, 1, OD_Table_33x33, 0);
  989. _od_read_table(cmdq, OD_TABLE_33, 2, OD_Table_33x33, 0);
  990. }
  991. DISP_REG_SET(cmdq, DISP_REG_OD_MISC, 0); /* [1]:can access OD table; [0]:can't access OD table */
  992. ODDBG(OD_DBG_ALWAYS, "OD TEST -- STRESS TABLE END\n");
  993. }
  994. void od_test(const char *cmd, char *debug_output)
  995. {
  996. cmdqRecHandle cmdq;
  997. unsigned long offset;
  998. unsigned int value, mask;
  999. OD_TLOG("od_test(%s)", cmd);
  1000. debug_output[0] = '\0';
  1001. DISP_CMDQ_BEGIN(cmdq, CMDQ_SCENARIO_DISP_CONFIG_OD);
  1002. if (strncmp(cmd, "set:", 4) == 0) {
  1003. int count = od_parse_triple(cmd + 4, &offset, &value, &mask);
  1004. if (count == 3) {
  1005. DISP_REG_MASK(cmdq, OD_BASE + offset, value, mask);
  1006. } else if (count == 2) {
  1007. DISP_REG_SET(cmdq, OD_BASE + offset, value);
  1008. mask = 0xffffffff;
  1009. }
  1010. if (count >= 2)
  1011. OD_TLOG("[+0x%03lx] = 0x%08x(%d) & 0x%08x", offset, value, value, mask);
  1012. } else if (strncmp(cmd, "dump:", 5) == 0) {
  1013. od_dump_reg(cmd + 5);
  1014. } else if (strncmp(cmd, "dumpall", 7) == 0) {
  1015. od_dump_all();
  1016. } else if (strncmp(cmd, "stress", 6) == 0) {
  1017. od_test_stress_table(NULL);
  1018. } else if (strncmp(cmd, "slow_mode", 9) == 0) {
  1019. od_test_slow_mode();
  1020. } else if (strncmp(cmd, "boundary", 6) == 0) {
  1021. od_verify_boundary();
  1022. #if 0
  1023. } else if (strncmp(cmd, "sodi:", 5) == 0) {
  1024. int enabled = (cmd[5] == '1' ? 1 : 0);
  1025. spm_enable_sodi(enabled);
  1026. #endif
  1027. } else if (strncmp(cmd, "en:", 3) == 0) {
  1028. int enabled = (cmd[3] == '1' ? 1 : 0);
  1029. disp_od_set_enabled(cmdq, enabled);
  1030. } else if (strncmp(cmd, "force:", 6) == 0) {
  1031. if (cmd[6] == '0') {
  1032. g_od_debug_enable = DEBUG_ENABLE_NEVER;
  1033. disp_od_set_enabled(cmdq, 0);
  1034. _disp_od_start(cmdq);
  1035. } else if (cmd[6] == '1') {
  1036. g_od_debug_enable = DEBUG_ENABLE_ALWAYS;
  1037. disp_od_set_enabled(cmdq, 1);
  1038. _disp_od_start(cmdq);
  1039. } else {
  1040. g_od_debug_enable = DEBUG_ENABLE_NORMAL;
  1041. }
  1042. } else if (strncmp(cmd, "ink:", 4) == 0) {
  1043. int enabled = (cmd[4] == '1' ? 1 : 0);
  1044. if (enabled) {
  1045. g_od_debug_mode = DEBUG_MODE_INK;
  1046. DISP_REG_MASK(cmdq, OD_REG03, (0x33 << 24) | (0xaa << 16) | (0x55 << 8) | 1, 0xffffff01);
  1047. } else {
  1048. g_od_debug_mode = DEBUG_MODE_NONE;
  1049. DISP_REG_MASK(cmdq, OD_REG03, 0, 0x1);
  1050. }
  1051. } else if (strncmp(cmd, "osd:", 4) == 0) {
  1052. if (cmd[4] == '1') {
  1053. g_od_debug_mode = DEBUG_MODE_INK;
  1054. OD_REG_SET_FIELD(cmdq, OD_REG46, 1, OD_OSD_SEL);
  1055. DISP_REG_MASK(cmdq, OD_REG03, 0, 0x1);
  1056. } else if (cmd[4] == '2') {
  1057. g_od_debug_mode = DEBUG_MODE_INK_OSD;
  1058. OD_REG_SET_FIELD(cmdq, OD_REG46, 1, OD_OSD_SEL);
  1059. DISP_REG_MASK(cmdq, OD_REG03, (0x33 << 24) | (0xaa << 16) | (0x55 << 8) | 1, 0xffffff01);
  1060. } else {
  1061. g_od_debug_mode = DEBUG_MODE_NONE;
  1062. OD_REG_SET_FIELD(cmdq, OD_REG46, 0, OD_OSD_SEL);
  1063. DISP_REG_MASK(cmdq, OD_REG03, 0, 0x1);
  1064. }
  1065. } else if (strncmp(cmd, "demo:", 5) == 0) {
  1066. int enabled = (cmd[5] == '1' ? 1 : 0);
  1067. OD_REG_SET_FIELD(cmdq, OD_REG02, enabled, DEMO_MODE);
  1068. ODDBG(OD_DBG_ALWAYS, "OD demo %d\n", enabled);
  1069. /* save demo mode flag for suspend/resume */
  1070. g_od_is_demo_mode = enabled;
  1071. } else if (strncmp(cmd, "base", 4) == 0) {
  1072. OD_TLOG("OD reg base = %lx", (unsigned long)(OD_BASE));
  1073. }
  1074. DISP_CMDQ_CONFIG_STREAM_DIRTY(cmdq);
  1075. DISP_CMDQ_END(cmdq);
  1076. od_refresh_screen();
  1077. }