上下电代码位于mdss_fb.c中。在mdss_fb_register()函数中会设置fb用户空间操作函数:
fbi->fbops = &mdss_fb_ops;
static struct fb_ops mdss_fb_ops = {
.owner = THIS_MODULE,
.fb_open = mdss_fb_open,
.fb_release = mdss_fb_release,
.fb_check_var = mdss_fb_check_var, /* vinfo check */
.fb_set_par = mdss_fb_set_par, /* set the video mode */
.fb_blank = mdss_fb_blank, /* blank display */
.fb_pan_display = mdss_fb_pan_display, /* pan display */
.fb_ioctl_v2 = mdss_fb_ioctl, /* perform fb specific ioctl */
#ifdef CONFIG_COMPAT
.fb_compat_ioctl_v2 = mdss_fb_compat_ioctl,
#endif
.fb_mmap = mdss_fb_mmap,
};
用户空间通过mdss_fb_blank()函数来设置屏的亮灭。
static int mdss_fb_blank(int blank_mode, struct fb_info *info)
{
int ret;
struct mdss_panel_data *pdata;
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
ret = mdss_fb_pan_idle(mfd);
if (ret) {
pr_warn("mdss_fb_pan_idle for fb%d failed. ret=%d
",
mfd->index, ret);
return ret;
}
// 注册成功后,op_enable = true
if (mfd->op_enable == 0) {
if (blank_mode == FB_BLANK_UNBLANK)
mfd->suspend.panel_power_state = MDSS_PANEL_POWER_ON;
else if (blank_mode == BLANK_FLAG_ULP)
mfd->suspend.panel_power_state = MDSS_PANEL_POWER_LP2;
else if (blank_mode == BLANK_FLAG_LP)
mfd->suspend.panel_power_state = MDSS_PANEL_POWER_LP1;
else
mfd->suspend.panel_power_state = MDSS_PANEL_POWER_OFF;
return 0;
}
pr_debug("mode: %d
", blank_mode);
pdata = dev_get_platdata(&mfd->pdev->dev);
if (pdata->panel_info.is_lpm_mode &&
blank_mode == FB_BLANK_UNBLANK) {
pr_debug("panel is in lpm mode
");
mfd->mdp.configure_panel(mfd, 0, 1);
mdss_fb_set_mdp_sync_pt_threshold(mfd, mfd->panel.type);
pdata->panel_info.is_lpm_mode = false;
}
return mdss_fb_blank_sub(blank_mode, info, mfd->op_enable);
}
最后调用函数mdss_fb_blank_sub()实现。
static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info, int op_enable)
blank_mode这个参数的值主要有两个,FB_BLANK_UNBLANK和 FB_BLANK_POWERDOWN:
- FB_BLANK_UNBLANK 是亮屏操作;
- FB_BLANK_POWERDOWN 是灭屏操作;
当亮屏时,传入参数FB_BLANK_UNBLANK,函数调用过程:
static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info, int op_enable)
{
switch (blank_mode) {
case FB_BLANK_UNBLANK:
pr_debug("unblank called. cur pwr state=%d
", cur_power_state);
ret = mdss_fb_blank_unblank(mfd);
break;
case FB_BLANK_HSYNC_SUSPEND:
case FB_BLANK_POWERDOWN:
default:
req_power_state = MDSS_PANEL_POWER_OFF;
pr_debug("blank powerdown called
");
ret = mdss_fb_blank_blank(mfd, req_power_state);
break;
}
}
查看mdss_fb_blank_unblank()的实现:
static int mdss_fb_blank_unblank(struct msm_fb_data_type *mfd)
{
/* Start Display thread 开一个线程处理什么,不懂 */
if (mfd->disp_thread == NULL) {
ret = mdss_fb_start_disp_thread(mfd);
if (IS_ERR_VALUE(ret))
return ret;
}
if (mfd->mdp.on_fnc) {
struct mdss_panel_info *panel_info = mfd->panel_info;
struct fb_var_screeninfo *var = &mfd->fbi->var;
/* 调用mdp.on_fnc回调函数 */
ret = mfd->mdp.on_fnc(mfd);
if (ret) {
mdss_fb_stop_disp_thread(mfd);
goto error;
}
mfd->panel_power_state = MDSS_PANEL_POWER_ON;
mfd->panel_info->panel_dead = false;
mutex_lock(&mfd->update.lock);
mfd->update.type = NOTIFY_TYPE_UPDATE;
mfd->update.is_suspend = 0;
mutex_unlock(&mfd->update.lock);
/*
* Panel info can change depending in the information
* programmed in the controller.
* Update this info in the upstream structs.
*/
mdss_panelinfo_to_fb_var(panel_info, var);
/* Start the work thread to signal idle time */
if (mfd->idle_time)
schedule_delayed_work(&mfd->idle_notify_work,
msecs_to_jiffies(mfd->idle_time));
}
}
亮屏过程,将调用mfd->mdp.on_fnc()回调函数,这个回调在mdp3_ctrl_init()函数中指定为mdp3_ctrl_on()。
@mdp3_ctrl.c
static int mdp3_ctrl_on(struct msm_fb_data_type *mfd)
{
int rc = 0;
struct mdp3_session_data *mdp3_session;
struct mdss_panel_data *panel;
if (panel->event_handler) {
rc = panel->event_handler(panel, MDSS_EVENT_LINK_READY, NULL);
rc |= panel->event_handler(panel, MDSS_EVENT_UNBLANK, NULL);
rc |= panel->event_handler(panel, MDSS_EVENT_PANEL_ON, NULL);
if (panel->panel_info.type == MIPI_CMD_PANEL) {
struct dsi_panel_clk_ctrl clk_ctrl;
clk_ctrl.state = MDSS_DSI_CLK_ON;
clk_ctrl.client = DSI_CLK_REQ_MDP_CLIENT;
rc |= panel->event_handler(panel,
MDSS_EVENT_PANEL_CLK_CTRL,
(void *)&clk_ctrl);
}
}
}
在mdp3_ctrl_on()中,调用panel->event_handler来处理亮屏的各个事件,包括:
1、MDSS_EVENT_LINK_READY
2、MDSS_EVENT_UNBLANK
3、MDSS_EVENT_PANEL_ON
4、MDSS_EVENT_PANEL_CLK_CTRL
接下来看panel->event_handler对这些事件的处理过程。
panel->event_handler在mdss_dsi.c中指向mdss_dsi_event_handler()函数。
首先处理MDSS_EVENT_LINK_READY事件:
static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
int event, void *arg)
{
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
switch (event) {
case MDSS_EVENT_CHECK_PARAMS:
pr_debug("%s:Entered Case MDSS_EVENT_CHECK_PARAMS
", __func__);
if (mdss_dsi_check_params(ctrl_pdata, arg)) {
ctrl_pdata->update_phy_timing = true;
/*
* Call to MDSS_EVENT_CHECK_PARAMS expects
* the return value of 1, if there is a change
* in panel timing parameters.
*/
rc = 1;
}
ctrl_pdata->refresh_clk_rate = true;
break;
case MDSS_EVENT_LINK_READY:
if (ctrl_pdata->refresh_clk_rate)
rc = mdss_dsi_clk_refresh(pdata,
ctrl_pdata->update_phy_timing);
mdss_dsi_get_hw_revision(ctrl_pdata);
mdss_dsi_get_phy_revision(ctrl_pdata);
rc = mdss_dsi_on(pdata);
mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode,
pdata);
break;
case MDSS_EVENT_UNBLANK:
if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE)
rc = mdss_dsi_unblank(pdata);
break;
case MDSS_EVENT_POST_PANEL_ON:
rc = mdss_dsi_post_panel_on(pdata);
break;
case MDSS_EVENT_PANEL_ON:
ctrl_pdata->ctrl_state |= CTRL_STATE_MDP_ACTIVE;
if (ctrl_pdata->on_cmds.link_state == DSI_HS_MODE)
rc = mdss_dsi_unblank(pdata);
pdata->panel_info.esd_rdy = true;
break;
}
}
在处理ready事件时,主要调用 mdss_dsi_on(pdata)函数。
int mdss_dsi_on(struct mdss_panel_data *pdata)
ret = mdss_dsi_panel_power_ctrl(pdata, MDSS_PANEL_POWER_ON);
mdss_dsi_panel_power_on(pdata);
static int mdss_dsi_panel_power_on(struct mdss_panel_data *pdata)
{
int ret = 0;
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
printk("~~~mdss_dsi_panel_power_on
");
if (pdata == NULL) {
pr_err("%s: Invalid input data
", __func__);
return -EINVAL;
}
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
ret = msm_dss_enable_vreg(
ctrl_pdata->panel_power_data.vreg_config,
ctrl_pdata->panel_power_data.num_vreg, 1);
if (ret) {
pr_err("%s: failed to enable vregs for %s
",
__func__, __mdss_dsi_pm_name(DSI_PANEL_PM));
return ret;
}
/*
* If continuous splash screen feature is enabled, then we need to
* request all the GPIOs that have already been configured in the
* bootloader. This needs to be done irresepective of whether
* the lp11_init flag is set or not.
*/
if (pdata->panel_info.cont_splash_enabled ||
!pdata->panel_info.mipi.lp11_init) {
if (mdss_dsi_pinctrl_set_state(ctrl_pdata, true))
pr_debug("reset enable: pinctrl not enabled
");
ret = mdss_dsi_panel_reset(pdata, 1);
if (ret)
pr_err("%s: Panel reset failed. rc=%d
",
__func__, ret);
}
return ret;
}
在处理MDSS_EVENT_UNBLANK事件时,主要调用mdss_dsi_unblank()函数。
@mdss_dsi.c
static int mdss_dsi_unblank(struct mdss_panel_data *pdata)
{
int ret = 0;
struct mipi_panel_info *mipi;
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data);
if (!(ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT)) {
if (!pdata->panel_info.dynamic_switch_pending) {
ATRACE_BEGIN("dsi_panel_on");
// 调用ctrl_pdata->on()回调函数
ret = ctrl_pdata->on(pdata);
if (ret) {
pr_err("%s: unable to initialize the panel
",
__func__);
goto error;
}
ATRACE_END("dsi_panel_on");
}
ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT;
}
}
ctrl_pdata->on指针指向mdss_dsi_panel_on()函数,在mdss_dsi_panel.c::mdss_dsi_panel_init()中定义:
static int mdss_dsi_panel_on(struct mdss_panel_data *pdata)
{
struct mdss_dsi_ctrl_pdata *ctrl = NULL;
struct mdss_panel_info *pinfo;
struct dsi_panel_cmds *on_cmds;
pinfo = &pdata->panel_info;
ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
on_cmds = &ctrl->on_cmds;
// 发送上电指令
if (on_cmds->cmd_cnt)
mdss_dsi_panel_cmds_send(ctrl, on_cmds, CMD_REQ_COMMIT);
}