riscv:linux:drm : fix vout pm bug
authorshengyang.chen <shengyang.chen@starfivetech.com>
Wed, 9 Nov 2022 02:15:19 +0000 (10:15 +0800)
committershengyang.chen <shengyang.chen@starfivetech.com>
Mon, 14 Nov 2022 06:53:42 +0000 (14:53 +0800)
fix display problem of hdmi sys pm

Signed-off-by: shengyang.chen<shengyang.chen@starfivetech.com>
arch/riscv/boot/dts/starfive/jh7110.dtsi
drivers/gpu/drm/verisilicon/inno_hdmi.c
drivers/gpu/drm/verisilicon/vs_drv.c
drivers/gpu/drm/verisilicon/vs_drv.h

index 58a968c..b61575f 100644 (file)
                        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 {
index a8c90a7..36c11c1 100644 (file)
@@ -24,6 +24,7 @@
 #include <drm/drm_probe_helper.h>
 #include <drm/drm_simple_kms_helper.h>
 #include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
 
 #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,
        },
 };
index 8e7be26..af5abe8 100644 (file)
@@ -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;
index b136f40..9d0d046 100644 (file)
@@ -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,