#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"
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);
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);
{
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,
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)
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)
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)
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");
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",
},
.driver = {
.name = "innohdmi-starfive",
.of_match_table = inno_hdmi_dt_ids,
+ .pm = &hdmi_pm_ops,
},
};
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,
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,
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;