mdp_cursor.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /* Copyright (c) 2008-2009, 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 <mach/hardware.h>
  21. #include <asm/io.h>
  22. #include <asm/system.h>
  23. #include <asm/mach-types.h>
  24. #include <linux/semaphore.h>
  25. #include <linux/spinlock.h>
  26. #include <linux/fb.h>
  27. #include "mdp.h"
  28. #include "msm_fb.h"
  29. static int cursor_enabled;
  30. #include "mdp4.h"
  31. #if defined(CONFIG_FB_MSM_OVERLAY) && defined(CONFIG_FB_MSM_MDP40)
  32. static struct workqueue_struct *mdp_cursor_ctrl_wq;
  33. static struct work_struct mdp_cursor_ctrl_worker;
  34. /* cursor configuration */
  35. static void *cursor_buf_phys;
  36. static __u32 width, height, bg_color;
  37. static int calpha_en, transp_en, alpha;
  38. static int sync_disabled = -1;
  39. void mdp_cursor_ctrl_workqueue_handler(struct work_struct *work)
  40. {
  41. unsigned long flag;
  42. /* disable vsync */
  43. spin_lock_irqsave(&mdp_spin_lock, flag);
  44. if (hdmi_prim_display)
  45. mdp_disable_irq(MDP_OVERLAY1_TERM);
  46. else
  47. mdp_disable_irq(MDP_OVERLAY0_TERM);
  48. spin_unlock_irqrestore(&mdp_spin_lock, flag);
  49. }
  50. void mdp_hw_cursor_init(void)
  51. {
  52. mdp_cursor_ctrl_wq =
  53. create_singlethread_workqueue("mdp_cursor_ctrl_wq");
  54. INIT_WORK(&mdp_cursor_ctrl_worker, mdp_cursor_ctrl_workqueue_handler);
  55. }
  56. void mdp_hw_cursor_done(void)
  57. {
  58. /* Cursor configuration:
  59. *
  60. * This is done in DMA_P_DONE ISR because the following registers are
  61. * not double buffered in hardware:
  62. *
  63. * MDP_DMA_P_CURSOR_SIZE, address = 0x90044
  64. * MDP_DMA_P_CURSOR_BLEND_CONFIG, address = 0x90060
  65. * MDP_DMA_P_CURSOR_BLEND_PARAM, address = 0x90064
  66. * MDP_DMA_P_CURSOR_BLEND_TRANS_LOW, address = 0x90068
  67. * MDP_DMA_P_CURSOR_BLEND_TRANS_HIG, address = 0x9006C
  68. *
  69. * Moving this code out of the ISR will cause the MDP to underrun!
  70. */
  71. uint32_t base = 0;
  72. if (hdmi_prim_display)
  73. base = ((uint32_t)(MDP_BASE + 0xB0000));
  74. else
  75. base = ((uint32_t)(MDP_BASE + 0x90000));
  76. spin_lock(&mdp_spin_lock);
  77. if (sync_disabled) {
  78. spin_unlock(&mdp_spin_lock);
  79. return;
  80. }
  81. MDP_OUTP(base + 0x44, (height << 16) | width);
  82. MDP_OUTP(base + 0x48, cursor_buf_phys);
  83. MDP_OUTP(base + 0x60,
  84. (transp_en << 3) | (calpha_en << 1) |
  85. (inp32(base + 0x60) & 0x1));
  86. MDP_OUTP(base + 0x64, (alpha << 24));
  87. MDP_OUTP(base + 0x68, (0xffffff & bg_color));
  88. MDP_OUTP(base + 0x6C, (0xffffff & bg_color));
  89. /* enable/disable the cursor as per the last request */
  90. if (cursor_enabled && !(inp32(base + 0x60) & (0x1)))
  91. MDP_OUTP(base + 0x60, inp32(base + 0x60) | 0x1);
  92. else if (!cursor_enabled && (inp32(base + 0x60) & (0x1)))
  93. MDP_OUTP(base + 0x60,
  94. inp32(base + 0x60) & (~0x1));
  95. /* enqueue the task to disable MDP interrupts */
  96. queue_work(mdp_cursor_ctrl_wq, &mdp_cursor_ctrl_worker);
  97. /* update done */
  98. sync_disabled = 1;
  99. spin_unlock(&mdp_spin_lock);
  100. }
  101. static void mdp_hw_cursor_enable_vsync(void)
  102. {
  103. /* if the cursor registers were updated (once or more) since the
  104. * last vsync, enable the vsync interrupt (if not already enabled)
  105. * for the next update
  106. */
  107. if (sync_disabled) {
  108. /* cancel pending task to disable MDP interrupts */
  109. if (work_pending(&mdp_cursor_ctrl_worker)) {
  110. cancel_work_sync(&mdp_cursor_ctrl_worker);
  111. } else {
  112. /* enable irq */
  113. if (hdmi_prim_display)
  114. mdp_enable_irq(MDP_OVERLAY1_TERM);
  115. else
  116. mdp_enable_irq(MDP_OVERLAY0_TERM);
  117. }
  118. sync_disabled = 0;
  119. /* enable vsync intr */
  120. if (hdmi_prim_display) {
  121. outp32(MDP_INTR_CLEAR, INTR_OVERLAY1_DONE);
  122. mdp_intr_mask |= INTR_OVERLAY1_DONE;
  123. } else {
  124. outp32(MDP_INTR_CLEAR, INTR_OVERLAY0_DONE);
  125. mdp_intr_mask |= INTR_OVERLAY0_DONE;
  126. }
  127. outp32(MDP_INTR_ENABLE, mdp_intr_mask);
  128. }
  129. }
  130. int mdp_hw_cursor_sync_update(struct fb_info *info, struct fb_cursor *cursor)
  131. {
  132. struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
  133. struct fb_image *img = &cursor->image;
  134. unsigned long flag;
  135. int sync_needed = 0, ret = 0;
  136. uint32_t base = 0;
  137. if ((img->width > MDP_CURSOR_WIDTH) ||
  138. (img->height > MDP_CURSOR_HEIGHT) ||
  139. (img->depth != 32))
  140. return -EINVAL;
  141. if (hdmi_prim_display)
  142. base = ((uint32_t)(MDP_BASE + 0xB0000));
  143. else
  144. base = ((uint32_t)(MDP_BASE + 0x90000));
  145. if (cursor->set & FB_CUR_SETPOS)
  146. MDP_OUTP(base + 0x4c, (img->dy << 16) | img->dx);
  147. if (cursor->set & FB_CUR_SETIMAGE) {
  148. ret = copy_from_user(mfd->cursor_buf, img->data,
  149. img->width*img->height*4);
  150. if (ret)
  151. return ret;
  152. spin_lock_irqsave(&mdp_spin_lock, flag);
  153. if (img->bg_color == 0xffffffff)
  154. transp_en = 0;
  155. else
  156. transp_en = 1;
  157. alpha = (img->fg_color & 0xff000000) >> 24;
  158. if (alpha)
  159. calpha_en = 0x2; /* xrgb */
  160. else
  161. calpha_en = 0x1; /* argb */
  162. /* cursor parameters */
  163. height = img->height;
  164. width = img->width;
  165. bg_color = img->bg_color;
  166. cursor_buf_phys = mfd->cursor_buf_phys;
  167. sync_needed = 1;
  168. } else
  169. spin_lock_irqsave(&mdp_spin_lock, flag);
  170. if ((cursor->enable) && (!cursor_enabled)) {
  171. cursor_enabled = 1;
  172. sync_needed = 1;
  173. } else if ((!cursor->enable) && (cursor_enabled)) {
  174. cursor_enabled = 0;
  175. sync_needed = 1;
  176. }
  177. /* if sync cursor update is needed, enable vsync */
  178. if (sync_needed)
  179. mdp_hw_cursor_enable_vsync();
  180. spin_unlock_irqrestore(&mdp_spin_lock, flag);
  181. return 0;
  182. }
  183. #endif /* CONFIG_FB_MSM_OVERLAY && CONFIG_FB_MSM_MDP40 */
  184. int mdp_hw_cursor_update(struct fb_info *info, struct fb_cursor *cursor)
  185. {
  186. struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
  187. struct fb_image *img = &cursor->image;
  188. int calpha_en, transp_en;
  189. int alpha;
  190. int ret = 0;
  191. if ((img->width > MDP_CURSOR_WIDTH) ||
  192. (img->height > MDP_CURSOR_HEIGHT) ||
  193. (img->depth != 32))
  194. return -EINVAL;
  195. mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
  196. if (cursor->set & FB_CUR_SETPOS)
  197. MDP_OUTP(MDP_BASE + 0x9004c, (img->dy << 16) | img->dx);
  198. if (cursor->set & FB_CUR_SETIMAGE) {
  199. ret = copy_from_user(mfd->cursor_buf, img->data,
  200. img->width*img->height*4);
  201. if (ret)
  202. return ret;
  203. if (img->bg_color == 0xffffffff)
  204. transp_en = 0;
  205. else
  206. transp_en = 1;
  207. alpha = (img->fg_color & 0xff000000) >> 24;
  208. if (alpha)
  209. calpha_en = 0x2; /* xrgb */
  210. else
  211. calpha_en = 0x1; /* argb */
  212. MDP_OUTP(MDP_BASE + 0x90044, (img->height << 16) | img->width);
  213. MDP_OUTP(MDP_BASE + 0x90048, mfd->cursor_buf_phys);
  214. /* order the writes the cursor_buf before updating the
  215. * hardware */
  216. dma_coherent_pre_ops();
  217. MDP_OUTP(MDP_BASE + 0x90060,
  218. (transp_en << 3) | (calpha_en << 1) |
  219. (inp32(MDP_BASE + 0x90060) & 0x1));
  220. #ifdef CONFIG_FB_MSM_MDP40
  221. MDP_OUTP(MDP_BASE + 0x90064, (alpha << 24));
  222. MDP_OUTP(MDP_BASE + 0x90068, (0xffffff & img->bg_color));
  223. MDP_OUTP(MDP_BASE + 0x9006C, (0xffffff & img->bg_color));
  224. #else
  225. MDP_OUTP(MDP_BASE + 0x90064,
  226. (alpha << 24) | (0xffffff & img->bg_color));
  227. MDP_OUTP(MDP_BASE + 0x90068, 0);
  228. #endif
  229. }
  230. if ((cursor->enable) && (!cursor_enabled)) {
  231. cursor_enabled = 1;
  232. MDP_OUTP(MDP_BASE + 0x90060, inp32(MDP_BASE + 0x90060) | 0x1);
  233. } else if ((!cursor->enable) && (cursor_enabled)) {
  234. cursor_enabled = 0;
  235. MDP_OUTP(MDP_BASE + 0x90060,
  236. inp32(MDP_BASE + 0x90060) & (~0x1));
  237. }
  238. mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
  239. return 0;
  240. }