logo.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. /* drivers/video/msm/logo.c
  2. *
  3. * Show Logo in RLE 565 format
  4. *
  5. * Copyright (C) 2008 Google Incorporated
  6. *
  7. * This software is licensed under the terms of the GNU General Public
  8. * License version 2, as published by the Free Software Foundation, and
  9. * may be copied, distributed, and modified under those terms.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. */
  17. #include <linux/module.h>
  18. #include <linux/types.h>
  19. #include <linux/fb.h>
  20. #include <linux/vt_kern.h>
  21. #include <linux/unistd.h>
  22. #include <linux/syscalls.h>
  23. #include <linux/irq.h>
  24. #include <asm/system.h>
  25. #include <linux/iopoll.h>
  26. #include <linux/delay.h>
  27. #include <linux/dma-mapping.h>
  28. #include "mdss_fb.h"
  29. #include "mdss_mdp.h"
  30. #include "mdss_dsi.h"
  31. #define fb_width(fb) ((fb)->var.xres)
  32. #define fb_height(fb) ((fb)->var.yres)
  33. #define fb_size(fb) ((fb)->var.xres * (fb)->var.yres * 2)
  34. #ifdef CONFIG_SAMSUNG_LPM_MODE
  35. extern int poweroff_charging;
  36. #endif
  37. #if defined(ENABLE_BOOTLOGO)
  38. static struct workqueue_struct *wq_bootlogo;
  39. static struct delayed_work w_bootlogo;
  40. #endif
  41. int get_lcd_attached(void);
  42. static void memset16(void *_ptr, unsigned short val, unsigned count)
  43. {
  44. unsigned short *ptr = _ptr;
  45. count >>= 1;
  46. while (count--)
  47. *ptr++ = val;
  48. }
  49. /* convert RGB565 to RBG8888 */
  50. static int total_pixel = 1;
  51. static int memset16_rgb8888(void *_ptr, unsigned short val, unsigned count,
  52. struct fb_info *fb)
  53. {
  54. unsigned short *ptr = _ptr;
  55. unsigned short red;
  56. unsigned short green;
  57. unsigned short blue;
  58. int need_align = (fb->fix.line_length >> 2) - fb->var.xres;
  59. int align_amount = need_align << 1;
  60. int pad = 0;
  61. red = (val & 0xF800) >> 8;
  62. green = (val & 0x7E0) >> 3;
  63. blue = (val & 0x1F) << 3;
  64. count >>= 1;
  65. while (count--) {
  66. *ptr++ = (green << 8) | red;
  67. *ptr++ = blue;
  68. if (need_align) {
  69. if (!(total_pixel % fb->var.xres)) {
  70. ptr += align_amount;
  71. pad++;
  72. }
  73. }
  74. total_pixel++;
  75. }
  76. return pad * align_amount;
  77. }
  78. /* 565RLE image format: [count(2 bytes), rle(2 bytes)] */
  79. int load_565rle_image(char *filename)
  80. {
  81. struct fb_info *info;
  82. int fd, count, err = 0;
  83. unsigned max;
  84. unsigned short *data, *bits, *ptr;
  85. int pad;
  86. info = registered_fb[0];
  87. if (!info) {
  88. printk(KERN_WARNING "%s: Can not access framebuffer\n",
  89. __func__);
  90. return -ENODEV;
  91. }
  92. fd = sys_open(filename, O_RDONLY, 0);
  93. if (fd < 0) {
  94. printk(KERN_WARNING "%s: Can not open %s\n",
  95. __func__, filename);
  96. return -ENOENT;
  97. }
  98. count = sys_lseek(fd, (off_t)0, 2);
  99. if (count <= 0) {
  100. err = -EIO;
  101. goto err_logo_close_file;
  102. }
  103. sys_lseek(fd, (off_t)0, 0);
  104. data = kmalloc(count, GFP_KERNEL);
  105. if (!data) {
  106. printk(KERN_WARNING "%s: Can not alloc data\n", __func__);
  107. err = -ENOMEM;
  108. goto err_logo_close_file;
  109. }
  110. if (sys_read(fd, (char *)data, count) != count) {
  111. err = -EIO;
  112. goto err_logo_free_data;
  113. }
  114. max = fb_width(info) * fb_height(info);
  115. ptr = data;
  116. if ((info->node == 1 || info->node == 2)) {
  117. err = -EPERM;
  118. pr_err("%s:%d no info->creen_base on fb%d!\n",
  119. __func__, __LINE__, info->node);
  120. goto err_logo_free_data;
  121. }
  122. bits = (unsigned short *)(info->screen_base);
  123. if(!bits)
  124. {
  125. printk(KERN_WARNING "%s: screen_base is not valid\n", __func__);
  126. goto err_logo_free_data;
  127. }
  128. while (count > 3) {
  129. unsigned n = ptr[0];
  130. if (n > max)
  131. break;
  132. if (info->var.bits_per_pixel >= 24) {
  133. pad = memset16_rgb8888(bits, ptr[1], n << 1, info);
  134. bits += n << 1;
  135. bits += pad;
  136. } else {
  137. memset16(bits, ptr[1], n << 1);
  138. bits += n;
  139. }
  140. max -= n;
  141. ptr += 2;
  142. count -= 4;
  143. }
  144. err_logo_free_data:
  145. kfree(data);
  146. err_logo_close_file:
  147. sys_close(fd);
  148. return err;
  149. }
  150. EXPORT_SYMBOL(load_565rle_image);
  151. #if 0
  152. static int samsung_copy_bootloader_screen(void *virt)
  153. {
  154. struct fb_info *info = registered_fb[0];
  155. unsigned long bl_fb_addr = 0;
  156. unsigned long *bl_fb_addr_va;
  157. unsigned long pipe_addr, pipe_src_size;
  158. u32 height, width, rgb_size, bpp;char *bit_src,*bit_dst;
  159. size_t size;int i,j;
  160. pr_info("%s:+\n",__func__);
  161. mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
  162. pipe_addr = MDSS_MDP_REG_SSPP_OFFSET(3) +
  163. MDSS_MDP_REG_SSPP_SRC0_ADDR;
  164. pipe_src_size =
  165. MDSS_MDP_REG_SSPP_OFFSET(3) + MDSS_MDP_REG_SSPP_SRC_SIZE;
  166. bpp = 3;
  167. rgb_size = MDSS_MDP_REG_READ(pipe_src_size);
  168. bl_fb_addr = MDSS_MDP_REG_READ(pipe_addr);
  169. height = (rgb_size >> 16) & 0xffff;
  170. width = rgb_size & 0xffff;
  171. size = PAGE_ALIGN(height * width * bpp);
  172. if( bl_fb_addr == 0x0)
  173. return -1;
  174. #if defined(CONFIG_FB_MSM_EDP_SAMSUNG)
  175. bl_fb_addr_va = (unsigned long *)ioremap(bl_fb_addr, size*2);
  176. #else
  177. bl_fb_addr_va = (unsigned long *)ioremap(bl_fb_addr, size);
  178. #endif
  179. pr_info("%s:%d addr:%pK->%pK, splash_height=%d splash_width=%d Buffer size=%d\n",
  180. __func__, __LINE__, (void *)bl_fb_addr,(void *)bl_fb_addr_va,
  181. height, width, size);
  182. bit_src = (char *) bl_fb_addr_va;
  183. bit_dst = (char *)info->screen_base;
  184. for( i = 0,j=0; j < size*2; i+=4,j+=3) {
  185. bit_dst[i] = bit_src[j];
  186. bit_dst[i+1] = bit_src[j+1];
  187. bit_dst[i+2] = bit_src[j+2];
  188. }
  189. mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
  190. return 0;
  191. }
  192. #endif
  193. static int samsung_mdss_allocate_framebuffer(struct fb_info *info){
  194. void *virt = NULL;size_t size;
  195. struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
  196. static struct ion_handle *ihdl;
  197. struct ion_client *iclient = mdss_get_ionclient();
  198. static ion_phys_addr_t phys;
  199. ihdl = ion_alloc(iclient, 0x1000000, SZ_1M,
  200. ION_HEAP(ION_QSECOM_HEAP_ID), 0);
  201. if (IS_ERR_OR_NULL(ihdl)) {
  202. pr_err("unable to alloc fbmem from ion (%pK)\n", ihdl);
  203. return -ENOMEM;
  204. }
  205. virt = ion_map_kernel(iclient, ihdl);
  206. ion_phys(iclient, ihdl, &phys, &size);
  207. info->screen_base = virt;
  208. info->fix.smem_start = phys;
  209. info->fix.smem_len = size;
  210. msm_iommu_map_contig_buffer(phys, mfd->mdp.fb_mem_get_iommu_domain(), 0, size, SZ_4K, 0,
  211. &mfd->iova);
  212. #if 0
  213. //Copy screen
  214. if(contsplash_lkstat == 1)
  215. ret = samsung_copy_bootloader_screen(virt);
  216. #endif
  217. return 1;
  218. }
  219. int load_samsung_boot_logo(void)
  220. {
  221. struct fb_info *info;
  222. struct msm_fb_data_type *mfd;
  223. struct mdss_panel_data *pdata;
  224. int ret;
  225. info = registered_fb[0];
  226. if (!info) {
  227. printk(KERN_WARNING "%s: Can not access framebuffer\n",
  228. __func__);
  229. return -ENODEV;
  230. }
  231. mfd = (struct msm_fb_data_type *)info->par;
  232. if (!mfd) {
  233. printk(KERN_WARNING "%s: Can not access info->par\n",
  234. __func__);
  235. return -ENODEV;
  236. }
  237. pdata = dev_get_platdata(&mfd->pdev->dev);
  238. #ifdef CONFIG_SAMSUNG_LPM_MODE
  239. // LPM mode : no boot logo
  240. if(poweroff_charging)
  241. return 0;
  242. #endif
  243. if (get_lcd_attached() == 0)
  244. {
  245. pr_err("%s: get_lcd_attached(0)!\n",__func__);
  246. return -ENODEV;
  247. }
  248. pr_info("%s:+\n",__func__);
  249. ret = samsung_mdss_allocate_framebuffer(info);
  250. info->fbops->fb_open(registered_fb[0], 0);
  251. if (ret && load_565rle_image("initlogo.rle")) {
  252. char *bits = info->screen_base;
  253. int i = 0;
  254. unsigned int max = fb_height(info) * fb_width(info);
  255. unsigned int val = 0xff;
  256. if(!bits)
  257. {
  258. printk(KERN_WARNING "%s: screen_base is not valid\n", __func__);
  259. return 0;
  260. }
  261. for (i = 0; i < 3; i++) {
  262. int count = max/3;
  263. while (count--) {
  264. unsigned int *addr = \
  265. (unsigned int *) bits;
  266. *addr = val;
  267. bits += 4;
  268. }
  269. val <<= 8;
  270. }
  271. } else
  272. pr_info("%s : load_565rle_image loading fail\n", __func__);
  273. fb_pan_display(info, &info->var);
  274. pdata->set_backlight(pdata, 114);
  275. pr_info("%s:-\n",__func__);
  276. return 0;
  277. }
  278. EXPORT_SYMBOL(load_samsung_boot_logo);
  279. #if defined(ENABLE_BOOTLOGO)
  280. static void bootlogo_work(struct work_struct *work)
  281. {
  282. struct msm_fb_data_type *mfd = NULL ;
  283. static int bootlogo_displayed = 0;
  284. if (get_lcd_attached() == 0)
  285. {
  286. pr_err("%s: get_lcd_attached(0)!\n",__func__);
  287. return ;
  288. }
  289. if(!registered_fb[0]) {
  290. queue_delayed_work(wq_bootlogo, &w_bootlogo, msecs_to_jiffies(200));
  291. return;
  292. }
  293. mfd = (struct msm_fb_data_type *)registered_fb[0]->par;
  294. if(bootlogo_displayed) {
  295. //Need to release framebuffer once someone from userspace opens fb.
  296. pr_info("%s: mfd->ref_cnt: %d\n",__func__, mfd->ref_cnt);
  297. if(mfd->ref_cnt >1) {
  298. registered_fb[0]->fbops->fb_release(registered_fb[0], 0);
  299. pr_info("Boot logo releasing fb0\n");
  300. memset(registered_fb[0]->screen_base,0x0,registered_fb[0]->fix.smem_len);
  301. }else {
  302. queue_delayed_work(wq_bootlogo, &w_bootlogo, msecs_to_jiffies(1000));
  303. }
  304. return;
  305. }
  306. load_samsung_boot_logo();
  307. bootlogo_displayed = 1;
  308. queue_delayed_work(wq_bootlogo, &w_bootlogo, msecs_to_jiffies(5000));
  309. }
  310. static int __init boot_logo_init(void) {
  311. #ifdef CONFIG_SAMSUNG_LPM_MODE
  312. // LPM mode : no boot logo
  313. if(poweroff_charging)
  314. return 0;
  315. #endif
  316. if (get_lcd_attached() == 0)
  317. {
  318. pr_err("%s: get_lcd_attached(0)!\n",__func__);
  319. return -ENODEV;
  320. }
  321. pr_info("%s:+\n",__func__);
  322. wq_bootlogo = create_singlethread_workqueue("bootlogo");
  323. if(wq_bootlogo==NULL)
  324. return -ENOMEM;
  325. INIT_DELAYED_WORK(&w_bootlogo, bootlogo_work);
  326. queue_delayed_work(wq_bootlogo,
  327. &w_bootlogo, msecs_to_jiffies(2000));
  328. return 0;
  329. }
  330. module_init(boot_logo_init)
  331. #endif