diff --git a/drivers/video/fbdev/msm/Makefile b/drivers/video/fbdev/msm/Makefile index 78a9e625b63d..264c0d7278f6 100644 --- a/drivers/video/fbdev/msm/Makefile +++ b/drivers/video/fbdev/msm/Makefile @@ -33,6 +33,7 @@ mdss-dsi-objs := mdss_dsi.o mdss_dsi_host.o mdss_dsi_cmd.o mdss_dsi_status.o mdss-dsi-objs += mdss_dsi_panel.o mdss-dsi-objs += msm_mdss_io_8974.o obj-$(CONFIG_FB_MSM_MDSS) += mdss-dsi.o +obj-$(CONFIG_FB_MSM_MDSS) += mdss_panel.o obj-$(CONFIG_FB_MSM_MDSS_EDP_PANEL) += mdss_edp.o obj-$(CONFIG_FB_MSM_MDSS_EDP_PANEL) += mdss_edp_aux.o diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index 771ee17e432c..4a0f323085db 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -1180,6 +1180,28 @@ int mdss_dsi_register_recovery_handler(struct mdss_dsi_ctrl_pdata *ctrl, return 0; } +static int mdss_dsi_clk_refresh(struct mdss_panel_data *pdata) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + int rc = 0; + + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + rc = mdss_dsi_clk_div_config(&pdata->panel_info, + pdata->panel_info.mipi.frame_rate); + if (rc) { + pr_err("%s: unable to initialize the clk dividers\n", + __func__); + return rc; + } + ctrl_pdata->refresh_clk_rate = false; + ctrl_pdata->pclk_rate = pdata->panel_info.mipi.dsi_pclk_rate; + ctrl_pdata->byte_clk_rate = pdata->panel_info.clk_rate / 8; + pr_debug("%s ctrl_pdata->byte_clk_rate=%d ctrl_pdata->pclk_rate=%d\n", + __func__, ctrl_pdata->byte_clk_rate, ctrl_pdata->pclk_rate); + return rc; +} + static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, int event, void *arg) { @@ -1198,12 +1220,19 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, MDSS_XLOG(event, arg, ctrl_pdata->ndx, 0x3333); switch (event) { + case MDSS_EVENT_CHECK_PARAMS: + pr_debug("%s:Entered Case MDSS_EVENT_CHECK_PARAMS\n", __func__); + ctrl_pdata->refresh_clk_rate = true; + break; case MDSS_EVENT_LINK_READY: rc = mdss_dsi_on(pdata); mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode, pdata); break; case MDSS_EVENT_UNBLANK: + if (ctrl_pdata->refresh_clk_rate) + rc = mdss_dsi_clk_refresh(pdata); + if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE) rc = mdss_dsi_unblank(pdata); break; diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index 550a5ff60c95..8878663d7722 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -342,6 +342,7 @@ struct mdss_dsi_ctrl_pdata { struct dsi_drv_cm_data shared_pdata; u32 pclk_rate; u32 byte_clk_rate; + bool refresh_clk_rate; /* flag to recalculate clk_rate */ struct dss_module_power power_data[DSI_MAX_PM]; u32 dsi_irq_mask; struct mdss_hw *dsi_hw; diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index 81f27d7fe04f..0ec25e5160b2 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -106,6 +106,8 @@ static int mdss_fb_pan_idle(struct msm_fb_data_type *mfd); static int mdss_fb_send_panel_event(struct msm_fb_data_type *mfd, int event, void *arg); static void mdss_fb_set_mdp_sync_pt_threshold(struct msm_fb_data_type *mfd); +static void mdss_panelinfo_to_fb_var(struct mdss_panel_info *pinfo, + struct fb_var_screeninfo *var); void mdss_fb_no_update_notify_timer_cb(unsigned long data) { struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data; @@ -1185,6 +1187,34 @@ static void mdss_fb_stop_disp_thread(struct msm_fb_data_type *mfd) mfd->disp_thread = NULL; } +static void mdss_panel_validate_debugfs_info(struct msm_fb_data_type *mfd) +{ + struct mdss_panel_info *panel_info = mfd->panel_info; + struct fb_info *fbi = mfd->fbi; + struct fb_var_screeninfo *var = &fbi->var; + struct mdss_panel_data *pdata = container_of(panel_info, + struct mdss_panel_data, panel_info); + + if (panel_info->debugfs_info->override_flag) { + if (mfd->mdp.off_fnc) { + mfd->panel_reconfig = true; + mfd->mdp.off_fnc(mfd); + mfd->panel_reconfig = false; + } + + pr_debug("Overriding panel_info with debugfs_info\n"); + panel_info->debugfs_info->override_flag = 0; + mdss_panel_debugfsinfo_to_panelinfo(panel_info); + if (is_panel_split(mfd) && pdata->next) + mdss_fb_validate_split(pdata->panel_info.xres, + pdata->next->panel_info.xres, mfd); + mdss_panelinfo_to_fb_var(panel_info, var); + if (mdss_fb_send_panel_event(mfd, MDSS_EVENT_CHECK_PARAMS, + panel_info)) + pr_err("Failed to send panel event CHECK_PARAMS\n"); + } +} + static int mdss_fb_unblank_sub(struct msm_fb_data_type *mfd) { int ret = 0; @@ -1193,6 +1223,9 @@ static int mdss_fb_unblank_sub(struct msm_fb_data_type *mfd) if (!mfd) return -EINVAL; + if (mfd->panel_info->debugfs_info) + mdss_panel_validate_debugfs_info(mfd); + /* Start Display thread */ if (mfd->disp_thread == NULL) { ret = mdss_fb_start_disp_thread(mfd); @@ -1995,6 +2028,7 @@ static int mdss_fb_register(struct msm_fb_data_type *mfd) return -EPERM; } + mdss_panel_debugfs_init(panel_info); pr_info("FrameBuffer[%d] %dx%d registered successfully!\n", mfd->index, fbi->var.xres, fbi->var.yres); @@ -2625,6 +2659,23 @@ static void mdss_fb_var_to_panelinfo(struct fb_var_screeninfo *var, pinfo->clk_rate = var->pixclock; } +static void mdss_panelinfo_to_fb_var(struct mdss_panel_info *pinfo, + struct fb_var_screeninfo *var) +{ + struct mdss_panel_data *pdata = container_of(pinfo, + struct mdss_panel_data, panel_info); + + var->xres = mdss_fb_get_panel_xres(&pdata->panel_info); + var->yres = pinfo->yres; + var->lower_margin = pinfo->lcdc.v_front_porch; + var->upper_margin = pinfo->lcdc.v_back_porch; + var->vsync_len = pinfo->lcdc.v_pulse_width; + var->right_margin = pinfo->lcdc.h_front_porch; + var->left_margin = pinfo->lcdc.h_back_porch; + var->hsync_len = pinfo->lcdc.h_pulse_width; + var->pixclock = pinfo->clk_rate; +} + /** * __mdss_fb_perform_commit() - process a frame to display * @mfd: Framebuffer data structure for display diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index 9747b5b65cc0..827c8dac9026 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -3464,8 +3464,14 @@ static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd) return -ENODEV; } - if (!mdss_mdp_ctl_is_power_on(mdp5_data->ctl)) + if (!mdss_mdp_ctl_is_power_on(mdp5_data->ctl)) { + if (mfd->panel_reconfig) { + mdp5_data->borderfill_enable = false; + mdss_mdp_ctl_destroy(mdp5_data->ctl); + mdp5_data->ctl = NULL; + } return 0; + } /* * Keep a reference to the runtime pm until the overlay is turned diff --git a/drivers/video/fbdev/msm/mdss_panel.c b/drivers/video/fbdev/msm/mdss_panel.c new file mode 100644 index 000000000000..ad4402821cbc --- /dev/null +++ b/drivers/video/fbdev/msm/mdss_panel.c @@ -0,0 +1,140 @@ +/* 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. + * + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include + +#include "mdss_panel.h" + +#define NUM_DSI_INTF 2 + +int mdss_panel_debugfs_setup(struct mdss_panel_info *panel_info, struct dentry + *parent, char *dsi_str) +{ + struct mdss_panel_debugfs_info *debugfs_info; + debugfs_info = kzalloc(sizeof(*debugfs_info), GFP_KERNEL); + if (!debugfs_info) { + pr_err("No memory to create panel debugfs info"); + return -ENOMEM; + } + + debugfs_info->root = debugfs_create_dir(dsi_str, parent); + if (IS_ERR_OR_NULL(debugfs_info->root)) { + pr_err("Debugfs create dir failed with error: %ld\n", + PTR_ERR(debugfs_info->root)); + return -ENODEV; + } + + debugfs_create_u32("override_flag", 0644, parent, + (u32 *)&debugfs_info->override_flag); + + debugfs_create_u32("xres", 0644, debugfs_info->root, + (u32 *)&debugfs_info->xres); + debugfs_create_u32("yres", 0644, debugfs_info->root, + (u32 *)&debugfs_info->yres); + + debugfs_create_u32("h_back_porch", 0644, debugfs_info->root, + (u32 *)&debugfs_info->lcdc.h_back_porch); + debugfs_create_u32("h_front_porch", 0644, debugfs_info->root, + (u32 *)&debugfs_info->lcdc.h_front_porch); + debugfs_create_u32("h_pulse_width", 0644, debugfs_info->root, + (u32 *)&debugfs_info->lcdc.h_pulse_width); + + debugfs_create_u32("v_back_porch", 0644, debugfs_info->root, + (u32 *)&debugfs_info->lcdc.v_back_porch); + debugfs_create_u32("v_front_porch", 0644, debugfs_info->root, + (u32 *)&debugfs_info->lcdc.v_front_porch); + debugfs_create_u32("v_pulse_width", 0644, debugfs_info->root, + (u32 *)&debugfs_info->lcdc.v_pulse_width); + + debugfs_create_u32("frame_rate", 0644, parent, + (u32 *)&debugfs_info->frame_rate); + + debugfs_info->xres = panel_info->xres; + debugfs_info->yres = panel_info->yres; + debugfs_info->lcdc = panel_info->lcdc; + debugfs_info->frame_rate = panel_info->mipi.frame_rate; + debugfs_info->override_flag = 0; + + panel_info->debugfs_info = debugfs_info; + return 0; +} + +int mdss_panel_debugfs_init(struct mdss_panel_info *panel_info) +{ + struct mdss_panel_data *pdata; + struct dentry *parent; + char dsi_str[10]; + int dsi_index = 0; + int rc = 0; + + if (panel_info->type != MIPI_VIDEO_PANEL + && panel_info->type != MIPI_CMD_PANEL) + return -ENOTSUPP; + + pdata = container_of(panel_info, struct mdss_panel_data, panel_info); + parent = debugfs_create_dir("mdss_panel", NULL); + if (IS_ERR_OR_NULL(parent)) { + pr_err("Debugfs create dir failed with error: %ld\n", + PTR_ERR(parent)); + return -ENODEV; + } + + do { + snprintf(dsi_str, sizeof(dsi_str), "dsi%d", dsi_index++); + rc = mdss_panel_debugfs_setup(&pdata->panel_info, parent, + dsi_str); + if (rc) { + pr_err("error in initilizing panel debugfs\n"); + return rc; + } + pdata = pdata->next; + } while (pdata && dsi_index < NUM_DSI_INTF); + + pr_debug("Initilized mdss_panel_debugfs_info\n"); + return 0; +} + +void mdss_panel_debugfs_cleanup(struct mdss_panel_info *panel_info) +{ + struct mdss_panel_data *pdata; + struct mdss_panel_debugfs_info *debugfs_info; + pdata = container_of(panel_info, struct mdss_panel_data, panel_info); + do { + debugfs_info = pdata->panel_info.debugfs_info; + if (debugfs_info && debugfs_info->root) + debugfs_remove_recursive(debugfs_info->root); + pdata = pdata->next; + } while (pdata); + pr_debug("Cleaned up mdss_panel_debugfs_info\n"); +} + +void mdss_panel_debugfsinfo_to_panelinfo(struct mdss_panel_info *panel_info) +{ + struct mdss_panel_data *pdata; + struct mdss_panel_info *pinfo; + pdata = container_of(panel_info, struct mdss_panel_data, panel_info); + + do { + pinfo = &pdata->panel_info; + pinfo->xres = pinfo->debugfs_info->xres; + pinfo->yres = pinfo->debugfs_info->yres; + pinfo->lcdc = pinfo->debugfs_info->lcdc; + pinfo->mipi.frame_rate = pinfo->debugfs_info->frame_rate; + pdata = pdata->next; + } while (pdata); +} diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h index f90287c548d2..6994ffbcc4f0 100644 --- a/drivers/video/fbdev/msm/mdss_panel.h +++ b/drivers/video/fbdev/msm/mdss_panel.h @@ -17,6 +17,7 @@ #include #include #include +#include /* panel id type */ struct panel_id { @@ -414,6 +415,9 @@ struct mdss_panel_info { struct mipi_panel_info mipi; struct lvds_panel_info lvds; struct edp_panel_info edp; + + /* debugfs structure for the panel */ + struct mdss_panel_debugfs_info *debugfs_info; }; struct mdss_panel_data { @@ -438,6 +442,16 @@ struct mdss_panel_data { struct mdss_panel_data *next; }; +struct mdss_panel_debugfs_info { + struct dentry *root; + u32 xres; + u32 yres; + struct lcd_panel_info lcdc; + u32 override_flag; + char frame_rate; + struct mdss_panel_debugfs_info *next; +}; + /** * mdss_get_panel_framerate() - get panel frame rate based on panel information * @panel_info: Pointer to panel info containing all panel information @@ -642,4 +656,16 @@ int mdss_panel_get_boot_cfg(void); * returns true if mdss is ready, else returns false. */ bool mdss_is_ready(void); +#ifdef CONFIG_FB_MSM_MDSS +int mdss_panel_debugfs_init(struct mdss_panel_info *panel_info); +void mdss_panel_debugfs_cleanup(struct mdss_panel_info *panel_info); +void mdss_panel_debugfsinfo_to_panelinfo(struct mdss_panel_info *panel_info); +#else +static inline int mdss_panel_debugfs_init( + struct mdss_panel_info *panel_info) { return 0; }; +static inline void mdss_panel_debugfs_cleanup( + struct mdss_panel_info *panel_info) { }; +static inline void mdss_panel_debugfsinfo_to_panelinfo( + struct mdss_panel_info *panel_info) { }; +#endif #endif /* MDSS_PANEL_H */ diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c index 44f86563133d..fac282e8fa64 100644 --- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c +++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c @@ -572,6 +572,10 @@ struct dsiphy_pll_divider_config pll_divider_config; int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info, int frame_rate) { + struct mdss_panel_data *pdata = container_of(panel_info, + struct mdss_panel_data, panel_info); + struct mdss_dsi_ctrl_pdata *ctrl_pdata = container_of(pdata, + struct mdss_dsi_ctrl_pdata, panel_data); u32 fb_divider, rate, vco; u32 div_ratio = 0; u32 pll_analog_posDiv = 1; @@ -607,7 +611,7 @@ int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info, h_period = mdss_panel_get_htotal(panel_info, true); v_period = mdss_panel_get_vtotal(panel_info); - if ((frame_rate != + if (ctrl_pdata->refresh_clk_rate || (frame_rate != panel_info->mipi.frame_rate) || (!panel_info->clk_rate)) { h_period += panel_info->lcdc.xres_pad;