mbox series

[00/10] Improvements and fixes for mxsfb DRM driver

Message ID 1561555938-21595-1-git-send-email-robert.chiras@nxp.com
Headers show
Series Improvements and fixes for mxsfb DRM driver | expand

Message

Robert Chiras June 26, 2019, 1:32 p.m. UTC
This patch-set improves the use of eLCDIF block on iMX 8 SoCs (like 8MQ, 8MM
and 8QXP). Following, are the new features added and fixes from this
patch-set:

1. Add support for drm_bridge
On 8MQ and 8MM, the LCDIF block is not directly connected to a parallel
display connector, where an LCD panel can be attached, but instead it is
connected to DSI controller. Since this DSI stands between the display
controller (eLCDIF) and the physical connector, the DSI can be implemented
as a DRM bridge. So, in order to be able to connect the mxsfb driver to
the DSI driver, the support for a drm_bridge was needed in mxsfb DRM
driver (the actual driver for the eLCDIF block).

2. Add support for additional pixel formats
Some of the pixel formats needed by Android were not implemented in this
driver, but they were actually supported. So, add support for them.

3. Add support for horizontal stride
Having support for horizontal stride allows the use of eLCDIF with a GPU
(for example) that can only output resolution sizes multiple of a power of
8. For example, 1080 is not a power of 16, so in order to support 1920x1080
output from GPUs that can produce linear buffers only in sizes multiple to 16,
this feature is needed.

3. Few minor features and bug-fixing
The addition of max-res DT property was actually needed in order to limit
the bandwidth usage of the eLCDIF block. This is need on systems where
multiple display controllers are presend and the memory bandwidth is not
enough to handle all of them at maximum capacity (like it is the case on
8MQ, where there are two display controllers: DCSS and eLCDIF).
The rest of the patches are bug-fixes.

Mirela Rabulea (1):
  drm/mxsfb: Signal mode changed when bpp changed

Robert Chiras (9):
  drm/mxsfb: Update mxsfb to support a bridge
  drm/mxsfb: Update mxsfb with additional pixel formats
  drm/mxsfb: Fix the vblank events
  dt-bindings: display: Add max-res property for mxsfb
  drm/mxsfb: Add max-res property for MXSFB
  drm/mxsfb: Update mxsfb to support LCD reset
  drm/mxsfb: Improve the axi clock usage
  drm/mxsfb: Clear OUTSTANDING_REQS bits
  drm/mxsfb: Add support for horizontal stride

 .../devicetree/bindings/display/mxsfb.txt          |   6 +
 drivers/gpu/drm/mxsfb/mxsfb_crtc.c                 | 290 ++++++++++++++++++---
 drivers/gpu/drm/mxsfb/mxsfb_drv.c                  | 189 +++++++++++---
 drivers/gpu/drm/mxsfb/mxsfb_drv.h                  |  10 +-
 drivers/gpu/drm/mxsfb/mxsfb_out.c                  |  26 +-
 drivers/gpu/drm/mxsfb/mxsfb_regs.h                 | 128 ++++++---
 6 files changed, 531 insertions(+), 118 deletions(-)

Comments

Guido Günther July 11, 2019, 3:04 p.m. UTC | #1
Hi Robert,
On Wed, Jun 26, 2019 at 04:32:08PM +0300, Robert Chiras wrote:
> This patch-set improves the use of eLCDIF block on iMX 8 SoCs (like 8MQ, 8MM
> and 8QXP). Following, are the new features added and fixes from this
> patch-set:
> 
> 1. Add support for drm_bridge
> On 8MQ and 8MM, the LCDIF block is not directly connected to a parallel
> display connector, where an LCD panel can be attached, but instead it is
> connected to DSI controller. Since this DSI stands between the display
> controller (eLCDIF) and the physical connector, the DSI can be implemented
> as a DRM bridge. So, in order to be able to connect the mxsfb driver to
> the DSI driver, the support for a drm_bridge was needed in mxsfb DRM
> driver (the actual driver for the eLCDIF block).

So I wanted to test this but with both my somewhat cleaned up nwl
driver¹ and the nwl driver forward ported from the nxp vendor tree I'm
looking at a black screen with current mainline - while my dcss forward
port gives me nice output on mipi dsi. Do you have a tree that uses mipi
dsi on imx8mq where I could look at to check for differences?

Cheers,
 -- Guido

> 
> 2. Add support for additional pixel formats
> Some of the pixel formats needed by Android were not implemented in this
> driver, but they were actually supported. So, add support for them.
> 
> 3. Add support for horizontal stride
> Having support for horizontal stride allows the use of eLCDIF with a GPU
> (for example) that can only output resolution sizes multiple of a power of
> 8. For example, 1080 is not a power of 16, so in order to support 1920x1080
> output from GPUs that can produce linear buffers only in sizes multiple to 16,
> this feature is needed.
> 
> 3. Few minor features and bug-fixing
> The addition of max-res DT property was actually needed in order to limit
> the bandwidth usage of the eLCDIF block. This is need on systems where
> multiple display controllers are presend and the memory bandwidth is not
> enough to handle all of them at maximum capacity (like it is the case on
> 8MQ, where there are two display controllers: DCSS and eLCDIF).
> The rest of the patches are bug-fixes.
> 
> Mirela Rabulea (1):
>   drm/mxsfb: Signal mode changed when bpp changed
> 
> Robert Chiras (9):
>   drm/mxsfb: Update mxsfb to support a bridge
>   drm/mxsfb: Update mxsfb with additional pixel formats
>   drm/mxsfb: Fix the vblank events
>   dt-bindings: display: Add max-res property for mxsfb
>   drm/mxsfb: Add max-res property for MXSFB
>   drm/mxsfb: Update mxsfb to support LCD reset
>   drm/mxsfb: Improve the axi clock usage
>   drm/mxsfb: Clear OUTSTANDING_REQS bits
>   drm/mxsfb: Add support for horizontal stride
> 
>  .../devicetree/bindings/display/mxsfb.txt          |   6 +
>  drivers/gpu/drm/mxsfb/mxsfb_crtc.c                 | 290 ++++++++++++++++++---
>  drivers/gpu/drm/mxsfb/mxsfb_drv.c                  | 189 +++++++++++---
>  drivers/gpu/drm/mxsfb/mxsfb_drv.h                  |  10 +-
>  drivers/gpu/drm/mxsfb/mxsfb_out.c                  |  26 +-
>  drivers/gpu/drm/mxsfb/mxsfb_regs.h                 | 128 ++++++---
>  6 files changed, 531 insertions(+), 118 deletions(-)
> 
> -- 
> 2.7.4
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

¹ https://lists.freedesktop.org/archives/dri-devel/2019-March/209685.html
Robert Chiras July 12, 2019, 8:15 a.m. UTC | #2
Hi Guido,

On Jo, 2019-07-11 at 17:04 +0200, Guido Günther wrote:
> Hi Robert,
> On Wed, Jun 26, 2019 at 04:32:08PM +0300, Robert Chiras wrote:
> > 
> > This patch-set improves the use of eLCDIF block on iMX 8 SoCs (like
> > 8MQ, 8MM
> > and 8QXP). Following, are the new features added and fixes from
> > this
> > patch-set:
> > 
> > 1. Add support for drm_bridge
> > On 8MQ and 8MM, the LCDIF block is not directly connected to a
> > parallel
> > display connector, where an LCD panel can be attached, but instead
> > it is
> > connected to DSI controller. Since this DSI stands between the
> > display
> > controller (eLCDIF) and the physical connector, the DSI can be
> > implemented
> > as a DRM bridge. So, in order to be able to connect the mxsfb
> > driver to
> > the DSI driver, the support for a drm_bridge was needed in mxsfb
> > DRM
> > driver (the actual driver for the eLCDIF block).
> So I wanted to test this but with both my somewhat cleaned up nwl
> driver¹ and the nwl driver forward ported from the nxp vendor tree
> I'm
> looking at a black screen with current mainline - while my dcss
> forward
> port gives me nice output on mipi dsi. Do you have a tree that uses
> mipi
> dsi on imx8mq where I could look at to check for differences?
Somewhere on the pixel path (between the display controller and the
DSI) there is a block that inverts the polarity. I can't remember
exactly what was the role of this block, but the polarity is inverted
when eLCDIF is used in combination with the DSI.
If you take a look at my DSI driver from NXP releases (I guess you have
them), you will see there is a hack in mode_fixup:

unsigned int *flags = &mode->flags;
if (dsi->sync_pol {
	*flags |= DRM_MODE_FLAG_PHSYNC;
	*flags |= DRM_MODE_FLAG_PVSYNC;
	*flags &= ~DRM_MODE_FLAG_NHSYNC;
	*flags &= ~DRM_MODE_FLAG_NVSYNC;
} else {
	*flags &= ~DRM_MODE_FLAG_PHSYNC;
	*flags &= ~DRM_MODE_FLAG_PVSYNC;
	*flags |= DRM_MODE_FLAG_NHSYNC;
	*flags |= DRM_MODE_FLAG_NVSYNC;
}

I know it's not clean, but it works for now. You can try this in your
driver and see if it helps.
These days I will also take your nwl-dsi driver and test it, and also
add support for bridge and eLCDIF to see if I can make it work.

Best regards,
Robert
> 
> Cheers,
>  -- Guido
> 
> > 
> > 
> > 2. Add support for additional pixel formats
> > Some of the pixel formats needed by Android were not implemented in
> > this
> > driver, but they were actually supported. So, add support for them.
> > 
> > 3. Add support for horizontal stride
> > Having support for horizontal stride allows the use of eLCDIF with
> > a GPU
> > (for example) that can only output resolution sizes multiple of a
> > power of
> > 8. For example, 1080 is not a power of 16, so in order to support
> > 1920x1080
> > output from GPUs that can produce linear buffers only in sizes
> > multiple to 16,
> > this feature is needed.
> > 
> > 3. Few minor features and bug-fixing
> > The addition of max-res DT property was actually needed in order to
> > limit
> > the bandwidth usage of the eLCDIF block. This is need on systems
> > where
> > multiple display controllers are presend and the memory bandwidth
> > is not
> > enough to handle all of them at maximum capacity (like it is the
> > case on
> > 8MQ, where there are two display controllers: DCSS and eLCDIF).
> > The rest of the patches are bug-fixes.
> > 
> > Mirela Rabulea (1):
> >   drm/mxsfb: Signal mode changed when bpp changed
> > 
> > Robert Chiras (9):
> >   drm/mxsfb: Update mxsfb to support a bridge
> >   drm/mxsfb: Update mxsfb with additional pixel formats
> >   drm/mxsfb: Fix the vblank events
> >   dt-bindings: display: Add max-res property for mxsfb
> >   drm/mxsfb: Add max-res property for MXSFB
> >   drm/mxsfb: Update mxsfb to support LCD reset
> >   drm/mxsfb: Improve the axi clock usage
> >   drm/mxsfb: Clear OUTSTANDING_REQS bits
> >   drm/mxsfb: Add support for horizontal stride
> > 
> >  .../devicetree/bindings/display/mxsfb.txt          |   6 +
> >  drivers/gpu/drm/mxsfb/mxsfb_crtc.c                 | 290
> > ++++++++++++++++++---
> >  drivers/gpu/drm/mxsfb/mxsfb_drv.c                  | 189
> > +++++++++++---
> >  drivers/gpu/drm/mxsfb/mxsfb_drv.h                  |  10 +-
> >  drivers/gpu/drm/mxsfb/mxsfb_out.c                  |  26 +-
> >  drivers/gpu/drm/mxsfb/mxsfb_regs.h                 | 128 ++++++---
> >  6 files changed, 531 insertions(+), 118 deletions(-)
> > 
> > --
> > 2.7.4
> > 
> > 
> > _______________________________________________
> > linux-arm-kernel mailing list
> > linux-arm-kernel@lists.infradead.org
> > https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fli
> > sts.infradead.org%2Fmailman%2Flistinfo%2Flinux-arm-
> > kernel&data=02%7C01%7Crobert.chiras%40nxp.com%7C7dc01a0bdf9245b
> > 8d87008d70611055b%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C6369
> > 84542481903425&sdata=ySInO6H1B4kJtJUwRs2uTIUve0SSNZF0s%2Bv%2FDU
> > 0Vy1E%3D&reserved=0
> > 
> ¹ https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fl
> ists.freedesktop.org%2Farchives%2Fdri-devel%2F2019-
> March%2F209685.html&data=02%7C01%7Crobert.chiras%40nxp.com%7C7dc0
> 1a0bdf9245b8d87008d70611055b%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7
> C0%7C636984542481913416&sdata=ucYDQLiK7RalRF%2B5MeB3%2F76cFLGWa7C
> mxCFLEg4Wvqc%3D&reserved=0
Guido Günther July 16, 2019, 2:54 p.m. UTC | #3
Hi Robert,
On Fri, Jul 12, 2019 at 08:15:32AM +0000, Robert Chiras wrote:
> Hi Guido,
> 
> On Jo, 2019-07-11 at 17:04 +0200, Guido Günther wrote:
> > Hi Robert,
> > On Wed, Jun 26, 2019 at 04:32:08PM +0300, Robert Chiras wrote:
> > > 
> > > This patch-set improves the use of eLCDIF block on iMX 8 SoCs (like
> > > 8MQ, 8MM
> > > and 8QXP). Following, are the new features added and fixes from
> > > this
> > > patch-set:
> > > 
> > > 1. Add support for drm_bridge
> > > On 8MQ and 8MM, the LCDIF block is not directly connected to a
> > > parallel
> > > display connector, where an LCD panel can be attached, but instead
> > > it is
> > > connected to DSI controller. Since this DSI stands between the
> > > display
> > > controller (eLCDIF) and the physical connector, the DSI can be
> > > implemented
> > > as a DRM bridge. So, in order to be able to connect the mxsfb
> > > driver to
> > > the DSI driver, the support for a drm_bridge was needed in mxsfb
> > > DRM
> > > driver (the actual driver for the eLCDIF block).
> > So I wanted to test this but with both my somewhat cleaned up nwl
> > driver¹ and the nwl driver forward ported from the nxp vendor tree
> > I'm
> > looking at a black screen with current mainline - while my dcss
> > forward
> > port gives me nice output on mipi dsi. Do you have a tree that uses
> > mipi
> > dsi on imx8mq where I could look at to check for differences?
> Somewhere on the pixel path (between the display controller and the
> DSI) there is a block that inverts the polarity. I can't remember
> exactly what was the role of this block, but the polarity is inverted
> when eLCDIF is used in combination with the DSI.
> If you take a look at my DSI driver from NXP releases (I guess you have
> them), you will see there is a hack in mode_fixup:
> 
> unsigned int *flags = &mode->flags;
> if (dsi->sync_pol {
> 	*flags |= DRM_MODE_FLAG_PHSYNC;
> 	*flags |= DRM_MODE_FLAG_PVSYNC;
> 	*flags &= ~DRM_MODE_FLAG_NHSYNC;
> 	*flags &= ~DRM_MODE_FLAG_NVSYNC;
> } else {
> 	*flags &= ~DRM_MODE_FLAG_PHSYNC;
> 	*flags &= ~DRM_MODE_FLAG_PVSYNC;
> 	*flags |= DRM_MODE_FLAG_NHSYNC;
> 	*flags |= DRM_MODE_FLAG_NVSYNC;
> }

Thanks for the suggestion! I'll try that.

> 
> I know it's not clean, but it works for now. You can try this in your
> driver and see if it helps.
> These days I will also take your nwl-dsi driver and test it, and also
> add support for bridge and eLCDIF to see if I can make it work.

I have hacky bridge support over here already. Give me some days to
clean it up and it might safe you some work.
Cheers,
 -- Guido
Guido Günther July 20, 2019, 9:09 p.m. UTC | #4
Hi Robert,
On Tue, Jul 16, 2019 at 04:54:50PM +0200, Guido Günther wrote:
> Hi Robert,
> On Fri, Jul 12, 2019 at 08:15:32AM +0000, Robert Chiras wrote:
> > Hi Guido,
> > 
> > On Jo, 2019-07-11 at 17:04 +0200, Guido Günther wrote:
> > > Hi Robert,
> > > On Wed, Jun 26, 2019 at 04:32:08PM +0300, Robert Chiras wrote:
> > > > 
> > > > This patch-set improves the use of eLCDIF block on iMX 8 SoCs (like
> > > > 8MQ, 8MM
> > > > and 8QXP). Following, are the new features added and fixes from
> > > > this
> > > > patch-set:
> > > > 
> > > > 1. Add support for drm_bridge
> > > > On 8MQ and 8MM, the LCDIF block is not directly connected to a
> > > > parallel
> > > > display connector, where an LCD panel can be attached, but instead
> > > > it is
> > > > connected to DSI controller. Since this DSI stands between the
> > > > display
> > > > controller (eLCDIF) and the physical connector, the DSI can be
> > > > implemented
> > > > as a DRM bridge. So, in order to be able to connect the mxsfb
> > > > driver to
> > > > the DSI driver, the support for a drm_bridge was needed in mxsfb
> > > > DRM
> > > > driver (the actual driver for the eLCDIF block).
> > > So I wanted to test this but with both my somewhat cleaned up nwl
> > > driver¹ and the nwl driver forward ported from the nxp vendor tree
> > > I'm
> > > looking at a black screen with current mainline - while my dcss
> > > forward
> > > port gives me nice output on mipi dsi. Do you have a tree that uses
> > > mipi
> > > dsi on imx8mq where I could look at to check for differences?
> > Somewhere on the pixel path (between the display controller and the
> > DSI) there is a block that inverts the polarity. I can't remember
> > exactly what was the role of this block, but the polarity is inverted
> > when eLCDIF is used in combination with the DSI.
> > If you take a look at my DSI driver from NXP releases (I guess you have
> > them), you will see there is a hack in mode_fixup:
> > 
> > unsigned int *flags = &mode->flags;
> > if (dsi->sync_pol {
> > 	*flags |= DRM_MODE_FLAG_PHSYNC;
> > 	*flags |= DRM_MODE_FLAG_PVSYNC;
> > 	*flags &= ~DRM_MODE_FLAG_NHSYNC;
> > 	*flags &= ~DRM_MODE_FLAG_NVSYNC;
> > } else {
> > 	*flags &= ~DRM_MODE_FLAG_PHSYNC;
> > 	*flags &= ~DRM_MODE_FLAG_PVSYNC;
> > 	*flags |= DRM_MODE_FLAG_NHSYNC;
> > 	*flags |= DRM_MODE_FLAG_NVSYNC;
> > }
> 
> Thanks for the suggestion! I'll try that.
>
> > 
> > I know it's not clean, but it works for now. You can try this in your
> > driver and see if it helps.
> > These days I will also take your nwl-dsi driver and test it, and also
> > add support for bridge and eLCDIF to see if I can make it work.
> 
> I have hacky bridge support over here already. Give me some days to
> clean it up and it might safe you some work.

Your suggestion above (plus some other fixes) worked and
mxsfb+nwl+mixel-dphy works over here. I'll try to send a v1 of the nwl
driver out during the week.
Cheers,
 -- Guido

> Cheers,
>  -- Guido
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
Guido Günther July 21, 2019, 10:26 a.m. UTC | #5
Hi Robert,
On Wed, Jun 26, 2019 at 04:32:09PM +0300, Robert Chiras wrote:
> Currently, the MXSFB DRM driver only supports a panel. But, its output
> display signal can also be redirected to another encoder, like a DSI
> controller. In this case, that DSI controller may act like a drm_bridge.
> In order support this use-case too, this patch adds support for
> drm_bridge in mxsfb.
> 
> Signed-off-by: Robert Chiras <robert.chiras@nxp.com>
> ---
>  drivers/gpu/drm/mxsfb/mxsfb_crtc.c | 46 +++++++++++++++++++++++++++++++++++---
>  drivers/gpu/drm/mxsfb/mxsfb_drv.c  | 46 +++++++++++++++++++++++++++++++++-----
>  drivers/gpu/drm/mxsfb/mxsfb_drv.h  |  4 +++-
>  drivers/gpu/drm/mxsfb/mxsfb_out.c  | 26 +++++++++++----------
>  drivers/gpu/drm/mxsfb/mxsfb_regs.h | 15 +++++++++++++
>  5 files changed, 116 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
> index 93f4133..14bde024 100644
> --- a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
> +++ b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
> @@ -93,8 +93,11 @@ static void mxsfb_set_bus_fmt(struct mxsfb_drm_private *mxsfb)
>  
>  	reg = readl(mxsfb->base + LCDC_CTRL);
>  
> -	if (mxsfb->connector.display_info.num_bus_formats)
> -		bus_format = mxsfb->connector.display_info.bus_formats[0];
> +	if (mxsfb->connector->display_info.num_bus_formats)
> +		bus_format = mxsfb->connector->display_info.bus_formats[0];
> +
> +	DRM_DEV_DEBUG_DRIVER(drm->dev, "Using bus_format: 0x%08X\n",
> +			     bus_format);
>  
>  	reg &= ~CTRL_BUS_WIDTH_MASK;
>  	switch (bus_format) {
> @@ -122,6 +125,9 @@ static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb)
>  		clk_prepare_enable(mxsfb->clk_disp_axi);
>  	clk_prepare_enable(mxsfb->clk);
>  
> +	writel(CTRL2_OUTSTANDING_REQS__REQ_16,
> +	       mxsfb->base + LCDC_V4_CTRL2 + REG_SET);
> +
>  	/* If it was disabled, re-enable the mode again */
>  	writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET);
>  
> @@ -131,12 +137,15 @@ static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb)
>  	writel(reg, mxsfb->base + LCDC_VDCTRL4);
>  
>  	writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_SET);
> +	writel(CTRL1_RECOVERY_ON_UNDERFLOW, mxsfb->base + LCDC_CTRL1 + REG_SET);
>  }
>  
>  static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb)
>  {
>  	u32 reg;
>  
> +	writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_CLR);
> +
>  	/*
>  	 * Even if we disable the controller here, it will still continue
>  	 * until its FIFOs are running out of data
> @@ -202,8 +211,9 @@ static dma_addr_t mxsfb_get_fb_paddr(struct mxsfb_drm_private *mxsfb)
>  
>  static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb)
>  {
> +	struct drm_device *drm = mxsfb->pipe.crtc.dev;
>  	struct drm_display_mode *m = &mxsfb->pipe.crtc.state->adjusted_mode;
> -	const u32 bus_flags = mxsfb->connector.display_info.bus_flags;
> +	const u32 bus_flags = mxsfb->connector->display_info.bus_flags;
>  	u32 vdctrl0, vsync_pulse_len, hsync_pulse_len;
>  	int err;
>  
> @@ -227,6 +237,13 @@ static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb)
>  
>  	clk_set_rate(mxsfb->clk, m->crtc_clock * 1000);
>  
> +	DRM_DEV_DEBUG_DRIVER(drm->dev, "Pixel clock: %dkHz (actual: %dkHz)\n",
> +			     m->crtc_clock,
> +			     (int)(clk_get_rate(mxsfb->clk) / 1000));
> +	DRM_DEV_DEBUG_DRIVER(drm->dev, "Connector bus_flags: 0x%08X\n",
> +			     bus_flags);
> +	DRM_DEV_DEBUG_DRIVER(drm->dev, "Mode flags: 0x%08X\n", m->flags);
> +
>  	writel(TRANSFER_COUNT_SET_VCOUNT(m->crtc_vdisplay) |
>  	       TRANSFER_COUNT_SET_HCOUNT(m->crtc_hdisplay),
>  	       mxsfb->base + mxsfb->devdata->transfer_count);
> @@ -279,6 +296,7 @@ void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb)
>  	dma_addr_t paddr;
>  
>  	mxsfb_enable_axi_clk(mxsfb);
> +	writel(0, mxsfb->base + LCDC_CTRL);
>  	mxsfb_crtc_mode_set_nofb(mxsfb);
>  
>  	/* Write cur_buf as well to avoid an initial corrupt frame */
> @@ -302,6 +320,8 @@ void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb,
>  {
>  	struct drm_simple_display_pipe *pipe = &mxsfb->pipe;
>  	struct drm_crtc *crtc = &pipe->crtc;
> +	struct drm_framebuffer *fb = pipe->plane.state->fb;
> +	struct drm_framebuffer *old_fb = old_state->fb;
>  	struct drm_pending_vblank_event *event;
>  	dma_addr_t paddr;
>  
> @@ -324,4 +344,24 @@ void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb,
>  		writel(paddr, mxsfb->base + mxsfb->devdata->next_buf);
>  		mxsfb_disable_axi_clk(mxsfb);
>  	}
> +
> +	if (!fb || !old_fb)
> +		return;
> +
> +	/*
> +	 * TODO: Currently, we only support pixel format change, but we need
> +	 * also to care about size changes too
> +	 */
> +	if (old_fb->format->format != fb->format->format) {
> +		struct drm_format_name_buf old_fmt_buf;
> +		struct drm_format_name_buf new_fmt_buf;
> +
> +		DRM_DEV_DEBUG_DRIVER(crtc->dev->dev,
> +				     "Switching pixel format: %s -> %s\n",
> +				     drm_get_format_name(old_fb->format->format,
> +							 &old_fmt_buf),
> +				     drm_get_format_name(fb->format->format,
> +							 &new_fmt_buf));
> +		mxsfb_set_pixel_fmt(mxsfb, true);

This assumes mxsfb_set_pixel_fmt has two arguments which is being introduced
in the following commit. With that fixed:

Tested-by: Guido Günther <agx@sigxcpu.org> 

Cheers,
 -- Guido

> +	}
>  }
> diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c
> index 6fafc90..0d171e9 100644
> --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c
> +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c
> @@ -98,9 +98,25 @@ static void mxsfb_pipe_enable(struct drm_simple_display_pipe *pipe,
>  			      struct drm_crtc_state *crtc_state,
>  			      struct drm_plane_state *plane_state)
>  {
> +	struct drm_connector *connector;
>  	struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
>  	struct drm_device *drm = pipe->plane.dev;
>  
> +	if (!mxsfb->connector) {
> +		list_for_each_entry(connector,
> +				    &drm->mode_config.connector_list,
> +				    head)
> +			if (connector->encoder == &mxsfb->pipe.encoder) {
> +				mxsfb->connector = connector;
> +				break;
> +			}
> +	}
> +
> +	if (!mxsfb->connector) {
> +		dev_warn(drm->dev, "No connector attached, using default\n");
> +		mxsfb->connector = &mxsfb->panel_connector;
> +	}
> +
>  	pm_runtime_get_sync(drm->dev);
>  	drm_panel_prepare(mxsfb->panel);
>  	mxsfb_crtc_enable(mxsfb);
> @@ -126,6 +142,9 @@ static void mxsfb_pipe_disable(struct drm_simple_display_pipe *pipe)
>  		drm_crtc_send_vblank_event(crtc, event);
>  	}
>  	spin_unlock_irq(&drm->event_lock);
> +
> +	if (mxsfb->connector != &mxsfb->panel_connector)
> +		mxsfb->connector = NULL;
>  }
>  
>  static void mxsfb_pipe_update(struct drm_simple_display_pipe *pipe,
> @@ -223,16 +242,33 @@ static int mxsfb_load(struct drm_device *drm, unsigned long flags)
>  
>  	ret = drm_simple_display_pipe_init(drm, &mxsfb->pipe, &mxsfb_funcs,
>  			mxsfb_formats, ARRAY_SIZE(mxsfb_formats), NULL,
> -			&mxsfb->connector);
> +			mxsfb->connector);
>  	if (ret < 0) {
>  		dev_err(drm->dev, "Cannot setup simple display pipe\n");
>  		goto err_vblank;
>  	}
>  
> -	ret = drm_panel_attach(mxsfb->panel, &mxsfb->connector);
> -	if (ret) {
> -		dev_err(drm->dev, "Cannot connect panel\n");
> -		goto err_vblank;
> +	/*
> +	 * Attach panel only if there is one.
> +	 * If there is no panel attach, it must be a bridge. In this case, we
> +	 * need a reference to its connector for a proper initialization.
> +	 * We will do this check in pipe->enable(), since the connector won't
> +	 * be attached to an encoder until then.
> +	 */
> +
> +	if (mxsfb->panel) {
> +		ret = drm_panel_attach(mxsfb->panel, mxsfb->connector);
> +		if (ret) {
> +			dev_err(drm->dev, "Cannot connect panel\n");
> +			goto err_vblank;
> +		}
> +	} else if (mxsfb->bridge) {
> +		ret = drm_simple_display_pipe_attach_bridge(&mxsfb->pipe,
> +							    mxsfb->bridge);
> +		if (ret) {
> +			dev_err(drm->dev, "Cannot connect bridge\n");
> +			goto err_vblank;
> +		}
>  	}
>  
>  	drm->mode_config.min_width	= MXSFB_MIN_XRES;
> diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.h b/drivers/gpu/drm/mxsfb/mxsfb_drv.h
> index d975300..0b65b51 100644
> --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.h
> +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.h
> @@ -27,8 +27,10 @@ struct mxsfb_drm_private {
>  	struct clk			*clk_disp_axi;
>  
>  	struct drm_simple_display_pipe	pipe;
> -	struct drm_connector		connector;
> +	struct drm_connector		panel_connector;
> +	struct drm_connector		*connector;
>  	struct drm_panel		*panel;
> +	struct drm_bridge		*bridge;
>  };
>  
>  int mxsfb_setup_crtc(struct drm_device *dev);
> diff --git a/drivers/gpu/drm/mxsfb/mxsfb_out.c b/drivers/gpu/drm/mxsfb/mxsfb_out.c
> index 91e76f9..b9acf2b 100644
> --- a/drivers/gpu/drm/mxsfb/mxsfb_out.c
> +++ b/drivers/gpu/drm/mxsfb/mxsfb_out.c
> @@ -22,7 +22,8 @@
>  static struct mxsfb_drm_private *
>  drm_connector_to_mxsfb_drm_private(struct drm_connector *connector)
>  {
> -	return container_of(connector, struct mxsfb_drm_private, connector);
> +	return container_of(connector, struct mxsfb_drm_private,
> +			    panel_connector);
>  }
>  
>  static int mxsfb_panel_get_modes(struct drm_connector *connector)
> @@ -77,22 +78,23 @@ static const struct drm_connector_funcs mxsfb_panel_connector_funcs = {
>  int mxsfb_create_output(struct drm_device *drm)
>  {
>  	struct mxsfb_drm_private *mxsfb = drm->dev_private;
> -	struct drm_panel *panel;
>  	int ret;
>  
> -	ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0, &panel, NULL);
> +	ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0,
> +					  &mxsfb->panel, &mxsfb->bridge);
>  	if (ret)
>  		return ret;
>  
> -	mxsfb->connector.dpms = DRM_MODE_DPMS_OFF;
> -	mxsfb->connector.polled = 0;
> -	drm_connector_helper_add(&mxsfb->connector,
> -			&mxsfb_panel_connector_helper_funcs);
> -	ret = drm_connector_init(drm, &mxsfb->connector,
> -				 &mxsfb_panel_connector_funcs,
> -				 DRM_MODE_CONNECTOR_Unknown);
> -	if (!ret)
> -		mxsfb->panel = panel;
> +	if (mxsfb->panel) {
> +		mxsfb->connector = &mxsfb->panel_connector;
> +		mxsfb->connector->dpms = DRM_MODE_DPMS_OFF;
> +		mxsfb->connector->polled = 0;
> +		drm_connector_helper_add(mxsfb->connector,
> +					 &mxsfb_panel_connector_helper_funcs);
> +		ret = drm_connector_init(drm, mxsfb->connector,
> +					 &mxsfb_panel_connector_funcs,
> +					 DRM_MODE_CONNECTOR_Unknown);
> +	}
>  
>  	return ret;
>  }
> diff --git a/drivers/gpu/drm/mxsfb/mxsfb_regs.h b/drivers/gpu/drm/mxsfb/mxsfb_regs.h
> index 932d7ea..71426aa 100644
> --- a/drivers/gpu/drm/mxsfb/mxsfb_regs.h
> +++ b/drivers/gpu/drm/mxsfb/mxsfb_regs.h
> @@ -14,19 +14,31 @@
>  
>  #define LCDC_CTRL			0x00
>  #define LCDC_CTRL1			0x10
> +#define LCDC_V4_CTRL2			0x20
>  #define LCDC_V3_TRANSFER_COUNT		0x20
>  #define LCDC_V4_TRANSFER_COUNT		0x30
>  #define LCDC_V4_CUR_BUF			0x40
>  #define LCDC_V4_NEXT_BUF		0x50
>  #define LCDC_V3_CUR_BUF			0x30
>  #define LCDC_V3_NEXT_BUF		0x40
> +#define LCDC_TIMING			0x60
>  #define LCDC_VDCTRL0			0x70
>  #define LCDC_VDCTRL1			0x80
>  #define LCDC_VDCTRL2			0x90
>  #define LCDC_VDCTRL3			0xa0
>  #define LCDC_VDCTRL4			0xb0
> +#define LCDC_DVICTRL0			0xc0
> +#define LCDC_DVICTRL1			0xd0
> +#define LCDC_DVICTRL2			0xe0
> +#define LCDC_DVICTRL3			0xf0
> +#define LCDC_DVICTRL4			0x100
> +#define LCDC_V4_DATA			0x180
> +#define LCDC_V3_DATA			0x1b0
>  #define LCDC_V4_DEBUG0			0x1d0
>  #define LCDC_V3_DEBUG0			0x1f0
> +#define LCDC_AS_CTRL			0x210
> +#define LCDC_AS_BUF			0x220
> +#define LCDC_AS_NEXT_BUF		0x230
>  
>  #define CTRL_SFTRST			(1 << 31)
>  #define CTRL_CLKGATE			(1 << 30)
> @@ -45,12 +57,15 @@
>  #define CTRL_DF24			(1 << 1)
>  #define CTRL_RUN			(1 << 0)
>  
> +#define CTRL1_RECOVERY_ON_UNDERFLOW	(1 << 24)
>  #define CTRL1_FIFO_CLEAR		(1 << 21)
>  #define CTRL1_SET_BYTE_PACKAGING(x)	(((x) & 0xf) << 16)
>  #define CTRL1_GET_BYTE_PACKAGING(x)	(((x) >> 16) & 0xf)
>  #define CTRL1_CUR_FRAME_DONE_IRQ_EN	(1 << 13)
>  #define CTRL1_CUR_FRAME_DONE_IRQ	(1 << 9)
>  
> +#define CTRL2_OUTSTANDING_REQS__REQ_16		(4 << 21)
> +
>  #define TRANSFER_COUNT_SET_VCOUNT(x)	(((x) & 0xffff) << 16)
>  #define TRANSFER_COUNT_GET_VCOUNT(x)	(((x) >> 16) & 0xffff)
>  #define TRANSFER_COUNT_SET_HCOUNT(x)	((x) & 0xffff)
> -- 
> 2.7.4
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
Guido Günther July 21, 2019, 10:27 a.m. UTC | #6
Hi,
I'm not very familiar with mxsfb, just some things that stood out while
looking at the code:

On Wed, Jun 26, 2019 at 04:32:10PM +0300, Robert Chiras wrote:
> Since version 4 of eLCDIF, there are some registers that can do
> transformations on the input data, like re-arranging the pixel
> components. By doing that, we can support more pixel formats.
> This patch adds support for X/ABGR and RGBX/A. Although, the local alpha
> is not supported by eLCDIF, the alpha pixel formats were added to the
> supported pixel formats but it will be ignored. This was necessary since
> there are systems (like Android) that requires such pixel formats.
> 
> Also, add support for the following pixel formats:
>         16 bpp: RG16 ,BG16, XR15, XB15, AR15, AB15
> Set the bus format based on input from the user and panel capabilities.
> Save the bus format in crtc->mode.private_flags, so the bridge can use
> it.
> 
> Signed-off-by: Robert Chiras <robert.chiras@nxp.com>
> Signed-off-by: Mirela Rabulea <mirela.rabulea@nxp.com>
> ---
>  drivers/gpu/drm/mxsfb/mxsfb_crtc.c | 158 ++++++++++++++++++++++++++++++-------
>  drivers/gpu/drm/mxsfb/mxsfb_drv.c  |  30 +++++--
>  drivers/gpu/drm/mxsfb/mxsfb_drv.h  |   3 +-
>  drivers/gpu/drm/mxsfb/mxsfb_regs.h | 100 ++++++++++++++---------
>  4 files changed, 217 insertions(+), 74 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
> index 14bde024..e48396d 100644
> --- a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
> +++ b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
> @@ -41,14 +41,17 @@ static u32 set_hsync_pulse_width(struct mxsfb_drm_private *mxsfb, u32 val)
>  }
>  
>  /* Setup the MXSFB registers for decoding the pixels out of the framebuffer */
> -static int mxsfb_set_pixel_fmt(struct mxsfb_drm_private *mxsfb)
> +static int mxsfb_set_pixel_fmt(struct mxsfb_drm_private *mxsfb, bool update)
>  {
>  	struct drm_crtc *crtc = &mxsfb->pipe.crtc;
>  	struct drm_device *drm = crtc->dev;
>  	const u32 format = crtc->primary->state->fb->format->format;
> -	u32 ctrl, ctrl1;
> +	u32 ctrl = 0, ctrl1 = 0;
> +	bool bgr_format = true;
> +	struct drm_format_name_buf format_name_buf;
>  
> -	ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER;
> +	if (!update)
> +		ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER;
>  
>  	/*
>  	 * WARNING: The bus width, CTRL_SET_BUS_WIDTH(), is configured to
> @@ -57,64 +60,158 @@ static int mxsfb_set_pixel_fmt(struct mxsfb_drm_private *mxsfb)
>  	 * to arbitrary value. This limitation should not pose an issue.
>  	 */
>  
> -	/* CTRL1 contains IRQ config and status bits, preserve those. */
> -	ctrl1 = readl(mxsfb->base + LCDC_CTRL1);
> -	ctrl1 &= CTRL1_CUR_FRAME_DONE_IRQ_EN | CTRL1_CUR_FRAME_DONE_IRQ;
> +	if (!update) {
> +		/* CTRL1 contains IRQ config and status bits, preserve those. */
> +		ctrl1 = readl(mxsfb->base + LCDC_CTRL1);
> +		ctrl1 &= CTRL1_CUR_FRAME_DONE_IRQ_EN | CTRL1_CUR_FRAME_DONE_IRQ;
> +	}
> +
> +	DRM_DEV_DEBUG_DRIVER(drm->dev, "Setting up %s mode\n",
> +			     drm_get_format_name(format, &format_name_buf));
> +
> +	/* Do some clean-up that we might have from a previous mode */
> +	ctrl &= ~CTRL_SHIFT_DIR(1);
> +	ctrl &= ~CTRL_SHIFT_NUM(0x3f);
> +	if (mxsfb->devdata->ipversion >= 4)
> +		writel(CTRL2_ODD_LINE_PATTERN(0x7) |
> +		       CTRL2_EVEN_LINE_PATTERN(0x7),

Would it make sense to not use magic constants here but rather '#define'
the different line pattern values as well?


> +		       mxsfb->base + LCDC_V4_CTRL2 + REG_CLR);
>  
>  	switch (format) {
> -	case DRM_FORMAT_RGB565:
> -		dev_dbg(drm->dev, "Setting up RGB565 mode\n");
> +	case DRM_FORMAT_BGR565: /* BG16 */
> +		if (mxsfb->devdata->ipversion < 4)
> +			goto err;
> +		writel(CTRL2_ODD_LINE_PATTERN(0x5) |
> +			CTRL2_EVEN_LINE_PATTERN(0x5),
> +			mxsfb->base + LCDC_V4_CTRL2 + REG_SET);
> +		/* Fall through */
> +	case DRM_FORMAT_RGB565: /* RG16 */
> +		ctrl |= CTRL_SET_WORD_LENGTH(0);
> +		ctrl &= ~CTRL_DF16;
> +		ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf);
> +		break;
> +	case DRM_FORMAT_XBGR1555: /* XB15 */
> +	case DRM_FORMAT_ABGR1555: /* AB15 */
> +		if (mxsfb->devdata->ipversion < 4)
> +			goto err;
> +		writel(CTRL2_ODD_LINE_PATTERN(0x5) |
> +			CTRL2_EVEN_LINE_PATTERN(0x5),
> +			mxsfb->base + LCDC_V4_CTRL2 + REG_SET);
> +		/* Fall through */
> +	case DRM_FORMAT_XRGB1555: /* XR15 */
> +	case DRM_FORMAT_ARGB1555: /* AR15 */
>  		ctrl |= CTRL_SET_WORD_LENGTH(0);
> +		ctrl |= CTRL_DF16;
>  		ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf);
>  		break;
> -	case DRM_FORMAT_XRGB8888:
> -		dev_dbg(drm->dev, "Setting up XRGB8888 mode\n");
> +	case DRM_FORMAT_RGBX8888: /* RX24 */
> +	case DRM_FORMAT_RGBA8888: /* RA24 */
> +		/* RGBX - > 0RGB */
> +		ctrl |= CTRL_SHIFT_DIR(1);
> +		ctrl |= CTRL_SHIFT_NUM(8);
> +		bgr_format = false;
> +		/* Fall through */
> +	case DRM_FORMAT_XBGR8888: /* XB24 */
> +	case DRM_FORMAT_ABGR8888: /* AB24 */
> +		if (bgr_format) {
> +			if (mxsfb->devdata->ipversion < 4)
> +				goto err;
> +			writel(CTRL2_ODD_LINE_PATTERN(0x5) |
> +			       CTRL2_EVEN_LINE_PATTERN(0x5),
> +			       mxsfb->base + LCDC_V4_CTRL2 + REG_SET);
> +		}
> +		/* Fall through */
> +	case DRM_FORMAT_XRGB8888: /* XR24 */
> +	case DRM_FORMAT_ARGB8888: /* AR24 */
>  		ctrl |= CTRL_SET_WORD_LENGTH(3);
>  		/* Do not use packed pixels = one pixel per word instead. */
>  		ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0x7);
>  		break;
>  	default:
> -		dev_err(drm->dev, "Unhandled pixel format %08x\n", format);
> -		return -EINVAL;
> +		goto err;
>  	}
>  
> -	writel(ctrl1, mxsfb->base + LCDC_CTRL1);
> -	writel(ctrl, mxsfb->base + LCDC_CTRL);
> +	if (update) {
> +		writel(ctrl, mxsfb->base + LCDC_CTRL + REG_SET);
> +		writel(ctrl1, mxsfb->base + LCDC_CTRL1 + REG_SET);
> +	} else {
> +		writel(ctrl, mxsfb->base + LCDC_CTRL);
> +		writel(ctrl1, mxsfb->base + LCDC_CTRL1);
> +	}
>  
>  	return 0;
> +
> +err:
> +	DRM_DEV_ERROR(drm->dev, "Unhandled pixel format: %s\n",
> +		      drm_get_format_name(format, &format_name_buf));
> +
> +	return -EINVAL;
> +}
> +
> +static u32 get_bus_format_from_bpp(u32 bpp)
> +{
> +	switch (bpp) {
> +	case 16:
> +		return MEDIA_BUS_FMT_RGB565_1X16;
> +	case 18:
> +		return MEDIA_BUS_FMT_RGB666_1X18;
> +	case 24:
> +		return MEDIA_BUS_FMT_RGB888_1X24;
> +	default:
> +		return MEDIA_BUS_FMT_RGB888_1X24;
> +	}
>  }
>  
>  static void mxsfb_set_bus_fmt(struct mxsfb_drm_private *mxsfb)
>  {
>  	struct drm_crtc *crtc = &mxsfb->pipe.crtc;
> +	unsigned int bits_per_pixel = crtc->primary->state->fb->format->depth;
>  	struct drm_device *drm = crtc->dev;
>  	u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
> -	u32 reg;
> -
> -	reg = readl(mxsfb->base + LCDC_CTRL);
> +	int num_bus_formats = mxsfb->connector->display_info.num_bus_formats;
> +	const u32 *bus_formats = mxsfb->connector->display_info.bus_formats;
> +	u32 reg = 0;
> +	int i = 0;
> +
> +	/* match the user requested bus_format to one supported by the panel */
> +	if (num_bus_formats) {
> +		u32 user_bus_format = get_bus_format_from_bpp(bits_per_pixel);
> +
> +		bus_format = bus_formats[0];
> +		for (i = 0; i < num_bus_formats; i++) {
> +			if (user_bus_format == bus_formats[i]) {
> +				bus_format = user_bus_format;
> +				break;
> +			}
> +		}
> +	}
>  
> -	if (mxsfb->connector->display_info.num_bus_formats)
> -		bus_format = mxsfb->connector->display_info.bus_formats[0];
> +	/*
> +	 * CRTC will dictate the bus format via private_flags[16:1]
> +	 * and private_flags[0] will signal a bus format change
> +	 */
> +	crtc->mode.private_flags &= ~0x1FFFF; /* clear bus format */
> +	crtc->mode.private_flags |= (bus_format << 1); /* set bus format */
> +	crtc->mode.private_flags |= 0x1; /* bus format change indication*/
>  
>  	DRM_DEV_DEBUG_DRIVER(drm->dev, "Using bus_format: 0x%08X\n",
>  			     bus_format);
>  
> -	reg &= ~CTRL_BUS_WIDTH_MASK;
>  	switch (bus_format) {
>  	case MEDIA_BUS_FMT_RGB565_1X16:
> -		reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_16BIT);
> +		reg = CTRL_SET_BUS_WIDTH(STMLCDIF_16BIT);
>  		break;
>  	case MEDIA_BUS_FMT_RGB666_1X18:
> -		reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_18BIT);
> +		reg = CTRL_SET_BUS_WIDTH(STMLCDIF_18BIT);
>  		break;
>  	case MEDIA_BUS_FMT_RGB888_1X24:
> -		reg |= CTRL_SET_BUS_WIDTH(STMLCDIF_24BIT);
> +		reg = CTRL_SET_BUS_WIDTH(STMLCDIF_24BIT);
>  		break;
>  	default:
>  		dev_err(drm->dev, "Unknown media bus format %d\n", bus_format);
>  		break;
>  	}
> -	writel(reg, mxsfb->base + LCDC_CTRL);
> +	writel(reg, mxsfb->base + LCDC_CTRL + REG_SET);
>  }
>  
>  static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb)
> @@ -125,8 +222,9 @@ static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb)
>  		clk_prepare_enable(mxsfb->clk_disp_axi);
>  	clk_prepare_enable(mxsfb->clk);
>  
> -	writel(CTRL2_OUTSTANDING_REQS__REQ_16,
> -	       mxsfb->base + LCDC_V4_CTRL2 + REG_SET);
> +	if (mxsfb->devdata->ipversion >= 4)
> +		writel(CTRL2_OUTSTANDING_REQS__REQ_16,
> +		       mxsfb->base + LCDC_V4_CTRL2 + REG_SET);
>  
>  	/* If it was disabled, re-enable the mode again */
>  	writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET);
> @@ -144,6 +242,10 @@ static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb)
>  {
>  	u32 reg;
>  
> +	if (mxsfb->devdata->ipversion >= 4)
> +		writel(CTRL2_OUTSTANDING_REQS(0x7),
> +		       mxsfb->base + LCDC_V4_CTRL2 + REG_CLR);
> +
>  	writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_CLR);
>  
>  	/*
> @@ -231,7 +333,7 @@ static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb)
>  	/* Clear the FIFOs */
>  	writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET);
>  
> -	err = mxsfb_set_pixel_fmt(mxsfb);
> +	err = mxsfb_set_pixel_fmt(mxsfb, false);
>  	if (err)
>  		return;
>  
> @@ -316,7 +418,7 @@ void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb)
>  }
>  
>  void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb,
> -			       struct drm_plane_state *state)
> +			       struct drm_plane_state *old_state)

This hunk belongs to the previous commit.

>  {
>  	struct drm_simple_display_pipe *pipe = &mxsfb->pipe;
>  	struct drm_crtc *crtc = &pipe->crtc;
> diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c
> index 0d171e9..d9fb734 100644
> --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c
> +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c
> @@ -40,6 +40,27 @@ enum mxsfb_devtype {
>  	MXSFB_V4,
>  };
>  
> +/*
> + * When adding new formats, make sure to update the num_formats from
> + * mxsfb_devdata below.
> + */
> +static const u32 mxsfb_formats[] = {
> +	/* MXSFB_V3 */
> +	DRM_FORMAT_XRGB8888,
> +	DRM_FORMAT_ARGB8888,
> +	DRM_FORMAT_RGB565,
> +	/* MXSFB_V4 */
> +	DRM_FORMAT_XBGR8888,
> +	DRM_FORMAT_ABGR8888,
> +	DRM_FORMAT_RGBX8888,
> +	DRM_FORMAT_RGBA8888,
> +	DRM_FORMAT_ARGB1555,
> +	DRM_FORMAT_XRGB1555,
> +	DRM_FORMAT_ABGR1555,
> +	DRM_FORMAT_XBGR1555,
> +	DRM_FORMAT_BGR565
> +};
> +
>  static const struct mxsfb_devdata mxsfb_devdata[] = {
>  	[MXSFB_V3] = {
>  		.transfer_count	= LCDC_V3_TRANSFER_COUNT,
> @@ -49,6 +70,7 @@ static const struct mxsfb_devdata mxsfb_devdata[] = {
>  		.hs_wdth_mask	= 0xff,
>  		.hs_wdth_shift	= 24,
>  		.ipversion	= 3,
> +		.num_formats	= 3,
>  	},
>  	[MXSFB_V4] = {
>  		.transfer_count	= LCDC_V4_TRANSFER_COUNT,
> @@ -58,14 +80,10 @@ static const struct mxsfb_devdata mxsfb_devdata[] = {
>  		.hs_wdth_mask	= 0x3fff,
>  		.hs_wdth_shift	= 18,
>  		.ipversion	= 4,
> +		.num_formats	= ARRAY_SIZE(mxsfb_formats),
>  	},
>  };
>  
> -static const uint32_t mxsfb_formats[] = {
> -	DRM_FORMAT_XRGB8888,
> -	DRM_FORMAT_RGB565
> -};
> -
>  static struct mxsfb_drm_private *
>  drm_pipe_to_mxsfb_drm_private(struct drm_simple_display_pipe *pipe)
>  {
> @@ -241,7 +259,7 @@ static int mxsfb_load(struct drm_device *drm, unsigned long flags)
>  	}
>  
>  	ret = drm_simple_display_pipe_init(drm, &mxsfb->pipe, &mxsfb_funcs,
> -			mxsfb_formats, ARRAY_SIZE(mxsfb_formats), NULL,
> +			mxsfb_formats, mxsfb->devdata->num_formats, NULL,
>  			mxsfb->connector);
>  	if (ret < 0) {
>  		dev_err(drm->dev, "Cannot setup simple display pipe\n");
> diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.h b/drivers/gpu/drm/mxsfb/mxsfb_drv.h
> index 0b65b51..8fb65d3 100644
> --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.h
> +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.h
> @@ -16,6 +16,7 @@ struct mxsfb_devdata {
>  	unsigned int	 hs_wdth_mask;
>  	unsigned int	 hs_wdth_shift;
>  	unsigned int	 ipversion;
> +	unsigned int	 num_formats;
>  };
>  
>  struct mxsfb_drm_private {
> @@ -42,6 +43,6 @@ void mxsfb_disable_axi_clk(struct mxsfb_drm_private *mxsfb);
>  void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb);
>  void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb);
>  void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb,
> -			       struct drm_plane_state *state);
> +			       struct drm_plane_state *old_state);
>  
>  #endif /* __MXSFB_DRV_H__ */
> diff --git a/drivers/gpu/drm/mxsfb/mxsfb_regs.h b/drivers/gpu/drm/mxsfb/mxsfb_regs.h
> index 71426aa..9ee0d3c7 100644
> --- a/drivers/gpu/drm/mxsfb/mxsfb_regs.h
> +++ b/drivers/gpu/drm/mxsfb/mxsfb_regs.h
> @@ -40,54 +40,76 @@
>  #define LCDC_AS_BUF			0x220
>  #define LCDC_AS_NEXT_BUF		0x230
>  
> -#define CTRL_SFTRST			(1 << 31)
> -#define CTRL_CLKGATE			(1 << 30)
> -#define CTRL_BYPASS_COUNT		(1 << 19)
> -#define CTRL_VSYNC_MODE			(1 << 18)
> -#define CTRL_DOTCLK_MODE		(1 << 17)
> -#define CTRL_DATA_SELECT		(1 << 16)
> -#define CTRL_SET_BUS_WIDTH(x)		(((x) & 0x3) << 10)
> -#define CTRL_GET_BUS_WIDTH(x)		(((x) >> 10) & 0x3)
> -#define CTRL_BUS_WIDTH_MASK		(0x3 << 10)
> -#define CTRL_SET_WORD_LENGTH(x)		(((x) & 0x3) << 8)
> -#define CTRL_GET_WORD_LENGTH(x)		(((x) >> 8) & 0x3)
> -#define CTRL_MASTER			(1 << 5)
> -#define CTRL_DF16			(1 << 3)
> -#define CTRL_DF18			(1 << 2)
> -#define CTRL_DF24			(1 << 1)
> -#define CTRL_RUN			(1 << 0)
> -
> -#define CTRL1_RECOVERY_ON_UNDERFLOW	(1 << 24)
> -#define CTRL1_FIFO_CLEAR		(1 << 21)
> -#define CTRL1_SET_BYTE_PACKAGING(x)	(((x) & 0xf) << 16)
> -#define CTRL1_GET_BYTE_PACKAGING(x)	(((x) >> 16) & 0xf)
> -#define CTRL1_CUR_FRAME_DONE_IRQ_EN	(1 << 13)
> -#define CTRL1_CUR_FRAME_DONE_IRQ	(1 << 9)
> -
> -#define CTRL2_OUTSTANDING_REQS__REQ_16		(4 << 21)
> +/* reg bit manipulation */
> +#define REG_MASK(e, s) (((1 << ((e) - (s) + 1)) - 1) << (s))
> +#define REG_PUT(x, e, s) (((x) << (s)) & REG_MASK(e, s))
> +#define REG_GET(x, e, s) (((x) & REG_MASK(e, s)) >> (s))
> +
> +#define SWIZZLE_LE		0 /* Little-Endian or No swap */
> +#define SWIZZLE_BE		1 /* Big-Endian or swap all */
> +#define SWIZZLE_HWD		2 /* Swap half-words */
> +#define SWIZZLE_HWD_BYTE	3 /* Swap bytes within each half-word */
> +
> +#define CTRL_SFTRST			BIT(31)
> +#define CTRL_CLKGATE			BIT(30)
> +#define CTRL_SHIFT_DIR(x)		REG_PUT((x), 26, 26)
> +#define CTRL_SHIFT_NUM(x)		REG_PUT((x), 25, 21)
> +#define CTRL_BYPASS_COUNT		BIT(19)
> +#define CTRL_VSYNC_MODE			BIT(18)
> +#define CTRL_DOTCLK_MODE		BIT(17)
> +#define CTRL_DATA_SELECT		BIT(16)
> +#define CTRL_INPUT_SWIZZLE(x)		REG_PUT((x), 15, 14)
> +#define CTRL_CSC_SWIZZLE(x)		REG_PUT((x), 13, 12)
> +#define CTRL_SET_BUS_WIDTH(x)		REG_PUT((x), 11, 10)
> +#define CTRL_GET_BUS_WIDTH(x)		REG_GET((x), 11, 10)
> +#define CTRL_BUS_WIDTH_MASK		REG_PUT((0x3), 11, 10)
> +#define CTRL_SET_WORD_LENGTH(x)		REG_PUT((x), 9, 8)
> +#define CTRL_GET_WORD_LENGTH(x)		REG_GET((x), 9, 8)
> +#define CTRL_MASTER			BIT(5)
> +#define CTRL_DF16			BIT(3)
> +#define CTRL_DF18			BIT(2)
> +#define CTRL_DF24			BIT(1)
> +#define CTRL_RUN			BIT(0)
> +
> +#define CTRL1_RECOVERY_ON_UNDERFLOW	BIT(24)
> +#define CTRL1_FIFO_CLEAR		BIT(21)
> +#define CTRL1_SET_BYTE_PACKAGING(x)	REG_PUT((x), 19, 16)
> +#define CTRL1_GET_BYTE_PACKAGING(x)	REG_GET((x), 19, 16)
> +#define CTRL1_CUR_FRAME_DONE_IRQ_EN	BIT(13)
> +#define CTRL1_CUR_FRAME_DONE_IRQ	BIT(9)

Splitting the cleanups (introduction of BIT(x) usage) from new defines
would ease reviewing.
Cheers,
 -- Guido

> +
> +#define REQ_1	0
> +#define REQ_2	1
> +#define REQ_4	2
> +#define REQ_8	3
> +#define REQ_16	4
> +
> +#define CTRL2_OUTSTANDING_REQS(x)	REG_PUT((x), 23, 21)
> +#define CTRL2_ODD_LINE_PATTERN(x)	REG_PUT((x), 18, 16)
> +#define CTRL2_EVEN_LINE_PATTERN(x)	REG_PUT((x), 14, 12)
>  
>  #define TRANSFER_COUNT_SET_VCOUNT(x)	(((x) & 0xffff) << 16)
>  #define TRANSFER_COUNT_GET_VCOUNT(x)	(((x) >> 16) & 0xffff)
>  #define TRANSFER_COUNT_SET_HCOUNT(x)	((x) & 0xffff)
>  #define TRANSFER_COUNT_GET_HCOUNT(x)	((x) & 0xffff)
>  
> -#define VDCTRL0_ENABLE_PRESENT		(1 << 28)
> -#define VDCTRL0_VSYNC_ACT_HIGH		(1 << 27)
> -#define VDCTRL0_HSYNC_ACT_HIGH		(1 << 26)
> -#define VDCTRL0_DOTCLK_ACT_FALLING	(1 << 25)
> -#define VDCTRL0_ENABLE_ACT_HIGH		(1 << 24)
> -#define VDCTRL0_VSYNC_PERIOD_UNIT	(1 << 21)
> -#define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT	(1 << 20)
> -#define VDCTRL0_HALF_LINE		(1 << 19)
> -#define VDCTRL0_HALF_LINE_MODE		(1 << 18)
> +#define VDCTRL0_ENABLE_PRESENT		BIT(28)
> +#define VDCTRL0_VSYNC_ACT_HIGH		BIT(27)
> +#define VDCTRL0_HSYNC_ACT_HIGH		BIT(26)
> +#define VDCTRL0_DOTCLK_ACT_FALLING	BIT(25)
> +#define VDCTRL0_ENABLE_ACT_HIGH		BIT(24)
> +#define VDCTRL0_VSYNC_PERIOD_UNIT	BIT(21)
> +#define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT	BIT(20)
> +#define VDCTRL0_HALF_LINE		BIT(19)
> +#define VDCTRL0_HALF_LINE_MODE		BIT(18)
>  #define VDCTRL0_SET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff)
>  #define VDCTRL0_GET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff)
>  
>  #define VDCTRL2_SET_HSYNC_PERIOD(x)	((x) & 0x3ffff)
>  #define VDCTRL2_GET_HSYNC_PERIOD(x)	((x) & 0x3ffff)
>  
> -#define VDCTRL3_MUX_SYNC_SIGNALS	(1 << 29)
> -#define VDCTRL3_VSYNC_ONLY		(1 << 28)
> +#define VDCTRL3_MUX_SYNC_SIGNALS	BIT(29)
> +#define VDCTRL3_VSYNC_ONLY		BIT(28)
>  #define SET_HOR_WAIT_CNT(x)		(((x) & 0xfff) << 16)
>  #define GET_HOR_WAIT_CNT(x)		(((x) >> 16) & 0xfff)
>  #define SET_VERT_WAIT_CNT(x)		((x) & 0xffff)
> @@ -95,7 +117,7 @@
>  
>  #define VDCTRL4_SET_DOTCLK_DLY(x)	(((x) & 0x7) << 29) /* v4 only */
>  #define VDCTRL4_GET_DOTCLK_DLY(x)	(((x) >> 29) & 0x7) /* v4 only */
> -#define VDCTRL4_SYNC_SIGNALS_ON		(1 << 18)
> +#define VDCTRL4_SYNC_SIGNALS_ON		BIT(18)
>  #define SET_DOTCLK_H_VALID_DATA_CNT(x)	((x) & 0x3ffff)
>  
>  #define DEBUG0_HSYNC			(1 < 26)
> @@ -116,7 +138,7 @@
>  #define STMLCDIF_18BIT 2 /* pixel data bus to the display is of 18 bit width */
>  #define STMLCDIF_24BIT 3 /* pixel data bus to the display is of 24 bit width */
>  
> -#define MXSFB_SYNC_DATA_ENABLE_HIGH_ACT	(1 << 6)
> -#define MXSFB_SYNC_DOTCLK_FALLING_ACT	(1 << 7) /* negative edge sampling */
> +#define MXSFB_SYNC_DATA_ENABLE_HIGH_ACT	BIT(6)
> +#define MXSFB_SYNC_DOTCLK_FALLING_ACT	BIT(7) /* negative edge sampling */
>  
>  #endif /* __MXSFB_REGS_H__ */
> -- 
> 2.7.4
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
Guido Günther Aug. 13, 2019, 10:23 a.m. UTC | #7
Hi Robert,
On Wed, Jun 26, 2019 at 04:32:08PM +0300, Robert Chiras wrote:
> This patch-set improves the use of eLCDIF block on iMX 8 SoCs (like 8MQ, 8MM
> and 8QXP). Following, are the new features added and fixes from this
> patch-set:

There was some feedback on various patches, do you intend to pick that
up again? That would be cool since there's some overlapping work popping
up already e.g. in

    https://patchwork.freedesktop.org/series/64595/

showing up and it's the base for the tiny

    https://patchwork.freedesktop.org/series/64300/    

Cheers,
 -- Guido
Robert Chiras Aug. 13, 2019, 10:36 a.m. UTC | #8
On Ma, 2019-08-13 at 12:23 +0200, Guido Günther wrote:
> Hi Robert,
> On Wed, Jun 26, 2019 at 04:32:08PM +0300, Robert Chiras wrote:
> > 
> > This patch-set improves the use of eLCDIF block on iMX 8 SoCs (like
> > 8MQ, 8MM
> > and 8QXP). Following, are the new features added and fixes from
> > this
> > patch-set:
> There was some feedback on various patches, do you intend to pick
> that
> up again? That would be cool since there's some overlapping work
> popping
> up already e.g. in
> 
>     https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2
> Fpatchwork.freedesktop.org%2Fseries%2F64595%2F&amp;data=02%7C01%7Crob
> ert.chiras%40nxp.com%7C6ca6724a656b41912f0408d71fd83da0%7C686ea1d3bc2
> b4c6fa92cd99c5c301635%7C0%7C0%7C637012885918631196&amp;sdata=b3CrbNu%
> 2FcsWBOA%2BcaQLX%2BrlrK7%2Fhf2%2F1vZS3eQGN7aM%3D&amp;reserved=0
> 
> showing up and it's the base for the tiny
> 
>     https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2
> Fpatchwork.freedesktop.org%2Fseries%2F64300%2F&amp;data=02%7C01%7Crob
> ert.chiras%40nxp.com%7C6ca6724a656b41912f0408d71fd83da0%7C686ea1d3bc2
> b4c6fa92cd99c5c301635%7C0%7C0%7C637012885918641196&amp;sdata=h6KLVnSx
> xBwvK%2FvPF9zt4DQR6WnF1pyQSwKBTO4rQTg%3D&amp;reserved=0
> 
> Cheers,
>  -- Guido

Hi Guido,

Yes, I plan to submit a next revision, but first I wanted to try it with your patch-set for the nwl-dsi driver.
Thanks for the heads-up.

Best regards,
Robert