diff mbox series

[RFC,18/28] drm: rcar-du: Add RZ/G2L LCDC Support

Message ID 20220112174612.10773-19-biju.das.jz@bp.renesas.com (mailing list archive)
State Superseded
Delegated to: Kieran Bingham
Headers show
Series Add RZ/G2L Display support | expand

Commit Message

Biju Das Jan. 12, 2022, 5:46 p.m. UTC
The LCD controller is composed of Frame Compression Processor (FCPVD),
Video Signal Processor (VSPD), and Display Unit (DU).

It has DPI/DSI interfaces and supports a maximum resolution of 1080p
along with 2 rpf's to support blending of two picture layers and
raster operations (ROPs).

A feature bit for RZ/G2L SoC is introduced to support RZ/G2L with
the rest of the SoC supported by this driver.

Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
 drivers/gpu/drm/rcar-du/rcar_du_crtc.c  | 148 ++++++++++++++++++------
 drivers/gpu/drm/rcar-du/rcar_du_crtc.h  |   2 +
 drivers/gpu/drm/rcar-du/rcar_du_drv.c   |  23 ++++
 drivers/gpu/drm/rcar-du/rcar_du_drv.h   |   1 +
 drivers/gpu/drm/rcar-du/rcar_du_group.c |   5 +
 drivers/gpu/drm/rcar-du/rcar_du_regs.h  |  52 +++++++++
 6 files changed, 195 insertions(+), 36 deletions(-)

Comments

Laurent Pinchart Jan. 23, 2022, 1:35 a.m. UTC | #1
Hi Biju,

Thank you for the patch.

On Wed, Jan 12, 2022 at 05:46:02PM +0000, Biju Das wrote:
> The LCD controller is composed of Frame Compression Processor (FCPVD),
> Video Signal Processor (VSPD), and Display Unit (DU).
> 
> It has DPI/DSI interfaces and supports a maximum resolution of 1080p
> along with 2 rpf's to support blending of two picture layers and
> raster operations (ROPs).
> 
> A feature bit for RZ/G2L SoC is introduced to support RZ/G2L with
> the rest of the SoC supported by this driver.

The RZ/G2L DU seems to be a completely different IP core than the DU in
R-Car and other RZ SoCs. I think it should be supported by a separate
driver, or at least with a different (and modularized) CRTC
implementation. This patch has too many RCAR_DU_FEATURE_RZG2L checks.

> Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
> ---
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.c  | 148 ++++++++++++++++++------
>  drivers/gpu/drm/rcar-du/rcar_du_crtc.h  |   2 +
>  drivers/gpu/drm/rcar-du/rcar_du_drv.c   |  23 ++++
>  drivers/gpu/drm/rcar-du/rcar_du_drv.h   |   1 +
>  drivers/gpu/drm/rcar-du/rcar_du_group.c |   5 +
>  drivers/gpu/drm/rcar-du/rcar_du_regs.h  |  52 +++++++++
>  6 files changed, 195 insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> index 521446890d3d..aea9178f3e7d 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> @@ -10,6 +10,7 @@
>  #include <linux/clk.h>
>  #include <linux/mutex.h>
>  #include <linux/platform_device.h>
> +#include <linux/reset.h>
>  #include <linux/sys_soc.h>
>  
>  #include <drm/drm_atomic.h>
> @@ -219,6 +220,42 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
>  	u32 dsmr;
>  	u32 escr;
>  
> +	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_RZG2L)) {
> +		u32 ditr0, ditr1, ditr2, ditr3, ditr4, ditr5, pbcr0;
> +
> +		clk_set_rate(rcrtc->extclock, mode_clock);
> +
> +		ditr0 = (DU_DITR0_DEMD_HIGH
> +		| ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? DU_DITR0_VSPOL : 0)
> +		| ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? DU_DITR0_HSPOL : 0));
> +
> +		ditr1 = DU_DITR1_VSA(mode->vsync_end - mode->vsync_start)
> +		      | DU_DITR1_VACTIVE(mode->vdisplay);
> +
> +		ditr2 = DU_DITR2_VBP(mode->vtotal - mode->vsync_end)
> +		      | DU_DITR2_VFP(mode->vsync_start - mode->vdisplay);
> +
> +		ditr3 = DU_DITR3_HSA(mode->hsync_end - mode->hsync_start)
> +		      | DU_DITR3_HACTIVE(mode->hdisplay);
> +
> +		ditr4 = DU_DITR4_HBP(mode->htotal - mode->hsync_end)
> +		      | DU_DITR4_HFP(mode->hsync_start - mode->hdisplay);
> +
> +		ditr5 = DU_DITR5_VSFT(0) | DU_DITR5_HSFT(0);
> +
> +		pbcr0 = DU_PBCR0_PB_DEP(0x1F);
> +
> +		rcar_du_write(rcdu, DU_DITR0, ditr0);
> +		rcar_du_write(rcdu, DU_DITR1, ditr1);
> +		rcar_du_write(rcdu, DU_DITR2, ditr2);
> +		rcar_du_write(rcdu, DU_DITR3, ditr3);
> +		rcar_du_write(rcdu, DU_DITR4, ditr4);
> +		rcar_du_write(rcdu, DU_DITR5, ditr5);
> +		rcar_du_write(rcdu, DU_PBCR0, pbcr0);
> +
> +		return;
> +	}
> +
>  	if (rcdu->info->dpll_mask & (1 << rcrtc->index)) {
>  		unsigned long target = mode_clock;
>  		struct dpll_info dpll = { 0 };
> @@ -531,16 +568,23 @@ static void rcar_du_cmm_setup(struct drm_crtc *crtc)
>  
>  static void rcar_du_crtc_setup(struct rcar_du_crtc *rcrtc)
>  {
> -	/* Set display off and background to black */
> -	rcar_du_crtc_write(rcrtc, DOOR, DOOR_RGB(0, 0, 0));
> -	rcar_du_crtc_write(rcrtc, BPOR, BPOR_RGB(0, 0, 0));
> +	struct rcar_du_device *rcdu = rcrtc->dev;
>  
> -	/* Configure display timings and output routing */
> -	rcar_du_crtc_set_display_timing(rcrtc);
> -	rcar_du_group_set_routing(rcrtc->group);
> +	if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_RZG2L)) {
> +		/* Set display off and background to black */
> +		rcar_du_crtc_write(rcrtc, DOOR, DOOR_RGB(0, 0, 0));
> +		rcar_du_crtc_write(rcrtc, BPOR, BPOR_RGB(0, 0, 0));
>  
> -	/* Start with all planes disabled. */
> -	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
> +		/* Configure display timings and output routing */
> +		rcar_du_crtc_set_display_timing(rcrtc);
> +		rcar_du_group_set_routing(rcrtc->group);
> +
> +		/* Start with all planes disabled. */
> +		rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
> +	} else {
> +		/* Configure display timings and output routing */
> +		rcar_du_crtc_set_display_timing(rcrtc);
> +	}
>  
>  	/* Enable the VSP compositor. */
>  	if (rcar_du_has(rcrtc->dev, RCAR_DU_FEATURE_VSP1_SOURCE))
> @@ -561,6 +605,12 @@ static int rcar_du_crtc_get(struct rcar_du_crtc *rcrtc)
>  	if (rcrtc->initialized)
>  		return 0;
>  
> +	if (rcrtc->rstc) {
> +		ret = reset_control_deassert(rcrtc->rstc);
> +		if (ret < 0)
> +			goto error_reset;
> +	}
> +
>  	ret = clk_prepare_enable(rcrtc->clock);
>  	if (ret < 0)
>  		return ret;
> @@ -582,6 +632,9 @@ static int rcar_du_crtc_get(struct rcar_du_crtc *rcrtc)
>  	clk_disable_unprepare(rcrtc->extclock);
>  error_clock:
>  	clk_disable_unprepare(rcrtc->clock);
> +error_reset:
> +	if (rcrtc->rstc)
> +		reset_control_assert(rcrtc->rstc);
>  	return ret;
>  }
>  
> @@ -591,23 +644,28 @@ static void rcar_du_crtc_put(struct rcar_du_crtc *rcrtc)
>  
>  	clk_disable_unprepare(rcrtc->extclock);
>  	clk_disable_unprepare(rcrtc->clock);
> +	if (rcrtc->rstc)
> +		reset_control_assert(rcrtc->rstc);
>  
>  	rcrtc->initialized = false;
>  }
>  
>  static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
>  {
> +	struct rcar_du_device *rcdu = rcrtc->dev;
>  	bool interlaced;
>  
> -	/*
> -	 * Select master sync mode. This enables display operation in master
> -	 * sync mode (with the HSYNC and VSYNC signals configured as outputs and
> -	 * actively driven).
> -	 */
> -	interlaced = rcrtc->crtc.mode.flags & DRM_MODE_FLAG_INTERLACE;
> -	rcar_du_crtc_dsysr_clr_set(rcrtc, DSYSR_TVM_MASK | DSYSR_SCM_MASK,
> -				   (interlaced ? DSYSR_SCM_INT_VIDEO : 0) |
> -				   DSYSR_TVM_MASTER);
> +	if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_RZG2L)) {
> +		/*
> +		 * Select master sync mode. This enables display operation in master
> +		 * sync mode (with the HSYNC and VSYNC signals configured as outputs and
> +		 * actively driven).
> +		 */
> +		interlaced = rcrtc->crtc.mode.flags & DRM_MODE_FLAG_INTERLACE;
> +		rcar_du_crtc_dsysr_clr_set(rcrtc, DSYSR_TVM_MASK | DSYSR_SCM_MASK,
> +					   (interlaced ? DSYSR_SCM_INT_VIDEO : 0) |
> +					   DSYSR_TVM_MASTER);
> +	}
>  
>  	rcar_du_group_start_stop(rcrtc->group, true);
>  }
> @@ -1229,6 +1287,14 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex,
>  		name = NULL;
>  	}
>  
> +	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_RZG2L)) {
> +		rcrtc->rstc = devm_reset_control_get_shared(rcdu->dev, NULL);
> +		if (IS_ERR(rcrtc->rstc)) {
> +			dev_err(rcdu->dev, "can't get cpg reset\n");
> +			return PTR_ERR(rcrtc->rstc);
> +		}
> +	}
> +
>  	rcrtc->clock = devm_clk_get(rcdu->dev, name);
>  	if (IS_ERR(rcrtc->clock)) {
>  		dev_err(rcdu->dev, "no clock for DU channel %u\n", hwindex);
> @@ -1251,6 +1317,14 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex,
>  		return ret;
>  	}
>  
> +	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_RZG2L)) {
> +		clk = devm_clk_get(rcdu->dev, "vclk");
> +		if (!IS_ERR(clk))
> +			rcrtc->extclock = clk;
> +		else if (PTR_ERR(clk) == -EPROBE_DEFER)
> +			return -EPROBE_DEFER;
> +	}
> +
>  	init_waitqueue_head(&rcrtc->flip_wait);
>  	init_waitqueue_head(&rcrtc->vblank_wait);
>  	spin_lock_init(&rcrtc->vblank_lock);
> @@ -1287,27 +1361,29 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex,
>  
>  	drm_crtc_helper_add(crtc, &crtc_helper_funcs);
>  
> -	/* Register the interrupt handler. */
> -	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CRTC_IRQ)) {
> -		/* The IRQ's are associated with the CRTC (sw)index. */
> -		irq = platform_get_irq(pdev, swindex);
> -		irqflags = 0;
> -	} else {
> -		irq = platform_get_irq(pdev, 0);
> -		irqflags = IRQF_SHARED;
> -	}
> +	if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_RZG2L)) {
> +		/* Register the interrupt handler. */
> +		if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CRTC_IRQ)) {
> +			/* The IRQ's are associated with the CRTC (sw)index. */
> +			irq = platform_get_irq(pdev, swindex);
> +			irqflags = 0;
> +		} else {
> +			irq = platform_get_irq(pdev, 0);
> +			irqflags = IRQF_SHARED;
> +		}
>  
> -	if (irq < 0) {
> -		dev_err(rcdu->dev, "no IRQ for CRTC %u\n", swindex);
> -		return irq;
> -	}
> +		if (irq < 0) {
> +			dev_err(rcdu->dev, "no IRQ for CRTC %u\n", swindex);
> +			return irq;
> +		}
>  
> -	ret = devm_request_irq(rcdu->dev, irq, rcar_du_crtc_irq, irqflags,
> -			       dev_name(rcdu->dev), rcrtc);
> -	if (ret < 0) {
> -		dev_err(rcdu->dev,
> -			"failed to register IRQ for CRTC %u\n", swindex);
> -		return ret;
> +		ret = devm_request_irq(rcdu->dev, irq, rcar_du_crtc_irq, irqflags,
> +				       dev_name(rcdu->dev), rcrtc);
> +		if (ret < 0) {
> +			dev_err(rcdu->dev,
> +				"failed to register IRQ for CRTC %u\n", swindex);
> +			return ret;
> +		}
>  	}
>  
>  	rcar_du_crtc_crc_init(rcrtc);
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
> index 66e8839db708..4ec2db46b131 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
> @@ -28,6 +28,7 @@ struct rcar_du_vsp;
>   * @dev: the DU device
>   * @clock: the CRTC functional clock
>   * @extclock: external pixel dot clock (optional)
> + * @rstc: reset controller (optional)
>   * @mmio_offset: offset of the CRTC registers in the DU MMIO block
>   * @index: CRTC hardware index
>   * @initialized: whether the CRTC has been initialized and clocks enabled
> @@ -50,6 +51,7 @@ struct rcar_du_crtc {
>  	struct rcar_du_device *dev;
>  	struct clk *clock;
>  	struct clk *extclock;
> +	struct reset_control *rstc;
>  	unsigned int mmio_offset;
>  	unsigned int index;
>  	bool initialized;
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> index f92636001f10..57edc3b3154f 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> @@ -596,6 +596,28 @@ static const struct rcar_du_device_info rcar_du_r8a779a0_info = {
>  	.dsi_clk_mask =  BIT(1) | BIT(0),
>  };
>  
> +static const struct rcar_du_device_info rcar_du_r9a07g044l_info = {
> +	.gen = 3,
> +	.features = RCAR_DU_FEATURE_CRTC_IRQ
> +		  | RCAR_DU_FEATURE_CRTC_CLOCK
> +		  | RCAR_DU_FEATURE_RZG2L
> +		  | RCAR_DU_FEATURE_VSP1_SOURCE,
> +	.channels_mask = BIT(0),
> +	.routes = {
> +		[RCAR_DU_OUTPUT_DPAD0] = {
> +			.possible_crtcs = BIT(0),
> +			.port = 0,
> +		},
> +		[RCAR_DU_OUTPUT_DSI0] = {
> +			.possible_crtcs = BIT(0),
> +			.port = 1,
> +		},
> +	},
> +	.num_rpf = 2,
> +	.max_width = 1920,
> +	.max_height = 1080,
> +};
> +
>  static const struct of_device_id rcar_du_of_table[] = {
>  	{ .compatible = "renesas,du-r8a7742", .data = &rcar_du_r8a7790_info },
>  	{ .compatible = "renesas,du-r8a7743", .data = &rzg1_du_r8a7743_info },
> @@ -621,6 +643,7 @@ static const struct of_device_id rcar_du_of_table[] = {
>  	{ .compatible = "renesas,du-r8a77990", .data = &rcar_du_r8a7799x_info },
>  	{ .compatible = "renesas,du-r8a77995", .data = &rcar_du_r8a7799x_info },
>  	{ .compatible = "renesas,du-r8a779a0", .data = &rcar_du_r8a779a0_info },
> +	{ .compatible = "renesas,du-r9a07g044l", .data = &rcar_du_r9a07g044l_info },
>  	{ }
>  };
>  
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
> index e28c2df66f8e..47da9da71bca 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
> @@ -33,6 +33,7 @@ struct rcar_du_device;
>  #define RCAR_DU_FEATURE_TVM_SYNC	BIT(4)	/* Has TV switch/sync modes */
>  #define RCAR_DU_FEATURE_PLANE		BIT(5)	/* HW supports DU planes */
>  #define RCAR_DU_FEATURE_GROUP		BIT(6)	/* HW supports DU groups */
> +#define RCAR_DU_FEATURE_RZG2L		BIT(7)	/* Use RZ/G2L registers */
>  
>  #define RCAR_DU_QUIRK_ALIGN_128B	BIT(0)	/* Align pitches to 128 bytes */
>  
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c
> index 3612bc9eab1b..632271c2881d 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_group.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c
> @@ -224,6 +224,11 @@ static void __rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start)
>  {
>  	struct rcar_du_device *rcdu = rgrp->dev;
>  
> +	if (!rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_GROUP)) {
> +		rcar_du_write(rgrp->dev, DU_MCR0, start ? DU_MCR0_DI_EN : 0);
> +		return;
> +	}
> +
>  	/*
>  	 * Group start/stop is controlled by the DRES and DEN bits of DSYSR0
>  	 * for the first group and DSYSR2 for the second group. On most DU
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_regs.h b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
> index 1cdaa51eb9ac..9e5c8d286bfc 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_regs.h
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
> @@ -15,6 +15,58 @@
>  #define DU2_REG_OFFSET		0x40000
>  #define DU3_REG_OFFSET		0x70000
>  
> +/* -----------------------------------------------------------------------------
> + * RZ/G2L Display Registers
> + */
> +
> +#define DU_MCR0			0x00
> +#define DU_MCR0_DPI_OE		BIT(0)
> +#define DU_MCR0_DI_EN		BIT(8)
> +#define DU_MCR0_PB_CLR		BIT(16)
> +
> +#define DU_MSR0			0x04
> +#define DU_MSR0_ST_DI_BSY	BIT(8)
> +#define DU_MSR0_ST_PB_WFULL	BIT(16)
> +#define DU_MSR0_ST_PB_WINIT	BIT(18)
> +#define DU_MSR0_ST_PB_REMPTY	BIT(20)
> +#define DU_MSR0_ST_PB_RUF	BIT(21)
> +#define DU_MSR0_ST_PB_RINIT	BIT(22)
> +
> +#define DU_MSR1			0x08
> +
> +#define DU_IMR0			0x0C
> +#define DU_MSR0_IM_PB_RUF	BIT(0)
> +
> +#define DU_DITR0		0x10
> +#define DU_DITR0_DPI_CLKMD	BIT(0)
> +#define DU_DITR0_DEMD_LOW	0x0
> +#define DU_DITR0_DEMD_HIGH	(BIT(8) | BIT(9))
> +#define DU_DITR0_VSPOL		BIT(16)
> +#define DU_DITR0_HSPOL		BIT(17)
> +
> +#define DU_DITR1		0x14
> +#define DU_DITR1_VSA(x)		((x) << 0)
> +#define DU_DITR1_VACTIVE(x)	((x) << 16)
> +
> +#define DU_DITR2		0x18
> +#define DU_DITR2_VBP(x)		((x) << 0)
> +#define DU_DITR2_VFP(x)		((x) << 16)
> +
> +#define DU_DITR3		0x1C
> +#define DU_DITR3_HSA(x)		((x) << 0)
> +#define DU_DITR3_HACTIVE(x)	((x) << 16)
> +
> +#define DU_DITR4		0x20
> +#define DU_DITR4_HBP(x)		((x) << 0)
> +#define DU_DITR4_HFP(x)		((x) << 16)
> +
> +#define DU_DITR5		0x24
> +#define DU_DITR5_VSFT(x)	((x) << 0)
> +#define DU_DITR5_HSFT(x)	((x) << 16)
> +
> +#define DU_PBCR0		0x4C
> +#define DU_PBCR0_PB_DEP(x)	((x) << 0)
> +
>  /* -----------------------------------------------------------------------------
>   * Display Control Registers
>   */
Biju Das March 8, 2022, 6:54 p.m. UTC | #2
Hi Laurent,

Thanks for the feedback.

> Subject: Re: [RFC 18/28] drm: rcar-du: Add RZ/G2L LCDC Support
> 
> Hi Biju,
> 
> Thank you for the patch.
> 
> On Wed, Jan 12, 2022 at 05:46:02PM +0000, Biju Das wrote:
> > The LCD controller is composed of Frame Compression Processor (FCPVD),
> > Video Signal Processor (VSPD), and Display Unit (DU).
> >
> > It has DPI/DSI interfaces and supports a maximum resolution of 1080p
> > along with 2 rpf's to support blending of two picture layers and
> > raster operations (ROPs).
> >
> > A feature bit for RZ/G2L SoC is introduced to support RZ/G2L with the
> > rest of the SoC supported by this driver.
> 
> The RZ/G2L DU seems to be a completely different IP core than the DU in R-
> Car and other RZ SoCs. I think it should be supported by a separate
> driver, or at least with a different (and modularized) CRTC
> implementation. This patch has too many RCAR_DU_FEATURE_RZG2L checks.

Agreed, May be will create separate RZ/G2L specific DU driver based on RCar-DU
driver removing the plane, Group, CMM, LVDS, HDMI and CRTC adaptation for RZ/G2L 
and will send next version for feedback.

Regards,
Biju


> 
> > Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
> > ---
> >  drivers/gpu/drm/rcar-du/rcar_du_crtc.c  | 148 ++++++++++++++++++------
> >  drivers/gpu/drm/rcar-du/rcar_du_crtc.h  |   2 +
> >  drivers/gpu/drm/rcar-du/rcar_du_drv.c   |  23 ++++
> >  drivers/gpu/drm/rcar-du/rcar_du_drv.h   |   1 +
> >  drivers/gpu/drm/rcar-du/rcar_du_group.c |   5 +
> >  drivers/gpu/drm/rcar-du/rcar_du_regs.h  |  52 +++++++++
> >  6 files changed, 195 insertions(+), 36 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> > b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> > index 521446890d3d..aea9178f3e7d 100644
> > --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> > +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
> > @@ -10,6 +10,7 @@
> >  #include <linux/clk.h>
> >  #include <linux/mutex.h>
> >  #include <linux/platform_device.h>
> > +#include <linux/reset.h>
> >  #include <linux/sys_soc.h>
> >
> >  #include <drm/drm_atomic.h>
> > @@ -219,6 +220,42 @@ static void rcar_du_crtc_set_display_timing(struct
> rcar_du_crtc *rcrtc)
> >  	u32 dsmr;
> >  	u32 escr;
> >
> > +	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_RZG2L)) {
> > +		u32 ditr0, ditr1, ditr2, ditr3, ditr4, ditr5, pbcr0;
> > +
> > +		clk_set_rate(rcrtc->extclock, mode_clock);
> > +
> > +		ditr0 = (DU_DITR0_DEMD_HIGH
> > +		| ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? DU_DITR0_VSPOL : 0)
> > +		| ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? DU_DITR0_HSPOL :
> 0));
> > +
> > +		ditr1 = DU_DITR1_VSA(mode->vsync_end - mode->vsync_start)
> > +		      | DU_DITR1_VACTIVE(mode->vdisplay);
> > +
> > +		ditr2 = DU_DITR2_VBP(mode->vtotal - mode->vsync_end)
> > +		      | DU_DITR2_VFP(mode->vsync_start - mode->vdisplay);
> > +
> > +		ditr3 = DU_DITR3_HSA(mode->hsync_end - mode->hsync_start)
> > +		      | DU_DITR3_HACTIVE(mode->hdisplay);
> > +
> > +		ditr4 = DU_DITR4_HBP(mode->htotal - mode->hsync_end)
> > +		      | DU_DITR4_HFP(mode->hsync_start - mode->hdisplay);
> > +
> > +		ditr5 = DU_DITR5_VSFT(0) | DU_DITR5_HSFT(0);
> > +
> > +		pbcr0 = DU_PBCR0_PB_DEP(0x1F);
> > +
> > +		rcar_du_write(rcdu, DU_DITR0, ditr0);
> > +		rcar_du_write(rcdu, DU_DITR1, ditr1);
> > +		rcar_du_write(rcdu, DU_DITR2, ditr2);
> > +		rcar_du_write(rcdu, DU_DITR3, ditr3);
> > +		rcar_du_write(rcdu, DU_DITR4, ditr4);
> > +		rcar_du_write(rcdu, DU_DITR5, ditr5);
> > +		rcar_du_write(rcdu, DU_PBCR0, pbcr0);
> > +
> > +		return;
> > +	}
> > +
> >  	if (rcdu->info->dpll_mask & (1 << rcrtc->index)) {
> >  		unsigned long target = mode_clock;
> >  		struct dpll_info dpll = { 0 };
> > @@ -531,16 +568,23 @@ static void rcar_du_cmm_setup(struct drm_crtc
> > *crtc)
> >
> >  static void rcar_du_crtc_setup(struct rcar_du_crtc *rcrtc)  {
> > -	/* Set display off and background to black */
> > -	rcar_du_crtc_write(rcrtc, DOOR, DOOR_RGB(0, 0, 0));
> > -	rcar_du_crtc_write(rcrtc, BPOR, BPOR_RGB(0, 0, 0));
> > +	struct rcar_du_device *rcdu = rcrtc->dev;
> >
> > -	/* Configure display timings and output routing */
> > -	rcar_du_crtc_set_display_timing(rcrtc);
> > -	rcar_du_group_set_routing(rcrtc->group);
> > +	if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_RZG2L)) {
> > +		/* Set display off and background to black */
> > +		rcar_du_crtc_write(rcrtc, DOOR, DOOR_RGB(0, 0, 0));
> > +		rcar_du_crtc_write(rcrtc, BPOR, BPOR_RGB(0, 0, 0));
> >
> > -	/* Start with all planes disabled. */
> > -	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR,
> 0);
> > +		/* Configure display timings and output routing */
> > +		rcar_du_crtc_set_display_timing(rcrtc);
> > +		rcar_du_group_set_routing(rcrtc->group);
> > +
> > +		/* Start with all planes disabled. */
> > +		rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR :
> DS1PR, 0);
> > +	} else {
> > +		/* Configure display timings and output routing */
> > +		rcar_du_crtc_set_display_timing(rcrtc);
> > +	}
> >
> >  	/* Enable the VSP compositor. */
> >  	if (rcar_du_has(rcrtc->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) @@ -561,6
> > +605,12 @@ static int rcar_du_crtc_get(struct rcar_du_crtc *rcrtc)
> >  	if (rcrtc->initialized)
> >  		return 0;
> >
> > +	if (rcrtc->rstc) {
> > +		ret = reset_control_deassert(rcrtc->rstc);
> > +		if (ret < 0)
> > +			goto error_reset;
> > +	}
> > +
> >  	ret = clk_prepare_enable(rcrtc->clock);
> >  	if (ret < 0)
> >  		return ret;
> > @@ -582,6 +632,9 @@ static int rcar_du_crtc_get(struct rcar_du_crtc
> *rcrtc)
> >  	clk_disable_unprepare(rcrtc->extclock);
> >  error_clock:
> >  	clk_disable_unprepare(rcrtc->clock);
> > +error_reset:
> > +	if (rcrtc->rstc)
> > +		reset_control_assert(rcrtc->rstc);
> >  	return ret;
> >  }
> >
> > @@ -591,23 +644,28 @@ static void rcar_du_crtc_put(struct rcar_du_crtc
> > *rcrtc)
> >
> >  	clk_disable_unprepare(rcrtc->extclock);
> >  	clk_disable_unprepare(rcrtc->clock);
> > +	if (rcrtc->rstc)
> > +		reset_control_assert(rcrtc->rstc);
> >
> >  	rcrtc->initialized = false;
> >  }
> >
> >  static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)  {
> > +	struct rcar_du_device *rcdu = rcrtc->dev;
> >  	bool interlaced;
> >
> > -	/*
> > -	 * Select master sync mode. This enables display operation in master
> > -	 * sync mode (with the HSYNC and VSYNC signals configured as outputs
> and
> > -	 * actively driven).
> > -	 */
> > -	interlaced = rcrtc->crtc.mode.flags & DRM_MODE_FLAG_INTERLACE;
> > -	rcar_du_crtc_dsysr_clr_set(rcrtc, DSYSR_TVM_MASK | DSYSR_SCM_MASK,
> > -				   (interlaced ? DSYSR_SCM_INT_VIDEO : 0) |
> > -				   DSYSR_TVM_MASTER);
> > +	if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_RZG2L)) {
> > +		/*
> > +		 * Select master sync mode. This enables display operation in
> master
> > +		 * sync mode (with the HSYNC and VSYNC signals configured as
> outputs and
> > +		 * actively driven).
> > +		 */
> > +		interlaced = rcrtc->crtc.mode.flags & DRM_MODE_FLAG_INTERLACE;
> > +		rcar_du_crtc_dsysr_clr_set(rcrtc, DSYSR_TVM_MASK |
> DSYSR_SCM_MASK,
> > +					   (interlaced ? DSYSR_SCM_INT_VIDEO : 0) |
> > +					   DSYSR_TVM_MASTER);
> > +	}
> >
> >  	rcar_du_group_start_stop(rcrtc->group, true);  } @@ -1229,6 +1287,14
> > @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int
> swindex,
> >  		name = NULL;
> >  	}
> >
> > +	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_RZG2L)) {
> > +		rcrtc->rstc = devm_reset_control_get_shared(rcdu->dev, NULL);
> > +		if (IS_ERR(rcrtc->rstc)) {
> > +			dev_err(rcdu->dev, "can't get cpg reset\n");
> > +			return PTR_ERR(rcrtc->rstc);
> > +		}
> > +	}
> > +
> >  	rcrtc->clock = devm_clk_get(rcdu->dev, name);
> >  	if (IS_ERR(rcrtc->clock)) {
> >  		dev_err(rcdu->dev, "no clock for DU channel %u\n", hwindex);
> @@
> > -1251,6 +1317,14 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp,
> unsigned int swindex,
> >  		return ret;
> >  	}
> >
> > +	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_RZG2L)) {
> > +		clk = devm_clk_get(rcdu->dev, "vclk");
> > +		if (!IS_ERR(clk))
> > +			rcrtc->extclock = clk;
> > +		else if (PTR_ERR(clk) == -EPROBE_DEFER)
> > +			return -EPROBE_DEFER;
> > +	}
> > +
> >  	init_waitqueue_head(&rcrtc->flip_wait);
> >  	init_waitqueue_head(&rcrtc->vblank_wait);
> >  	spin_lock_init(&rcrtc->vblank_lock);
> > @@ -1287,27 +1361,29 @@ int rcar_du_crtc_create(struct rcar_du_group
> > *rgrp, unsigned int swindex,
> >
> >  	drm_crtc_helper_add(crtc, &crtc_helper_funcs);
> >
> > -	/* Register the interrupt handler. */
> > -	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CRTC_IRQ)) {
> > -		/* The IRQ's are associated with the CRTC (sw)index. */
> > -		irq = platform_get_irq(pdev, swindex);
> > -		irqflags = 0;
> > -	} else {
> > -		irq = platform_get_irq(pdev, 0);
> > -		irqflags = IRQF_SHARED;
> > -	}
> > +	if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_RZG2L)) {
> > +		/* Register the interrupt handler. */
> > +		if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CRTC_IRQ)) {
> > +			/* The IRQ's are associated with the CRTC (sw)index. */
> > +			irq = platform_get_irq(pdev, swindex);
> > +			irqflags = 0;
> > +		} else {
> > +			irq = platform_get_irq(pdev, 0);
> > +			irqflags = IRQF_SHARED;
> > +		}
> >
> > -	if (irq < 0) {
> > -		dev_err(rcdu->dev, "no IRQ for CRTC %u\n", swindex);
> > -		return irq;
> > -	}
> > +		if (irq < 0) {
> > +			dev_err(rcdu->dev, "no IRQ for CRTC %u\n", swindex);
> > +			return irq;
> > +		}
> >
> > -	ret = devm_request_irq(rcdu->dev, irq, rcar_du_crtc_irq, irqflags,
> > -			       dev_name(rcdu->dev), rcrtc);
> > -	if (ret < 0) {
> > -		dev_err(rcdu->dev,
> > -			"failed to register IRQ for CRTC %u\n", swindex);
> > -		return ret;
> > +		ret = devm_request_irq(rcdu->dev, irq, rcar_du_crtc_irq,
> irqflags,
> > +				       dev_name(rcdu->dev), rcrtc);
> > +		if (ret < 0) {
> > +			dev_err(rcdu->dev,
> > +				"failed to register IRQ for CRTC %u\n", swindex);
> > +			return ret;
> > +		}
> >  	}
> >
> >  	rcar_du_crtc_crc_init(rcrtc);
> > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
> > b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
> > index 66e8839db708..4ec2db46b131 100644
> > --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
> > +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
> > @@ -28,6 +28,7 @@ struct rcar_du_vsp;
> >   * @dev: the DU device
> >   * @clock: the CRTC functional clock
> >   * @extclock: external pixel dot clock (optional)
> > + * @rstc: reset controller (optional)
> >   * @mmio_offset: offset of the CRTC registers in the DU MMIO block
> >   * @index: CRTC hardware index
> >   * @initialized: whether the CRTC has been initialized and clocks
> > enabled @@ -50,6 +51,7 @@ struct rcar_du_crtc {
> >  	struct rcar_du_device *dev;
> >  	struct clk *clock;
> >  	struct clk *extclock;
> > +	struct reset_control *rstc;
> >  	unsigned int mmio_offset;
> >  	unsigned int index;
> >  	bool initialized;
> > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> > b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> > index f92636001f10..57edc3b3154f 100644
> > --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> > +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
> > @@ -596,6 +596,28 @@ static const struct rcar_du_device_info
> rcar_du_r8a779a0_info = {
> >  	.dsi_clk_mask =  BIT(1) | BIT(0),
> >  };
> >
> > +static const struct rcar_du_device_info rcar_du_r9a07g044l_info = {
> > +	.gen = 3,
> > +	.features = RCAR_DU_FEATURE_CRTC_IRQ
> > +		  | RCAR_DU_FEATURE_CRTC_CLOCK
> > +		  | RCAR_DU_FEATURE_RZG2L
> > +		  | RCAR_DU_FEATURE_VSP1_SOURCE,
> > +	.channels_mask = BIT(0),
> > +	.routes = {
> > +		[RCAR_DU_OUTPUT_DPAD0] = {
> > +			.possible_crtcs = BIT(0),
> > +			.port = 0,
> > +		},
> > +		[RCAR_DU_OUTPUT_DSI0] = {
> > +			.possible_crtcs = BIT(0),
> > +			.port = 1,
> > +		},
> > +	},
> > +	.num_rpf = 2,
> > +	.max_width = 1920,
> > +	.max_height = 1080,
> > +};
> > +
> >  static const struct of_device_id rcar_du_of_table[] = {
> >  	{ .compatible = "renesas,du-r8a7742", .data = &rcar_du_r8a7790_info
> },
> >  	{ .compatible = "renesas,du-r8a7743", .data = &rzg1_du_r8a7743_info
> > }, @@ -621,6 +643,7 @@ static const struct of_device_id
> rcar_du_of_table[] = {
> >  	{ .compatible = "renesas,du-r8a77990", .data =
> &rcar_du_r8a7799x_info },
> >  	{ .compatible = "renesas,du-r8a77995", .data =
> &rcar_du_r8a7799x_info },
> >  	{ .compatible = "renesas,du-r8a779a0", .data =
> > &rcar_du_r8a779a0_info },
> > +	{ .compatible = "renesas,du-r9a07g044l", .data =
> > +&rcar_du_r9a07g044l_info },
> >  	{ }
> >  };
> >
> > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h
> > b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
> > index e28c2df66f8e..47da9da71bca 100644
> > --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h
> > +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
> > @@ -33,6 +33,7 @@ struct rcar_du_device;
> >  #define RCAR_DU_FEATURE_TVM_SYNC	BIT(4)	/* Has TV switch/sync
> modes */
> >  #define RCAR_DU_FEATURE_PLANE		BIT(5)	/* HW supports DU
> planes */
> >  #define RCAR_DU_FEATURE_GROUP		BIT(6)	/* HW supports DU
> groups */
> > +#define RCAR_DU_FEATURE_RZG2L		BIT(7)	/* Use RZ/G2L
> registers */
> >
> >  #define RCAR_DU_QUIRK_ALIGN_128B	BIT(0)	/* Align pitches to 128
> bytes */
> >
> > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c
> > b/drivers/gpu/drm/rcar-du/rcar_du_group.c
> > index 3612bc9eab1b..632271c2881d 100644
> > --- a/drivers/gpu/drm/rcar-du/rcar_du_group.c
> > +++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c
> > @@ -224,6 +224,11 @@ static void __rcar_du_group_start_stop(struct
> > rcar_du_group *rgrp, bool start)  {
> >  	struct rcar_du_device *rcdu = rgrp->dev;
> >
> > +	if (!rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_GROUP)) {
> > +		rcar_du_write(rgrp->dev, DU_MCR0, start ? DU_MCR0_DI_EN : 0);
> > +		return;
> > +	}
> > +
> >  	/*
> >  	 * Group start/stop is controlled by the DRES and DEN bits of DSYSR0
> >  	 * for the first group and DSYSR2 for the second group. On most DU
> > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_regs.h
> > b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
> > index 1cdaa51eb9ac..9e5c8d286bfc 100644
> > --- a/drivers/gpu/drm/rcar-du/rcar_du_regs.h
> > +++ b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
> > @@ -15,6 +15,58 @@
> >  #define DU2_REG_OFFSET		0x40000
> >  #define DU3_REG_OFFSET		0x70000
> >
> > +/*
> > +---------------------------------------------------------------------
> > +--------
> > + * RZ/G2L Display Registers
> > + */
> > +
> > +#define DU_MCR0			0x00
> > +#define DU_MCR0_DPI_OE		BIT(0)
> > +#define DU_MCR0_DI_EN		BIT(8)
> > +#define DU_MCR0_PB_CLR		BIT(16)
> > +
> > +#define DU_MSR0			0x04
> > +#define DU_MSR0_ST_DI_BSY	BIT(8)
> > +#define DU_MSR0_ST_PB_WFULL	BIT(16)
> > +#define DU_MSR0_ST_PB_WINIT	BIT(18)
> > +#define DU_MSR0_ST_PB_REMPTY	BIT(20)
> > +#define DU_MSR0_ST_PB_RUF	BIT(21)
> > +#define DU_MSR0_ST_PB_RINIT	BIT(22)
> > +
> > +#define DU_MSR1			0x08
> > +
> > +#define DU_IMR0			0x0C
> > +#define DU_MSR0_IM_PB_RUF	BIT(0)
> > +
> > +#define DU_DITR0		0x10
> > +#define DU_DITR0_DPI_CLKMD	BIT(0)
> > +#define DU_DITR0_DEMD_LOW	0x0
> > +#define DU_DITR0_DEMD_HIGH	(BIT(8) | BIT(9))
> > +#define DU_DITR0_VSPOL		BIT(16)
> > +#define DU_DITR0_HSPOL		BIT(17)
> > +
> > +#define DU_DITR1		0x14
> > +#define DU_DITR1_VSA(x)		((x) << 0)
> > +#define DU_DITR1_VACTIVE(x)	((x) << 16)
> > +
> > +#define DU_DITR2		0x18
> > +#define DU_DITR2_VBP(x)		((x) << 0)
> > +#define DU_DITR2_VFP(x)		((x) << 16)
> > +
> > +#define DU_DITR3		0x1C
> > +#define DU_DITR3_HSA(x)		((x) << 0)
> > +#define DU_DITR3_HACTIVE(x)	((x) << 16)
> > +
> > +#define DU_DITR4		0x20
> > +#define DU_DITR4_HBP(x)		((x) << 0)
> > +#define DU_DITR4_HFP(x)		((x) << 16)
> > +
> > +#define DU_DITR5		0x24
> > +#define DU_DITR5_VSFT(x)	((x) << 0)
> > +#define DU_DITR5_HSFT(x)	((x) << 16)
> > +
> > +#define DU_PBCR0		0x4C
> > +#define DU_PBCR0_PB_DEP(x)	((x) << 0)
> > +
> >  /* --------------------------------------------------------------------
> ---------
> >   * Display Control Registers
> >   */
> 
> --
> Regards,
> 
> Laurent Pinchart
diff mbox series

Patch

diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 521446890d3d..aea9178f3e7d 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -10,6 +10,7 @@ 
 #include <linux/clk.h>
 #include <linux/mutex.h>
 #include <linux/platform_device.h>
+#include <linux/reset.h>
 #include <linux/sys_soc.h>
 
 #include <drm/drm_atomic.h>
@@ -219,6 +220,42 @@  static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
 	u32 dsmr;
 	u32 escr;
 
+	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_RZG2L)) {
+		u32 ditr0, ditr1, ditr2, ditr3, ditr4, ditr5, pbcr0;
+
+		clk_set_rate(rcrtc->extclock, mode_clock);
+
+		ditr0 = (DU_DITR0_DEMD_HIGH
+		| ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? DU_DITR0_VSPOL : 0)
+		| ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? DU_DITR0_HSPOL : 0));
+
+		ditr1 = DU_DITR1_VSA(mode->vsync_end - mode->vsync_start)
+		      | DU_DITR1_VACTIVE(mode->vdisplay);
+
+		ditr2 = DU_DITR2_VBP(mode->vtotal - mode->vsync_end)
+		      | DU_DITR2_VFP(mode->vsync_start - mode->vdisplay);
+
+		ditr3 = DU_DITR3_HSA(mode->hsync_end - mode->hsync_start)
+		      | DU_DITR3_HACTIVE(mode->hdisplay);
+
+		ditr4 = DU_DITR4_HBP(mode->htotal - mode->hsync_end)
+		      | DU_DITR4_HFP(mode->hsync_start - mode->hdisplay);
+
+		ditr5 = DU_DITR5_VSFT(0) | DU_DITR5_HSFT(0);
+
+		pbcr0 = DU_PBCR0_PB_DEP(0x1F);
+
+		rcar_du_write(rcdu, DU_DITR0, ditr0);
+		rcar_du_write(rcdu, DU_DITR1, ditr1);
+		rcar_du_write(rcdu, DU_DITR2, ditr2);
+		rcar_du_write(rcdu, DU_DITR3, ditr3);
+		rcar_du_write(rcdu, DU_DITR4, ditr4);
+		rcar_du_write(rcdu, DU_DITR5, ditr5);
+		rcar_du_write(rcdu, DU_PBCR0, pbcr0);
+
+		return;
+	}
+
 	if (rcdu->info->dpll_mask & (1 << rcrtc->index)) {
 		unsigned long target = mode_clock;
 		struct dpll_info dpll = { 0 };
@@ -531,16 +568,23 @@  static void rcar_du_cmm_setup(struct drm_crtc *crtc)
 
 static void rcar_du_crtc_setup(struct rcar_du_crtc *rcrtc)
 {
-	/* Set display off and background to black */
-	rcar_du_crtc_write(rcrtc, DOOR, DOOR_RGB(0, 0, 0));
-	rcar_du_crtc_write(rcrtc, BPOR, BPOR_RGB(0, 0, 0));
+	struct rcar_du_device *rcdu = rcrtc->dev;
 
-	/* Configure display timings and output routing */
-	rcar_du_crtc_set_display_timing(rcrtc);
-	rcar_du_group_set_routing(rcrtc->group);
+	if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_RZG2L)) {
+		/* Set display off and background to black */
+		rcar_du_crtc_write(rcrtc, DOOR, DOOR_RGB(0, 0, 0));
+		rcar_du_crtc_write(rcrtc, BPOR, BPOR_RGB(0, 0, 0));
 
-	/* Start with all planes disabled. */
-	rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
+		/* Configure display timings and output routing */
+		rcar_du_crtc_set_display_timing(rcrtc);
+		rcar_du_group_set_routing(rcrtc->group);
+
+		/* Start with all planes disabled. */
+		rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
+	} else {
+		/* Configure display timings and output routing */
+		rcar_du_crtc_set_display_timing(rcrtc);
+	}
 
 	/* Enable the VSP compositor. */
 	if (rcar_du_has(rcrtc->dev, RCAR_DU_FEATURE_VSP1_SOURCE))
@@ -561,6 +605,12 @@  static int rcar_du_crtc_get(struct rcar_du_crtc *rcrtc)
 	if (rcrtc->initialized)
 		return 0;
 
+	if (rcrtc->rstc) {
+		ret = reset_control_deassert(rcrtc->rstc);
+		if (ret < 0)
+			goto error_reset;
+	}
+
 	ret = clk_prepare_enable(rcrtc->clock);
 	if (ret < 0)
 		return ret;
@@ -582,6 +632,9 @@  static int rcar_du_crtc_get(struct rcar_du_crtc *rcrtc)
 	clk_disable_unprepare(rcrtc->extclock);
 error_clock:
 	clk_disable_unprepare(rcrtc->clock);
+error_reset:
+	if (rcrtc->rstc)
+		reset_control_assert(rcrtc->rstc);
 	return ret;
 }
 
@@ -591,23 +644,28 @@  static void rcar_du_crtc_put(struct rcar_du_crtc *rcrtc)
 
 	clk_disable_unprepare(rcrtc->extclock);
 	clk_disable_unprepare(rcrtc->clock);
+	if (rcrtc->rstc)
+		reset_control_assert(rcrtc->rstc);
 
 	rcrtc->initialized = false;
 }
 
 static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
 {
+	struct rcar_du_device *rcdu = rcrtc->dev;
 	bool interlaced;
 
-	/*
-	 * Select master sync mode. This enables display operation in master
-	 * sync mode (with the HSYNC and VSYNC signals configured as outputs and
-	 * actively driven).
-	 */
-	interlaced = rcrtc->crtc.mode.flags & DRM_MODE_FLAG_INTERLACE;
-	rcar_du_crtc_dsysr_clr_set(rcrtc, DSYSR_TVM_MASK | DSYSR_SCM_MASK,
-				   (interlaced ? DSYSR_SCM_INT_VIDEO : 0) |
-				   DSYSR_TVM_MASTER);
+	if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_RZG2L)) {
+		/*
+		 * Select master sync mode. This enables display operation in master
+		 * sync mode (with the HSYNC and VSYNC signals configured as outputs and
+		 * actively driven).
+		 */
+		interlaced = rcrtc->crtc.mode.flags & DRM_MODE_FLAG_INTERLACE;
+		rcar_du_crtc_dsysr_clr_set(rcrtc, DSYSR_TVM_MASK | DSYSR_SCM_MASK,
+					   (interlaced ? DSYSR_SCM_INT_VIDEO : 0) |
+					   DSYSR_TVM_MASTER);
+	}
 
 	rcar_du_group_start_stop(rcrtc->group, true);
 }
@@ -1229,6 +1287,14 @@  int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex,
 		name = NULL;
 	}
 
+	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_RZG2L)) {
+		rcrtc->rstc = devm_reset_control_get_shared(rcdu->dev, NULL);
+		if (IS_ERR(rcrtc->rstc)) {
+			dev_err(rcdu->dev, "can't get cpg reset\n");
+			return PTR_ERR(rcrtc->rstc);
+		}
+	}
+
 	rcrtc->clock = devm_clk_get(rcdu->dev, name);
 	if (IS_ERR(rcrtc->clock)) {
 		dev_err(rcdu->dev, "no clock for DU channel %u\n", hwindex);
@@ -1251,6 +1317,14 @@  int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex,
 		return ret;
 	}
 
+	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_RZG2L)) {
+		clk = devm_clk_get(rcdu->dev, "vclk");
+		if (!IS_ERR(clk))
+			rcrtc->extclock = clk;
+		else if (PTR_ERR(clk) == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+	}
+
 	init_waitqueue_head(&rcrtc->flip_wait);
 	init_waitqueue_head(&rcrtc->vblank_wait);
 	spin_lock_init(&rcrtc->vblank_lock);
@@ -1287,27 +1361,29 @@  int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex,
 
 	drm_crtc_helper_add(crtc, &crtc_helper_funcs);
 
-	/* Register the interrupt handler. */
-	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CRTC_IRQ)) {
-		/* The IRQ's are associated with the CRTC (sw)index. */
-		irq = platform_get_irq(pdev, swindex);
-		irqflags = 0;
-	} else {
-		irq = platform_get_irq(pdev, 0);
-		irqflags = IRQF_SHARED;
-	}
+	if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_RZG2L)) {
+		/* Register the interrupt handler. */
+		if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CRTC_IRQ)) {
+			/* The IRQ's are associated with the CRTC (sw)index. */
+			irq = platform_get_irq(pdev, swindex);
+			irqflags = 0;
+		} else {
+			irq = platform_get_irq(pdev, 0);
+			irqflags = IRQF_SHARED;
+		}
 
-	if (irq < 0) {
-		dev_err(rcdu->dev, "no IRQ for CRTC %u\n", swindex);
-		return irq;
-	}
+		if (irq < 0) {
+			dev_err(rcdu->dev, "no IRQ for CRTC %u\n", swindex);
+			return irq;
+		}
 
-	ret = devm_request_irq(rcdu->dev, irq, rcar_du_crtc_irq, irqflags,
-			       dev_name(rcdu->dev), rcrtc);
-	if (ret < 0) {
-		dev_err(rcdu->dev,
-			"failed to register IRQ for CRTC %u\n", swindex);
-		return ret;
+		ret = devm_request_irq(rcdu->dev, irq, rcar_du_crtc_irq, irqflags,
+				       dev_name(rcdu->dev), rcrtc);
+		if (ret < 0) {
+			dev_err(rcdu->dev,
+				"failed to register IRQ for CRTC %u\n", swindex);
+			return ret;
+		}
 	}
 
 	rcar_du_crtc_crc_init(rcrtc);
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
index 66e8839db708..4ec2db46b131 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -28,6 +28,7 @@  struct rcar_du_vsp;
  * @dev: the DU device
  * @clock: the CRTC functional clock
  * @extclock: external pixel dot clock (optional)
+ * @rstc: reset controller (optional)
  * @mmio_offset: offset of the CRTC registers in the DU MMIO block
  * @index: CRTC hardware index
  * @initialized: whether the CRTC has been initialized and clocks enabled
@@ -50,6 +51,7 @@  struct rcar_du_crtc {
 	struct rcar_du_device *dev;
 	struct clk *clock;
 	struct clk *extclock;
+	struct reset_control *rstc;
 	unsigned int mmio_offset;
 	unsigned int index;
 	bool initialized;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index f92636001f10..57edc3b3154f 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -596,6 +596,28 @@  static const struct rcar_du_device_info rcar_du_r8a779a0_info = {
 	.dsi_clk_mask =  BIT(1) | BIT(0),
 };
 
+static const struct rcar_du_device_info rcar_du_r9a07g044l_info = {
+	.gen = 3,
+	.features = RCAR_DU_FEATURE_CRTC_IRQ
+		  | RCAR_DU_FEATURE_CRTC_CLOCK
+		  | RCAR_DU_FEATURE_RZG2L
+		  | RCAR_DU_FEATURE_VSP1_SOURCE,
+	.channels_mask = BIT(0),
+	.routes = {
+		[RCAR_DU_OUTPUT_DPAD0] = {
+			.possible_crtcs = BIT(0),
+			.port = 0,
+		},
+		[RCAR_DU_OUTPUT_DSI0] = {
+			.possible_crtcs = BIT(0),
+			.port = 1,
+		},
+	},
+	.num_rpf = 2,
+	.max_width = 1920,
+	.max_height = 1080,
+};
+
 static const struct of_device_id rcar_du_of_table[] = {
 	{ .compatible = "renesas,du-r8a7742", .data = &rcar_du_r8a7790_info },
 	{ .compatible = "renesas,du-r8a7743", .data = &rzg1_du_r8a7743_info },
@@ -621,6 +643,7 @@  static const struct of_device_id rcar_du_of_table[] = {
 	{ .compatible = "renesas,du-r8a77990", .data = &rcar_du_r8a7799x_info },
 	{ .compatible = "renesas,du-r8a77995", .data = &rcar_du_r8a7799x_info },
 	{ .compatible = "renesas,du-r8a779a0", .data = &rcar_du_r8a779a0_info },
+	{ .compatible = "renesas,du-r9a07g044l", .data = &rcar_du_r9a07g044l_info },
 	{ }
 };
 
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
index e28c2df66f8e..47da9da71bca 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
@@ -33,6 +33,7 @@  struct rcar_du_device;
 #define RCAR_DU_FEATURE_TVM_SYNC	BIT(4)	/* Has TV switch/sync modes */
 #define RCAR_DU_FEATURE_PLANE		BIT(5)	/* HW supports DU planes */
 #define RCAR_DU_FEATURE_GROUP		BIT(6)	/* HW supports DU groups */
+#define RCAR_DU_FEATURE_RZG2L		BIT(7)	/* Use RZ/G2L registers */
 
 #define RCAR_DU_QUIRK_ALIGN_128B	BIT(0)	/* Align pitches to 128 bytes */
 
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c
index 3612bc9eab1b..632271c2881d 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_group.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c
@@ -224,6 +224,11 @@  static void __rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start)
 {
 	struct rcar_du_device *rcdu = rgrp->dev;
 
+	if (!rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_GROUP)) {
+		rcar_du_write(rgrp->dev, DU_MCR0, start ? DU_MCR0_DI_EN : 0);
+		return;
+	}
+
 	/*
 	 * Group start/stop is controlled by the DRES and DEN bits of DSYSR0
 	 * for the first group and DSYSR2 for the second group. On most DU
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_regs.h b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
index 1cdaa51eb9ac..9e5c8d286bfc 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_regs.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
@@ -15,6 +15,58 @@ 
 #define DU2_REG_OFFSET		0x40000
 #define DU3_REG_OFFSET		0x70000
 
+/* -----------------------------------------------------------------------------
+ * RZ/G2L Display Registers
+ */
+
+#define DU_MCR0			0x00
+#define DU_MCR0_DPI_OE		BIT(0)
+#define DU_MCR0_DI_EN		BIT(8)
+#define DU_MCR0_PB_CLR		BIT(16)
+
+#define DU_MSR0			0x04
+#define DU_MSR0_ST_DI_BSY	BIT(8)
+#define DU_MSR0_ST_PB_WFULL	BIT(16)
+#define DU_MSR0_ST_PB_WINIT	BIT(18)
+#define DU_MSR0_ST_PB_REMPTY	BIT(20)
+#define DU_MSR0_ST_PB_RUF	BIT(21)
+#define DU_MSR0_ST_PB_RINIT	BIT(22)
+
+#define DU_MSR1			0x08
+
+#define DU_IMR0			0x0C
+#define DU_MSR0_IM_PB_RUF	BIT(0)
+
+#define DU_DITR0		0x10
+#define DU_DITR0_DPI_CLKMD	BIT(0)
+#define DU_DITR0_DEMD_LOW	0x0
+#define DU_DITR0_DEMD_HIGH	(BIT(8) | BIT(9))
+#define DU_DITR0_VSPOL		BIT(16)
+#define DU_DITR0_HSPOL		BIT(17)
+
+#define DU_DITR1		0x14
+#define DU_DITR1_VSA(x)		((x) << 0)
+#define DU_DITR1_VACTIVE(x)	((x) << 16)
+
+#define DU_DITR2		0x18
+#define DU_DITR2_VBP(x)		((x) << 0)
+#define DU_DITR2_VFP(x)		((x) << 16)
+
+#define DU_DITR3		0x1C
+#define DU_DITR3_HSA(x)		((x) << 0)
+#define DU_DITR3_HACTIVE(x)	((x) << 16)
+
+#define DU_DITR4		0x20
+#define DU_DITR4_HBP(x)		((x) << 0)
+#define DU_DITR4_HFP(x)		((x) << 16)
+
+#define DU_DITR5		0x24
+#define DU_DITR5_VSFT(x)	((x) << 0)
+#define DU_DITR5_HSFT(x)	((x) << 16)
+
+#define DU_PBCR0		0x4C
+#define DU_PBCR0_PB_DEP(x)	((x) << 0)
+
 /* -----------------------------------------------------------------------------
  * Display Control Registers
  */