msm: mdss: added support to change panel resolution dynamically

Helpful in changing the panel resoultion on the fly with the help of
debugfs nodes and when used along with simulated panels, it allows to
test different panel configurations dynamically.

Change-Id: I9cdf82e4fffd3dd618ee97601f169d72ab76a473
Signed-off-by: Veera Sundaram Sankaran <veeras@codeaurora.org>
[cip@codeaurora.org: Moved mdss_panel.c file location]
Signed-off-by: Clarence Ip <cip@codeaurora.org>
This commit is contained in:
Veera Sundaram Sankaran 2014-08-29 14:03:48 -07:00 committed by David Keitel
parent d7f8dde109
commit 0507b2f2e2
8 changed files with 260 additions and 2 deletions

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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 <linux/kernel.h>
#include <linux/debugfs.h>
#include <linux/slab.h>
#include <linux/fb.h>
#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);
}

View file

@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/stringify.h>
#include <linux/types.h>
#include <linux/debugfs.h>
/* 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 */

View file

@ -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;