[PATCH 4/7] drm/pl111: Enable PL110 variant

Eric Engestrom eric.engestrom at imgtec.com
Thu Aug 31 03:19:13 PDT 2017


On Wednesday, 2017-08-30 20:07:08 +0200, Linus Walleij wrote:
> We detect and enable the use of the PL110 variant, an earlier
> incarnation of PL111. The only real difference is that the
> control and interrupt enable registers have swapped place.
> The Versatile AB and Versatile PB have a variant inbetween
> PL110 and PL111, it is PL110 but they have already swapped the
> two registers so those two need a bit of special handling.
> 
> Signed-off-by: Linus Walleij <linus.walleij at linaro.org>
> ---
>  drivers/gpu/drm/pl111/pl111_display.c | 27 +++--------
>  drivers/gpu/drm/pl111/pl111_drm.h     | 17 +++++++
>  drivers/gpu/drm/pl111/pl111_drv.c     | 84 ++++++++++++++++++++++++++++++++++-
>  3 files changed, 105 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/gpu/drm/pl111/pl111_display.c b/drivers/gpu/drm/pl111/pl111_display.c
> index ef86ef60aed1..6447f36c243a 100644
> --- a/drivers/gpu/drm/pl111/pl111_display.c
> +++ b/drivers/gpu/drm/pl111/pl111_display.c
> @@ -201,7 +201,7 @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe,
>  		break;
>  	}
>  
> -	writel(cntl, priv->regs + CLCD_PL111_CNTL);
> +	writel(cntl, priv->regs + priv->ctrl);
>  
>  	drm_panel_enable(priv->panel);
>  
> @@ -219,7 +219,7 @@ void pl111_display_disable(struct drm_simple_display_pipe *pipe)
>  	drm_panel_disable(priv->panel);
>  
>  	/* Disable and Power Down */
> -	writel(0, priv->regs + CLCD_PL111_CNTL);
> +	writel(0, priv->regs + priv->ctrl);
>  
>  	drm_panel_unprepare(priv->panel);
>  
> @@ -259,7 +259,7 @@ int pl111_enable_vblank(struct drm_device *drm, unsigned int crtc)
>  {
>  	struct pl111_drm_dev_private *priv = drm->dev_private;
>  
> -	writel(CLCD_IRQ_NEXTBASE_UPDATE, priv->regs + CLCD_PL111_IENB);
> +	writel(CLCD_IRQ_NEXTBASE_UPDATE, priv->regs + priv->ienb);
>  
>  	return 0;
>  }
> @@ -268,7 +268,7 @@ void pl111_disable_vblank(struct drm_device *drm, unsigned int crtc)
>  {
>  	struct pl111_drm_dev_private *priv = drm->dev_private;
>  
> -	writel(0, priv->regs + CLCD_PL111_IENB);
> +	writel(0, priv->regs + priv->ienb);
>  }
>  
>  static int pl111_display_prepare_fb(struct drm_simple_display_pipe *pipe,
> @@ -412,22 +412,6 @@ int pl111_display_init(struct drm_device *drm)
>  	struct device_node *endpoint;
>  	u32 tft_r0b0g0[3];
>  	int ret;
> -	static const u32 formats[] = {
> -		DRM_FORMAT_ABGR8888,
> -		DRM_FORMAT_XBGR8888,
> -		DRM_FORMAT_ARGB8888,
> -		DRM_FORMAT_XRGB8888,
> -		DRM_FORMAT_BGR565,
> -		DRM_FORMAT_RGB565,
> -		DRM_FORMAT_ABGR1555,
> -		DRM_FORMAT_XBGR1555,
> -		DRM_FORMAT_ARGB1555,
> -		DRM_FORMAT_XRGB1555,
> -		DRM_FORMAT_ABGR4444,
> -		DRM_FORMAT_XBGR4444,
> -		DRM_FORMAT_ARGB4444,
> -		DRM_FORMAT_XRGB4444,
> -	};
>  
>  	endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
>  	if (!endpoint)
> @@ -456,7 +440,8 @@ int pl111_display_init(struct drm_device *drm)
>  
>  	ret = drm_simple_display_pipe_init(drm, &priv->pipe,
>  					   &pl111_display_funcs,
> -					   formats, ARRAY_SIZE(formats),
> +					   priv->variant->formats,
> +					   priv->variant->nformats,
>  					   priv->connector);
>  	if (ret)
>  		return ret;
> diff --git a/drivers/gpu/drm/pl111/pl111_drm.h b/drivers/gpu/drm/pl111/pl111_drm.h
> index 8804af0f8997..b316a8a0fbc0 100644
> --- a/drivers/gpu/drm/pl111/pl111_drm.h
> +++ b/drivers/gpu/drm/pl111/pl111_drm.h
> @@ -31,6 +31,20 @@
>  
>  struct drm_minor;
>  
> +/**
> + * struct pl111_variant_data - encodes IP differences
> + * @name: the name of this variant
> + * @is_pl110: this is the early PL110 variant
> + * @formats: array of supported pixel formats on this variant
> + * @nformats: the length of the array of supported pixel formats
> + */
> +struct pl111_variant_data {
> +	const char *name;
> +	bool is_pl110;
> +	const u32 *formats;
> +	unsigned int nformats;
> +};
> +
>  struct pl111_drm_dev_private {
>  	struct drm_device *drm;
>  
> @@ -42,6 +56,8 @@ struct pl111_drm_dev_private {
>  	struct drm_fbdev_cma *fbdev;
>  
>  	void *regs;
> +	u32 ienb;
> +	u32 ctrl;
>  	/* The pixel clock (a reference to our clock divider off of CLCDCLK). */
>  	struct clk *clk;
>  	/* pl111's internal clock divider. */
> @@ -50,6 +66,7 @@ struct pl111_drm_dev_private {
>  	 * subsystem and pl111_display_enable().
>  	 */
>  	spinlock_t tim2_lock;
> +	struct pl111_variant_data *variant;
>  };
>  
>  int pl111_display_init(struct drm_device *dev);
> diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c
> index e66cbf202e17..f6863c0fb809 100644
> --- a/drivers/gpu/drm/pl111/pl111_drv.c
> +++ b/drivers/gpu/drm/pl111/pl111_drv.c
> @@ -206,6 +206,7 @@ static int pl111_amba_probe(struct amba_device *amba_dev,
>  {
>  	struct device *dev = &amba_dev->dev;
>  	struct pl111_drm_dev_private *priv;
> +	struct pl111_variant_data *variant = id->data;
>  	struct drm_device *drm;
>  	int ret;
>  
> @@ -219,6 +220,33 @@ static int pl111_amba_probe(struct amba_device *amba_dev,
>  	amba_set_drvdata(amba_dev, drm);
>  	priv->drm = drm;
>  	drm->dev_private = priv;
> +	priv->variant = variant;
> +
> +	/*
> +	 * The PL110 and PL111 variants have two registers
> +	 * swapped: interrupt enable and control. For this reason
> +	 * we use offsets that we can change per variant.
> +	 */
> +	if (variant->is_pl110) {
> +		/*
> +		 * The ARM Versatile boards are even more special:
> +		 * their PrimeCell ID say they are PL110 but the
> +		 * control and interrupt enable registers are anyway
> +		 * swapped to the PL111 order so they are not following
> +		 * the PL110 datasheet.
> +		 */
> +		if (of_machine_is_compatible("arm,versatile-ab") ||
> +		    of_machine_is_compatible("arm,versatile-pb")) {
> +			priv->ienb = CLCD_PL111_IENB;
> +			priv->ctrl = CLCD_PL111_CNTL;
> +		} else {
> +			priv->ienb = CLCD_PL110_IENB;
> +			priv->ctrl = CLCD_PL110_CNTL;
> +		}
> +	} else {
> +		priv->ienb = CLCD_PL111_IENB;
> +		priv->ctrl = CLCD_PL111_CNTL;
> +	}
>  
>  	priv->regs = devm_ioremap_resource(dev, &amba_dev->res);
>  	if (IS_ERR(priv->regs)) {
> @@ -227,10 +255,10 @@ static int pl111_amba_probe(struct amba_device *amba_dev,
>  	}
>  
>  	/* turn off interrupts before requesting the irq */
> -	writel(0, priv->regs + CLCD_PL111_IENB);
> +	writel(0, priv->regs + priv->ienb);
>  
>  	ret = devm_request_irq(dev, amba_dev->irq[0], pl111_irq, 0,
> -			       "pl111", priv);
> +			       variant->name, priv);
>  	if (ret != 0) {
>  		dev_err(dev, "%s failed irq %d\n", __func__, ret);
>  		return ret;
> @@ -269,10 +297,62 @@ static int pl111_amba_remove(struct amba_device *amba_dev)
>  	return 0;
>  }
>  
> +/*
> + * This variant exist in early versions like the ARM Integrator
> + * and this version lacks the 565 and 444 pixel formats.
> + */
> +static const u32 pl110_pixel_formats[] = {
> +	DRM_FORMAT_ABGR8888,
> +	DRM_FORMAT_XBGR8888,
> +	DRM_FORMAT_ARGB8888,
> +	DRM_FORMAT_XRGB8888,
> +	DRM_FORMAT_ABGR1555,
> +	DRM_FORMAT_XBGR1555,
> +	DRM_FORMAT_ARGB1555,
> +	DRM_FORMAT_XRGB1555,
> +};
> +
> +struct pl111_variant_data pl110_variant = {

I think this (and `pl111_variant` below) can be `static const`, right?

> +	.name = "PL110",
> +	.is_pl110 = true,
> +	.formats = pl110_pixel_formats,
> +	.nformats = ARRAY_SIZE(pl110_pixel_formats),
> +};
> +
> +/* RealView, Versatile Express etc use this modern variant */
> +static const u32 pl111_pixel_formats[] = {
> +	DRM_FORMAT_ABGR8888,
> +	DRM_FORMAT_XBGR8888,
> +	DRM_FORMAT_ARGB8888,
> +	DRM_FORMAT_XRGB8888,
> +	DRM_FORMAT_BGR565,
> +	DRM_FORMAT_RGB565,
> +	DRM_FORMAT_ABGR1555,
> +	DRM_FORMAT_XBGR1555,
> +	DRM_FORMAT_ARGB1555,
> +	DRM_FORMAT_XRGB1555,
> +	DRM_FORMAT_ABGR4444,
> +	DRM_FORMAT_XBGR4444,
> +	DRM_FORMAT_ARGB4444,
> +	DRM_FORMAT_XRGB4444,
> +};
> +
> +struct pl111_variant_data pl111_variant = {
> +	.name = "PL111",
> +	.formats = pl111_pixel_formats,
> +	.nformats = ARRAY_SIZE(pl111_pixel_formats),
> +};
> +
>  static struct amba_id pl111_id_table[] = {

Not 100% sure on this one, but I think it can also be `const`, as
amba_lookup() and pl111_amba_probe() are the only users I could find and
both take a `const struct amba_id *` (and pl111_amba_probe() doesn't
even use it).

(Just a couple drive-by comments, I don't know enough for an actual
review, sorry...)

>  	{
> +		.id = 0x00041110,
> +		.mask = 0x000fffff,
> +		.data = &pl110_variant,
> +	},
> +	{
>  		.id = 0x00041111,
>  		.mask = 0x000fffff,
> +		.data = &pl111_variant,
>  	},
>  	{0, 0},
>  };
> -- 
> 2.13.5
> 



More information about the linux-arm-kernel mailing list