diff mbox series

[03/11] drm: meson: add S4 compatible for DRM driver

Message ID 20250110-drm-s4-v1-3-cbc2d5edaae8@amlogic.com (mailing list archive)
State New
Delegated to: Neil Armstrong
Headers show
Series Subject: [PATCH 00/11] Add DRM support for Amlogic S4 | expand

Commit Message

Ao Xu via B4 Relay Jan. 10, 2025, 5:39 a.m. UTC
From: Ao Xu <ao.xu@amlogic.com>

Add S4 compatible for DRM driver. This update driver logic to support
S4-specific configurations. This also add vpu clock operation in
bind, suspend, resume, shutdown stage.

Signed-off-by: Ao Xu <ao.xu@amlogic.com>
---
 drivers/gpu/drm/meson/meson_drv.c | 127 +++++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/meson/meson_drv.h |   6 ++
 2 files changed, 132 insertions(+), 1 deletion(-)

Comments

Jerome Brunet Jan. 10, 2025, 1:36 p.m. UTC | #1
On Fri 10 Jan 2025 at 13:39, Ao Xu via B4 Relay <devnull+ao.xu.amlogic.com@kernel.org> wrote:

> From: Ao Xu <ao.xu@amlogic.com>
>
> Add S4 compatible for DRM driver. This update driver logic to support
> S4-specific configurations. This also add vpu clock operation in
> bind, suspend, resume, shutdown stage.
>
> Signed-off-by: Ao Xu <ao.xu@amlogic.com>
> ---
>  drivers/gpu/drm/meson/meson_drv.c | 127 +++++++++++++++++++++++++++++++++++++-
>  drivers/gpu/drm/meson/meson_drv.h |   6 ++
>  2 files changed, 132 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
> index 81d2ee37e7732dca89d02347b9c972300b38771a..d28094efeb137ae0b9990ab3608825d563358dba 100644
> --- a/drivers/gpu/drm/meson/meson_drv.c
> +++ b/drivers/gpu/drm/meson/meson_drv.c
> @@ -11,6 +11,7 @@
>  #include <linux/aperture.h>
>  #include <linux/component.h>
>  #include <linux/module.h>
> +#include <linux/clk.h>
>  #include <linux/of_graph.h>
>  #include <linux/sys_soc.h>
>  #include <linux/platform_device.h>
> @@ -160,6 +161,34 @@ static void meson_vpu_init(struct meson_drm *priv)
>  	writel_relaxed(value, priv->io_base + _REG(VPU_WRARB_MODE_L2C1));
>  }
>  
> +static void meson_setup_clk(struct meson_drm *priv, bool enable)
> +{
> +	int ret;
> +
> +	if (!priv || !priv->vpu_clk || !priv->vapb_clk)
> +		return;
> +
> +	if (!meson_vpu_is_compatible(priv, VPU_COMPATIBLE_S4))
> +		return;
> +
> +	if (enable) {
> +		ret = clk_prepare_enable(priv->vpu_clk);
> +		if (ret) {
> +			dev_err(priv->dev, "Failed to set vpu clk\n");
> +			return;
> +		}
> +		ret = clk_prepare_enable(priv->vapb_clk);
> +		if (ret) {
> +			dev_err(priv->dev, "Failed to Set vapb clk\n");
> +			clk_disable_unprepare(priv->vpu_clk);
> +			return;
> +		}
> +	} else {
> +		clk_disable_unprepare(priv->vpu_clk);
> +		clk_disable_unprepare(priv->vapb_clk);
> +	}
> +}
> +
>  struct meson_drm_soc_attr {
>  	struct meson_drm_soc_limits limits;
>  	const struct soc_device_attribute *attrs;
> @@ -241,6 +270,83 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
>  		goto free_drm;
>  	}
>  
> +	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_S4)) {
> +		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sysctrl");
> +		if (!res) {
> +			ret = -EINVAL;
> +			goto free_drm;
> +		}
> +		/* Simply ioremap since it may be a shared register zone */

This comment, the name of the zone and even the usage you are making of
it clearly show this is repeating the error of past, directly accessing
improperly shared registers which should otherwise have been implemented
as proper controller using the kernel available framework, such PD, phys,
clock, reset, etc ...

Worse, it gets encoded into the dt binding, making extremely difficult
to fix later on.

> +		regs = devm_ioremap(dev, res->start, resource_size(res));
> +		if (!regs) {
> +			ret = -EADDRNOTAVAIL;
> +			goto free_drm;
> +		}
> +
> +		priv->sysctrl = devm_regmap_init_mmio(dev, regs,
> +						  &meson_regmap_config);
> +		if (IS_ERR(priv->sysctrl)) {
> +			dev_err(&pdev->dev, "Couldn't create the SYSCTRL regmap\n");
> +			ret = PTR_ERR(priv->sysctrl);
> +			goto free_drm;
> +		}
> +
> +		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clkctrl");
> +		if (!res) {
> +			ret = -EINVAL;
> +			goto free_drm;
> +		}
> +		/* Simply ioremap since it may be a shared register zone */
> +		regs = devm_ioremap(dev, res->start, resource_size(res));
> +		if (!regs) {
> +			ret = -EADDRNOTAVAIL;
> +			goto free_drm;
> +		}
> +
> +		priv->clkctrl = devm_regmap_init_mmio(dev, regs,
> +						  &meson_regmap_config);
> +		if (IS_ERR(priv->clkctrl)) {
> +			dev_err(&pdev->dev, "Couldn't create the clkctrl regmap\n");
> +			ret = PTR_ERR(priv->clkctrl);
> +			goto free_drm;
> +		}
> +
> +		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwrctrl");
> +		if (!res) {
> +			ret = -EINVAL;
> +			goto free_drm;
> +		}
> +		/* Simply ioremap since it may be a shared register zone */
> +		regs = devm_ioremap(dev, res->start, resource_size(res));
> +		if (!regs) {
> +			ret = -EADDRNOTAVAIL;
> +			goto free_drm;
> +		}
> +
> +		priv->pwrctrl = devm_regmap_init_mmio(dev, regs,
> +						  &meson_regmap_config);
> +		if (IS_ERR(priv->pwrctrl)) {
> +			dev_err(&pdev->dev, "Couldn't create the pwrctrl regmap\n");
> +			ret = PTR_ERR(priv->pwrctrl);
> +			goto free_drm;
> +		}
> +
> +		priv->vpu_clk = devm_clk_get(&pdev->dev, "vpu");
> +		if (IS_ERR(priv->vpu_clk)) {
> +			dev_err(&pdev->dev, "vpu clock request failed\n");
> +			ret = PTR_ERR(priv->vpu_clk);
> +			goto free_drm;
> +		}
> +
> +		priv->vapb_clk = devm_clk_get(&pdev->dev, "vapb");
> +		if (IS_ERR(priv->vapb_clk)) {
> +			dev_err(&pdev->dev, "vapb clock request failed\n");
> +			ret = PTR_ERR(priv->vapb_clk);
> +			goto free_drm;
> +		}
> +		meson_setup_clk(priv, true);
> +	}
> +
>  	priv->canvas = meson_canvas_get(dev);
>  	if (IS_ERR(priv->canvas)) {
>  		ret = PTR_ERR(priv->canvas);
> @@ -424,12 +530,21 @@ static const struct component_master_ops meson_drv_master_ops = {
>  
>  static int __maybe_unused meson_drv_pm_suspend(struct device *dev)
>  {
> +	int ret;
>  	struct meson_drm *priv = dev_get_drvdata(dev);
>  
>  	if (!priv)
>  		return 0;
>  
> -	return drm_mode_config_helper_suspend(priv->drm);
> +	ret = drm_mode_config_helper_suspend(priv->drm);
> +	if (unlikely(ret)) {
> +		drm_err(dev, "suspend error: %d", ret);
> +		return ret;
> +	}
> +
> +	meson_setup_clk(priv, false);
> +
> +	return ret;
>  }
>  
>  static int __maybe_unused meson_drv_pm_resume(struct device *dev)
> @@ -439,6 +554,7 @@ static int __maybe_unused meson_drv_pm_resume(struct device *dev)
>  	if (!priv)
>  		return 0;
>  
> +	meson_setup_clk(priv, true);
>  	meson_vpu_init(priv);
>  	meson_venc_init(priv);
>  	meson_vpp_init(priv);
> @@ -458,6 +574,7 @@ static void meson_drv_shutdown(struct platform_device *pdev)
>  
>  	drm_kms_helper_poll_fini(priv->drm);
>  	drm_atomic_helper_shutdown(priv->drm);
> +	meson_setup_clk(priv, false);
>  }
>  
>  /*
> @@ -471,6 +588,7 @@ static const struct of_device_id components_dev_match[] = {
>  	{ .compatible = "amlogic,meson-gxl-dw-hdmi" },
>  	{ .compatible = "amlogic,meson-gxm-dw-hdmi" },
>  	{ .compatible = "amlogic,meson-g12a-dw-hdmi" },
> +	{ .compatible = "amlogic,meson-s4-dw-hdmi" },
>  	{}
>  };
>  
> @@ -539,6 +657,11 @@ static struct meson_drm_match_data meson_drm_g12a_data = {
>  	.afbcd_ops = &meson_afbcd_g12a_ops,
>  };
>  
> +static struct meson_drm_match_data meson_drm_s4_data = {
> +	.compat = VPU_COMPATIBLE_S4,
> +	.afbcd_ops = &meson_afbcd_g12a_ops,
> +};
> +
>  static const struct of_device_id dt_match[] = {
>  	{ .compatible = "amlogic,meson-gxbb-vpu",
>  	  .data       = (void *)&meson_drm_gxbb_data },
> @@ -548,6 +671,8 @@ static const struct of_device_id dt_match[] = {
>  	  .data       = (void *)&meson_drm_gxm_data },
>  	{ .compatible = "amlogic,meson-g12a-vpu",
>  	  .data       = (void *)&meson_drm_g12a_data },
> +	{ .compatible = "amlogic,meson-s4-vpu",
> +	  .data       = (void *)&meson_drm_s4_data },
>  	{}
>  };
>  MODULE_DEVICE_TABLE(of, dt_match);
> diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h
> index 3f9345c14f31c13b071f420533fe8a450d3e0f36..c801a2e3e55a054247710aebae5602e44c9e1624 100644
> --- a/drivers/gpu/drm/meson/meson_drv.h
> +++ b/drivers/gpu/drm/meson/meson_drv.h
> @@ -22,6 +22,7 @@ enum vpu_compatible {
>  	VPU_COMPATIBLE_GXL  = 1,
>  	VPU_COMPATIBLE_GXM  = 2,
>  	VPU_COMPATIBLE_G12A = 3,
> +	VPU_COMPATIBLE_S4 = 4,
>  };
>  
>  enum {
> @@ -45,6 +46,11 @@ struct meson_drm {
>  	enum vpu_compatible compat;
>  	void __iomem *io_base;
>  	struct regmap *hhi;
> +	struct regmap *sysctrl;
> +	struct regmap *clkctrl;
> +	struct regmap *pwrctrl;
> +	struct clk *vpu_clk;
> +	struct clk *vapb_clk;
>  	int vsync_irq;
>  
>  	struct meson_canvas *canvas;
kernel test robot Jan. 11, 2025, 6:40 a.m. UTC | #2
Hi Ao,

kernel test robot noticed the following build errors:

[auto build test ERROR on 6ecd20965bdc21b265a0671ccf36d9ad8043f5ab]

url:    https://github.com/intel-lab-lkp/linux/commits/Ao-Xu-via-B4-Relay/dt-bindings-display-meson-dw-hdmi-Add-compatible-for-S4-HDMI-controller/20250110-134113
base:   6ecd20965bdc21b265a0671ccf36d9ad8043f5ab
patch link:    https://lore.kernel.org/r/20250110-drm-s4-v1-3-cbc2d5edaae8%40amlogic.com
patch subject: [PATCH 03/11] drm: meson: add S4 compatible for DRM driver
config: csky-randconfig-002-20250111 (https://download.01.org/0day-ci/archive/20250111/202501111433.iVcR3vZY-lkp@intel.com/config)
compiler: csky-linux-gcc (GCC) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250111/202501111433.iVcR3vZY-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202501111433.iVcR3vZY-lkp@intel.com/

All errors (new ones prefixed by >>):

   In file included from include/linux/device.h:15,
                    from include/linux/sys_soc.h:9,
                    from drivers/gpu/drm/meson/meson_drv.c:16:
   drivers/gpu/drm/meson/meson_drv.c: In function 'meson_drv_pm_suspend':
>> include/drm/drm_print.h:588:42: error: 'struct device' has no member named 'dev'; did you mean 'devt'?
     588 |         dev_##level##type((drm) ? (drm)->dev : NULL, "[drm] " fmt, ##__VA_ARGS__)
         |                                          ^~~
   include/linux/dev_printk.h:110:25: note: in definition of macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                         ^~~
   include/drm/drm_print.h:588:9: note: in expansion of macro 'dev_err'
     588 |         dev_##level##type((drm) ? (drm)->dev : NULL, "[drm] " fmt, ##__VA_ARGS__)
         |         ^~~~
   include/drm/drm_print.h:601:9: note: in expansion of macro '__drm_printk'
     601 |         __drm_printk((drm), err,, "*ERROR* " fmt, ##__VA_ARGS__)
         |         ^~~~~~~~~~~~
   drivers/gpu/drm/meson/meson_drv.c:541:17: note: in expansion of macro 'drm_err'
     541 |                 drm_err(dev, "suspend error: %d", ret);
         |                 ^~~~~~~
--
   In file included from include/linux/device.h:15,
                    from include/linux/sys_soc.h:9,
                    from meson_drv.c:16:
   meson_drv.c: In function 'meson_drv_pm_suspend':
>> include/drm/drm_print.h:588:42: error: 'struct device' has no member named 'dev'; did you mean 'devt'?
     588 |         dev_##level##type((drm) ? (drm)->dev : NULL, "[drm] " fmt, ##__VA_ARGS__)
         |                                          ^~~
   include/linux/dev_printk.h:110:25: note: in definition of macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                         ^~~
   include/drm/drm_print.h:588:9: note: in expansion of macro 'dev_err'
     588 |         dev_##level##type((drm) ? (drm)->dev : NULL, "[drm] " fmt, ##__VA_ARGS__)
         |         ^~~~
   include/drm/drm_print.h:601:9: note: in expansion of macro '__drm_printk'
     601 |         __drm_printk((drm), err,, "*ERROR* " fmt, ##__VA_ARGS__)
         |         ^~~~~~~~~~~~
   meson_drv.c:541:17: note: in expansion of macro 'drm_err'
     541 |                 drm_err(dev, "suspend error: %d", ret);
         |                 ^~~~~~~


vim +588 include/drm/drm_print.h

e820f52577b14c Jim Cromie            2022-09-11  548  
02c9656b2f0d69 Haneen Mohammed       2017-10-17  549  /**
b52817e9de06a3 Mauro Carvalho Chehab 2020-10-27  550   * DRM_DEV_DEBUG() - Debug output for generic drm code
02c9656b2f0d69 Haneen Mohammed       2017-10-17  551   *
306589856399e1 Douglas Anderson      2021-09-21  552   * NOTE: this is deprecated in favor of drm_dbg_core().
306589856399e1 Douglas Anderson      2021-09-21  553   *
091756bbb1a961 Haneen Mohammed       2017-10-17  554   * @dev: device pointer
091756bbb1a961 Haneen Mohammed       2017-10-17  555   * @fmt: printf() like format string.
02c9656b2f0d69 Haneen Mohammed       2017-10-17  556   */
db87086492581c Joe Perches           2018-03-16  557  #define DRM_DEV_DEBUG(dev, fmt, ...)					\
db87086492581c Joe Perches           2018-03-16  558  	drm_dev_dbg(dev, DRM_UT_CORE, fmt, ##__VA_ARGS__)
b52817e9de06a3 Mauro Carvalho Chehab 2020-10-27  559  /**
b52817e9de06a3 Mauro Carvalho Chehab 2020-10-27  560   * DRM_DEV_DEBUG_DRIVER() - Debug output for vendor specific part of the driver
b52817e9de06a3 Mauro Carvalho Chehab 2020-10-27  561   *
306589856399e1 Douglas Anderson      2021-09-21  562   * NOTE: this is deprecated in favor of drm_dbg() or dev_dbg().
306589856399e1 Douglas Anderson      2021-09-21  563   *
b52817e9de06a3 Mauro Carvalho Chehab 2020-10-27  564   * @dev: device pointer
b52817e9de06a3 Mauro Carvalho Chehab 2020-10-27  565   * @fmt: printf() like format string.
b52817e9de06a3 Mauro Carvalho Chehab 2020-10-27  566   */
db87086492581c Joe Perches           2018-03-16  567  #define DRM_DEV_DEBUG_DRIVER(dev, fmt, ...)				\
db87086492581c Joe Perches           2018-03-16  568  	drm_dev_dbg(dev, DRM_UT_DRIVER,	fmt, ##__VA_ARGS__)
b52817e9de06a3 Mauro Carvalho Chehab 2020-10-27  569  /**
b52817e9de06a3 Mauro Carvalho Chehab 2020-10-27  570   * DRM_DEV_DEBUG_KMS() - Debug output for modesetting code
b52817e9de06a3 Mauro Carvalho Chehab 2020-10-27  571   *
306589856399e1 Douglas Anderson      2021-09-21  572   * NOTE: this is deprecated in favor of drm_dbg_kms().
306589856399e1 Douglas Anderson      2021-09-21  573   *
b52817e9de06a3 Mauro Carvalho Chehab 2020-10-27  574   * @dev: device pointer
b52817e9de06a3 Mauro Carvalho Chehab 2020-10-27  575   * @fmt: printf() like format string.
b52817e9de06a3 Mauro Carvalho Chehab 2020-10-27  576   */
db87086492581c Joe Perches           2018-03-16  577  #define DRM_DEV_DEBUG_KMS(dev, fmt, ...)				\
db87086492581c Joe Perches           2018-03-16  578  	drm_dev_dbg(dev, DRM_UT_KMS, fmt, ##__VA_ARGS__)
a18b21929453af Lyude Paul            2018-07-16  579  
fb6c7ab8718eb2 Jani Nikula           2019-12-10  580  /*
fb6c7ab8718eb2 Jani Nikula           2019-12-10  581   * struct drm_device based logging
fb6c7ab8718eb2 Jani Nikula           2019-12-10  582   *
fb6c7ab8718eb2 Jani Nikula           2019-12-10  583   * Prefer drm_device based logging over device or prink based logging.
fb6c7ab8718eb2 Jani Nikula           2019-12-10  584   */
fb6c7ab8718eb2 Jani Nikula           2019-12-10  585  
fb6c7ab8718eb2 Jani Nikula           2019-12-10  586  /* Helper for struct drm_device based logging. */
fb6c7ab8718eb2 Jani Nikula           2019-12-10  587  #define __drm_printk(drm, level, type, fmt, ...)			\
e04d24c4e8062b Luben Tuikov          2023-11-16 @588  	dev_##level##type((drm) ? (drm)->dev : NULL, "[drm] " fmt, ##__VA_ARGS__)
fb6c7ab8718eb2 Jani Nikula           2019-12-10  589  
fb6c7ab8718eb2 Jani Nikula           2019-12-10  590
kernel test robot Jan. 11, 2025, 7:47 a.m. UTC | #3
Hi Ao,

kernel test robot noticed the following build errors:

[auto build test ERROR on 6ecd20965bdc21b265a0671ccf36d9ad8043f5ab]

url:    https://github.com/intel-lab-lkp/linux/commits/Ao-Xu-via-B4-Relay/dt-bindings-display-meson-dw-hdmi-Add-compatible-for-S4-HDMI-controller/20250110-134113
base:   6ecd20965bdc21b265a0671ccf36d9ad8043f5ab
patch link:    https://lore.kernel.org/r/20250110-drm-s4-v1-3-cbc2d5edaae8%40amlogic.com
patch subject: [PATCH 03/11] drm: meson: add S4 compatible for DRM driver
config: arm64-randconfig-002-20250111 (https://download.01.org/0day-ci/archive/20250111/202501111505.wNSI9zrC-lkp@intel.com/config)
compiler: clang version 20.0.0git (https://github.com/llvm/llvm-project f5cd181ffbb7cb61d582fe130d46580d5969d47a)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250111/202501111505.wNSI9zrC-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202501111505.wNSI9zrC-lkp@intel.com/

All errors (new ones prefixed by >>):

>> drivers/gpu/drm/meson/meson_drv.c:541:3: error: no member named 'dev' in 'struct device'; did you mean 'devt'?
     541 |                 drm_err(dev, "suspend error: %d", ret);
         |                 ^
   include/drm/drm_print.h:601:2: note: expanded from macro 'drm_err'
     601 |         __drm_printk((drm), err,, "*ERROR* " fmt, ##__VA_ARGS__)
         |         ^
   include/drm/drm_print.h:588:35: note: expanded from macro '__drm_printk'
     588 |         dev_##level##type((drm) ? (drm)->dev : NULL, "[drm] " fmt, ##__VA_ARGS__)
         |                                          ^
   include/linux/device.h:794:10: note: 'devt' declared here
     794 |         dev_t                   devt;   /* dev_t, creates the sysfs "dev" */
         |                                 ^
   1 error generated.


vim +541 drivers/gpu/drm/meson/meson_drv.c

   530	
   531	static int __maybe_unused meson_drv_pm_suspend(struct device *dev)
   532	{
   533		int ret;
   534		struct meson_drm *priv = dev_get_drvdata(dev);
   535	
   536		if (!priv)
   537			return 0;
   538	
   539		ret = drm_mode_config_helper_suspend(priv->drm);
   540		if (unlikely(ret)) {
 > 541			drm_err(dev, "suspend error: %d", ret);
   542			return ret;
   543		}
   544	
   545		meson_setup_clk(priv, false);
   546	
   547		return ret;
   548	}
   549
diff mbox series

Patch

diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
index 81d2ee37e7732dca89d02347b9c972300b38771a..d28094efeb137ae0b9990ab3608825d563358dba 100644
--- a/drivers/gpu/drm/meson/meson_drv.c
+++ b/drivers/gpu/drm/meson/meson_drv.c
@@ -11,6 +11,7 @@ 
 #include <linux/aperture.h>
 #include <linux/component.h>
 #include <linux/module.h>
+#include <linux/clk.h>
 #include <linux/of_graph.h>
 #include <linux/sys_soc.h>
 #include <linux/platform_device.h>
@@ -160,6 +161,34 @@  static void meson_vpu_init(struct meson_drm *priv)
 	writel_relaxed(value, priv->io_base + _REG(VPU_WRARB_MODE_L2C1));
 }
 
+static void meson_setup_clk(struct meson_drm *priv, bool enable)
+{
+	int ret;
+
+	if (!priv || !priv->vpu_clk || !priv->vapb_clk)
+		return;
+
+	if (!meson_vpu_is_compatible(priv, VPU_COMPATIBLE_S4))
+		return;
+
+	if (enable) {
+		ret = clk_prepare_enable(priv->vpu_clk);
+		if (ret) {
+			dev_err(priv->dev, "Failed to set vpu clk\n");
+			return;
+		}
+		ret = clk_prepare_enable(priv->vapb_clk);
+		if (ret) {
+			dev_err(priv->dev, "Failed to Set vapb clk\n");
+			clk_disable_unprepare(priv->vpu_clk);
+			return;
+		}
+	} else {
+		clk_disable_unprepare(priv->vpu_clk);
+		clk_disable_unprepare(priv->vapb_clk);
+	}
+}
+
 struct meson_drm_soc_attr {
 	struct meson_drm_soc_limits limits;
 	const struct soc_device_attribute *attrs;
@@ -241,6 +270,83 @@  static int meson_drv_bind_master(struct device *dev, bool has_components)
 		goto free_drm;
 	}
 
+	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_S4)) {
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sysctrl");
+		if (!res) {
+			ret = -EINVAL;
+			goto free_drm;
+		}
+		/* Simply ioremap since it may be a shared register zone */
+		regs = devm_ioremap(dev, res->start, resource_size(res));
+		if (!regs) {
+			ret = -EADDRNOTAVAIL;
+			goto free_drm;
+		}
+
+		priv->sysctrl = devm_regmap_init_mmio(dev, regs,
+						  &meson_regmap_config);
+		if (IS_ERR(priv->sysctrl)) {
+			dev_err(&pdev->dev, "Couldn't create the SYSCTRL regmap\n");
+			ret = PTR_ERR(priv->sysctrl);
+			goto free_drm;
+		}
+
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clkctrl");
+		if (!res) {
+			ret = -EINVAL;
+			goto free_drm;
+		}
+		/* Simply ioremap since it may be a shared register zone */
+		regs = devm_ioremap(dev, res->start, resource_size(res));
+		if (!regs) {
+			ret = -EADDRNOTAVAIL;
+			goto free_drm;
+		}
+
+		priv->clkctrl = devm_regmap_init_mmio(dev, regs,
+						  &meson_regmap_config);
+		if (IS_ERR(priv->clkctrl)) {
+			dev_err(&pdev->dev, "Couldn't create the clkctrl regmap\n");
+			ret = PTR_ERR(priv->clkctrl);
+			goto free_drm;
+		}
+
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwrctrl");
+		if (!res) {
+			ret = -EINVAL;
+			goto free_drm;
+		}
+		/* Simply ioremap since it may be a shared register zone */
+		regs = devm_ioremap(dev, res->start, resource_size(res));
+		if (!regs) {
+			ret = -EADDRNOTAVAIL;
+			goto free_drm;
+		}
+
+		priv->pwrctrl = devm_regmap_init_mmio(dev, regs,
+						  &meson_regmap_config);
+		if (IS_ERR(priv->pwrctrl)) {
+			dev_err(&pdev->dev, "Couldn't create the pwrctrl regmap\n");
+			ret = PTR_ERR(priv->pwrctrl);
+			goto free_drm;
+		}
+
+		priv->vpu_clk = devm_clk_get(&pdev->dev, "vpu");
+		if (IS_ERR(priv->vpu_clk)) {
+			dev_err(&pdev->dev, "vpu clock request failed\n");
+			ret = PTR_ERR(priv->vpu_clk);
+			goto free_drm;
+		}
+
+		priv->vapb_clk = devm_clk_get(&pdev->dev, "vapb");
+		if (IS_ERR(priv->vapb_clk)) {
+			dev_err(&pdev->dev, "vapb clock request failed\n");
+			ret = PTR_ERR(priv->vapb_clk);
+			goto free_drm;
+		}
+		meson_setup_clk(priv, true);
+	}
+
 	priv->canvas = meson_canvas_get(dev);
 	if (IS_ERR(priv->canvas)) {
 		ret = PTR_ERR(priv->canvas);
@@ -424,12 +530,21 @@  static const struct component_master_ops meson_drv_master_ops = {
 
 static int __maybe_unused meson_drv_pm_suspend(struct device *dev)
 {
+	int ret;
 	struct meson_drm *priv = dev_get_drvdata(dev);
 
 	if (!priv)
 		return 0;
 
-	return drm_mode_config_helper_suspend(priv->drm);
+	ret = drm_mode_config_helper_suspend(priv->drm);
+	if (unlikely(ret)) {
+		drm_err(dev, "suspend error: %d", ret);
+		return ret;
+	}
+
+	meson_setup_clk(priv, false);
+
+	return ret;
 }
 
 static int __maybe_unused meson_drv_pm_resume(struct device *dev)
@@ -439,6 +554,7 @@  static int __maybe_unused meson_drv_pm_resume(struct device *dev)
 	if (!priv)
 		return 0;
 
+	meson_setup_clk(priv, true);
 	meson_vpu_init(priv);
 	meson_venc_init(priv);
 	meson_vpp_init(priv);
@@ -458,6 +574,7 @@  static void meson_drv_shutdown(struct platform_device *pdev)
 
 	drm_kms_helper_poll_fini(priv->drm);
 	drm_atomic_helper_shutdown(priv->drm);
+	meson_setup_clk(priv, false);
 }
 
 /*
@@ -471,6 +588,7 @@  static const struct of_device_id components_dev_match[] = {
 	{ .compatible = "amlogic,meson-gxl-dw-hdmi" },
 	{ .compatible = "amlogic,meson-gxm-dw-hdmi" },
 	{ .compatible = "amlogic,meson-g12a-dw-hdmi" },
+	{ .compatible = "amlogic,meson-s4-dw-hdmi" },
 	{}
 };
 
@@ -539,6 +657,11 @@  static struct meson_drm_match_data meson_drm_g12a_data = {
 	.afbcd_ops = &meson_afbcd_g12a_ops,
 };
 
+static struct meson_drm_match_data meson_drm_s4_data = {
+	.compat = VPU_COMPATIBLE_S4,
+	.afbcd_ops = &meson_afbcd_g12a_ops,
+};
+
 static const struct of_device_id dt_match[] = {
 	{ .compatible = "amlogic,meson-gxbb-vpu",
 	  .data       = (void *)&meson_drm_gxbb_data },
@@ -548,6 +671,8 @@  static const struct of_device_id dt_match[] = {
 	  .data       = (void *)&meson_drm_gxm_data },
 	{ .compatible = "amlogic,meson-g12a-vpu",
 	  .data       = (void *)&meson_drm_g12a_data },
+	{ .compatible = "amlogic,meson-s4-vpu",
+	  .data       = (void *)&meson_drm_s4_data },
 	{}
 };
 MODULE_DEVICE_TABLE(of, dt_match);
diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h
index 3f9345c14f31c13b071f420533fe8a450d3e0f36..c801a2e3e55a054247710aebae5602e44c9e1624 100644
--- a/drivers/gpu/drm/meson/meson_drv.h
+++ b/drivers/gpu/drm/meson/meson_drv.h
@@ -22,6 +22,7 @@  enum vpu_compatible {
 	VPU_COMPATIBLE_GXL  = 1,
 	VPU_COMPATIBLE_GXM  = 2,
 	VPU_COMPATIBLE_G12A = 3,
+	VPU_COMPATIBLE_S4 = 4,
 };
 
 enum {
@@ -45,6 +46,11 @@  struct meson_drm {
 	enum vpu_compatible compat;
 	void __iomem *io_base;
 	struct regmap *hhi;
+	struct regmap *sysctrl;
+	struct regmap *clkctrl;
+	struct regmap *pwrctrl;
+	struct clk *vpu_clk;
+	struct clk *vapb_clk;
 	int vsync_irq;
 
 	struct meson_canvas *canvas;