mdp_dma_lcdc.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. /* Copyright (c) 2008-2009, 2012 The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. */
  13. #include <linux/module.h>
  14. #include <linux/kernel.h>
  15. #include <linux/sched.h>
  16. #include <linux/time.h>
  17. #include <linux/init.h>
  18. #include <linux/interrupt.h>
  19. #include <linux/hrtimer.h>
  20. #include <linux/delay.h>
  21. #include <mach/hardware.h>
  22. #include <linux/io.h>
  23. #include <asm/system.h>
  24. #include <asm/mach-types.h>
  25. #include <linux/semaphore.h>
  26. #include <linux/spinlock.h>
  27. #include <linux/fb.h>
  28. #include "mdp.h"
  29. #include "msm_fb.h"
  30. #include "mdp4.h"
  31. #ifdef CONFIG_FB_MSM_MDP40
  32. #define LCDC_BASE 0xC0000
  33. #define DTV_BASE 0xD0000
  34. #define DMA_E_BASE 0xB0000
  35. #else
  36. #define LCDC_BASE 0xE0000
  37. #endif
  38. #define DMA_P_BASE 0x90000
  39. extern spinlock_t mdp_spin_lock;
  40. #ifndef CONFIG_FB_MSM_MDP40
  41. extern uint32 mdp_intr_mask;
  42. #endif
  43. int first_pixel_start_x;
  44. int first_pixel_start_y;
  45. ssize_t mdp_dma_lcdc_show_event(struct device *dev,
  46. struct device_attribute *attr, char *buf)
  47. {
  48. ssize_t ret = 0;
  49. if (atomic_read(&vsync_cntrl.suspend) > 0 ||
  50. atomic_read(&vsync_cntrl.vsync_resume) == 0)
  51. return 0;
  52. INIT_COMPLETION(vsync_cntrl.vsync_wait);
  53. wait_for_completion(&vsync_cntrl.vsync_wait);
  54. ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu",
  55. ktime_to_ns(vsync_cntrl.vsync_time));
  56. buf[strlen(buf) + 1] = '\0';
  57. return ret;
  58. }
  59. int mdp_lcdc_on(struct platform_device *pdev)
  60. {
  61. int lcdc_width;
  62. int lcdc_height;
  63. int lcdc_bpp;
  64. int lcdc_border_clr;
  65. int lcdc_underflow_clr;
  66. int lcdc_hsync_skew;
  67. int hsync_period;
  68. int hsync_ctrl;
  69. int vsync_period;
  70. int display_hctl;
  71. int display_v_start;
  72. int display_v_end;
  73. int active_hctl;
  74. int active_h_start;
  75. int active_h_end;
  76. int active_v_start;
  77. int active_v_end;
  78. int ctrl_polarity;
  79. int h_back_porch;
  80. int h_front_porch;
  81. int v_back_porch;
  82. int v_front_porch;
  83. int hsync_pulse_width;
  84. int vsync_pulse_width;
  85. int hsync_polarity;
  86. int vsync_polarity;
  87. int data_en_polarity;
  88. int hsync_start_x;
  89. int hsync_end_x;
  90. uint8 *buf;
  91. int bpp;
  92. uint32 dma2_cfg_reg;
  93. struct fb_info *fbi;
  94. struct fb_var_screeninfo *var;
  95. struct msm_fb_data_type *mfd;
  96. uint32 dma_base;
  97. uint32 timer_base = LCDC_BASE;
  98. uint32 block = MDP_DMA2_BLOCK;
  99. int ret;
  100. uint32_t mask, curr;
  101. mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
  102. if (!mfd)
  103. return -ENODEV;
  104. if (mfd->key != MFD_KEY)
  105. return -EINVAL;
  106. fbi = mfd->fbi;
  107. var = &fbi->var;
  108. vsync_cntrl.dev = mfd->fbi->dev;
  109. atomic_set(&vsync_cntrl.suspend, 0);
  110. /* MDP cmd block enable */
  111. mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
  112. bpp = fbi->var.bits_per_pixel / 8;
  113. buf = (uint8 *) fbi->fix.smem_start;
  114. buf += calc_fb_offset(mfd, fbi, bpp);
  115. dma2_cfg_reg = DMA_PACK_ALIGN_LSB | DMA_OUT_SEL_LCDC;
  116. if (mfd->fb_imgType == MDP_BGR_565)
  117. dma2_cfg_reg |= DMA_PACK_PATTERN_BGR;
  118. else if (mfd->fb_imgType == MDP_RGBA_8888)
  119. dma2_cfg_reg |= DMA_PACK_PATTERN_BGR;
  120. else
  121. dma2_cfg_reg |= DMA_PACK_PATTERN_RGB;
  122. if (bpp == 2)
  123. dma2_cfg_reg |= DMA_IBUF_FORMAT_RGB565;
  124. else if (bpp == 3)
  125. dma2_cfg_reg |= DMA_IBUF_FORMAT_RGB888;
  126. else
  127. dma2_cfg_reg |= DMA_IBUF_FORMAT_xRGB8888_OR_ARGB8888;
  128. switch (mfd->panel_info.bpp) {
  129. case 24:
  130. dma2_cfg_reg |= DMA_DSTC0G_8BITS |
  131. DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS;
  132. break;
  133. case 18:
  134. dma2_cfg_reg |= DMA_DSTC0G_6BITS |
  135. DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS;
  136. break;
  137. case 16:
  138. dma2_cfg_reg |= DMA_DSTC0G_6BITS |
  139. DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS;
  140. break;
  141. default:
  142. printk(KERN_ERR "mdp lcdc can't support format %d bpp!\n",
  143. mfd->panel_info.bpp);
  144. return -ENODEV;
  145. }
  146. /* DMA register config */
  147. dma_base = DMA_P_BASE;
  148. #ifdef CONFIG_FB_MSM_MDP40
  149. if (mfd->panel.type == HDMI_PANEL)
  150. dma_base = DMA_E_BASE;
  151. #endif
  152. /* starting address */
  153. MDP_OUTP(MDP_BASE + dma_base + 0x8, (uint32) buf);
  154. /* active window width and height */
  155. MDP_OUTP(MDP_BASE + dma_base + 0x4, ((fbi->var.yres) << 16) |
  156. (fbi->var.xres));
  157. /* buffer ystride */
  158. MDP_OUTP(MDP_BASE + dma_base + 0xc, fbi->fix.line_length);
  159. /* x/y coordinate = always 0 for lcdc */
  160. MDP_OUTP(MDP_BASE + dma_base + 0x10, 0);
  161. /* dma config */
  162. curr = inpdw(MDP_BASE + DMA_P_BASE);
  163. mask = 0x0FFFFFFF;
  164. dma2_cfg_reg = (dma2_cfg_reg & mask) | (curr & ~mask);
  165. MDP_OUTP(MDP_BASE + dma_base, dma2_cfg_reg);
  166. /*
  167. * LCDC timing setting
  168. */
  169. h_back_porch = var->left_margin;
  170. h_front_porch = var->right_margin;
  171. v_back_porch = var->upper_margin;
  172. v_front_porch = var->lower_margin;
  173. hsync_pulse_width = var->hsync_len;
  174. vsync_pulse_width = var->vsync_len;
  175. lcdc_border_clr = mfd->panel_info.lcdc.border_clr;
  176. lcdc_underflow_clr = mfd->panel_info.lcdc.underflow_clr;
  177. lcdc_hsync_skew = mfd->panel_info.lcdc.hsync_skew;
  178. lcdc_width = mfd->panel_info.xres;
  179. lcdc_height = mfd->panel_info.yres;
  180. lcdc_bpp = mfd->panel_info.bpp;
  181. hsync_period =
  182. hsync_pulse_width + h_back_porch + lcdc_width + h_front_porch;
  183. hsync_ctrl = (hsync_period << 16) | hsync_pulse_width;
  184. hsync_start_x = hsync_pulse_width + h_back_porch;
  185. hsync_end_x = hsync_period - h_front_porch - 1;
  186. display_hctl = (hsync_end_x << 16) | hsync_start_x;
  187. vsync_period =
  188. (vsync_pulse_width + v_back_porch + lcdc_height +
  189. v_front_porch) * hsync_period;
  190. display_v_start =
  191. (vsync_pulse_width + v_back_porch) * hsync_period + lcdc_hsync_skew;
  192. display_v_end =
  193. vsync_period - (v_front_porch * hsync_period) + lcdc_hsync_skew - 1;
  194. if (lcdc_width != var->xres) {
  195. active_h_start = hsync_start_x + first_pixel_start_x;
  196. active_h_end = active_h_start + var->xres - 1;
  197. active_hctl =
  198. ACTIVE_START_X_EN | (active_h_end << 16) | active_h_start;
  199. } else {
  200. active_hctl = 0;
  201. }
  202. if (lcdc_height != var->yres) {
  203. active_v_start =
  204. display_v_start + first_pixel_start_y * hsync_period;
  205. active_v_end = active_v_start + (var->yres) * hsync_period - 1;
  206. active_v_start |= ACTIVE_START_Y_EN;
  207. } else {
  208. active_v_start = 0;
  209. active_v_end = 0;
  210. }
  211. #ifdef CONFIG_FB_MSM_MDP40
  212. if (mfd->panel.type == HDMI_PANEL) {
  213. block = MDP_DMA_E_BLOCK;
  214. timer_base = DTV_BASE;
  215. hsync_polarity = 0;
  216. vsync_polarity = 0;
  217. } else {
  218. hsync_polarity = 1;
  219. vsync_polarity = 1;
  220. }
  221. lcdc_underflow_clr |= 0x80000000; /* enable recovery */
  222. #else
  223. hsync_polarity = 0;
  224. vsync_polarity = 0;
  225. #endif
  226. data_en_polarity = 0;
  227. ctrl_polarity =
  228. (data_en_polarity << 2) | (vsync_polarity << 1) | (hsync_polarity);
  229. if (!(mfd->cont_splash_done)) {
  230. mdp_pipe_ctrl(MDP_CMD_BLOCK,
  231. MDP_BLOCK_POWER_OFF, FALSE);
  232. MDP_OUTP(MDP_BASE + timer_base, 0);
  233. }
  234. MDP_OUTP(MDP_BASE + timer_base + 0x4, hsync_ctrl);
  235. MDP_OUTP(MDP_BASE + timer_base + 0x8, vsync_period);
  236. MDP_OUTP(MDP_BASE + timer_base + 0xc, vsync_pulse_width * hsync_period);
  237. if (timer_base == LCDC_BASE) {
  238. MDP_OUTP(MDP_BASE + timer_base + 0x10, display_hctl);
  239. MDP_OUTP(MDP_BASE + timer_base + 0x14, display_v_start);
  240. MDP_OUTP(MDP_BASE + timer_base + 0x18, display_v_end);
  241. MDP_OUTP(MDP_BASE + timer_base + 0x28, lcdc_border_clr);
  242. MDP_OUTP(MDP_BASE + timer_base + 0x2c, lcdc_underflow_clr);
  243. MDP_OUTP(MDP_BASE + timer_base + 0x30, lcdc_hsync_skew);
  244. MDP_OUTP(MDP_BASE + timer_base + 0x38, ctrl_polarity);
  245. MDP_OUTP(MDP_BASE + timer_base + 0x1c, active_hctl);
  246. MDP_OUTP(MDP_BASE + timer_base + 0x20, active_v_start);
  247. MDP_OUTP(MDP_BASE + timer_base + 0x24, active_v_end);
  248. } else {
  249. MDP_OUTP(MDP_BASE + timer_base + 0x18, display_hctl);
  250. MDP_OUTP(MDP_BASE + timer_base + 0x1c, display_v_start);
  251. MDP_OUTP(MDP_BASE + timer_base + 0x20, display_v_end);
  252. MDP_OUTP(MDP_BASE + timer_base + 0x40, lcdc_border_clr);
  253. MDP_OUTP(MDP_BASE + timer_base + 0x44, lcdc_underflow_clr);
  254. MDP_OUTP(MDP_BASE + timer_base + 0x48, lcdc_hsync_skew);
  255. MDP_OUTP(MDP_BASE + timer_base + 0x50, ctrl_polarity);
  256. MDP_OUTP(MDP_BASE + timer_base + 0x2c, active_hctl);
  257. MDP_OUTP(MDP_BASE + timer_base + 0x30, active_v_start);
  258. MDP_OUTP(MDP_BASE + timer_base + 0x38, active_v_end);
  259. }
  260. ret = panel_next_on(pdev);
  261. if (ret == 0) {
  262. /* enable LCDC block */
  263. MDP_OUTP(MDP_BASE + timer_base, 1);
  264. mdp_pipe_ctrl(block, MDP_BLOCK_POWER_ON, FALSE);
  265. }
  266. /* MDP cmd block disable */
  267. mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
  268. return ret;
  269. }
  270. int mdp_lcdc_off(struct platform_device *pdev)
  271. {
  272. int ret = 0;
  273. struct msm_fb_data_type *mfd;
  274. uint32 timer_base = LCDC_BASE;
  275. uint32 block = MDP_DMA2_BLOCK;
  276. mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
  277. #ifdef CONFIG_FB_MSM_MDP40
  278. if (mfd->panel.type == HDMI_PANEL) {
  279. block = MDP_DMA_E_BLOCK;
  280. timer_base = DTV_BASE;
  281. }
  282. #endif
  283. down(&mfd->dma->mutex);
  284. /* MDP cmd block enable */
  285. mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
  286. MDP_OUTP(MDP_BASE + timer_base, 0);
  287. /* MDP cmd block disable */
  288. mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
  289. mdp_pipe_ctrl(block, MDP_BLOCK_POWER_OFF, FALSE);
  290. ret = panel_next_off(pdev);
  291. up(&mfd->dma->mutex);
  292. atomic_set(&vsync_cntrl.suspend, 1);
  293. atomic_set(&vsync_cntrl.vsync_resume, 0);
  294. complete_all(&vsync_cntrl.vsync_wait);
  295. /* delay to make sure the last frame finishes */
  296. msleep(16);
  297. return ret;
  298. }
  299. void mdp_dma_lcdc_vsync_ctrl(int enable)
  300. {
  301. unsigned long flag;
  302. int disabled_clocks;
  303. if (vsync_cntrl.vsync_irq_enabled == enable)
  304. return;
  305. spin_lock_irqsave(&mdp_spin_lock, flag);
  306. if (!enable)
  307. INIT_COMPLETION(vsync_cntrl.vsync_wait);
  308. vsync_cntrl.vsync_irq_enabled = enable;
  309. if (!enable)
  310. vsync_cntrl.disabled_clocks = 0;
  311. disabled_clocks = vsync_cntrl.disabled_clocks;
  312. spin_unlock_irqrestore(&mdp_spin_lock, flag);
  313. if (enable && disabled_clocks) {
  314. mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
  315. spin_lock_irqsave(&mdp_spin_lock, flag);
  316. outp32(MDP_INTR_CLEAR, LCDC_FRAME_START);
  317. mdp_intr_mask |= LCDC_FRAME_START;
  318. outp32(MDP_INTR_ENABLE, mdp_intr_mask);
  319. mdp_enable_irq(MDP_VSYNC_TERM);
  320. spin_unlock_irqrestore(&mdp_spin_lock, flag);
  321. }
  322. if (vsync_cntrl.vsync_irq_enabled &&
  323. atomic_read(&vsync_cntrl.suspend) == 0)
  324. atomic_set(&vsync_cntrl.vsync_resume, 1);
  325. }
  326. void mdp_lcdc_update(struct msm_fb_data_type *mfd)
  327. {
  328. struct fb_info *fbi = mfd->fbi;
  329. uint8 *buf;
  330. int bpp;
  331. unsigned long flag;
  332. uint32 dma_base;
  333. int irq_block = MDP_DMA2_TERM;
  334. #ifdef CONFIG_FB_MSM_MDP40
  335. int intr = INTR_DMA_P_DONE;
  336. #endif
  337. if (!mfd->panel_power_on)
  338. return;
  339. down(&mfd->dma->mutex);
  340. /* no need to power on cmd block since it's lcdc mode */
  341. bpp = fbi->var.bits_per_pixel / 8;
  342. buf = (uint8 *) fbi->fix.smem_start;
  343. buf += calc_fb_offset(mfd, fbi, bpp);
  344. dma_base = DMA_P_BASE;
  345. #ifdef CONFIG_FB_MSM_MDP40
  346. if (mfd->panel.type == HDMI_PANEL) {
  347. intr = INTR_DMA_E_DONE;
  348. irq_block = MDP_DMA_E_TERM;
  349. dma_base = DMA_E_BASE;
  350. }
  351. #endif
  352. /* starting address */
  353. MDP_OUTP(MDP_BASE + dma_base + 0x8, (uint32) buf);
  354. /* enable LCDC irq */
  355. spin_lock_irqsave(&mdp_spin_lock, flag);
  356. mdp_enable_irq(irq_block);
  357. INIT_COMPLETION(mfd->dma->comp);
  358. mfd->dma->waiting = TRUE;
  359. #ifdef CONFIG_FB_MSM_MDP40
  360. outp32(MDP_INTR_CLEAR, intr);
  361. mdp_intr_mask |= intr;
  362. outp32(MDP_INTR_ENABLE, mdp_intr_mask);
  363. #else
  364. outp32(MDP_INTR_CLEAR, LCDC_FRAME_START);
  365. mdp_intr_mask |= LCDC_FRAME_START;
  366. outp32(MDP_INTR_ENABLE, mdp_intr_mask);
  367. #endif
  368. spin_unlock_irqrestore(&mdp_spin_lock, flag);
  369. wait_for_completion_killable(&mfd->dma->comp);
  370. mdp_disable_irq(irq_block);
  371. up(&mfd->dma->mutex);
  372. }