From 2418be03bcc9bb35ce3f0e7f1309cecf5d263f88 Mon Sep 17 00:00:00 2001 From: "shengyang.chen" Date: Wed, 9 Nov 2022 10:15:19 +0800 Subject: [PATCH] riscv:linux:drm : fix vout pm bug fix display problem of hdmi sys pm Signed-off-by: shengyang.chen --- arch/riscv/boot/dts/starfive/jh7110.dtsi | 6 -- drivers/gpu/drm/verisilicon/inno_hdmi.c | 172 +++++++++++++++++++++---------- drivers/gpu/drm/verisilicon/vs_drv.c | 134 +----------------------- drivers/gpu/drm/verisilicon/vs_drv.h | 4 - 4 files changed, 123 insertions(+), 193 deletions(-) diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi index 58a968c..b61575f 100644 --- a/arch/riscv/boot/dts/starfive/jh7110.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi @@ -1544,12 +1544,6 @@ compatible = "starfive,jh7110-display","verisilicon,display-subsystem"; ports = <&dc_out_dpi0>; status = "disabled"; - clocks = <&clkvout JH7110_U0_HDMI_TX_CLK_SYS>, - <&clkvout JH7110_U0_HDMI_TX_CLK_MCLK>, - <&clkvout JH7110_U0_HDMI_TX_CLK_BCLK>; - clock-names = "hdmi_sysclk","hdmi_mclk","hdmi_bclk"; - resets = <&rstgen RSTN_U0_HDMI_TX_HDMI>; - reset-names = "hdmi_txrst"; }; dssctrl: dssctrl@295B0000 { diff --git a/drivers/gpu/drm/verisilicon/inno_hdmi.c b/drivers/gpu/drm/verisilicon/inno_hdmi.c index a8c90a7..36c11c1 100644 --- a/drivers/gpu/drm/verisilicon/inno_hdmi.c +++ b/drivers/gpu/drm/verisilicon/inno_hdmi.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "vs_drv.h" @@ -115,6 +116,80 @@ inline void hdmi_modb(struct inno_hdmi *hdmi, u16 offset, hdmi_writeb(hdmi, offset, temp); } +static int inno_hdmi_enable_clk_deassert_rst(struct device *dev, struct inno_hdmi *hdmi) +{ + int ret; + + ret = clk_prepare_enable(hdmi->sys_clk); + if (ret) { + DRM_DEV_ERROR(dev, + "Cannot enable HDMI sys clock: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(hdmi->mclk); + if (ret) { + DRM_DEV_ERROR(dev, + "Cannot enable HDMI mclk clock: %d\n", ret); + return ret; + } + ret = clk_prepare_enable(hdmi->bclk); + if (ret) { + DRM_DEV_ERROR(dev, + "Cannot enable HDMI bclk clock: %d\n", ret); + return ret; + } + ret = reset_control_deassert(hdmi->tx_rst); + if (ret < 0) { + dev_err(dev, "failed to deassert tx_rst\n"); + return ret; + } + return 0; +} + +static void inno_hdmi_disable_clk_assert_rst(struct device *dev, struct inno_hdmi *hdmi) +{ + int ret; + + ret = reset_control_assert(hdmi->tx_rst); + if (ret < 0) + dev_err(dev, "failed to assert tx_rst\n"); + + clk_disable_unprepare(hdmi->sys_clk); + clk_disable_unprepare(hdmi->mclk); + clk_disable_unprepare(hdmi->bclk); +} + +#ifdef CONFIG_PM_SLEEP +static int hdmi_system_pm_suspend(struct device *dev) +{ + return pm_runtime_force_suspend(dev); +} + +static int hdmi_system_pm_resume(struct device *dev) +{ + return pm_runtime_force_resume(dev); +} +#endif + +#ifdef CONFIG_PM +static int hdmi_runtime_suspend(struct device *dev) +{ + struct inno_hdmi *hdmi = dev_get_drvdata(dev); + + inno_hdmi_disable_clk_assert_rst(dev, hdmi); + + return 0; +} + +static int hdmi_runtime_resume(struct device *dev) +{ + struct inno_hdmi *hdmi = dev_get_drvdata(dev); + + return inno_hdmi_enable_clk_deassert_rst(dev, hdmi); +} +#endif + static void inno_hdmi_tx_phy_power_down(struct inno_hdmi *hdmi) { hdmi_writeb(hdmi, 0x00, 0x63); @@ -275,6 +350,7 @@ static void inno_hdmi_set_pwr_mode(struct inno_hdmi *hdmi, int mode) for (; hdmi->post_cfg->tmdsclock != 0; hdmi->post_cfg++) if (tmdsclock <= hdmi->post_cfg->tmdsclock) break; + mdelay(100); dev_info(hdmi->dev, "%s hdmi->pre_cfg->pixclock = %lu\n",__func__, hdmi->pre_cfg->pixclock); dev_info(hdmi->dev, "%s hdmi->pre_cfg->tmdsclock = %lu\n",__func__, hdmi->pre_cfg->tmdsclock); @@ -472,28 +548,36 @@ static void inno_hdmi_encoder_mode_set(struct drm_encoder *encoder, { struct inno_hdmi *hdmi = to_inno_hdmi(encoder); - inno_hdmi_setup(hdmi, adj_mode); - - /* Store the display mode for plugin/DPMS poweron events */ memcpy(&hdmi->previous_mode, adj_mode, sizeof(hdmi->previous_mode)); } static void inno_hdmi_encoder_enable(struct drm_encoder *encoder) { struct inno_hdmi *hdmi = to_inno_hdmi(encoder); + int ret; - /* for powerdown the innohdmi, syspm can use*/ - inno_hdmi_set_pwr_mode(hdmi, LOWER_PWR); + ret = pm_runtime_get_sync(hdmi->dev); + if (ret < 0) + return; + mdelay(10); + inno_hdmi_setup(hdmi, &hdmi->previous_mode); + /* for powerdown the innohdmi, syspm can use*/ inno_hdmi_set_pwr_mode(hdmi, NORMAL); } static void inno_hdmi_encoder_disable(struct drm_encoder *encoder) { + struct inno_hdmi *hdmi = to_inno_hdmi(encoder); + + inno_hdmi_set_pwr_mode(hdmi, LOWER_PWR); + + pm_runtime_put(hdmi->dev); + return; /*mention: if enable, sys pm test will be crashed*/ //struct inno_hdmi *hdmi = to_inno_hdmi(encoder); - //inno_hdmi_set_pwr_mode(hdmi, LOWER_PWR); + // } static bool inno_hdmi_encoder_mode_fixup(struct drm_encoder *encoder, @@ -523,9 +607,17 @@ static enum drm_connector_status inno_hdmi_connector_detect(struct drm_connector *connector, bool force) { struct inno_hdmi *hdmi = to_inno_hdmi(connector); + int ret; - return (hdmi_readb(hdmi, HDMI_STATUS) & m_HOTPLUG) ? + ret = pm_runtime_get_sync(hdmi->dev); + if (ret < 0) + return ret; + ret = (hdmi_readb(hdmi, HDMI_STATUS) & m_HOTPLUG) ? connector_status_connected : connector_status_disconnected; + + pm_runtime_put(hdmi->dev); + + return ret; } static int inno_hdmi_connector_get_modes(struct drm_connector *connector) @@ -568,7 +660,17 @@ static int inno_hdmi_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY) { - return drm_helper_probe_single_connector_modes(connector, 3840, 2160);//3840x2160 + struct inno_hdmi *hdmi = to_inno_hdmi(connector); + int ret; + + ret = pm_runtime_get_sync(hdmi->dev); + if (ret < 0) + return ret; + ret = drm_helper_probe_single_connector_modes(connector, 3840, 2160); + + pm_runtime_put(hdmi->dev); + + return ret; } static void inno_hdmi_connector_destroy(struct drm_connector *connector) @@ -822,50 +924,6 @@ static int inno_hdmi_get_clk_rst(struct device *dev, struct inno_hdmi *hdmi) return 0; } -static int inno_hdmi_enable_clk_deassert_rst(struct device *dev, struct inno_hdmi *hdmi) -{ - int ret; - - ret = clk_prepare_enable(hdmi->sys_clk); - if (ret) { - DRM_DEV_ERROR(dev, - "Cannot enable HDMI sys clock: %d\n", ret); - return ret; - } - - ret = clk_prepare_enable(hdmi->mclk); - if (ret) { - DRM_DEV_ERROR(dev, - "Cannot enable HDMI mclk clock: %d\n", ret); - return ret; - } - ret = clk_prepare_enable(hdmi->bclk); - if (ret) { - DRM_DEV_ERROR(dev, - "Cannot enable HDMI bclk clock: %d\n", ret); - return ret; - } - ret = reset_control_deassert(hdmi->tx_rst); - if (ret < 0) { - dev_err(dev, "failed to deassert tx_rst\n"); - return ret; - } - return 0; -} - -static void inno_hdmi_disable_clk_assert_rst(struct device *dev, struct inno_hdmi *hdmi) -{ - int ret; - - ret = reset_control_assert(hdmi->tx_rst); - if (ret < 0) - dev_err(dev, "failed to assert tx_rst\n"); - - clk_disable_unprepare(hdmi->sys_clk); - clk_disable_unprepare(hdmi->mclk); - clk_disable_unprepare(hdmi->bclk); -} - static int inno_hdmi_bind(struct device *dev, struct device *master, void *data) @@ -952,6 +1010,10 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, if (ret) dev_err(dev, "failed to audio init\n"); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); + pm_runtime_enable(&pdev->dev); + inno_hdmi_disable_clk_assert_rst(dev, hdmi); dev_info(dev, "inno hdmi bind end\n"); @@ -1004,6 +1066,11 @@ static int inno_hdmi_remove(struct platform_device *pdev) return 0; } +static const struct dev_pm_ops hdmi_pm_ops = { + SET_RUNTIME_PM_OPS(hdmi_runtime_suspend, hdmi_runtime_resume, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(hdmi_system_pm_suspend, hdmi_system_pm_resume) +}; + static const struct of_device_id inno_hdmi_dt_ids[] = { { .compatible = "inno,hdmi", }, @@ -1017,5 +1084,6 @@ struct platform_driver inno_hdmi_driver = { .driver = { .name = "innohdmi-starfive", .of_match_table = inno_hdmi_dt_ids, + .pm = &hdmi_pm_ops, }, }; diff --git a/drivers/gpu/drm/verisilicon/vs_drv.c b/drivers/gpu/drm/verisilicon/vs_drv.c index 8e7be26..af5abe8 100644 --- a/drivers/gpu/drm/verisilicon/vs_drv.c +++ b/drivers/gpu/drm/verisilicon/vs_drv.c @@ -51,132 +51,10 @@ extern struct platform_driver starfive_encoder_driver; static bool has_iommu = true; static struct platform_driver vs_drm_platform_driver; -struct drm_minor *drm_minor_acquire(unsigned int minor_id); - -static int vs_hdmi_get_clk_rst(struct device *dev, struct vs_drm_private *priv) -{ - priv->vs_hdmi_sys_clk = devm_clk_get(dev, "hdmi_sysclk"); - if (IS_ERR(priv->vs_hdmi_sys_clk)) { - DRM_DEV_ERROR(dev, "Unable to get HDMI sysclk clk\n"); - return PTR_ERR(priv->vs_hdmi_sys_clk); - } - - priv->vs_hdmi_mclk = devm_clk_get(dev, "hdmi_mclk"); - if (IS_ERR(priv->vs_hdmi_mclk)) { - DRM_DEV_ERROR(dev, "Unable to get HDMI mclk clk\n"); - return PTR_ERR(priv->vs_hdmi_mclk); - } - priv->vs_hdmi_bclk = devm_clk_get(dev, "hdmi_bclk"); - if (IS_ERR(priv->vs_hdmi_bclk)) { - DRM_DEV_ERROR(dev, "Unable to get HDMI bclk clk\n"); - return PTR_ERR(priv->vs_hdmi_bclk); - } - - priv->vs_hdmi_tx_rst = reset_control_get_shared(dev, "hdmi_txrst"); - if (IS_ERR(priv->vs_hdmi_tx_rst)) { - DRM_DEV_ERROR(dev, "Unable to get HDMI tx rst in vs_drm\n"); - return PTR_ERR(priv->vs_hdmi_tx_rst); - } - - return 0; -} - -static int vs_hdmi_enable_clk_deassert_rst(struct device *dev, struct vs_drm_private *priv) -{ - int ret; - - ret = clk_prepare_enable(priv->vs_hdmi_sys_clk); - if (ret) { - DRM_DEV_ERROR(dev, - "Cannot enable HDMI sys clock: %d\n", ret); - return ret; - } - - ret = clk_prepare_enable(priv->vs_hdmi_mclk); - if (ret) { - DRM_DEV_ERROR(dev, - "Cannot enable HDMI mclk clock: %d\n", ret); - return ret; - } - ret = clk_prepare_enable(priv->vs_hdmi_bclk); - if (ret) { - DRM_DEV_ERROR(dev, - "Cannot enable HDMI bclk clock: %d\n", ret); - return ret; - } - ret = reset_control_deassert(priv->vs_hdmi_tx_rst); - if (ret < 0) { - dev_err(dev, "failed to deassert tx_rst\n"); - return ret; - } - return 0; -} - -static void vs_hdmi_disable_clk_assert_rst(struct device *dev, struct vs_drm_private *priv) -{ - int ret; - - ret = reset_control_assert(priv->vs_hdmi_tx_rst); - if (ret < 0) - dev_err(dev, "failed to assert tx_rst in vs_drm\n"); - - clk_disable_unprepare(priv->vs_hdmi_sys_clk); - clk_disable_unprepare(priv->vs_hdmi_mclk); - clk_disable_unprepare(priv->vs_hdmi_bclk); -} - -static int vs_drm_open(struct inode *inode, struct file *filp) -{ - struct drm_minor *minor; //= file_priv->minor; - struct drm_device *drm_dev; //= minor->dev; - struct device *dev; - int ret; - struct vs_drm_private *priv; - - minor = drm_minor_acquire(iminor(inode)); - if (IS_ERR(minor)) - return PTR_ERR(minor); - - dev = minor->dev->dev; - dev_info(dev, "vs drm open\n"); - - drm_dev = dev_get_drvdata(dev); - priv = drm_dev->dev_private; - - ret = vs_hdmi_enable_clk_deassert_rst(dev, priv); - if (ret < 0) { - dev_err(dev, "failed to enable clk or deassert rst in %s\n", __func__); - return ret; - } - return drm_open(inode, filp); -} - -static int vs_drm_release(struct inode *inode, struct file *filp) -{ - struct drm_file *file_priv = filp->private_data; - struct drm_minor *minor = file_priv->minor; - struct device *dev; - - dev = minor->dev->dev; - dev_info(dev, "vs drm release\n"); - - return drm_release(inode, filp); -} - -static void vs_drm_lastclose(struct drm_device *dev) -{ - struct vs_drm_private *priv; - - dev_info(dev->dev, "vs drm lastclose\n"); - drm_fb_helper_lastclose(dev); - priv = dev->dev_private; - vs_hdmi_disable_clk_assert_rst(dev->dev, priv); -} - static const struct file_operations fops = { .owner = THIS_MODULE, - .open = vs_drm_open,//drm_open, - .release = vs_drm_release,//drm_release, + .open = drm_open, + .release = drm_release, .unlocked_ioctl = drm_ioctl, .compat_ioctl = drm_compat_ioctl, .poll = drm_poll, @@ -246,7 +124,7 @@ static int vs_debugfs_init(struct drm_minor *minor) static struct drm_driver vs_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM, - .lastclose = vs_drm_lastclose,//drm_fb_helper_lastclose, + .lastclose = drm_fb_helper_lastclose, .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, .gem_prime_import = vs_gem_prime_import, @@ -345,12 +223,6 @@ static int vs_drm_bind(struct device *dev) goto err_put_dev; } - ret = vs_hdmi_get_clk_rst(dev, priv); - if (ret) { - dev_err(dev, "vs_hdmi_get_clk_rst failed\n"); - goto err_put_dev; - } - priv->pitch_alignment = 64; priv->dma_dev = drm_dev->dev; priv->dma_dev->coherent_dma_mask = dma_mask; diff --git a/drivers/gpu/drm/verisilicon/vs_drv.h b/drivers/gpu/drm/verisilicon/vs_drv.h index b136f40..9d0d046 100644 --- a/drivers/gpu/drm/verisilicon/vs_drv.h +++ b/drivers/gpu/drm/verisilicon/vs_drv.h @@ -39,10 +39,6 @@ struct vs_drm_private { #endif unsigned int pitch_alignment; - struct clk *vs_hdmi_sys_clk; - struct clk *vs_hdmi_mclk; - struct clk *vs_hdmi_bclk; - struct reset_control *vs_hdmi_tx_rst; }; int vs_drm_iommu_attach_device(struct drm_device *drm_dev, -- 2.7.4