msm: mdss: Display splash screen during boot up

It is required to display the splash screen as soon
as fb driver is probed. This shows the device life
at early stage before boot animation rendered by
surface flinger. Current implementation shows the
splash screen only when continuous splash is disabled.

Change-Id: Ib1e049c9ae82a621cc709339414096b954d79a09
Signed-off-by: Dhaval Patel <pdhaval@codeaurora.org>
This commit is contained in:
Dhaval Patel 2013-12-11 21:18:06 -08:00
parent 446a396c4a
commit f98a9339ca
5 changed files with 5500 additions and 47 deletions

View file

@ -28,7 +28,10 @@
#define MDP_CORE_CLK_RATE 100000000
#define VSYNC_EXPIRE_TICK 4
static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd);
static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd,
struct mdp_overlay *req,
int image_size,
int *pipe_ndx);
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);
@ -1004,7 +1007,10 @@ static int mdp3_ctrl_display_commit_kickoff(struct msm_fb_data_type *mfd,
return rc;
}
static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd)
static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd,
struct mdp_overlay *req,
int image_size,
int *pipe_ndx)
{
struct fb_info *fbi;
struct mdp3_session_data *mdp3_session;

View file

@ -147,6 +147,47 @@ 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,
@ -405,6 +446,16 @@ static int mdss_fb_probe(struct platform_device *pdev)
else
mfd->mdp_sync_pt_data.threshold = 2;
if (mfd->index == 0) {
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;
}
}
return rc;
}
@ -1212,6 +1263,12 @@ 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;
}
return 0;
blank_error:
@ -1591,7 +1648,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);
mfd->mdp.dma_fnc(mfd, NULL, 0, NULL);
else
pr_warn("dma function not set for panel type=%d\n",
mfd->panel.type);

View file

@ -36,6 +36,8 @@
#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
@ -70,6 +72,11 @@ 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;
@ -113,7 +120,8 @@ 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);
void (*dma_fnc)(struct msm_fb_data_type *mfd, struct mdp_overlay *req,
int image_len, int *pipe_ndx);
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);
@ -122,6 +130,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);
struct msm_sync_pt_data *(*get_sync_fnc)(struct msm_fb_data_type *mfd,
const struct mdp_buf_sync *buf_sync);
void *private1;
@ -204,6 +213,8 @@ struct msm_fb_data_type {
wait_queue_head_t idle_wait_q;
bool shutdown_pending;
struct task_struct *splash_thread;
struct msm_fb_backup_type msm_fb_backup;
struct completion power_set_comp;
u32 is_power_setting;

View file

@ -34,6 +34,8 @@
#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) \
@ -44,6 +46,8 @@
#define MEM_PROTECT_SD_CTRL 0xF
#define INVALID_PIPE_INDEX 0xFFFF
struct sd_ctrl_req {
unsigned int enable;
} __attribute__ ((__packed__));
@ -1377,18 +1381,18 @@ 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)
int mixer_mux,
struct mdp_overlay *req_ov)
{
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdss_mdp_pipe *pipe;
int ret;
pipe = mdss_mdp_mixer_stage_pipe(mdp5_data->ctl, mixer_mux,
MDSS_MDP_STAGE_BASE);
if (pipe == NULL) {
struct mdp_overlay req;
struct fb_info *fbi = mfd->fbi;
struct mdss_mdp_mixer *mixer;
int ret, bpp;
mixer = mdss_mdp_mixer_get(mdp5_data->ctl,
MDSS_MDP_MIXER_MUX_LEFT);
@ -1397,49 +1401,73 @@ static int mdss_mdp_overlay_get_fb_pipe(struct msm_fb_data_type *mfd,
return -ENODEV;
}
memset(&req, 0, sizeof(req));
if (req_ov == NULL) {
struct mdp_overlay req;
struct fb_info *fbi = mfd->fbi;
int bpp;
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;
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.flags |= MDSS_MDP_RIGHT_MIXER;
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);
}
req.flags |= MDSS_MDP_RIGHT_MIXER;
req.src_rect.x = mixer->width;
req.src_rect.w = fbi->var.xres - mixer->width;
req.src_rect.y = 0;
req.src_rect.h = req.src.height;
req.dst_rect.x = 0;
req.dst_rect.y = 0;
req.dst_rect.w = req.src_rect.w;
req.dst_rect.h = req.src_rect.h;
req.z_order = MDSS_MDP_STAGE_BASE;
pr_debug("allocating base pipe mux=%d\n", mixer_mux);
ret = mdss_mdp_overlay_pipe_setup(mfd, &req, &pipe);
if (ret)
return ret;
} else {
req.src_rect.x = 0;
req.src_rect.w = MIN(fbi->var.xres, mixer->width);
if (mixer_mux == MDSS_MDP_MIXER_MUX_RIGHT) {
req_ov->id = MSMFB_NEW_REQUEST;
req_ov->flags |= MDSS_MDP_RIGHT_MIXER;
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;
req_ov->dst_rect.x = 0;
}
ret = mdss_mdp_overlay_pipe_setup(mfd, req_ov, &pipe);
if (ret)
return ret;
}
req.src_rect.y = 0;
req.src_rect.h = req.src.height;
req.dst_rect.x = 0;
req.dst_rect.y = 0;
req.dst_rect.w = req.src_rect.w;
req.dst_rect.h = req.src_rect.h;
req.z_order = MDSS_MDP_STAGE_BASE;
pr_debug("allocating base pipe mux=%d\n", mixer_mux);
ret = mdss_mdp_overlay_pipe_setup(mfd, &req, &pipe);
if (ret)
return ret;
pr_debug("ctl=%d pnum=%d\n", mdp5_data->ctl->num, pipe->num);
}
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)
static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd,
struct mdp_overlay *req,
int image_size,
int *pipe_ndx)
{
struct mdss_mdp_data *buf;
struct mdss_mdp_pipe *pipe;
@ -1487,8 +1515,8 @@ static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd)
goto pan_display_error;
}
ret = mdss_mdp_overlay_get_fb_pipe(mfd, &pipe, MDSS_MDP_MIXER_MUX_LEFT);
ret = mdss_mdp_overlay_get_fb_pipe(mfd, &pipe,
MDSS_MDP_MIXER_MUX_LEFT, req);
if (ret) {
pr_err("unable to allocate base pipe\n");
goto pan_display_error;
@ -1498,12 +1526,14 @@ 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");
goto pan_display_error;
goto attach_err;
}
buf->p[0].addr = mfd->iova;
} else {
@ -1511,22 +1541,28 @@ static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd)
}
buf->p[0].addr += offset;
buf->p[0].len = fbi->fix.smem_len - offset;
if (image_size)
buf->p[0].len = image_size;
else
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);
MDSS_MDP_MIXER_MUX_RIGHT, req);
if (ret) {
pr_err("unable to allocate right base pipe\n");
goto pan_display_error;
goto attach_err;
}
if (mdss_mdp_pipe_map(pipe)) {
pr_err("unable to map right base pipe\n");
goto pan_display_error;
goto attach_err;
}
if (pipe_ndx)
pipe_ndx[1] = pipe->ndx;
pipe->back_buf = *buf;
pipe->has_buf = 1;
mdss_mdp_pipe_unmap(pipe);
@ -1539,6 +1575,12 @@ static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd)
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;
return;
pan_display_error:
mutex_unlock(&mdp5_data->ov_lock);
}
@ -2666,6 +2708,63 @@ 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 || !mfd->fbi->screen_base || !pipe_ndx) {
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;
}
int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
{
struct device *dev = mfd->fbi->dev;
@ -2683,6 +2782,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_data = kmalloc(sizeof(struct mdss_overlay_private), GFP_KERNEL);
if (!mdp5_data) {

File diff suppressed because it is too large Load diff