msm: mdss: hdmi: add pll_enable property to support clock recovery
PLL_ENABLE property is used to enable or disable the PLL update function. With this property PLL update function only works when PLL_ENABLE is set, and all changes done to hardware will be discarded once PLL_ENABLE is cleared. Change-Id: I4a6173de22285b37df1b9371ad29e634ef076edc Signed-off-by: Narender Ankam <nankam@codeaurora.org>
This commit is contained in:
parent
6f777b2385
commit
c93c1652fc
2 changed files with 112 additions and 0 deletions
|
@ -119,6 +119,8 @@ static int hdmi_tx_get_audio_edid_blk(struct platform_device *pdev,
|
||||||
struct msm_ext_disp_audio_edid_blk *blk);
|
struct msm_ext_disp_audio_edid_blk *blk);
|
||||||
static int hdmi_tx_get_cable_status(struct platform_device *pdev, u32 vote);
|
static int hdmi_tx_get_cable_status(struct platform_device *pdev, u32 vote);
|
||||||
static int hdmi_tx_update_ppm(struct hdmi_tx_ctrl *hdmi_ctrl, s32 ppm);
|
static int hdmi_tx_update_ppm(struct hdmi_tx_ctrl *hdmi_ctrl, s32 ppm);
|
||||||
|
static int hdmi_tx_enable_pll_update(struct hdmi_tx_ctrl *hdmi_ctrl,
|
||||||
|
int enable);
|
||||||
|
|
||||||
static struct mdss_hw hdmi_tx_hw = {
|
static struct mdss_hw hdmi_tx_hw = {
|
||||||
.hw_ndx = MDSS_HW_HDMI,
|
.hw_ndx = MDSS_HW_HDMI,
|
||||||
|
@ -1361,6 +1363,59 @@ end:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t hdmi_tx_sysfs_rda_pll_enable(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
ssize_t ret;
|
||||||
|
struct hdmi_tx_ctrl *hdmi_ctrl =
|
||||||
|
hdmi_tx_get_drvdata_from_sysfs_dev(dev);
|
||||||
|
|
||||||
|
if (!hdmi_ctrl) {
|
||||||
|
pr_err("invalid input\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&hdmi_ctrl->tx_lock);
|
||||||
|
ret = snprintf(buf, PAGE_SIZE, "%d\n",
|
||||||
|
hdmi_ctrl->pll_update_enable);
|
||||||
|
pr_debug("HDMI PLL update: %s\n",
|
||||||
|
hdmi_ctrl->pll_update_enable ? "enable" : "disable");
|
||||||
|
|
||||||
|
mutex_unlock(&hdmi_ctrl->tx_lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
} /* hdmi_tx_sysfs_rda_pll_enable */
|
||||||
|
|
||||||
|
|
||||||
|
static ssize_t hdmi_tx_sysfs_wta_pll_enable(struct device *dev,
|
||||||
|
struct device_attribute *attr, const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
int enable, rc;
|
||||||
|
struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
|
||||||
|
|
||||||
|
hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev);
|
||||||
|
|
||||||
|
if (!hdmi_ctrl) {
|
||||||
|
DEV_ERR("%s: invalid input\n", __func__);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&hdmi_ctrl->tx_lock);
|
||||||
|
|
||||||
|
rc = kstrtoint(buf, 10, &enable);
|
||||||
|
if (rc) {
|
||||||
|
DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
hdmi_tx_enable_pll_update(hdmi_ctrl, enable);
|
||||||
|
|
||||||
|
rc = strnlen(buf, PAGE_SIZE);
|
||||||
|
end:
|
||||||
|
mutex_unlock(&hdmi_ctrl->tx_lock);
|
||||||
|
return rc;
|
||||||
|
} /* hdmi_tx_sysfs_wta_pll_enable */
|
||||||
|
|
||||||
static DEVICE_ATTR(connected, S_IRUGO, hdmi_tx_sysfs_rda_connected, NULL);
|
static DEVICE_ATTR(connected, S_IRUGO, hdmi_tx_sysfs_rda_connected, NULL);
|
||||||
static DEVICE_ATTR(hot_plug, S_IWUSR, NULL, hdmi_tx_sysfs_wta_hot_plug);
|
static DEVICE_ATTR(hot_plug, S_IWUSR, NULL, hdmi_tx_sysfs_wta_hot_plug);
|
||||||
static DEVICE_ATTR(sim_mode, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_sim_mode,
|
static DEVICE_ATTR(sim_mode, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_sim_mode,
|
||||||
|
@ -1383,6 +1438,9 @@ static DEVICE_ATTR(5v, S_IWUSR, NULL, hdmi_tx_sysfs_wta_5v);
|
||||||
static DEVICE_ATTR(hdr_stream, S_IWUSR, NULL, hdmi_tx_sysfs_wta_hdr_stream);
|
static DEVICE_ATTR(hdr_stream, S_IWUSR, NULL, hdmi_tx_sysfs_wta_hdr_stream);
|
||||||
static DEVICE_ATTR(hdmi_ppm, S_IRUGO | S_IWUSR, NULL,
|
static DEVICE_ATTR(hdmi_ppm, S_IRUGO | S_IWUSR, NULL,
|
||||||
hdmi_tx_sysfs_wta_hdmi_ppm);
|
hdmi_tx_sysfs_wta_hdmi_ppm);
|
||||||
|
static DEVICE_ATTR(pll_enable, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_pll_enable,
|
||||||
|
hdmi_tx_sysfs_wta_pll_enable);
|
||||||
|
|
||||||
|
|
||||||
static struct attribute *hdmi_tx_fs_attrs[] = {
|
static struct attribute *hdmi_tx_fs_attrs[] = {
|
||||||
&dev_attr_connected.attr,
|
&dev_attr_connected.attr,
|
||||||
|
@ -1399,6 +1457,7 @@ static struct attribute *hdmi_tx_fs_attrs[] = {
|
||||||
&dev_attr_5v.attr,
|
&dev_attr_5v.attr,
|
||||||
&dev_attr_hdr_stream.attr,
|
&dev_attr_hdr_stream.attr,
|
||||||
&dev_attr_hdmi_ppm.attr,
|
&dev_attr_hdmi_ppm.attr,
|
||||||
|
&dev_attr_pll_enable.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
static struct attribute_group hdmi_tx_fs_attrs_group = {
|
static struct attribute_group hdmi_tx_fs_attrs_group = {
|
||||||
|
@ -3565,6 +3624,7 @@ static int hdmi_tx_dev_init(struct hdmi_tx_ctrl *hdmi_ctrl)
|
||||||
hdmi_ctrl->hpd_state = false;
|
hdmi_ctrl->hpd_state = false;
|
||||||
hdmi_ctrl->hpd_initialized = false;
|
hdmi_ctrl->hpd_initialized = false;
|
||||||
hdmi_ctrl->hpd_off_pending = false;
|
hdmi_ctrl->hpd_off_pending = false;
|
||||||
|
hdmi_ctrl->pll_update_enable = false;
|
||||||
init_completion(&hdmi_ctrl->hpd_int_done);
|
init_completion(&hdmi_ctrl->hpd_int_done);
|
||||||
|
|
||||||
INIT_WORK(&hdmi_ctrl->hpd_int_work, hdmi_tx_hpd_int_work);
|
INIT_WORK(&hdmi_ctrl->hpd_int_work, hdmi_tx_hpd_int_work);
|
||||||
|
@ -3738,6 +3798,11 @@ static int hdmi_tx_update_ppm(struct hdmi_tx_ctrl *hdmi_ctrl, s32 ppm)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!hdmi_ctrl->pll_update_enable) {
|
||||||
|
pr_err("PLL update feature not enabled\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
/* get current pclk */
|
/* get current pclk */
|
||||||
cur_pclk = pinfo->clk_rate;
|
cur_pclk = pinfo->clk_rate;
|
||||||
/* get desired pclk */
|
/* get desired pclk */
|
||||||
|
@ -3761,6 +3826,49 @@ static int hdmi_tx_update_ppm(struct hdmi_tx_ctrl *hdmi_ctrl, s32 ppm)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int hdmi_tx_enable_pll_update(struct hdmi_tx_ctrl *hdmi_ctrl,
|
||||||
|
int enable)
|
||||||
|
{
|
||||||
|
struct mdss_panel_info *pinfo = NULL;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (!hdmi_ctrl) {
|
||||||
|
pr_err("invalid input\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* only available in case HDMI is up */
|
||||||
|
if (!hdmi_tx_is_panel_on(hdmi_ctrl)) {
|
||||||
|
pr_err("hdmi is not on\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
enable = !!enable;
|
||||||
|
if (hdmi_ctrl->pll_update_enable == enable) {
|
||||||
|
pr_warn("HDMI PLL update already %s\n",
|
||||||
|
hdmi_ctrl->pll_update_enable ? "enabled" : "disabled");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pinfo = &hdmi_ctrl->panel_data.panel_info;
|
||||||
|
|
||||||
|
if (!enable && hdmi_ctrl->actual_clk_rate != pinfo->clk_rate) {
|
||||||
|
if (hdmi_ctrl->actual_clk_rate) {
|
||||||
|
/* reset pixel clock when disable */
|
||||||
|
pinfo->clk_rate = hdmi_ctrl->actual_clk_rate;
|
||||||
|
rc = hdmi_tx_update_pixel_clk(hdmi_ctrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hdmi_ctrl->actual_clk_rate = pinfo->clk_rate;
|
||||||
|
hdmi_ctrl->pll_update_enable = enable;
|
||||||
|
|
||||||
|
pr_debug("HDMI PLL update: %s\n",
|
||||||
|
hdmi_ctrl->pll_update_enable ? "enable" : "disable");
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
static int hdmi_tx_evt_handle_register(struct hdmi_tx_ctrl *hdmi_ctrl)
|
static int hdmi_tx_evt_handle_register(struct hdmi_tx_ctrl *hdmi_ctrl)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
@ -3933,6 +4041,7 @@ static int hdmi_tx_evt_handle_panel_off(struct hdmi_tx_ctrl *hdmi_ctrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
hdmi_ctrl->timing_gen_on = false;
|
hdmi_ctrl->timing_gen_on = false;
|
||||||
|
hdmi_ctrl->pll_update_enable = false;
|
||||||
end:
|
end:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,6 +141,9 @@ struct hdmi_tx_ctrl {
|
||||||
|
|
||||||
char disp_switch_name[MAX_SWITCH_NAME_SIZE];
|
char disp_switch_name[MAX_SWITCH_NAME_SIZE];
|
||||||
|
|
||||||
|
u64 actual_clk_rate;
|
||||||
|
bool pll_update_enable;
|
||||||
|
|
||||||
/* pre/post is done in the context without tx_lock */
|
/* pre/post is done in the context without tx_lock */
|
||||||
hdmi_tx_evt_handler pre_evt_handler[MDSS_EVENT_MAX - 1];
|
hdmi_tx_evt_handler pre_evt_handler[MDSS_EVENT_MAX - 1];
|
||||||
hdmi_tx_evt_handler evt_handler[MDSS_EVENT_MAX - 1];
|
hdmi_tx_evt_handler evt_handler[MDSS_EVENT_MAX - 1];
|
||||||
|
|
Loading…
Add table
Reference in a new issue