diff options
| author | Dhaval Patel <pdhaval@codeaurora.org> | 2014-03-19 17:04:29 -0700 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:29:25 -0700 |
| commit | fb9d80000c238a0c0224a3b453ff2a1c371e3405 (patch) | |
| tree | 702886f078e2660f457ec18489c59fac0f2600f7 | |
| parent | cbac77a73662bba79b4b7a533e807c2199b1126f (diff) | |
msm: mdss: Move splash thread functionality
framebuffer and overlay drivers are tightly coupled with
splash thread functionality. This adds lots of code
related to continuous splash screen handling in
both drivers. Moving them to separate file cleans up
both drivers and allows to handle continuous splash screen
cases efficiently.
CRs-fixed: 605934
Change-Id: Id89bb281dbbf22e726cf5fd97e93f891e5c73f60
Signed-off-by: Dhaval Patel <pdhaval@codeaurora.org>
[cip@codeaurora.org: Moved new file locations]
Signed-off-by: Clarence Ip <cip@codeaurora.org>
| -rw-r--r-- | drivers/video/fbdev/msm/Makefile | 1 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdp3_ctrl.c | 10 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_fb.c | 65 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_fb.h | 16 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp.h | 19 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_intf_video.c | 7 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_overlay.c | 296 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_splash_logo.c | 630 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_splash_logo.h | 43 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_qpic.c | 3 |
10 files changed, 750 insertions, 340 deletions
diff --git a/drivers/video/fbdev/msm/Makefile b/drivers/video/fbdev/msm/Makefile index fa22828c6c47..dc14df665fab 100644 --- a/drivers/video/fbdev/msm/Makefile +++ b/drivers/video/fbdev/msm/Makefile @@ -11,6 +11,7 @@ mdss-mdp-objs += mdss_mdp_intf_cmd.o mdss-mdp-objs += mdss_mdp_intf_writeback.o mdss-mdp-objs += mdss_mdp_rotator.o mdss-mdp-objs += mdss_mdp_overlay.o +mdss-mdp-objs += mdss_mdp_splash_logo.o mdss-mdp-objs += mdss_mdp_wb.o obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp.o diff --git a/drivers/video/fbdev/msm/mdp3_ctrl.c b/drivers/video/fbdev/msm/mdp3_ctrl.c index 5f789b14bb88..5a5ad2ff8c67 100644 --- a/drivers/video/fbdev/msm/mdp3_ctrl.c +++ b/drivers/video/fbdev/msm/mdp3_ctrl.c @@ -27,10 +27,7 @@ #define VSYNC_EXPIRE_TICK 4 -static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd, - struct mdp_overlay *req, - int image_size, - int *pipe_ndx); +static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd); static int mdp3_overlay_unset(struct msm_fb_data_type *mfd, int ndx); static int mdp3_histogram_stop(struct mdp3_session_data *session, u32 block); @@ -1087,10 +1084,7 @@ static int mdp3_ctrl_display_commit_kickoff(struct msm_fb_data_type *mfd, return 0; } -static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd, - struct mdp_overlay *req, - int image_size, - int *pipe_ndx) +static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd) { struct fb_info *fbi; struct mdp3_session_data *mdp3_session; diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index f387b963061e..a991e1810823 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -51,6 +51,7 @@ #include <linux/msm_iommu_domains.h> #include "mdss_fb.h" +#include "mdss_mdp_splash_logo.h" #ifdef CONFIG_FB_MSM_TRIPLE_BUFFER #define MDSS_FB_NUM 3 @@ -195,47 +196,6 @@ static int mdss_fb_notify_update(struct msm_fb_data_type *mfd, return ret; } -static int mdss_fb_splash_thread(void *data) -{ - struct msm_fb_data_type *mfd = data; - int ret = -EINVAL; - struct fb_info *fbi = NULL; - int ov_index[2]; - - if (!mfd || !mfd->fbi || !mfd->mdp.splash_fnc) { - pr_err("Invalid input parameter\n"); - goto end; - } - - fbi = mfd->fbi; - - ret = mdss_fb_open(fbi, current->tgid); - if (ret) { - pr_err("fb_open failed\n"); - goto end; - } - - mfd->bl_updated = true; - mdss_fb_set_backlight(mfd, mfd->panel_info->bl_max >> 1); - - ret = mfd->mdp.splash_fnc(mfd, ov_index, MDP_CREATE_SPLASH_OV); - if (ret) { - pr_err("Splash image failed\n"); - goto splash_err; - } - - do { - schedule_timeout_interruptible(SPLASH_THREAD_WAIT_TIMEOUT * HZ); - } while (!kthread_should_stop()); - - mfd->mdp.splash_fnc(mfd, ov_index, MDP_REMOVE_SPLASH_OV); - -splash_err: - mdss_fb_release(fbi, current->tgid); -end: - return ret; -} - static int lcd_backlight_registered; static void mdss_fb_set_bl_brightness(struct led_classdev *led_cdev, @@ -342,9 +302,6 @@ static void mdss_fb_parse_dt_split(struct msm_fb_data_type *mfd) u32 data[2] = {0}; struct platform_device *pdev = mfd->pdev; - mfd->splash_logo_enabled = of_property_read_bool(pdev->dev.of_node, - "qcom,mdss-fb-splash-logo-enabled"); - of_property_read_u32_array(pdev->dev.of_node, "qcom,mdss-fb-split", data, 2); @@ -642,15 +599,8 @@ static int mdss_fb_probe(struct platform_device *pdev) break; } - if (mfd->splash_logo_enabled) { - mfd->splash_thread = kthread_run(mdss_fb_splash_thread, mfd, - "mdss_fb_splash"); - if (IS_ERR(mfd->splash_thread)) { - pr_err("unable to start splash thread %d\n", - mfd->index); - mfd->splash_thread = NULL; - } - } + if (mfd->mdp.splash_init_fnc) + mfd->mdp.splash_init_fnc(mfd); INIT_DELAYED_WORK(&mfd->idle_notify_work, __mdss_fb_idle_notify_work); @@ -1549,13 +1499,6 @@ static int mdss_fb_open(struct fb_info *info, int user) pinfo->ref_cnt++; mfd->ref_cnt++; - /* Stop the splash thread once userspace open the fb node */ - if (mfd->splash_thread && mfd->ref_cnt > 1) { - kthread_stop(mfd->splash_thread); - mfd->splash_thread = NULL; - mdss_fb_free_fb_ion_memory(mfd); - } - return 0; blank_error: @@ -1979,7 +1922,7 @@ static int mdss_fb_pan_display_sub(struct fb_var_screeninfo *var, (var->yoffset / info->fix.ypanstep) * info->fix.ypanstep; if (mfd->mdp.dma_fnc) - mfd->mdp.dma_fnc(mfd, NULL, 0, NULL); + mfd->mdp.dma_fnc(mfd); else pr_warn("dma function not set for panel type=%d\n", mfd->panel.type); diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h index f99c02d4e867..5f844f073334 100644 --- a/drivers/video/fbdev/msm/mdss_fb.h +++ b/drivers/video/fbdev/msm/mdss_fb.h @@ -21,6 +21,7 @@ #include <linux/notifier.h> #include "mdss_panel.h" +#include "mdss_mdp_splash_logo.h" #define MDSS_LPAE_CHECK(phys) \ ((sizeof(phys) > sizeof(unsigned long)) ? ((phys >> 32) & 0xFF) : (0)) @@ -36,8 +37,6 @@ #define WAIT_DISP_OP_TIMEOUT ((WAIT_FENCE_FIRST_TIMEOUT + \ WAIT_FENCE_FINAL_TIMEOUT) * MDP_MAX_FENCE_FD) -#define SPLASH_THREAD_WAIT_TIMEOUT 3 - #ifndef MAX #define MAX(x, y) (((x) > (y)) ? (x) : (y)) #endif @@ -72,11 +71,6 @@ enum mdp_notify_event { MDP_NOTIFY_FRAME_TIMEOUT, }; -enum mdp_splash_event { - MDP_CREATE_SPLASH_OV = 0, - MDP_REMOVE_SPLASH_OV, -}; - struct disp_info_type_suspend { int op_enable; int panel_power_on; @@ -125,8 +119,7 @@ struct msm_mdp_interface { int (*kickoff_fnc)(struct msm_fb_data_type *mfd, struct mdp_display_commit *data); int (*ioctl_handler)(struct msm_fb_data_type *mfd, u32 cmd, void *arg); - void (*dma_fnc)(struct msm_fb_data_type *mfd, struct mdp_overlay *req, - int image_len, int *pipe_ndx); + void (*dma_fnc)(struct msm_fb_data_type *mfd); int (*cursor_update)(struct msm_fb_data_type *mfd, struct fb_cursor *cursor); int (*lut_update)(struct msm_fb_data_type *mfd, struct fb_cmap *cmap); @@ -135,7 +128,7 @@ struct msm_mdp_interface { int (*update_ad_input)(struct msm_fb_data_type *mfd); int (*panel_register_done)(struct mdss_panel_data *pdata); u32 (*fb_stride)(u32 fb_index, u32 xres, int bpp); - int (*splash_fnc) (struct msm_fb_data_type *mfd, int *index, int req); + int (*splash_init_fnc)(struct msm_fb_data_type *mfd); struct msm_sync_pt_data *(*get_sync_fnc)(struct msm_fb_data_type *mfd, const struct mdp_buf_sync *buf_sync); void (*check_dsi_status)(struct work_struct *work, uint32_t interval); @@ -223,8 +216,7 @@ struct msm_fb_data_type { wait_queue_head_t kickoff_wait_q; bool shutdown_pending; - struct task_struct *splash_thread; - bool splash_logo_enabled; + struct msm_fb_splash_info splash_info; wait_queue_head_t ioctl_q; atomic_t ioctl_ref_cnt; diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index e3fbd2850e9e..08c8b15d1632 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -34,6 +34,7 @@ #define MDP_CLK_DEFAULT_RATE 200000000 #define PHASE_STEP_SHIFT 21 #define MAX_MIXER_WIDTH 2048 +#define MAX_LINE_BUFFER_WIDTH 2048 #define MAX_MIXER_HEIGHT 0xFFFF #define MAX_IMG_WIDTH 0x3FFF #define MAX_IMG_HEIGHT 0x3FFF @@ -542,6 +543,17 @@ static inline int mdss_mdp_pipe_is_sw_reset_available( } } +static inline int mdss_mdp_iommu_dyn_attach_supported( + struct mdss_data_type *mdata) +{ + return (mdata->mdp_rev >= MDSS_MDP_HW_REV_103); +} + +static inline int mdss_mdp_line_buffer_width(void) +{ + return MAX_LINE_BUFFER_WIDTH; +} + irqreturn_t mdss_mdp_isr(int irq, void *ptr); int mdss_iommu_attach(struct mdss_data_type *mdata); int mdss_iommu_dettach(struct mdss_data_type *mdata); @@ -574,6 +586,13 @@ int mdss_mdp_overlay_get_buf(struct msm_fb_data_type *mfd, struct msmfb_data *planes, int num_planes, u32 flags); +int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd, + struct mdp_overlay *req, struct mdss_mdp_pipe **ppipe, + struct mdss_mdp_pipe *left_blend_pipe); +void mdss_mdp_handoff_cleanup_pipes(struct msm_fb_data_type *mfd, + u32 type); +int mdss_mdp_overlay_release(struct msm_fb_data_type *mfd, int ndx); +int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd); int mdss_mdp_video_addr_setup(struct mdss_data_type *mdata, u32 *offsets, u32 count); int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl); diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c index bea461f5d91c..d6485820ddd4 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c @@ -16,7 +16,6 @@ #include <linux/iopoll.h> #include <linux/delay.h> #include <linux/dma-mapping.h> -#include <linux/bootmem.h> #include <linux/memblock.h> #include "mdss_fb.h" @@ -735,7 +734,6 @@ int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl, { struct mdss_panel_data *pdata; int i, ret = 0, off; - struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(ctl->mfd); u32 data, flush; struct mdss_mdp_video_ctx *ctx; @@ -781,11 +779,6 @@ int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl, MDSS_EVENT_CONT_SPLASH_FINISH, NULL); } - /* Give back the reserved memory to the system */ - memblock_free(mdp5_data->splash_mem_addr, mdp5_data->splash_mem_size); - free_bootmem_late(mdp5_data->splash_mem_addr, - mdp5_data->splash_mem_size); - return ret; } diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index a6f90ce48bdf..5c6e5d3119b8 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -36,8 +36,6 @@ #include "mdss_mdp.h" #include "mdss_mdp_rotator.h" -#include "splash.h" - #define VSYNC_PERIOD 16 #define BORDERFILL_NDX 0x0BF000BF #define CHECK_BOUNDS(offset, size, max_size) \ @@ -51,7 +49,6 @@ #define MEM_PROTECT_SD_CTRL 0xF -#define INVALID_PIPE_INDEX 0xFFFF #define OVERLAY_MAX 10 struct sd_ctrl_req { @@ -62,7 +59,6 @@ static atomic_t ov_active_panels = ATOMIC_INIT(0); static int mdss_mdp_overlay_free_fb_pipe(struct msm_fb_data_type *mfd); static int mdss_mdp_overlay_fb_parse_dt(struct msm_fb_data_type *mfd); static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd); -static int mdss_mdp_overlay_splash_parse_dt(struct msm_fb_data_type *mfd); static void __overlay_kickoff_requeue(struct msm_fb_data_type *mfd); static inline bool is_ov_right_blend(struct mdp_rect *left_blend, @@ -466,7 +462,7 @@ static inline void __mdss_mdp_overlay_set_chroma_sample( pipe->chroma_sample_v = 0; } -static int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd, +int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd, struct mdp_overlay *req, struct mdss_mdp_pipe **ppipe, struct mdss_mdp_pipe *left_blend_pipe) { @@ -1054,7 +1050,7 @@ static void mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd) mutex_unlock(&mdp5_data->list_lock); } -static void __mdss_mdp_handoff_cleanup_pipes(struct msm_fb_data_type *mfd, +void mdss_mdp_handoff_cleanup_pipes(struct msm_fb_data_type *mfd, u32 type) { u32 i, npipes; @@ -1100,7 +1096,7 @@ static void __mdss_mdp_handoff_cleanup_pipes(struct msm_fb_data_type *mfd, * from the the splash screen to the android boot animation when the * continuous splash screen feature is enabled. */ -static int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd) +int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd) { int rc; struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); @@ -1116,6 +1112,7 @@ static int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd) mdss_mdp_batfet_ctrl(mdp5_data->mdata, true); if (!mfd->panel_info->cont_splash_enabled) mdss_iommu_attach(mdp5_data->mdata); + mdss_mdp_release_splash_pipe(mfd); return 0; } @@ -1152,48 +1149,7 @@ static int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd) goto error; } - if (mfd->panel_info->cont_splash_enabled) { - if (mdp5_data->handoff) { - /* - * Set up border-fill on the handed off pipes. - * This is needed to ensure that there are no memory - * accesses prior to attaching iommu during continuous - * splash screen case. However, for command mode - * displays, this is not necessary since the panels can - * refresh from their internal memory if no data is sent - * out on the dsi lanes. - */ - if (ctl && ctl->is_video_mode) { - rc = mdss_mdp_display_commit(ctl, NULL); - if (!IS_ERR_VALUE(rc)) { - mdss_mdp_display_wait4comp(ctl); - } else { - /* - * Since border-fill setup failed, we - * need to ensure that we turn off the - * MDP timing generator before attaching - * iommu - */ - pr_err("failed to set BF at handoff\n"); - mdp5_data->handoff = false; - rc = 0; - } - } - - /* Add all the handed off pipes to the cleanup list */ - __mdss_mdp_handoff_cleanup_pipes(mfd, - MDSS_MDP_PIPE_TYPE_RGB); - __mdss_mdp_handoff_cleanup_pipes(mfd, - MDSS_MDP_PIPE_TYPE_VIG); - __mdss_mdp_handoff_cleanup_pipes(mfd, - MDSS_MDP_PIPE_TYPE_DMA); - } - mdss_mdp_ctl_splash_finish(ctl, mdp5_data->handoff); - mdss_mdp_footswitch_ctrl_splash(0); - if (!is_mdss_iommu_attached()) - mdss_iommu_attach(mdss_res); - } - + rc = mdss_mdp_splash_cleanup(mfd, true); error: if (rc) { mdss_mdp_ctl_destroy(ctl); @@ -1396,7 +1352,7 @@ commit_fail: return ret; } -static int mdss_mdp_overlay_release(struct msm_fb_data_type *mfd, int ndx) +int mdss_mdp_overlay_release(struct msm_fb_data_type *mfd, int ndx) { struct mdss_mdp_pipe *pipe, *tmp; struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); @@ -1713,8 +1669,7 @@ static int mdss_mdp_overlay_free_fb_pipe(struct msm_fb_data_type *mfd) static int mdss_mdp_overlay_get_fb_pipe(struct msm_fb_data_type *mfd, struct mdss_mdp_pipe **ppipe, - int mixer_mux, - struct mdp_overlay *req_ov) + int mixer_mux) { struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); struct mdss_mdp_pipe *pipe; @@ -1724,7 +1679,10 @@ static int mdss_mdp_overlay_get_fb_pipe(struct msm_fb_data_type *mfd, MDSS_MDP_STAGE_BASE, false); if (pipe == NULL) { + struct mdp_overlay req; + struct fb_info *fbi = mfd->fbi; struct mdss_mdp_mixer *mixer; + int bpp; mixer = mdss_mdp_mixer_get(mdp5_data->ctl, MDSS_MDP_MIXER_MUX_LEFT); @@ -1733,78 +1691,45 @@ static int mdss_mdp_overlay_get_fb_pipe(struct msm_fb_data_type *mfd, return -ENODEV; } - if (req_ov == NULL) { - struct mdp_overlay req; - struct fb_info *fbi = mfd->fbi; - int bpp; - - memset(&req, 0, sizeof(req)); + memset(&req, 0, sizeof(req)); - bpp = fbi->var.bits_per_pixel / 8; - req.id = MSMFB_NEW_REQUEST; - req.src.format = mfd->fb_imgType; - req.src.height = fbi->var.yres; - req.src.width = fbi->fix.line_length / bpp; - if (mixer_mux == MDSS_MDP_MIXER_MUX_RIGHT) { - if (req.src.width <= mixer->width) { - pr_warn("right fb pipe not needed\n"); - return -EINVAL; - } - - req.src_rect.x = mixer->width; - req.src_rect.w = fbi->var.xres - mixer->width; - } else { - req.src_rect.x = 0; - req.src_rect.w = MIN(fbi->var.xres, - mixer->width); + bpp = fbi->var.bits_per_pixel / 8; + req.id = MSMFB_NEW_REQUEST; + req.src.format = mfd->fb_imgType; + req.src.height = fbi->var.yres; + req.src.width = fbi->fix.line_length / bpp; + if (mixer_mux == MDSS_MDP_MIXER_MUX_RIGHT) { + if (req.src.width <= mixer->width) { + pr_warn("right fb pipe not needed\n"); + return -EINVAL; } - req.src_rect.y = 0; - req.src_rect.h = req.src.height; - req.dst_rect = req.src_rect; - req.z_order = MDSS_MDP_STAGE_BASE; + req.src_rect.x = mixer->width; + req.src_rect.w = fbi->var.xres - mixer->width; + } else { + req.src_rect.x = 0; + req.src_rect.w = MIN(fbi->var.xres, + mixer->width); + } - pr_debug("allocating base pipe mux=%d\n", mixer_mux); + req.src_rect.y = 0; + req.src_rect.h = req.src.height; + req.dst_rect = req.src_rect; + req.z_order = MDSS_MDP_STAGE_BASE; - ret = mdss_mdp_overlay_pipe_setup(mfd, &req, &pipe, - NULL); - if (ret) - return ret; - } else { - if (mixer_mux == MDSS_MDP_MIXER_MUX_RIGHT) { - req_ov->id = MSMFB_NEW_REQUEST; - req_ov->src_rect.w = MIN(mixer->width, - req_ov->src_rect.w >> 1); - req_ov->dst_rect.w = req_ov->src_rect.w; - req_ov->src_rect.x = req_ov->src_rect.w; - /* - * following dst_x assigment will have two - * different outcomes depending on the chipset's - * source split capability. If non-src-split - * chip-set then left mixer width will be - * deducted from dst_x later on inside - * mdss_mdp_ov_xres_check function. - */ - req_ov->dst_rect.x = mixer->width; - } + pr_debug("allocating base pipe mux=%d\n", mixer_mux); - ret = mdss_mdp_overlay_pipe_setup(mfd, req_ov, &pipe, - NULL); - if (ret) - return ret; - } + ret = mdss_mdp_overlay_pipe_setup(mfd, &req, &pipe, NULL); + if (ret) + return ret; } - pr_debug("ctl=%d pnum=%d\n", mdp5_data->ctl->num, pipe->num); *ppipe = pipe; return 0; } -static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd, - struct mdp_overlay *req, - int image_size, - int *pipe_ndx) +static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd) { struct mdss_mdp_data *buf; struct mdss_mdp_pipe *pipe; @@ -1854,7 +1779,7 @@ static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd, } ret = mdss_mdp_overlay_get_fb_pipe(mfd, &pipe, - MDSS_MDP_MIXER_MUX_LEFT, req); + MDSS_MDP_MIXER_MUX_LEFT); if (ret) { pr_err("unable to allocate base pipe\n"); goto pan_display_error; @@ -1864,15 +1789,13 @@ static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd, pr_err("unable to map base pipe\n"); goto pan_display_error; } - if (pipe_ndx) - pipe_ndx[0] = pipe->ndx; buf = &pipe->back_buf; if (is_mdss_iommu_attached()) { if (!mfd->iova) { pr_err("mfd iova is zero\n"); mdss_mdp_pipe_unmap(pipe); - goto attach_err; + goto pan_display_error; } buf->p[0].addr = mfd->iova; } else { @@ -1880,27 +1803,22 @@ static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd, } buf->p[0].addr += offset; - if (image_size) - buf->p[0].len = image_size; - else - buf->p[0].len = fbi->fix.smem_len - offset; + buf->p[0].len = fbi->fix.smem_len - offset; buf->num_planes = 1; pipe->has_buf = 1; mdss_mdp_pipe_unmap(pipe); if (fbi->var.xres > MAX_MIXER_WIDTH || mfd->split_display) { ret = mdss_mdp_overlay_get_fb_pipe(mfd, &pipe, - MDSS_MDP_MIXER_MUX_RIGHT, req); + MDSS_MDP_MIXER_MUX_RIGHT); if (ret) { pr_err("unable to allocate right base pipe\n"); - goto attach_err; + goto pan_display_error; } if (mdss_mdp_pipe_map(pipe)) { pr_err("unable to map right base pipe\n"); - goto attach_err; + goto pan_display_error; } - if (pipe_ndx) - pipe_ndx[1] = pipe->ndx; pipe->back_buf = *buf; pipe->has_buf = 1; @@ -1915,13 +1833,6 @@ static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd, mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); return; -attach_err: - mutex_unlock(&mdp5_data->ov_lock); - mdss_mdp_overlay_unset(mfd, pipe->ndx); - if (pipe_ndx) - pipe_ndx[0] = INVALID_PIPE_INDEX; - mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); - return; pan_display_error: mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); mutex_unlock(&mdp5_data->ov_lock); @@ -3380,9 +3291,9 @@ static int mdss_mdp_overlay_handoff(struct msm_fb_data_type *mfd) error: if (rc && ctl) { - __mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_RGB); - __mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_VIG); - __mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_DMA); + mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_RGB); + mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_VIG); + mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_DMA); mdss_mdp_ctl_destroy(ctl); mdp5_data->ctl = NULL; mdp5_data->handoff = false; @@ -3391,74 +3302,6 @@ error: return rc; } -static int mdss_mdp_overlay_splash_image(struct msm_fb_data_type *mfd, - int *pipe_ndx, int splash_event) -{ - struct mdp_overlay req; - int rc = 0; - struct fb_info *fbi = NULL; - int image_len = 0; - - if (!mfd || !mfd->fbi || !pipe_ndx) { - pr_err("Invalid input parameter\n"); - return -EINVAL; - } - /* - * Allocate fb memory here for splash screen to display. - * It gets removed once the splash screen thread stops. - */ - if (!mfd->fbi->screen_base) { - rc = mdss_fb_alloc_fb_ion_memory(mfd); - if (rc < 0) { - pr_err("Invalid input parameter\n"); - return -EINVAL; - } - } - - fbi = mfd->fbi; - image_len = SPLASH_IMAGE_WIDTH * SPLASH_IMAGE_HEIGHT * SPLASH_IMAGE_BPP; - - if (SPLASH_IMAGE_WIDTH > fbi->var.xres || - SPLASH_IMAGE_HEIGHT > fbi->var.yres || - SPLASH_IMAGE_BPP > fbi->var.bits_per_pixel / 8 || - image_len > fbi->fix.smem_len) { - pr_err("Invalid splash parameter configuration\n"); - return -EINVAL; - } - - if (splash_event == MDP_CREATE_SPLASH_OV) { - pipe_ndx[0] = INVALID_PIPE_INDEX; - pipe_ndx[1] = INVALID_PIPE_INDEX; - - memset(&req, 0, sizeof(struct mdp_overlay)); - req.src.width = req.dst_rect.w = req.src_rect.w = - SPLASH_IMAGE_WIDTH; - req.src.height = req.dst_rect.h = req.src_rect.h = - SPLASH_IMAGE_HEIGHT; - req.src.format = SPLASH_IMAGE_FORMAT; - req.id = MSMFB_NEW_REQUEST; - req.z_order = MDSS_MDP_STAGE_0; - req.is_fg = 1; - req.alpha = 0xff; - req.transp_mask = MDP_TRANSP_NOP; - req.dst_rect.x = - (fbi->var.xres >> 1) - (SPLASH_IMAGE_WIDTH >> 1); - req.dst_rect.y = - (fbi->var.yres >> 1) - (SPLASH_IMAGE_HEIGHT >> 1); - - memcpy(fbi->screen_base, splash_bgr888_image, image_len); - mdss_mdp_overlay_pan_display(mfd, &req, image_len, pipe_ndx); - - } else if (splash_event == MDP_REMOVE_SPLASH_OV) { - if (pipe_ndx[0] != INVALID_PIPE_INDEX) - mdss_mdp_overlay_unset(mfd, pipe_ndx[0]); - if (pipe_ndx[1] != INVALID_PIPE_INDEX) - mdss_mdp_overlay_unset(mfd, pipe_ndx[1]); - } - - return rc; -} - static void __vsync_retire_handle_vsync(struct mdss_mdp_ctl *ctl, ktime_t t) { struct msm_fb_data_type *mfd = ctl->mfd; @@ -3577,7 +3420,7 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd) mdp5_interface->panel_register_done = mdss_panel_register_done; mdp5_interface->kickoff_fnc = mdss_mdp_overlay_kickoff; mdp5_interface->get_sync_fnc = mdss_mdp_rotator_sync_pt_get; - mdp5_interface->splash_fnc = mdss_mdp_overlay_splash_image; + mdp5_interface->splash_init_fnc = mdss_mdp_splash_init; mdp5_data = kzalloc(sizeof(struct mdss_overlay_private), GFP_KERNEL); if (!mdp5_data) { @@ -3677,45 +3520,6 @@ init_fail: return rc; } -static __ref int mdss_mdp_overlay_splash_parse_dt(struct msm_fb_data_type *mfd) -{ - struct platform_device *pdev = mfd->pdev; - struct mdss_overlay_private *mdp5_mdata = mfd_to_mdp5_data(mfd); - int len = 0, rc = 0; - u32 offsets[2]; - - of_find_property(pdev->dev.of_node, "qcom,memblock-reserve", &len); - - if (len < 1) { - pr_debug("mem reservation for splash screen fb not present\n"); - rc = -EINVAL; - goto error; - } - - len = len/sizeof(u32); - - rc = of_property_read_u32_array(pdev->dev.of_node, - "qcom,memblock-reserve", offsets, len); - if (rc) { - pr_debug("Error reading mem reserve settings for fb\n"); - goto error; - } - - if (!memblock_is_reserved(offsets[0])) { - pr_debug("failed to reserve memory for fb splash\n"); - rc = -EINVAL; - goto error; - } - - mdp5_mdata->splash_mem_addr = offsets[0]; - mdp5_mdata->splash_mem_size = offsets[1]; - pr_debug("memaddr=%x size=%x\n", mdp5_mdata->splash_mem_addr, - mdp5_mdata->splash_mem_size); - -error: - return rc; -} - static int mdss_mdp_overlay_fb_parse_dt(struct msm_fb_data_type *mfd) { int rc = 0; @@ -3729,13 +3533,5 @@ static int mdss_mdp_overlay_fb_parse_dt(struct msm_fb_data_type *mfd) pdev->name); } - rc = mdss_mdp_overlay_splash_parse_dt(mfd); - if (rc && mfd->panel_info->cont_splash_enabled) { - pr_err("No rsvd mem found in DT for splash screen\n"); - } else { - pr_debug("Mem reservation not reqd if cont splash diasbled\n"); - rc = 0; - } - return rc; } diff --git a/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c b/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c new file mode 100644 index 000000000000..d003ba07c50e --- /dev/null +++ b/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c @@ -0,0 +1,630 @@ +/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/kthread.h> +#include <linux/memblock.h> +#include <linux/bootmem.h> +#include <linux/iommu.h> +#include <linux/fb.h> + +#include "mdss_fb.h" +#include "mdss_mdp.h" +#include "splash.h" +#include "mdss_mdp_splash_logo.h" + +#define INVALID_PIPE_INDEX 0xFFFF +#define MAX_FRAME_DONE_COUNT_WAIT 2 + +static int mdss_mdp_splash_alloc_memory(struct msm_fb_data_type *mfd, + uint32_t size) +{ + int rc; + struct msm_fb_splash_info *sinfo; + unsigned long buf_size = size; + struct mdss_data_type *mdata; + + if (!mfd || !size) + return -EINVAL; + + mdata = mfd_to_mdata(mfd); + sinfo = &mfd->splash_info; + + if (!mdata || !mdata->iclient || sinfo->splash_buffer) + return -EINVAL; + + sinfo->ion_handle = ion_alloc(mdata->iclient, size, SZ_4K, + ION_HEAP(ION_SYSTEM_HEAP_ID), 0); + if (IS_ERR_OR_NULL(sinfo->ion_handle)) { + pr_err("ion memory allocation failed\n"); + rc = PTR_RET(sinfo->ion_handle); + goto end; + } + + rc = ion_map_iommu(mdata->iclient, sinfo->ion_handle, + mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE), + 0, SZ_4K, 0, &sinfo->iova, &buf_size, 0, 0); + if (rc) { + pr_err("ion memory map failed\n"); + goto imap_err; + } + + sinfo->splash_buffer = ion_map_kernel(mdata->iclient, + sinfo->ion_handle); + if (IS_ERR_OR_NULL(sinfo->splash_buffer)) { + pr_err("ion kernel memory mapping failed\n"); + rc = IS_ERR(sinfo->splash_buffer); + goto kmap_err; + } + + return rc; + +kmap_err: + ion_unmap_iommu(mdata->iclient, sinfo->ion_handle, + mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE), 0); +imap_err: + ion_free(mdata->iclient, sinfo->ion_handle); +end: + return rc; +} + +static void mdss_mdp_splash_free_memory(struct msm_fb_data_type *mfd) +{ + struct msm_fb_splash_info *sinfo; + struct mdss_data_type *mdata; + + if (!mfd) + return; + + sinfo = &mfd->splash_info; + mdata = mfd_to_mdata(mfd); + + if (!mdata || !mdata->iclient || !sinfo->ion_handle) + return; + + ion_unmap_kernel(mdata->iclient, sinfo->ion_handle); + + ion_unmap_iommu(mdata->iclient, sinfo->ion_handle, + mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE), 0); + + ion_free(mdata->iclient, sinfo->ion_handle); + sinfo->splash_buffer = NULL; +} + +static int mdss_mdp_splash_iommu_attach(struct msm_fb_data_type *mfd) +{ + struct iommu_domain *domain; + struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); + int rc; + + /* + * iommu dynamic attach for following conditions. + * 1. it is still not attached + * 2. MDP hardware version supports the feature + * 3. configuration is with valid splash buffer + */ + if (is_mdss_iommu_attached() || + !mfd->panel_info->cont_splash_enabled || + !mdss_mdp_iommu_dyn_attach_supported(mdp5_data->mdata) || + !mdp5_data->splash_mem_addr || + !mdp5_data->splash_mem_size) { + pr_debug("dynamic attach is not supported\n"); + return -EPERM; + } + + domain = msm_get_iommu_domain(mdss_get_iommu_domain( + MDSS_IOMMU_DOMAIN_UNSECURE)); + if (!domain) { + pr_debug("mdss iommu domain get failed\n"); + return -EINVAL; + } + + rc = iommu_map(domain, mdp5_data->splash_mem_addr, + mdp5_data->splash_mem_addr, + mdp5_data->splash_mem_size, IOMMU_READ); + if (rc) { + pr_debug("iommu memory mapping failed rc=%d\n", rc); + } else { + rc = mdss_iommu_attach(mdss_res); + if (rc) { + pr_debug("mdss iommu attach failed\n"); + iommu_unmap(domain, mdp5_data->splash_mem_addr, + mdp5_data->splash_mem_size); + } else { + mfd->splash_info.iommu_dynamic_attached = true; + } + } + + return rc; +} + +static void mdss_mdp_splash_unmap_splash_mem(struct msm_fb_data_type *mfd) +{ + struct iommu_domain *domain; + struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); + + if (mfd->splash_info.iommu_dynamic_attached) { + domain = msm_get_iommu_domain(mdss_get_iommu_domain( + MDSS_IOMMU_DOMAIN_UNSECURE)); + if (!domain) { + pr_err("mdss iommu domain get failed\n"); + return; + } + + iommu_unmap(domain, mdp5_data->splash_mem_addr, + mdp5_data->splash_mem_size); + mfd->splash_info.iommu_dynamic_attached = false; + } +} + +void mdss_mdp_release_splash_pipe(struct msm_fb_data_type *mfd) +{ + struct msm_fb_splash_info *sinfo; + + if (!mfd || !mfd->splash_info.splash_pipe_allocated) + return; + + sinfo = &mfd->splash_info; + + if (sinfo->pipe_ndx[0] != INVALID_PIPE_INDEX) + mdss_mdp_overlay_release(mfd, sinfo->pipe_ndx[0]); + if (sinfo->pipe_ndx[1] != INVALID_PIPE_INDEX) + mdss_mdp_overlay_release(mfd, sinfo->pipe_ndx[1]); + sinfo->splash_pipe_allocated = false; +} + +int mdss_mdp_splash_cleanup(struct msm_fb_data_type *mfd, + bool use_borderfill) +{ + struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); + struct mdss_mdp_ctl *ctl = mdp5_data->ctl; + int rc = 0; + + if (!mfd || !mdp5_data) + return -EINVAL; + + if (mfd->splash_info.iommu_dynamic_attached || + !mfd->panel_info->cont_splash_enabled) + goto end; + + if (use_borderfill && mdp5_data->handoff) { + /* + * Set up border-fill on the handed off pipes. + * This is needed to ensure that there are no memory + * accesses prior to attaching iommu during continuous + * splash screen case. However, for command mode + * displays, this is not necessary since the panels can + * refresh from their internal memory if no data is sent + * out on the dsi lanes. + */ + if (mdp5_data->handoff && ctl && ctl->is_video_mode) { + rc = mdss_mdp_display_commit(ctl, NULL); + if (!IS_ERR_VALUE(rc)) { + mdss_mdp_display_wait4comp(ctl); + } else { + /* + * Since border-fill setup failed, we + * need to ensure that we turn off the + * MDP timing generator before attaching + * iommu + */ + pr_err("failed to set BF at handoff\n"); + mdp5_data->handoff = false; + } + } + } + + if (rc || mdp5_data->handoff) { + /* Add all the handed off pipes to the cleanup list */ + mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_RGB); + mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_VIG); + mdss_mdp_handoff_cleanup_pipes(mfd, MDSS_MDP_PIPE_TYPE_DMA); + } + + mdss_mdp_ctl_splash_finish(ctl, mdp5_data->handoff); + + if (mdp5_data->splash_mem_addr) { + /* Give back the reserved memory to the system */ + memblock_free(mdp5_data->splash_mem_addr, + mdp5_data->splash_mem_size); + free_bootmem_late(mdp5_data->splash_mem_addr, + mdp5_data->splash_mem_size); + } + + mdss_mdp_footswitch_ctrl_splash(0); + if (!is_mdss_iommu_attached()) { + rc = mdss_iommu_attach(mdss_res); + if (rc) + pr_err("iommu attach failed rc=%d\n", rc); + } + +end: + return rc; +} + +static struct mdss_mdp_pipe *mdss_mdp_splash_get_pipe( + struct msm_fb_data_type *mfd, + struct mdp_overlay *req) +{ + struct mdss_mdp_pipe *pipe; + int ret; + struct mdss_mdp_data *buf; + uint32_t image_size = SPLASH_IMAGE_WIDTH * SPLASH_IMAGE_HEIGHT + * SPLASH_IMAGE_BPP; + + ret = mdss_mdp_overlay_pipe_setup(mfd, req, &pipe, NULL); + if (ret) + return NULL; + + if (mdss_mdp_pipe_map(pipe)) { + pr_err("unable to map base pipe\n"); + return NULL; + } + + buf = &pipe->back_buf; + buf->p[0].addr = mfd->splash_info.iova; + buf->p[0].len = image_size; + buf->num_planes = 1; + pipe->has_buf = 1; + mdss_mdp_pipe_unmap(pipe); + + return pipe; +} + +static int mdss_mdp_splash_kickoff(struct msm_fb_data_type *mfd, + struct mdss_mdp_img_rect *src_rect, + struct mdss_mdp_img_rect *dest_rect) +{ + struct mdss_mdp_pipe *pipe; + struct fb_info *fbi; + struct mdp_overlay req; + struct mdss_overlay_private *mdp5_data; + struct mdss_data_type *mdata; + struct mdss_mdp_mixer *mixer; + int ret; + bool use_single_pipe = false; + struct msm_fb_splash_info *sinfo; + + if (!mfd) + return -EINVAL; + + fbi = mfd->fbi; + mdp5_data = mfd_to_mdp5_data(mfd); + mdata = mfd_to_mdata(mfd); + sinfo = &mfd->splash_info; + + if (!mdp5_data || !mdp5_data->ctl) + return -EINVAL; + + if (mutex_lock_interruptible(&mdp5_data->ov_lock)) + return -EINVAL; + + ret = mdss_mdp_overlay_start(mfd); + if (ret) { + pr_err("unable to start overlay %d (%d)\n", mfd->index, ret); + goto end; + } + + mixer = mdss_mdp_mixer_get(mdp5_data->ctl, MDSS_MDP_MIXER_MUX_LEFT); + if (!mixer) { + pr_err("unable to retrieve mixer\n"); + ret = -EINVAL; + goto end; + } + + memset(&req, 0, sizeof(struct mdp_overlay)); + /* + * use single pipe for + * 1. split display disabled + * 2. splash image is only on one side of panel + * 3. source split is enabled and splash image is within line + * buffer boundry + */ + use_single_pipe = + !mfd->split_display || + (mfd->split_display && + ((dest_rect->x + dest_rect->w) < mfd->split_fb_left || + dest_rect->x > mfd->split_fb_left)) || + (mdata->has_src_split && + src_rect->w < min_t(u16, mixer->width, + mdss_mdp_line_buffer_width()) && + dest_rect->w < min_t(u16, mixer->width, + mdss_mdp_line_buffer_width())); + + req.src.width = src_rect->w; + if (use_single_pipe) + req.src_rect.w = src_rect->w; + else + req.src_rect.w = min_t(u16, mixer->width, src_rect->w >> 1); + req.dst_rect.w = req.src_rect.w; + req.src.height = req.dst_rect.h = req.src_rect.h = + src_rect->h; + req.src.format = SPLASH_IMAGE_FORMAT; + req.id = MSMFB_NEW_REQUEST; + req.z_order = MDSS_MDP_STAGE_0; + req.alpha = 0xff; + req.transp_mask = MDP_TRANSP_NOP; + req.dst_rect.x = dest_rect->x; + req.dst_rect.y = dest_rect->y; + + pipe = mdss_mdp_splash_get_pipe(mfd, &req); + if (!pipe) { + pr_err("unable to allocate base pipe\n"); + ret = -EINVAL; + goto end; + } + + sinfo->pipe_ndx[0] = pipe->ndx; + + if (!use_single_pipe) { + req.id = MSMFB_NEW_REQUEST; + req.src_rect.x = src_rect->x + min_t(u16, mixer->width, + src_rect->w - req.src_rect.w); + req.dst_rect.x = mixer->width; + pipe = mdss_mdp_splash_get_pipe(mfd, &req); + if (!pipe) { + pr_err("unable to allocate right base pipe\n"); + mdss_mdp_overlay_release(mfd, sinfo->pipe_ndx[0]); + ret = -EINVAL; + goto end; + } + sinfo->pipe_ndx[1] = pipe->ndx; + } + mutex_unlock(&mdp5_data->ov_lock); + + ret = mfd->mdp.kickoff_fnc(mfd, NULL); + if (ret) { + pr_err("error in displaying image\n"); + mdss_mdp_overlay_release(mfd, sinfo->pipe_ndx[0] | + sinfo->pipe_ndx[1]); + } + + return ret; +end: + sinfo->pipe_ndx[0] = INVALID_PIPE_INDEX; + sinfo->pipe_ndx[1] = INVALID_PIPE_INDEX; + mutex_unlock(&mdp5_data->ov_lock); + return ret; +} + +static int mdss_mdp_display_splash_image(struct msm_fb_data_type *mfd) +{ + int rc = 0; + struct fb_info *fbi; + uint32_t image_len = SPLASH_IMAGE_WIDTH * SPLASH_IMAGE_HEIGHT + * SPLASH_IMAGE_BPP; + struct mdss_mdp_img_rect src_rect, dest_rect; + struct msm_fb_splash_info *sinfo; + + if (!mfd || !mfd->fbi) { + pr_err("invalid input parameter\n"); + rc = -EINVAL; + goto end; + } + + fbi = mfd->fbi; + sinfo = &mfd->splash_info; + + if (SPLASH_IMAGE_WIDTH > fbi->var.xres || + SPLASH_IMAGE_HEIGHT > fbi->var.yres || + SPLASH_IMAGE_BPP > (fbi->var.bits_per_pixel >> 3)) { + pr_err("invalid splash parameter configuration\n"); + rc = -EINVAL; + goto end; + } + + sinfo->pipe_ndx[0] = INVALID_PIPE_INDEX; + sinfo->pipe_ndx[1] = INVALID_PIPE_INDEX; + + src_rect.x = 0; + src_rect.y = 0; + dest_rect.w = src_rect.w = SPLASH_IMAGE_WIDTH; + dest_rect.h = src_rect.h = SPLASH_IMAGE_HEIGHT; + dest_rect.x = (fbi->var.xres >> 1) - (SPLASH_IMAGE_WIDTH >> 1); + dest_rect.y = (fbi->var.yres >> 1) - (SPLASH_IMAGE_HEIGHT >> 1); + + rc = mdss_mdp_splash_alloc_memory(mfd, image_len); + if (rc) { + pr_err("splash buffer allocation failed\n"); + goto end; + } + + memcpy(sinfo->splash_buffer, splash_bgr888_image, image_len); + + rc = mdss_mdp_splash_iommu_attach(mfd); + if (rc) + pr_debug("iommu dynamic attach failed\n"); + + rc = mdss_mdp_splash_kickoff(mfd, &src_rect, &dest_rect); + if (rc) + pr_err("splash image display failed\n"); + else + sinfo->splash_pipe_allocated = true; +end: + return rc; +} + +static int mdss_mdp_splash_ctl_cb(struct notifier_block *self, + unsigned long event, void *data) +{ + struct msm_fb_splash_info *sinfo = container_of(self, + struct msm_fb_splash_info, notifier); + struct msm_fb_data_type *mfd; + + if (!sinfo) + goto done; + + mfd = container_of(sinfo, struct msm_fb_data_type, splash_info); + + if (!mfd) + goto done; + + if (event != MDP_NOTIFY_FRAME_DONE) + goto done; + + if (!sinfo->frame_done_count) { + mdss_mdp_splash_unmap_splash_mem(mfd); + mdss_mdp_splash_cleanup(mfd, false); + /* wait for 2 frame done events before releasing memory */ + } else if (sinfo->frame_done_count > MAX_FRAME_DONE_COUNT_WAIT && + sinfo->splash_thread) { + complete(&sinfo->frame_done); + sinfo->splash_thread = NULL; + } + + /* increase frame done count after pipes are staged from other client */ + if (!sinfo->splash_pipe_allocated) + sinfo->frame_done_count++; +done: + return NOTIFY_OK; +} + +static int mdss_mdp_splash_thread(void *data) +{ + struct msm_fb_data_type *mfd = data; + struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); + int ret = -EINVAL; + + if (!mfd) { + pr_err("invalid input parameter\n"); + goto end; + } + + lock_fb_info(mfd->fbi); + ret = fb_blank(mfd->fbi, FB_BLANK_UNBLANK); + if (ret) { + pr_err("can't turn on fb!\n"); + goto end; + } + unlock_fb_info(mfd->fbi); + + mfd->bl_updated = true; + mutex_lock(&mfd->bl_lock); + mdss_fb_set_backlight(mfd, mfd->panel_info->bl_max >> 1); + mutex_unlock(&mfd->bl_lock); + + init_completion(&mfd->splash_info.frame_done); + + mfd->splash_info.notifier.notifier_call = mdss_mdp_splash_ctl_cb; + mdss_mdp_ctl_notifier_register(mdp5_data->ctl, + &mfd->splash_info.notifier); + + ret = mdss_mdp_display_splash_image(mfd); + if (ret) { + /* + * keep thread alive to release dynamically allocated + * resources + */ + pr_err("splash image display failed\n"); + } + + /* wait for second display complete to release splash resources */ + ret = wait_for_completion_killable(&mfd->splash_info.frame_done); + + mdss_mdp_splash_free_memory(mfd); + + mdss_mdp_ctl_notifier_unregister(mdp5_data->ctl, + &mfd->splash_info.notifier); +end: + return ret; +} + +static __ref int mdss_mdp_splash_parse_dt(struct msm_fb_data_type *mfd) +{ + struct platform_device *pdev = mfd->pdev; + struct mdss_overlay_private *mdp5_mdata = mfd_to_mdp5_data(mfd); + int len = 0, rc = 0; + u32 offsets[2]; + + mfd->splash_info.splash_logo_enabled = + of_property_read_bool(pdev->dev.of_node, + "qcom,mdss-fb-splash-logo-enabled"); + + of_find_property(pdev->dev.of_node, "qcom,memblock-reserve", &len); + if (len < 1) { + pr_debug("mem reservation for splash screen fb not present\n"); + rc = -EINVAL; + goto error; + } + + len = len / sizeof(u32); + + rc = of_property_read_u32_array(pdev->dev.of_node, + "qcom,memblock-reserve", offsets, len); + if (rc) { + pr_debug("error reading mem reserve settings for fb\n"); + goto error; + } + + if (!memblock_is_reserved(offsets[0])) { + pr_debug("failed to reserve memory for fb splash\n"); + rc = -EINVAL; + goto error; + } + + mdp5_mdata->splash_mem_addr = offsets[0]; + mdp5_mdata->splash_mem_size = offsets[1]; + pr_debug("memaddr=%x size=%x\n", mdp5_mdata->splash_mem_addr, + mdp5_mdata->splash_mem_size); + +error: + if (!rc && !mfd->panel_info->cont_splash_enabled && + mdp5_mdata->splash_mem_addr) { + pr_debug("mem reservation not reqd if cont splash disabled\n"); + memblock_free(mdp5_mdata->splash_mem_addr, + mdp5_mdata->splash_mem_size); + free_bootmem_late(mdp5_mdata->splash_mem_addr, + mdp5_mdata->splash_mem_size); + } else if (rc && mfd->panel_info->cont_splash_enabled) { + pr_err("no rsvd mem found in DT for splash screen\n"); + } else { + rc = 0; + } + + return rc; +} + +int mdss_mdp_splash_init(struct msm_fb_data_type *mfd) +{ + int rc; + + if (!mfd) { + rc = -EINVAL; + goto end; + } + + rc = mdss_mdp_splash_parse_dt(mfd); + if (rc) { + pr_err("splash memory reserve failed\n"); + goto end; + } + + if (!mfd->splash_info.splash_logo_enabled) { + rc = -EINVAL; + goto end; + } + + mfd->splash_info.splash_thread = kthread_run(mdss_mdp_splash_thread, + mfd, "mdss_fb_splash"); + + if (IS_ERR(mfd->splash_info.splash_thread)) { + pr_err("unable to start splash thread %d\n", mfd->index); + mfd->splash_info.splash_thread = NULL; + } + +end: + return rc; +} diff --git a/drivers/video/fbdev/msm/mdss_mdp_splash_logo.h b/drivers/video/fbdev/msm/mdss_mdp_splash_logo.h new file mode 100644 index 000000000000..0a4e83b13efb --- /dev/null +++ b/drivers/video/fbdev/msm/mdss_mdp_splash_logo.h @@ -0,0 +1,43 @@ +/* Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef MDSS_MDP_SPLASH_LOGO +#define MDSS_MDP_SPLASH_LOGO + +#include <linux/types.h> +#include <linux/notifier.h> +#include <linux/kthread.h> +#include <linux/completion.h> + +struct msm_fb_splash_info { + struct task_struct *splash_thread; + bool splash_logo_enabled; + bool iommu_dynamic_attached; + struct notifier_block notifier; + uint32_t frame_done_count; + struct completion frame_done; + + struct ion_handle *ion_handle; + dma_addr_t iova; + void *splash_buffer; + int pipe_ndx[2]; + bool splash_pipe_allocated; +}; + +struct msm_fb_data_type; + +void mdss_mdp_release_splash_pipe(struct msm_fb_data_type *mfd); +int mdss_mdp_splash_cleanup(struct msm_fb_data_type *mfd, + bool use_borderfill); +int mdss_mdp_splash_init(struct msm_fb_data_type *mfd); + +#endif diff --git a/drivers/video/fbdev/msm/mdss_qpic.c b/drivers/video/fbdev/msm/mdss_qpic.c index 0bcc3d068ce6..98ad50d9324b 100644 --- a/drivers/video/fbdev/msm/mdss_qpic.c +++ b/drivers/video/fbdev/msm/mdss_qpic.c @@ -96,8 +96,7 @@ static int msm_qpic_bus_set_vote(u32 vote) return ret; } -static void mdss_qpic_pan_display(struct msm_fb_data_type *mfd, - struct mdp_overlay *req, int image_len, int *pipe_ndx) +static void mdss_qpic_pan_display(struct msm_fb_data_type *mfd) { struct fb_info *fbi; |
