mdss_mdp_splash_logo.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. /* Copyright (c) 2013-2015, 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. #define pr_fmt(fmt) "%s: " fmt, __func__
  14. #include <linux/errno.h>
  15. #include <linux/kernel.h>
  16. #include <linux/kthread.h>
  17. #include <linux/memblock.h>
  18. #include <linux/bootmem.h>
  19. #include <linux/iommu.h>
  20. #include <linux/fb.h>
  21. #include "mdss_fb.h"
  22. #include "mdss_mdp.h"
  23. #include "splash.h"
  24. #include "mdss_mdp_splash_logo.h"
  25. #define INVALID_PIPE_INDEX 0xFFFF
  26. #define MAX_FRAME_DONE_COUNT_WAIT 2
  27. static int mdss_mdp_splash_alloc_memory(struct msm_fb_data_type *mfd,
  28. uint32_t size)
  29. {
  30. int rc;
  31. struct msm_fb_splash_info *sinfo;
  32. unsigned long buf_size = size;
  33. struct mdss_data_type *mdata;
  34. if (!mfd || !size)
  35. return -EINVAL;
  36. mdata = mfd_to_mdata(mfd);
  37. sinfo = &mfd->splash_info;
  38. if (!mdata || !mdata->iclient || sinfo->splash_buffer)
  39. return -EINVAL;
  40. sinfo->ion_handle = ion_alloc(mdata->iclient, size, SZ_4K,
  41. ION_HEAP(ION_SYSTEM_HEAP_ID), 0);
  42. if (IS_ERR_OR_NULL(sinfo->ion_handle)) {
  43. pr_err("ion memory allocation failed\n");
  44. rc = PTR_RET(sinfo->ion_handle);
  45. goto end;
  46. }
  47. rc = ion_map_iommu(mdata->iclient, sinfo->ion_handle,
  48. mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE),
  49. 0, SZ_4K, 0, (unsigned long *)&sinfo->iova,
  50. (unsigned long *)&buf_size, 0, 0);
  51. if (rc) {
  52. pr_err("ion memory map failed\n");
  53. goto imap_err;
  54. }
  55. sinfo->splash_buffer = ion_map_kernel(mdata->iclient,
  56. sinfo->ion_handle);
  57. if (IS_ERR_OR_NULL(sinfo->splash_buffer)) {
  58. pr_err("ion kernel memory mapping failed\n");
  59. rc = IS_ERR(sinfo->splash_buffer);
  60. goto kmap_err;
  61. }
  62. return rc;
  63. kmap_err:
  64. ion_unmap_iommu(mdata->iclient, sinfo->ion_handle,
  65. mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE), 0);
  66. imap_err:
  67. ion_free(mdata->iclient, sinfo->ion_handle);
  68. end:
  69. return rc;
  70. }
  71. static void mdss_mdp_splash_free_memory(struct msm_fb_data_type *mfd)
  72. {
  73. struct msm_fb_splash_info *sinfo;
  74. struct mdss_data_type *mdata;
  75. if (!mfd)
  76. return;
  77. sinfo = &mfd->splash_info;
  78. mdata = mfd_to_mdata(mfd);
  79. if (!mdata || !mdata->iclient || !sinfo->ion_handle)
  80. return;
  81. ion_unmap_kernel(mdata->iclient, sinfo->ion_handle);
  82. ion_unmap_iommu(mdata->iclient, sinfo->ion_handle,
  83. mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE), 0);
  84. ion_free(mdata->iclient, sinfo->ion_handle);
  85. sinfo->splash_buffer = NULL;
  86. }
  87. static int mdss_mdp_splash_iommu_attach(struct msm_fb_data_type *mfd)
  88. {
  89. struct iommu_domain *domain;
  90. struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
  91. int rc, ret;
  92. /*
  93. * iommu dynamic attach for following conditions.
  94. * 1. it is still not attached
  95. * 2. MDP hardware version supports the feature
  96. * 3. configuration is with valid splash buffer
  97. */
  98. if (is_mdss_iommu_attached() ||
  99. !mfd->panel_info->cont_splash_enabled ||
  100. !mdss_mdp_iommu_dyn_attach_supported(mdp5_data->mdata) ||
  101. !mdp5_data->splash_mem_addr ||
  102. !mdp5_data->splash_mem_size) {
  103. pr_debug("dynamic attach is not supported\n");
  104. return -EPERM;
  105. }
  106. domain = msm_get_iommu_domain(mdss_get_iommu_domain(
  107. MDSS_IOMMU_DOMAIN_UNSECURE));
  108. if (!domain) {
  109. pr_debug("mdss iommu domain get failed\n");
  110. return -EINVAL;
  111. }
  112. rc = iommu_map(domain, mdp5_data->splash_mem_addr,
  113. mdp5_data->splash_mem_addr,
  114. mdp5_data->splash_mem_size, IOMMU_READ);
  115. if (rc) {
  116. pr_debug("iommu memory mapping failed rc=%d\n", rc);
  117. } else {
  118. ret = mdss_iommu_ctrl(1);
  119. if (IS_ERR_VALUE(ret)) {
  120. pr_err("mdss iommu attach failed\n");
  121. iommu_unmap(domain, mdp5_data->splash_mem_addr,
  122. mdp5_data->splash_mem_size);
  123. } else {
  124. mfd->splash_info.iommu_dynamic_attached = true;
  125. }
  126. }
  127. return rc;
  128. }
  129. static void mdss_mdp_splash_unmap_splash_mem(struct msm_fb_data_type *mfd)
  130. {
  131. struct iommu_domain *domain;
  132. struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
  133. if (mfd->splash_info.iommu_dynamic_attached) {
  134. domain = msm_get_iommu_domain(mdss_get_iommu_domain(
  135. MDSS_IOMMU_DOMAIN_UNSECURE));
  136. if (!domain) {
  137. pr_err("mdss iommu domain get failed\n");
  138. return;
  139. }
  140. iommu_unmap(domain, mdp5_data->splash_mem_addr,
  141. mdp5_data->splash_mem_size);
  142. mdss_iommu_ctrl(0);
  143. mfd->splash_info.iommu_dynamic_attached = false;
  144. }
  145. }
  146. void mdss_mdp_release_splash_pipe(struct msm_fb_data_type *mfd)
  147. {
  148. struct msm_fb_splash_info *sinfo;
  149. if (!mfd || !mfd->splash_info.splash_pipe_allocated)
  150. return;
  151. sinfo = &mfd->splash_info;
  152. if (sinfo->pipe_ndx[0] != INVALID_PIPE_INDEX)
  153. mdss_mdp_overlay_release(mfd, sinfo->pipe_ndx[0]);
  154. if (sinfo->pipe_ndx[1] != INVALID_PIPE_INDEX)
  155. mdss_mdp_overlay_release(mfd, sinfo->pipe_ndx[1]);
  156. sinfo->splash_pipe_allocated = false;
  157. }
  158. int mdss_mdp_splash_cleanup(struct msm_fb_data_type *mfd,
  159. bool use_borderfill)
  160. {
  161. struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
  162. struct mdss_mdp_ctl *ctl = mdp5_data->ctl;
  163. int rc = 0;
  164. if (!mfd || !mdp5_data)
  165. return -EINVAL;
  166. if (mfd->splash_info.iommu_dynamic_attached ||
  167. !mfd->panel_info->cont_splash_enabled)
  168. goto end;
  169. if (use_borderfill && mdp5_data->handoff) {
  170. /*
  171. * Set up border-fill on the handed off pipes.
  172. * This is needed to ensure that there are no memory
  173. * accesses prior to attaching iommu during continuous
  174. * splash screen case. However, for command mode
  175. * displays, this is not necessary since the panels can
  176. * refresh from their internal memory if no data is sent
  177. * out on the dsi lanes.
  178. */
  179. if (mdp5_data->handoff && ctl && ctl->is_video_mode) {
  180. rc = mdss_mdp_display_commit(ctl, NULL);
  181. if (!IS_ERR_VALUE(rc)) {
  182. mdss_mdp_display_wait4comp(ctl);
  183. } else {
  184. /*
  185. * Since border-fill setup failed, we
  186. * need to ensure that we turn off the
  187. * MDP timing generator before attaching
  188. * iommu
  189. */
  190. pr_err("failed to set BF at handoff\n");
  191. mdp5_data->handoff = false;
  192. }
  193. }
  194. }
  195. if (rc || mdp5_data->handoff)
  196. {
  197. /* Add all the handed off pipes to the cleanup list */
  198. mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_RGB);
  199. mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_VIG);
  200. mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_DMA);
  201. }
  202. mdss_mdp_ctl_splash_finish(ctl, mdp5_data->handoff);
  203. if (!sec_debug_is_enabled()) {
  204. if (mdp5_data->splash_mem_addr) {
  205. /* Give back the reserved memory to the system */
  206. memblock_free(mdp5_data->splash_mem_addr,
  207. mdp5_data->splash_mem_size);
  208. free_bootmem_late(mdp5_data->splash_mem_addr,
  209. mdp5_data->splash_mem_size);
  210. }
  211. }
  212. mdss_mdp_footswitch_ctrl_splash(0);
  213. end:
  214. return rc;
  215. }
  216. static struct mdss_mdp_pipe *mdss_mdp_splash_get_pipe(
  217. struct msm_fb_data_type *mfd,
  218. struct mdp_overlay *req)
  219. {
  220. struct mdss_mdp_pipe *pipe;
  221. int ret;
  222. struct mdss_mdp_data *buf;
  223. uint32_t image_size = SPLASH_IMAGE_WIDTH * SPLASH_IMAGE_HEIGHT
  224. * SPLASH_IMAGE_BPP;
  225. ret = mdss_mdp_overlay_pipe_setup(mfd, req, &pipe);
  226. if (ret)
  227. return NULL;
  228. if (mdss_mdp_pipe_map(pipe)) {
  229. pr_err("unable to map base pipe\n");
  230. return NULL;
  231. }
  232. buf = &pipe->back_buf;
  233. buf->p[0].addr = mfd->splash_info.iova;
  234. buf->p[0].len = image_size;
  235. buf->num_planes = 1;
  236. mdss_mdp_pipe_unmap(pipe);
  237. return pipe;
  238. }
  239. static int mdss_mdp_splash_kickoff(struct msm_fb_data_type *mfd,
  240. struct mdss_mdp_img_rect *src_rect,
  241. struct mdss_mdp_img_rect *dest_rect)
  242. {
  243. struct mdss_mdp_pipe *pipe;
  244. struct fb_info *fbi;
  245. struct mdp_overlay req;
  246. struct mdss_overlay_private *mdp5_data;
  247. struct mdss_data_type *mdata;
  248. struct mdss_mdp_mixer *mixer;
  249. int ret;
  250. bool use_single_pipe = false;
  251. struct msm_fb_splash_info *sinfo;
  252. if (!mfd)
  253. return -EINVAL;
  254. fbi = mfd->fbi;
  255. mdp5_data = mfd_to_mdp5_data(mfd);
  256. mdata = mfd_to_mdata(mfd);
  257. sinfo = &mfd->splash_info;
  258. if (!mdp5_data || !mdp5_data->ctl)
  259. return -EINVAL;
  260. if (mutex_lock_interruptible(&mdp5_data->ov_lock))
  261. return -EINVAL;
  262. ret = mdss_mdp_overlay_start(mfd);
  263. if (ret) {
  264. pr_err("unable to start overlay %d (%d)\n", mfd->index, ret);
  265. goto end;
  266. }
  267. mixer = mdss_mdp_mixer_get(mdp5_data->ctl, MDSS_MDP_MIXER_MUX_LEFT);
  268. if (!mixer) {
  269. pr_err("unable to retrieve mixer\n");
  270. ret = -EINVAL;
  271. goto end;
  272. }
  273. memset(&req, 0, sizeof(struct mdp_overlay));
  274. /*
  275. * use single pipe for
  276. * 1. split display disabled
  277. * 2. splash image is only on one side of panel
  278. */
  279. use_single_pipe =
  280. !mfd->split_display ||
  281. (mfd->split_display &&
  282. ((dest_rect->x + dest_rect->w) < mfd->split_fb_left ||
  283. dest_rect->x > mfd->split_fb_left));
  284. req.src.width = src_rect->w;
  285. if (use_single_pipe)
  286. req.src_rect.w = src_rect->w;
  287. else
  288. req.src_rect.w = min_t(u16, mixer->width, src_rect->w >> 1);
  289. req.dst_rect.w = req.src_rect.w;
  290. req.src.height = req.dst_rect.h = req.src_rect.h =
  291. src_rect->h;
  292. req.src.format = SPLASH_IMAGE_FORMAT;
  293. req.id = MSMFB_NEW_REQUEST;
  294. req.z_order = MDSS_MDP_STAGE_0;
  295. req.alpha = 0xff;
  296. req.transp_mask = MDP_TRANSP_NOP;
  297. req.dst_rect.x = dest_rect->x;
  298. req.dst_rect.y = dest_rect->y;
  299. pipe = mdss_mdp_splash_get_pipe(mfd, &req);
  300. if (!pipe) {
  301. pr_err("unable to allocate base pipe\n");
  302. ret = -EINVAL;
  303. goto end;
  304. }
  305. sinfo->pipe_ndx[0] = pipe->ndx;
  306. if (!use_single_pipe) {
  307. req.id = MSMFB_NEW_REQUEST;
  308. req.src_rect.x = src_rect->x + min_t(u16, mixer->width,
  309. src_rect->w - req.src_rect.w);
  310. req.dst_rect.x = mixer->width;
  311. pipe = mdss_mdp_splash_get_pipe(mfd, &req);
  312. if (!pipe) {
  313. pr_err("unable to allocate right base pipe\n");
  314. mdss_mdp_overlay_release(mfd, sinfo->pipe_ndx[0]);
  315. ret = -EINVAL;
  316. goto end;
  317. }
  318. sinfo->pipe_ndx[1] = pipe->ndx;
  319. }
  320. mutex_unlock(&mdp5_data->ov_lock);
  321. ret = mfd->mdp.kickoff_fnc(mfd, NULL);
  322. if (ret) {
  323. pr_err("error in displaying image\n");
  324. mdss_mdp_overlay_release(mfd, sinfo->pipe_ndx[0] |
  325. sinfo->pipe_ndx[1]);
  326. }
  327. return ret;
  328. end:
  329. sinfo->pipe_ndx[0] = INVALID_PIPE_INDEX;
  330. sinfo->pipe_ndx[1] = INVALID_PIPE_INDEX;
  331. mutex_unlock(&mdp5_data->ov_lock);
  332. return ret;
  333. }
  334. static int mdss_mdp_display_splash_image(struct msm_fb_data_type *mfd)
  335. {
  336. int rc = 0;
  337. struct fb_info *fbi;
  338. uint32_t image_len = SPLASH_IMAGE_WIDTH * SPLASH_IMAGE_HEIGHT
  339. * SPLASH_IMAGE_BPP;
  340. struct mdss_mdp_img_rect src_rect, dest_rect;
  341. struct msm_fb_splash_info *sinfo;
  342. if (!mfd || !mfd->fbi) {
  343. pr_err("invalid input parameter\n");
  344. rc = -EINVAL;
  345. goto end;
  346. }
  347. fbi = mfd->fbi;
  348. sinfo = &mfd->splash_info;
  349. if (SPLASH_IMAGE_WIDTH > fbi->var.xres ||
  350. SPLASH_IMAGE_HEIGHT > fbi->var.yres ||
  351. SPLASH_IMAGE_BPP > (fbi->var.bits_per_pixel >> 3)) {
  352. pr_err("invalid splash parameter configuration\n");
  353. rc = -EINVAL;
  354. goto end;
  355. }
  356. sinfo->pipe_ndx[0] = INVALID_PIPE_INDEX;
  357. sinfo->pipe_ndx[1] = INVALID_PIPE_INDEX;
  358. src_rect.x = 0;
  359. src_rect.y = 0;
  360. dest_rect.w = src_rect.w = SPLASH_IMAGE_WIDTH;
  361. dest_rect.h = src_rect.h = SPLASH_IMAGE_HEIGHT;
  362. dest_rect.x = (fbi->var.xres >> 1) - (SPLASH_IMAGE_WIDTH >> 1);
  363. dest_rect.y = (fbi->var.yres >> 1) - (SPLASH_IMAGE_HEIGHT >> 1);
  364. rc = mdss_mdp_splash_alloc_memory(mfd, image_len);
  365. if (rc) {
  366. pr_err("splash buffer allocation failed\n");
  367. goto end;
  368. }
  369. memcpy(sinfo->splash_buffer, splash_bgr888_image, image_len);
  370. rc = mdss_mdp_splash_iommu_attach(mfd);
  371. if (rc)
  372. pr_debug("iommu dynamic attach failed\n");
  373. rc = mdss_mdp_splash_kickoff(mfd, &src_rect, &dest_rect);
  374. if (rc)
  375. pr_err("splash image display failed\n");
  376. else
  377. sinfo->splash_pipe_allocated = true;
  378. end:
  379. return rc;
  380. }
  381. static int mdss_mdp_splash_ctl_cb(struct notifier_block *self,
  382. unsigned long event, void *data)
  383. {
  384. struct msm_fb_splash_info *sinfo = container_of(self,
  385. struct msm_fb_splash_info, notifier);
  386. struct msm_fb_data_type *mfd;
  387. if (!sinfo)
  388. goto done;
  389. mfd = container_of(sinfo, struct msm_fb_data_type, splash_info);
  390. if (!mfd)
  391. goto done;
  392. if (event != MDP_NOTIFY_FRAME_DONE)
  393. goto done;
  394. if (!sinfo->frame_done_count) {
  395. mdss_mdp_splash_unmap_splash_mem(mfd);
  396. /* wait for 2 frame done events before releasing memory */
  397. } else if (sinfo->frame_done_count > MAX_FRAME_DONE_COUNT_WAIT &&
  398. sinfo->splash_thread) {
  399. complete(&sinfo->frame_done);
  400. sinfo->splash_thread = NULL;
  401. }
  402. /* increase frame done count after pipes are staged from other client */
  403. if (!sinfo->splash_pipe_allocated)
  404. sinfo->frame_done_count++;
  405. done:
  406. return NOTIFY_OK;
  407. }
  408. static int mdss_mdp_splash_thread(void *data)
  409. {
  410. struct msm_fb_data_type *mfd = data;
  411. struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
  412. int ret = -EINVAL;
  413. if (!mfd) {
  414. pr_err("invalid input parameter\n");
  415. goto end;
  416. }
  417. lock_fb_info(mfd->fbi);
  418. ret = fb_blank(mfd->fbi, FB_BLANK_UNBLANK);
  419. if (ret) {
  420. pr_err("can't turn on fb!\n");
  421. goto end;
  422. }
  423. unlock_fb_info(mfd->fbi);
  424. mutex_lock(&mfd->bl_lock);
  425. mfd->bl_updated = true;
  426. mdss_fb_set_backlight(mfd, mfd->panel_info->bl_max >> 1);
  427. mutex_unlock(&mfd->bl_lock);
  428. init_completion(&mfd->splash_info.frame_done);
  429. mfd->splash_info.notifier.notifier_call = mdss_mdp_splash_ctl_cb;
  430. mdss_mdp_ctl_notifier_register(mdp5_data->ctl,
  431. &mfd->splash_info.notifier);
  432. ret = mdss_mdp_display_splash_image(mfd);
  433. if (ret) {
  434. /*
  435. * keep thread alive to release dynamically allocated
  436. * resources
  437. */
  438. pr_err("splash image display failed\n");
  439. }
  440. /* wait for second display complete to release splash resources */
  441. ret = wait_for_completion_killable(&mfd->splash_info.frame_done);
  442. mdss_mdp_splash_free_memory(mfd);
  443. mdss_mdp_ctl_notifier_unregister(mdp5_data->ctl,
  444. &mfd->splash_info.notifier);
  445. end:
  446. return ret;
  447. }
  448. static __ref int mdss_mdp_splash_parse_dt(struct msm_fb_data_type *mfd)
  449. {
  450. struct platform_device *pdev = mfd->pdev;
  451. struct mdss_overlay_private *mdp5_mdata = mfd_to_mdp5_data(mfd);
  452. int len = 0, rc = 0;
  453. u32 offsets[2];
  454. mfd->splash_info.splash_logo_enabled =
  455. of_property_read_bool(pdev->dev.of_node,
  456. "qcom,mdss-fb-splash-logo-enabled");
  457. of_find_property(pdev->dev.of_node, "qcom,memblock-reserve", &len);
  458. if (len < 1) {
  459. pr_debug("mem reservation for splash screen fb not present\n");
  460. rc = -EINVAL;
  461. goto error;
  462. }
  463. len = len / sizeof(u32);
  464. rc = of_property_read_u32_array(pdev->dev.of_node,
  465. "qcom,memblock-reserve", offsets, len);
  466. if (rc) {
  467. pr_debug("error reading mem reserve settings for fb\n");
  468. goto error;
  469. }
  470. if (!memblock_is_reserved(offsets[0])) {
  471. pr_debug("failed to reserve memory for fb splash\n");
  472. rc = -EINVAL;
  473. goto error;
  474. }
  475. mdp5_mdata->splash_mem_addr = offsets[0];
  476. mdp5_mdata->splash_mem_size = offsets[1];
  477. pr_debug("memaddr=%x size=%x\n", mdp5_mdata->splash_mem_addr,
  478. mdp5_mdata->splash_mem_size);
  479. error:
  480. if (!rc && !mfd->panel_info->cont_splash_enabled &&
  481. mdp5_mdata->splash_mem_addr) {
  482. pr_debug("mem reservation not reqd if cont splash disabled\n");
  483. memblock_free(mdp5_mdata->splash_mem_addr,
  484. mdp5_mdata->splash_mem_size);
  485. free_bootmem_late(mdp5_mdata->splash_mem_addr,
  486. mdp5_mdata->splash_mem_size);
  487. } else if (rc && mfd->panel_info->cont_splash_enabled) {
  488. pr_err("no rsvd mem found in DT for splash screen\n");
  489. } else {
  490. rc = 0;
  491. }
  492. return rc;
  493. }
  494. int mdss_mdp_splash_init(struct msm_fb_data_type *mfd)
  495. {
  496. int rc;
  497. if (!mfd) {
  498. rc = -EINVAL;
  499. goto end;
  500. }
  501. rc = mdss_mdp_splash_parse_dt(mfd);
  502. if (rc) {
  503. pr_err("splash memory reserve failed\n");
  504. goto end;
  505. }
  506. if (!mfd->splash_info.splash_logo_enabled) {
  507. rc = -EINVAL;
  508. goto end;
  509. }
  510. mfd->splash_info.splash_thread = kthread_run(mdss_mdp_splash_thread,
  511. mfd, "mdss_fb_splash");
  512. if (IS_ERR(mfd->splash_info.splash_thread)) {
  513. pr_err("unable to start splash thread %d\n", mfd->index);
  514. mfd->splash_info.splash_thread = NULL;
  515. }
  516. end:
  517. return rc;
  518. }