mirror of
https://github.com/LibreELEC/LibreELEC.tv.git
synced 2025-07-29 13:46:49 +00:00
Merge pull request #5626 from jernejsk/aw-hdmi-fix
Allwinner: linux: Fix HDMI driver
This commit is contained in:
commit
2d87cff8b0
@ -140,7 +140,7 @@ Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
.is_custom_phy = true,
|
||||
.phy_init = &sun8i_hdmi_phy_init_h3,
|
||||
@@ -725,10 +766,36 @@ static int sun8i_hdmi_phy_probe(struct p
|
||||
clk_prepare_enable(phy->clk_phy);
|
||||
goto err_put_clk_pll1;
|
||||
}
|
||||
|
||||
+ if (phy->variant->bit_bang_cec) {
|
||||
@ -173,9 +173,9 @@ Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
+ cec_delete_adapter(phy->cec_adapter);
|
||||
+err_disable_clk_phy:
|
||||
+ clk_disable_unprepare(phy->clk_phy);
|
||||
err_disable_clk_mod:
|
||||
clk_disable_unprepare(phy->clk_mod);
|
||||
err_disable_clk_bus:
|
||||
err_put_clk_pll1:
|
||||
clk_put(phy->clk_pll1);
|
||||
err_put_clk_pll0:
|
||||
@@ -753,6 +820,9 @@ static int sun8i_hdmi_phy_remove(struct
|
||||
{
|
||||
struct sun8i_hdmi_phy *phy = platform_get_drvdata(pdev);
|
||||
@ -183,6 +183,6 @@ Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
+ cec_notifier_cec_adap_unregister(phy->cec_notifier, phy->cec_adapter);
|
||||
+ cec_unregister_adapter(phy->cec_adapter);
|
||||
+
|
||||
clk_disable_unprepare(phy->clk_mod);
|
||||
clk_disable_unprepare(phy->clk_bus);
|
||||
clk_disable_unprepare(phy->clk_phy);
|
||||
reset_control_put(phy->rst_phy);
|
||||
|
||||
clk_put(phy->clk_pll0);
|
||||
|
@ -0,0 +1,210 @@
|
||||
From 887d1018e2c5ab5e81edbd1318bbf4bbd2c739b0 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
Date: Sun, 12 Sep 2021 20:15:26 +0200
|
||||
Subject: [PATCH] drm/sun4i: dw-hdmi: Fix HDMI PHY clock setup
|
||||
|
||||
Recent rework which made HDMI PHY driver a platform device inadvertely
|
||||
reversed clock setup order. HW is very touch about it. Proper way is to
|
||||
handle controllers resets and clocks first and HDMI PHYs second.
|
||||
|
||||
Move HDMI PHY reset & clocks handling to sun8i_hdmi_phy_init() which
|
||||
will assure that code is executed after controllers reset & clocks are
|
||||
handled. Additionally, add sun8i_hdmi_phy_deinit() which will deinit it
|
||||
at controllers driver unload.
|
||||
|
||||
Fixes: 9bf3797796f5 ("drm/sun4i: dw-hdmi: Make HDMI PHY into a platform device")
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 7 +-
|
||||
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 4 +-
|
||||
drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 97 ++++++++++++++------------
|
||||
3 files changed, 61 insertions(+), 47 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
index f75fb157f2ff..5fa5407ac583 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
|
||||
@@ -216,11 +216,13 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
goto err_disable_clk_tmds;
|
||||
}
|
||||
|
||||
+ ret = sun8i_hdmi_phy_init(hdmi->phy);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
drm_encoder_helper_add(encoder, &sun8i_dw_hdmi_encoder_helper_funcs);
|
||||
drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
|
||||
|
||||
- sun8i_hdmi_phy_init(hdmi->phy);
|
||||
-
|
||||
plat_data->mode_valid = hdmi->quirks->mode_valid;
|
||||
plat_data->use_drm_infoframe = hdmi->quirks->use_drm_infoframe;
|
||||
sun8i_hdmi_phy_set_ops(hdmi->phy, plat_data);
|
||||
@@ -262,6 +264,7 @@ static void sun8i_dw_hdmi_unbind(struct device *dev, struct device *master,
|
||||
struct sun8i_dw_hdmi *hdmi = dev_get_drvdata(dev);
|
||||
|
||||
dw_hdmi_unbind(hdmi->hdmi);
|
||||
+ sun8i_hdmi_phy_deinit(hdmi->phy);
|
||||
clk_disable_unprepare(hdmi->clk_tmds);
|
||||
reset_control_assert(hdmi->rst_ctrl);
|
||||
gpiod_set_value(hdmi->ddc_en, 0);
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
|
||||
index 74f6ed0e2570..bffe1b9cd3dc 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
|
||||
@@ -169,6 +169,7 @@ struct sun8i_hdmi_phy {
|
||||
struct clk *clk_phy;
|
||||
struct clk *clk_pll0;
|
||||
struct clk *clk_pll1;
|
||||
+ struct device *dev;
|
||||
unsigned int rcal;
|
||||
struct regmap *regs;
|
||||
struct reset_control *rst_phy;
|
||||
@@ -205,7 +206,8 @@ encoder_to_sun8i_dw_hdmi(struct drm_encoder *encoder)
|
||||
|
||||
int sun8i_hdmi_phy_get(struct sun8i_dw_hdmi *hdmi, struct device_node *node);
|
||||
|
||||
-void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy);
|
||||
+int sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy);
|
||||
+void sun8i_hdmi_phy_deinit(struct sun8i_hdmi_phy *phy);
|
||||
void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy,
|
||||
struct dw_hdmi_plat_data *plat_data);
|
||||
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
|
||||
index c9239708d398..78b152973957 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
|
||||
@@ -506,9 +506,60 @@ static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy *phy)
|
||||
phy->rcal = (val & SUN8I_HDMI_PHY_ANA_STS_RCAL_MASK) >> 2;
|
||||
}
|
||||
|
||||
-void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy)
|
||||
+int sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy)
|
||||
{
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = reset_control_deassert(phy->rst_phy);
|
||||
+ if (ret) {
|
||||
+ dev_err(phy->dev, "Cannot deassert phy reset control: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = clk_prepare_enable(phy->clk_bus);
|
||||
+ if (ret) {
|
||||
+ dev_err(phy->dev, "Cannot enable bus clock: %d\n", ret);
|
||||
+ goto err_deassert_rst_phy;
|
||||
+ }
|
||||
+
|
||||
+ ret = clk_prepare_enable(phy->clk_mod);
|
||||
+ if (ret) {
|
||||
+ dev_err(phy->dev, "Cannot enable mod clock: %d\n", ret);
|
||||
+ goto err_disable_clk_bus;
|
||||
+ }
|
||||
+
|
||||
+ if (phy->variant->has_phy_clk) {
|
||||
+ ret = sun8i_phy_clk_create(phy, phy->dev,
|
||||
+ phy->variant->has_second_pll);
|
||||
+ if (ret) {
|
||||
+ dev_err(phy->dev, "Couldn't create the PHY clock\n");
|
||||
+ goto err_disable_clk_mod;
|
||||
+ }
|
||||
+
|
||||
+ clk_prepare_enable(phy->clk_phy);
|
||||
+ }
|
||||
+
|
||||
phy->variant->phy_init(phy);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_disable_clk_mod:
|
||||
+ clk_disable_unprepare(phy->clk_mod);
|
||||
+err_disable_clk_bus:
|
||||
+ clk_disable_unprepare(phy->clk_bus);
|
||||
+err_deassert_rst_phy:
|
||||
+ reset_control_assert(phy->rst_phy);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+void sun8i_hdmi_phy_deinit(struct sun8i_hdmi_phy *phy)
|
||||
+{
|
||||
+ clk_disable_unprepare(phy->clk_mod);
|
||||
+ clk_disable_unprepare(phy->clk_bus);
|
||||
+ clk_disable_unprepare(phy->clk_phy);
|
||||
+
|
||||
+ reset_control_assert(phy->rst_phy);
|
||||
}
|
||||
|
||||
void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy,
|
||||
@@ -638,6 +689,7 @@ static int sun8i_hdmi_phy_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
phy->variant = (struct sun8i_hdmi_phy_variant *)match->data;
|
||||
+ phy->dev = dev;
|
||||
|
||||
ret = of_address_to_resource(node, 0, &res);
|
||||
if (ret) {
|
||||
@@ -696,47 +748,10 @@ static int sun8i_hdmi_phy_probe(struct platform_device *pdev)
|
||||
goto err_put_clk_pll1;
|
||||
}
|
||||
|
||||
- ret = reset_control_deassert(phy->rst_phy);
|
||||
- if (ret) {
|
||||
- dev_err(dev, "Cannot deassert phy reset control: %d\n", ret);
|
||||
- goto err_put_rst_phy;
|
||||
- }
|
||||
-
|
||||
- ret = clk_prepare_enable(phy->clk_bus);
|
||||
- if (ret) {
|
||||
- dev_err(dev, "Cannot enable bus clock: %d\n", ret);
|
||||
- goto err_deassert_rst_phy;
|
||||
- }
|
||||
-
|
||||
- ret = clk_prepare_enable(phy->clk_mod);
|
||||
- if (ret) {
|
||||
- dev_err(dev, "Cannot enable mod clock: %d\n", ret);
|
||||
- goto err_disable_clk_bus;
|
||||
- }
|
||||
-
|
||||
- if (phy->variant->has_phy_clk) {
|
||||
- ret = sun8i_phy_clk_create(phy, dev,
|
||||
- phy->variant->has_second_pll);
|
||||
- if (ret) {
|
||||
- dev_err(dev, "Couldn't create the PHY clock\n");
|
||||
- goto err_disable_clk_mod;
|
||||
- }
|
||||
-
|
||||
- clk_prepare_enable(phy->clk_phy);
|
||||
- }
|
||||
-
|
||||
platform_set_drvdata(pdev, phy);
|
||||
|
||||
return 0;
|
||||
|
||||
-err_disable_clk_mod:
|
||||
- clk_disable_unprepare(phy->clk_mod);
|
||||
-err_disable_clk_bus:
|
||||
- clk_disable_unprepare(phy->clk_bus);
|
||||
-err_deassert_rst_phy:
|
||||
- reset_control_assert(phy->rst_phy);
|
||||
-err_put_rst_phy:
|
||||
- reset_control_put(phy->rst_phy);
|
||||
err_put_clk_pll1:
|
||||
clk_put(phy->clk_pll1);
|
||||
err_put_clk_pll0:
|
||||
@@ -753,12 +768,6 @@ static int sun8i_hdmi_phy_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sun8i_hdmi_phy *phy = platform_get_drvdata(pdev);
|
||||
|
||||
- clk_disable_unprepare(phy->clk_mod);
|
||||
- clk_disable_unprepare(phy->clk_bus);
|
||||
- clk_disable_unprepare(phy->clk_phy);
|
||||
-
|
||||
- reset_control_assert(phy->rst_phy);
|
||||
-
|
||||
reset_control_put(phy->rst_phy);
|
||||
|
||||
clk_put(phy->clk_pll0);
|
||||
--
|
||||
2.33.0
|
||||
|
Loading…
x
Reference in New Issue
Block a user