msm_fb: HDMI: Update HPD logic to address HDMI PLL related issues
In the current implementation, the regulators pertaining to the
HDMI core are turned off/on as part of the configuration of the
HDP circuitry. As a result, the regulator that powers the HDMI
PLL is turned off before the HDMI clocks on the PLL are disabled.
This might lead to the PLL not getting locked when it is re-enabled.
This change turns on and off the regulators and clocks in proper
sequence.
CRs-Fixed: 360135
CRs-Fixed: 358598
Change-Id: Ie3630b543e78e83dc565edc32239935135ca4ca5
Signed-off-by: Aravind Venkateswaran <aravindh@codeaurora.org>
Signed-off-by: Ajay Singh Parmar <aparmar@codeaurora.org>
diff --git a/arch/arm/mach-msm/board-8064-display.c b/arch/arm/mach-msm/board-8064-display.c
index 7368f6e..101a26d 100644
--- a/arch/arm/mach-msm/board-8064-display.c
+++ b/arch/arm/mach-msm/board-8064-display.c
@@ -293,12 +293,16 @@
static int hdmi_enable_5v(int on);
static int hdmi_core_power(int on, int show);
static int hdmi_cec_power(int on);
+static int hdmi_gpio_config(int on);
+static int hdmi_panel_power(int on);
static struct msm_hdmi_platform_data hdmi_msm_data = {
.irq = HDMI_IRQ,
.enable_5v = hdmi_enable_5v,
.core_power = hdmi_core_power,
.cec_power = hdmi_cec_power,
+ .panel_power = hdmi_panel_power,
+ .gpio_config = hdmi_gpio_config,
};
static struct platform_device hdmi_msm_device = {
@@ -716,8 +720,22 @@
static struct lcdc_platform_data dtv_pdata = {
.bus_scale_table = &dtv_bus_scale_pdata,
+ .lcdc_power_save = hdmi_panel_power,
};
+static int hdmi_panel_power(int on)
+{
+ int rc;
+
+ pr_debug("%s: HDMI Core: %s\n", __func__, (on ? "ON" : "OFF"));
+ rc = hdmi_core_power(on, 1);
+ if (rc)
+ rc = hdmi_cec_power(on);
+
+ pr_debug("%s: HDMI Core: %s Success\n", __func__, (on ? "ON" : "OFF"));
+ return rc;
+}
+
static int hdmi_enable_5v(int on)
{
/* TBD: PM8921 regulator instead of 8901 */
@@ -765,7 +783,6 @@
static struct regulator *reg_8921_lvs7, *reg_8921_s4, *reg_ext_3p3v;
static int prev_on;
int rc;
- int pmic_gpio14 = PM8921_GPIO_PM_TO_SYS(14);
if (on == prev_on)
return 0;
@@ -822,20 +839,61 @@
rc = regulator_enable(reg_ext_3p3v);
if (rc) {
pr_err("enable reg_ext_3p3v failed, rc=%d\n", rc);
- return -ENODEV;
+ return rc;
}
rc = regulator_enable(reg_8921_lvs7);
if (rc) {
pr_err("'%s' regulator enable failed, rc=%d\n",
"hdmi_vdda", rc);
- return rc;
+ goto error1;
}
rc = regulator_enable(reg_8921_s4);
if (rc) {
pr_err("'%s' regulator enable failed, rc=%d\n",
"hdmi_lvl_tsl", rc);
- return rc;
+ goto error2;
}
+ pr_debug("%s(on): success\n", __func__);
+ } else {
+ rc = regulator_disable(reg_ext_3p3v);
+ if (rc) {
+ pr_err("disable reg_ext_3p3v failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ rc = regulator_disable(reg_8921_lvs7);
+ if (rc) {
+ pr_err("disable reg_8921_l23 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ rc = regulator_disable(reg_8921_s4);
+ if (rc) {
+ pr_err("disable reg_8921_s4 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ pr_debug("%s(off): success\n", __func__);
+ }
+
+ prev_on = on;
+
+ return 0;
+
+error2:
+ regulator_disable(reg_8921_lvs7);
+error1:
+ regulator_disable(reg_ext_3p3v);
+ return rc;
+}
+
+static int hdmi_gpio_config(int on)
+{
+ int rc = 0;
+ static int prev_on;
+ int pmic_gpio14 = PM8921_GPIO_PM_TO_SYS(14);
+
+ if (on == prev_on)
+ return 0;
+
+ if (on) {
rc = gpio_request(HDMI_DDC_CLK_GPIO, "HDMI_DDC_CLK");
if (rc) {
pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
@@ -873,27 +931,10 @@
gpio_set_value_cansleep(pmic_gpio14, 1);
gpio_free(pmic_gpio14);
}
-
- rc = regulator_disable(reg_ext_3p3v);
- if (rc) {
- pr_err("disable reg_ext_3p3v failed, rc=%d\n", rc);
- return -ENODEV;
- }
- rc = regulator_disable(reg_8921_lvs7);
- if (rc) {
- pr_err("disable reg_8921_l23 failed, rc=%d\n", rc);
- return -ENODEV;
- }
- rc = regulator_disable(reg_8921_s4);
- if (rc) {
- pr_err("disable reg_8921_s4 failed, rc=%d\n", rc);
- return -ENODEV;
- }
pr_debug("%s(off): success\n", __func__);
}
prev_on = on;
-
return 0;
error4:
@@ -903,8 +944,6 @@
error2:
gpio_free(HDMI_DDC_CLK_GPIO);
error1:
- regulator_disable(reg_8921_lvs7);
- regulator_disable(reg_8921_s4);
return rc;
}
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index e18e40d..8a837d6 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -516,12 +516,16 @@
static int hdmi_enable_5v(int on);
static int hdmi_core_power(int on, int show);
static int hdmi_cec_power(int on);
+static int hdmi_gpio_config(int on);
+static int hdmi_panel_power(int on);
static struct msm_hdmi_platform_data hdmi_msm_data = {
.irq = HDMI_IRQ,
.enable_5v = hdmi_enable_5v,
.core_power = hdmi_core_power,
.cec_power = hdmi_cec_power,
+ .panel_power = hdmi_panel_power,
+ .gpio_config = hdmi_gpio_config,
};
static struct platform_device hdmi_msm_device = {
@@ -594,7 +598,21 @@
static struct lcdc_platform_data dtv_pdata = {
.bus_scale_table = &dtv_bus_scale_pdata,
+ .lcdc_power_save = hdmi_panel_power,
};
+
+static int hdmi_panel_power(int on)
+{
+ int rc;
+
+ pr_debug("%s: HDMI Core: %s\n", __func__, (on ? "ON" : "OFF"));
+ rc = hdmi_core_power(on, 1);
+ if (rc)
+ rc = hdmi_cec_power(on);
+
+ pr_debug("%s: HDMI Core: %s Success\n", __func__, (on ? "ON" : "OFF"));
+ return rc;
+}
#endif
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
@@ -674,30 +692,8 @@
"hdmi_avdd", rc);
return rc;
}
- rc = gpio_request(100, "HDMI_DDC_CLK");
- if (rc) {
- pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
- "HDMI_DDC_CLK", 100, rc);
- goto error1;
- }
- rc = gpio_request(101, "HDMI_DDC_DATA");
- if (rc) {
- pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
- "HDMI_DDC_DATA", 101, rc);
- goto error2;
- }
- rc = gpio_request(102, "HDMI_HPD");
- if (rc) {
- pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
- "HDMI_HPD", 102, rc);
- goto error3;
- }
pr_debug("%s(on): success\n", __func__);
} else {
- gpio_free(100);
- gpio_free(101);
- gpio_free(102);
-
rc = regulator_disable(reg_8038_l23);
if (rc) {
pr_err("disable reg_8038_l23 failed, rc=%d\n", rc);
@@ -714,13 +710,50 @@
prev_on = on;
return 0;
+}
-error3:
- gpio_free(101);
+static int hdmi_gpio_config(int on)
+{
+ int rc = 0;
+ static int prev_on;
+
+ if (on == prev_on)
+ return 0;
+
+ if (on) {
+ rc = gpio_request(100, "HDMI_DDC_CLK");
+ if (rc) {
+ pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+ "HDMI_DDC_CLK", 100, rc);
+ return rc;
+ }
+ rc = gpio_request(101, "HDMI_DDC_DATA");
+ if (rc) {
+ pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+ "HDMI_DDC_DATA", 101, rc);
+ goto error1;
+ }
+ rc = gpio_request(102, "HDMI_HPD");
+ if (rc) {
+ pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+ "HDMI_HPD", 102, rc);
+ goto error2;
+ }
+ pr_debug("%s(on): success\n", __func__);
+ } else {
+ gpio_free(100);
+ gpio_free(101);
+ gpio_free(102);
+ pr_debug("%s(off): success\n", __func__);
+ }
+
+ prev_on = on;
+ return 0;
+
error2:
- gpio_free(100);
+ gpio_free(101);
error1:
- regulator_disable(reg_8038_l23);
+ gpio_free(100);
return rc;
}
diff --git a/arch/arm/mach-msm/board-8960-display.c b/arch/arm/mach-msm/board-8960-display.c
index a9b2a59..c1017a9 100644
--- a/arch/arm/mach-msm/board-8960-display.c
+++ b/arch/arm/mach-msm/board-8960-display.c
@@ -717,12 +717,16 @@
static int hdmi_enable_5v(int on);
static int hdmi_core_power(int on, int show);
static int hdmi_cec_power(int on);
+static int hdmi_gpio_config(int on);
+static int hdmi_panel_power(int on);
static struct msm_hdmi_platform_data hdmi_msm_data = {
.irq = HDMI_IRQ,
.enable_5v = hdmi_enable_5v,
.core_power = hdmi_core_power,
.cec_power = hdmi_cec_power,
+ .panel_power = hdmi_panel_power,
+ .gpio_config = hdmi_gpio_config,
};
static struct platform_device hdmi_msm_device = {
@@ -784,7 +788,21 @@
static struct lcdc_platform_data dtv_pdata = {
.bus_scale_table = &dtv_bus_scale_pdata,
+ .lcdc_power_save = hdmi_panel_power,
};
+
+static int hdmi_panel_power(int on)
+{
+ int rc;
+
+ pr_debug("%s: HDMI Core: %s\n", __func__, (on ? "ON" : "OFF"));
+ rc = hdmi_core_power(on, 1);
+ if (rc)
+ rc = hdmi_cec_power(on);
+
+ pr_debug("%s: HDMI Core: %s Success\n", __func__, (on ? "ON" : "OFF"));
+ return rc;
+}
#endif
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
@@ -885,30 +903,8 @@
"hdmi_vcc", rc);
return rc;
}
- rc = gpio_request(100, "HDMI_DDC_CLK");
- if (rc) {
- pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
- "HDMI_DDC_CLK", 100, rc);
- goto error1;
- }
- rc = gpio_request(101, "HDMI_DDC_DATA");
- if (rc) {
- pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
- "HDMI_DDC_DATA", 101, rc);
- goto error2;
- }
- rc = gpio_request(102, "HDMI_HPD");
- if (rc) {
- pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
- "HDMI_HPD", 102, rc);
- goto error3;
- }
pr_debug("%s(on): success\n", __func__);
} else {
- gpio_free(100);
- gpio_free(101);
- gpio_free(102);
-
rc = regulator_disable(reg_8921_l23);
if (rc) {
pr_err("disable reg_8921_l23 failed, rc=%d\n", rc);
@@ -930,14 +926,50 @@
prev_on = on;
return 0;
+}
-error3:
- gpio_free(101);
+static int hdmi_gpio_config(int on)
+{
+ int rc = 0;
+ static int prev_on;
+
+ if (on == prev_on)
+ return 0;
+
+ if (on) {
+ rc = gpio_request(100, "HDMI_DDC_CLK");
+ if (rc) {
+ pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+ "HDMI_DDC_CLK", 100, rc);
+ return rc;
+ }
+ rc = gpio_request(101, "HDMI_DDC_DATA");
+ if (rc) {
+ pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+ "HDMI_DDC_DATA", 101, rc);
+ goto error1;
+ }
+ rc = gpio_request(102, "HDMI_HPD");
+ if (rc) {
+ pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+ "HDMI_HPD", 102, rc);
+ goto error2;
+ }
+ pr_debug("%s(on): success\n", __func__);
+ } else {
+ gpio_free(100);
+ gpio_free(101);
+ gpio_free(102);
+ pr_debug("%s(off): success\n", __func__);
+ }
+
+ prev_on = on;
+ return 0;
+
error2:
- gpio_free(100);
+ gpio_free(101);
error1:
- regulator_disable(reg_8921_l23);
- regulator_disable(reg_8921_s4);
+ gpio_free(100);
return rc;
}
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 3488fb3..102f6ac 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -3083,13 +3083,17 @@
static int hdmi_enable_5v(int on);
static int hdmi_core_power(int on, int show);
+static int hdmi_gpio_config(int on);
static int hdmi_cec_power(int on);
+static int hdmi_panel_power(int on);
static struct msm_hdmi_platform_data hdmi_msm_data = {
.irq = HDMI_IRQ,
.enable_5v = hdmi_enable_5v,
.core_power = hdmi_core_power,
.cec_power = hdmi_cec_power,
+ .panel_power = hdmi_panel_power,
+ .gpio_config = hdmi_gpio_config,
};
static struct platform_device hdmi_msm_device = {
@@ -9006,6 +9010,29 @@
"8058_l16", rc);
return rc;
}
+ pr_debug("%s(on): success\n", __func__);
+ } else {
+ rc = regulator_disable(reg_8058_l16);
+ if (rc)
+ pr_warning("'%s' regulator disable failed, rc=%d\n",
+ "8058_l16", rc);
+ pr_debug("%s(off): success\n", __func__);
+ }
+
+ prev_on = on;
+
+ return 0;
+}
+
+static int hdmi_gpio_config(int on)
+{
+ int rc = 0;
+ static int prev_on;
+
+ if (on == prev_on)
+ return 0;
+
+ if (on) {
rc = gpio_request(170, "HDMI_DDC_CLK");
if (rc) {
pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
@@ -9024,20 +9051,15 @@
"HDMI_HPD", 172, rc);
goto error3;
}
- pr_info("%s(on): success\n", __func__);
+ pr_debug("%s(on): success\n", __func__);
} else {
gpio_free(170);
gpio_free(171);
gpio_free(172);
- rc = regulator_disable(reg_8058_l16);
- if (rc)
- pr_warning("'%s' regulator disable failed, rc=%d\n",
- "8058_l16", rc);
- pr_info("%s(off): success\n", __func__);
+ pr_debug("%s(off): success\n", __func__);
}
prev_on = on;
-
return 0;
error3:
@@ -9045,7 +9067,6 @@
error2:
gpio_free(170);
error1:
- regulator_disable(reg_8058_l16);
return rc;
}
@@ -9094,6 +9115,18 @@
return rc;
}
+static int hdmi_panel_power(int on)
+{
+ int rc;
+
+ pr_debug("%s: HDMI Core: %s\n", __func__, (on ? "ON" : "OFF"));
+ rc = hdmi_core_power(on, 1);
+ if (rc)
+ rc = hdmi_cec_power(on);
+
+ pr_debug("%s: HDMI Core: %s Success\n", __func__, (on ? "ON" : "OFF"));
+ return rc;
+}
#undef _GET_REGULATOR
#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL */
@@ -9516,6 +9549,7 @@
static struct lcdc_platform_data dtv_pdata = {
.bus_scale_table = &dtv_bus_scale_pdata,
+ .lcdc_power_save = hdmi_panel_power,
};
static struct msm_bus_paths dtv_hdmi_prim_bus_scale_usecases[] = {
diff --git a/arch/arm/mach-msm/clock-dss-8960.c b/arch/arm/mach-msm/clock-dss-8960.c
index 8331899..7f3646f 100644
--- a/arch/arm/mach-msm/clock-dss-8960.c
+++ b/arch/arm/mach-msm/clock-dss-8960.c
@@ -97,6 +97,7 @@
{
unsigned int val;
u32 ahb_en_reg, ahb_enabled;
+ unsigned int timeout_count;
ahb_en_reg = readl_relaxed(AHB_EN_REG);
ahb_enabled = ahb_en_reg & BIT(4);
@@ -110,6 +111,12 @@
writel_relaxed(0x8D, HDMI_PHY_PLL_LOCKDET_CFG2);
writel_relaxed(0x10, HDMI_PHY_PLL_LOCKDET_CFG0);
writel_relaxed(0x1A, HDMI_PHY_PLL_LOCKDET_CFG1);
+ /* Wait for a short time before de-asserting
+ * to allow the hardware to complete its job.
+ * This much of delay should be fine for hardware
+ * to assert and de-assert.
+ */
+ udelay(10);
/* De-assert PLL S/W reset */
writel_relaxed(0x0D, HDMI_PHY_PLL_LOCKDET_CFG2);
@@ -118,6 +125,11 @@
/* Assert PHY S/W reset */
writel_relaxed(val, HDMI_PHY_REG_12);
val &= ~BIT(5);
+ /* Wait for a short time before de-asserting
+ to allow the hardware to complete its job.
+ This much of delay should be fine for hardware
+ to assert and de-assert. */
+ udelay(10);
/* De-assert PHY S/W reset */
writel_relaxed(val, HDMI_PHY_REG_12);
writel_relaxed(0x3f, HDMI_PHY_REG_2);
@@ -135,8 +147,32 @@
writel_relaxed(val, HDMI_PHY_PLL_PWRDN_B);
writel_relaxed(0x80, HDMI_PHY_REG_2);
- while (!(readl_relaxed(HDMI_PHY_PLL_STATUS0) & BIT(0)))
- cpu_relax();
+ timeout_count = 1000;
+ while (!(readl_relaxed(HDMI_PHY_PLL_STATUS0) & BIT(0)) &&
+ timeout_count) {
+ if (--timeout_count == 0) {
+ /*
+ * PLL has still not locked.
+ * Do a software reset and try again
+ * Assert PLL S/W reset first
+ */
+ writel_relaxed(0x8D, HDMI_PHY_PLL_LOCKDET_CFG2);
+
+ /* Wait for a short time before de-asserting
+ * to allow the hardware to complete its job.
+ * This much of delay should be fine for hardware
+ * to assert and de-assert.
+ */
+ udelay(10);
+ writel_relaxed(0x0D, HDMI_PHY_PLL_LOCKDET_CFG2);
+ timeout_count = 1000;
+
+ pr_err("%s: PLL not locked after %d iterations\n",
+ __func__, timeout_count);
+ pr_err("%s: Asserting PLL S/W reset & trying again\n",
+ __func__);
+ }
+ }
if (!ahb_enabled)
writel_relaxed(ahb_en_reg & ~BIT(4), AHB_EN_REG);
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index bae5cbc..8c1d5b7 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -485,6 +485,8 @@
int (*enable_5v)(int on);
int (*core_power)(int on, int show);
int (*cec_power)(int on);
+ int (*panel_power)(int on);
+ int (*gpio_config)(int on);
int (*init_irq)(void);
bool (*check_hdcp_hw_support)(void);
};