[PATCH v2 08/10] drm/ingenic: Add support for OSD mode

Sam Ravnborg sam at ravnborg.org
Tue Jun 30 12:05:18 UTC 2020


Hi Paul.

On Tue, Jun 30, 2020 at 01:52:08AM +0200, Paul Cercueil wrote:
> All Ingenic SoCs starting from the JZ4725B support OSD mode.
> 
> In this mode, two separate planes can be used. They can have different
> positions and sizes, and one can be overlayed on top of the other.
> 
> Signed-off-by: Paul Cercueil <paul at crapouillou.net>

OSD? On screen Display?

Some random comments in the following - from my attempt to follow the
code.

	Sam


> ---
> 
> Notes:
>     v2: Use fallthrough; instead of /* fall-through */
> 
>  drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 271 +++++++++++++++++-----
>  drivers/gpu/drm/ingenic/ingenic-drm.h     |  35 +++
>  2 files changed, 254 insertions(+), 52 deletions(-)
> 
> diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
> index 6590b61cb915..a8573da1d577 100644
> --- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
> +++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
> @@ -43,12 +43,13 @@ struct ingenic_dma_hwdesc {
>  
>  struct jz_soc_info {
>  	bool needs_dev_clk;
> +	bool has_osd;
>  	unsigned int max_width, max_height;
>  };
>  
>  struct ingenic_drm {
>  	struct drm_device drm;
> -	struct drm_plane primary;
> +	struct drm_plane f0, f1;

A small comment about when f0 and f1 is used and how they are the
primary plane would be good here.


>  	struct drm_crtc crtc;
>  	struct drm_encoder encoder;
>  
> @@ -57,8 +58,8 @@ struct ingenic_drm {
>  	struct clk *lcd_clk, *pix_clk;
>  	const struct jz_soc_info *soc_info;
>  
> -	struct ingenic_dma_hwdesc *dma_hwdesc;
> -	dma_addr_t dma_hwdesc_phys;
> +	struct ingenic_dma_hwdesc *dma_hwdesc[2];
> +	dma_addr_t dma_hwdesc_phys[2];
>  
>  	bool panel_is_sharp;
>  };
> @@ -90,7 +91,7 @@ static const struct regmap_config ingenic_drm_regmap_config = {
>  	.val_bits = 32,
>  	.reg_stride = 4,
>  
> -	.max_register = JZ_REG_LCD_CMD1,
> +	.max_register = JZ_REG_LCD_SIZE1,
>  	.writeable_reg = ingenic_drm_writeable_reg,
>  };
>  
> @@ -110,11 +111,6 @@ drm_encoder_get_priv(struct drm_encoder *encoder)
>  	return container_of(encoder, struct ingenic_drm, encoder);
>  }
>  
> -static inline struct ingenic_drm *drm_plane_get_priv(struct drm_plane *plane)
> -{
> -	return container_of(plane, struct ingenic_drm, primary);
> -}
> -
>  static void ingenic_drm_crtc_atomic_enable(struct drm_crtc *crtc,
>  					   struct drm_crtc_state *state)
>  {
> @@ -185,34 +181,17 @@ static void ingenic_drm_crtc_update_timings(struct ingenic_drm *priv,
>  		regmap_write(priv->map, JZ_REG_LCD_SPL, hpe << 16 | (hpe + 1));
>  		regmap_write(priv->map, JZ_REG_LCD_REV, mode->htotal << 16);
>  	}
> -}
> -
> -static void ingenic_drm_crtc_update_ctrl(struct ingenic_drm *priv,
> -					 const struct drm_format_info *finfo)
> -{
> -	unsigned int ctrl = JZ_LCD_CTRL_OFUP | JZ_LCD_CTRL_BURST_16;
> -
> -	switch (finfo->format) {
> -	case DRM_FORMAT_XRGB1555:
> -		ctrl |= JZ_LCD_CTRL_RGB555;
> -		/* fall-through */
> -	case DRM_FORMAT_RGB565:
> -		ctrl |= JZ_LCD_CTRL_BPP_15_16;
> -		break;
> -	case DRM_FORMAT_XRGB8888:
> -		ctrl |= JZ_LCD_CTRL_BPP_18_24;
> -		break;
> -	}
>  
>  	regmap_update_bits(priv->map, JZ_REG_LCD_CTRL,
> -			   JZ_LCD_CTRL_OFUP | JZ_LCD_CTRL_BURST_16 |
> -			   JZ_LCD_CTRL_BPP_MASK, ctrl);
> +			   JZ_LCD_CTRL_OFUP | JZ_LCD_CTRL_BURST_16,
> +			   JZ_LCD_CTRL_OFUP | JZ_LCD_CTRL_BURST_16);
It looks like regmap_update_bits() is no longer the best choice here.

>  }
>  
>  static int ingenic_drm_crtc_atomic_check(struct drm_crtc *crtc,
>  					 struct drm_crtc_state *state)
>  {
>  	struct ingenic_drm *priv = drm_crtc_get_priv(crtc);
> +	struct drm_plane_state *f1_state, *f0_state;
>  	long rate;
>  
>  	if (!drm_atomic_crtc_needs_modeset(state))
> @@ -227,6 +206,15 @@ static int ingenic_drm_crtc_atomic_check(struct drm_crtc *crtc,
>  	if (rate < 0)
>  		return rate;
>  
> +	if (priv->soc_info->has_osd) {
> +		f1_state = drm_atomic_get_plane_state(state->state, &priv->f1);
> +		f0_state = drm_atomic_get_plane_state(state->state, &priv->f0);
> +
> +		/* If all the planes are disabled, we won't get a VBLANK IRQ */
> +		if (!f1_state->fb && !f0_state->fb)
> +			state->no_vblank = true;
> +	}
> +
>  	return 0;
>  }
>  
> @@ -236,14 +224,9 @@ static void ingenic_drm_crtc_atomic_flush(struct drm_crtc *crtc,
>  	struct ingenic_drm *priv = drm_crtc_get_priv(crtc);
>  	struct drm_crtc_state *state = crtc->state;
>  	struct drm_pending_vblank_event *event = state->event;
> -	struct drm_framebuffer *drm_fb = crtc->primary->state->fb;
> -	const struct drm_format_info *finfo;
>  
>  	if (drm_atomic_crtc_needs_modeset(state)) {
> -		finfo = drm_format_info(drm_fb->format->format);
> -
>  		ingenic_drm_crtc_update_timings(priv, &state->mode);
> -		ingenic_drm_crtc_update_ctrl(priv, finfo);
>  
>  		clk_set_rate(priv->pix_clk, state->adjusted_mode.clock * 1000);
>  	}
> @@ -260,12 +243,149 @@ static void ingenic_drm_crtc_atomic_flush(struct drm_crtc *crtc,
>  	}
>  }
>  
> +static int ingenic_drm_plane_atomic_check(struct drm_plane *plane,
> +					  struct drm_plane_state *state)
> +{
> +	struct ingenic_drm *priv = drm_device_get_priv(plane->dev);
> +	struct drm_crtc_state *crtc_state;
> +	struct drm_crtc *crtc = state->crtc ?: plane->state->crtc;
> +	int ret;
> +
> +	if (!crtc)
> +		return 0;
> +
> +	crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
> +	if (WARN_ON(!crtc_state))
> +		return -EINVAL;
> +
> +	ret = drm_atomic_helper_check_plane_state(state, crtc_state,
> +						  DRM_PLANE_HELPER_NO_SCALING,
> +						  DRM_PLANE_HELPER_NO_SCALING,
> +						  priv->soc_info->has_osd,
> +						  true);
> +	if (ret)
> +		return ret;
> +
> +	if (!priv->soc_info->has_osd &&
> +	    (state->src_x != 0 ||
> +	     (state->src_w >> 16) != state->crtc_w ||
> +	     (state->src_h >> 16) != state->crtc_h))
> +		return -EINVAL;
This check could bebefit from a small comment.
I cannot see the purpose of " >> 16" on the src_* fields...


> +
> +	/*
> +	 * Require full modeset if if enabling or disabling a plane, or changing
Too many ifs?

> +	 * its position, size or depth.
> +	 */
> +	if (priv->soc_info->has_osd &&
> +	    (!plane->state->fb || !state->fb ||
> +	     plane->state->crtc_x != state->crtc_x ||
> +	     plane->state->crtc_y != state->crtc_y ||
> +	     plane->state->crtc_w != state->crtc_w ||
> +	     plane->state->crtc_h != state->crtc_h ||
> +	     plane->state->fb->format->format != state->fb->format->format))
> +		crtc_state->mode_changed = true;
> +
> +	return 0;
> +}
> +
> +static void ingenic_drm_plane_enable(struct ingenic_drm *priv,
> +				      struct drm_plane *plane)
> +{
> +	unsigned int en_bit;
> +
> +	if (priv->soc_info->has_osd) {
> +		if (plane->type == DRM_PLANE_TYPE_PRIMARY)
> +			en_bit = JZ_LCD_OSDC_F1EN;
> +		else
> +			en_bit = JZ_LCD_OSDC_F0EN;
> +
> +		regmap_update_bits(priv->map, JZ_REG_LCD_OSDC, en_bit, en_bit);
I think you can use a more direct way to do the assignment.
Like before where the same pattern was used (last two arguments the
same).

> +	}
> +}
> +
> +static void ingenic_drm_plane_atomic_disable(struct drm_plane *plane,
> +					     struct drm_plane_state *old_state)
> +{
> +	struct ingenic_drm *priv = drm_device_get_priv(plane->dev);
> +	unsigned int en_bit;
> +
> +	if (priv->soc_info->has_osd) {
> +		if (plane->type == DRM_PLANE_TYPE_PRIMARY)
> +			en_bit = JZ_LCD_OSDC_F1EN;
> +		else
> +			en_bit = JZ_LCD_OSDC_F0EN;
> +
> +		regmap_update_bits(priv->map, JZ_REG_LCD_OSDC, en_bit, 0);
> +	}
> +}
> +
> +static void ingenic_drm_plane_config(struct ingenic_drm *priv,
> +				     struct drm_plane *plane, u32 fourcc)
> +{
> +	struct drm_plane_state *state = plane->state;
> +	unsigned int xy_reg, size_reg;
> +	unsigned int ctrl = 0;
> +
> +	ingenic_drm_plane_enable(priv, plane);
> +
> +	if (priv->soc_info->has_osd &&
> +	    plane->type == DRM_PLANE_TYPE_PRIMARY) {
> +		switch (fourcc) {
> +		case DRM_FORMAT_XRGB1555:
> +			ctrl |= JZ_LCD_OSDCTRL_RGB555;
> +			fallthrough;
> +		case DRM_FORMAT_RGB565:
> +			ctrl |= JZ_LCD_OSDCTRL_BPP_15_16;
> +			break;
> +		case DRM_FORMAT_XRGB8888:
> +			ctrl |= JZ_LCD_OSDCTRL_BPP_18_24;
> +			break;
> +		}
> +
> +		regmap_update_bits(priv->map, JZ_REG_LCD_OSDCTRL,
> +				   JZ_LCD_OSDCTRL_BPP_MASK, ctrl);
> +	} else {
> +		switch (fourcc) {
> +		case DRM_FORMAT_XRGB1555:
> +			ctrl |= JZ_LCD_CTRL_RGB555;
> +			fallthrough;
> +		case DRM_FORMAT_RGB565:
> +			ctrl |= JZ_LCD_CTRL_BPP_15_16;
> +			break;
> +		case DRM_FORMAT_XRGB8888:
> +			ctrl |= JZ_LCD_CTRL_BPP_18_24;
> +			break;
> +		}
> +
> +		regmap_update_bits(priv->map, JZ_REG_LCD_CTRL,
> +				   JZ_LCD_CTRL_BPP_MASK, ctrl);
> +	}
> +
> +	if (priv->soc_info->has_osd) {
> +		if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
> +			xy_reg = JZ_REG_LCD_XYP1;
> +			size_reg = JZ_REG_LCD_SIZE1;
> +		} else {
> +			xy_reg = JZ_REG_LCD_XYP0;
> +			size_reg = JZ_REG_LCD_SIZE0;
> +		}
> +
> +		regmap_write(priv->map, xy_reg,
> +			     state->crtc_x << JZ_LCD_XYP01_XPOS_LSB |
> +			     state->crtc_y << JZ_LCD_XYP01_YPOS_LSB);
> +		regmap_write(priv->map, size_reg,
> +			     state->crtc_w << JZ_LCD_SIZE01_WIDTH_LSB |
> +			     state->crtc_h << JZ_LCD_SIZE01_HEIGHT_LSB);
> +	}
> +}
> +
>  static void ingenic_drm_plane_atomic_update(struct drm_plane *plane,
>  					    struct drm_plane_state *oldstate)
>  {
> -	struct ingenic_drm *priv = drm_plane_get_priv(plane);
> +	struct ingenic_drm *priv = drm_device_get_priv(plane->dev);
>  	struct drm_plane_state *state = plane->state;
>  	unsigned int width, height, cpp;
> +	unsigned int hwdesc_idx;
>  	dma_addr_t addr;
>  
>  	if (state && state->fb) {
> @@ -274,9 +394,18 @@ static void ingenic_drm_plane_atomic_update(struct drm_plane *plane,
>  		height = state->src_h >> 16;
>  		cpp = state->fb->format->cpp[0];
>  
> -		priv->dma_hwdesc->addr = addr;
> -		priv->dma_hwdesc->cmd = width * height * cpp / 4;
> -		priv->dma_hwdesc->cmd |= JZ_LCD_CMD_EOF_IRQ;
> +		if (!priv->soc_info->has_osd)
> +			hwdesc_idx = 0;
> +		else

> +			hwdesc_idx = plane->type == DRM_PLANE_TYPE_PRIMARY;
This looks ugly.
"plane->type == DRM_PLANE_TYPE_PRIMARY" evaluates to a boolean.
This is then ocnverted to an int used as index to an array later.
Something a bit more explicit would be more readable.


> +
> +		priv->dma_hwdesc[hwdesc_idx]->addr = addr;
> +		priv->dma_hwdesc[hwdesc_idx]->cmd = width * height * cpp / 4;
> +		priv->dma_hwdesc[hwdesc_idx]->cmd |= JZ_LCD_CMD_EOF_IRQ;
> +
> +		if (drm_atomic_crtc_needs_modeset(state->crtc->state))
> +			ingenic_drm_plane_config(priv, plane,
> +						 state->fb->format->format);
>  	}
>  }
>  
> @@ -437,6 +566,8 @@ static const struct drm_crtc_funcs ingenic_drm_crtc_funcs = {
>  
>  static const struct drm_plane_helper_funcs ingenic_drm_plane_helper_funcs = {
>  	.atomic_update		= ingenic_drm_plane_atomic_update,
> +	.atomic_check		= ingenic_drm_plane_atomic_check,
> +	.atomic_disable		= ingenic_drm_plane_atomic_disable,
>  	.prepare_fb		= drm_gem_fb_prepare_fb,
>  };
>  
> @@ -463,8 +594,10 @@ static void ingenic_drm_free_dma_hwdesc(void *d)
>  {
>  	struct ingenic_drm *priv = d;
>  
> -	dma_free_coherent(priv->dev, sizeof(*priv->dma_hwdesc),
> -			  priv->dma_hwdesc, priv->dma_hwdesc_phys);
> +	dma_free_coherent(priv->dev, sizeof(*priv->dma_hwdesc[0]),
> +			  priv->dma_hwdesc[0], priv->dma_hwdesc_phys[0]);
> +	dma_free_coherent(priv->dev, sizeof(*priv->dma_hwdesc[1]),
> +			  priv->dma_hwdesc[1], priv->dma_hwdesc_phys[1]);
>  }
>  
>  static int ingenic_drm_probe(struct platform_device *pdev)
> @@ -549,23 +682,32 @@ static int ingenic_drm_probe(struct platform_device *pdev)
>  		bridge = devm_drm_panel_bridge_add_typed(dev, panel,
>  							 DRM_MODE_CONNECTOR_DPI);
>  
> -	priv->dma_hwdesc = dma_alloc_coherent(dev, sizeof(*priv->dma_hwdesc),
> -					      &priv->dma_hwdesc_phys,
> -					      GFP_KERNEL);
> -	if (!priv->dma_hwdesc)
> +	priv->dma_hwdesc[0] = dma_alloc_coherent(dev, sizeof(*priv->dma_hwdesc[0]),
> +						 &priv->dma_hwdesc_phys[0],
> +						 GFP_KERNEL);
> +	if (!priv->dma_hwdesc[0])
> +		return -ENOMEM;
> +
> +	priv->dma_hwdesc[0]->next = priv->dma_hwdesc_phys[0];
> +	priv->dma_hwdesc[0]->id = 0xdeafbead;
> +
> +	priv->dma_hwdesc[1] = dma_alloc_coherent(dev, sizeof(*priv->dma_hwdesc[1]),
> +						 &priv->dma_hwdesc_phys[1],
> +						 GFP_KERNEL);
> +	if (!priv->dma_hwdesc[1])
>  		return -ENOMEM;
Here you should undo the first allocation??
I think the code could benefit from using dmam_alloc_coherent().

>  
> +	priv->dma_hwdesc[1]->next = priv->dma_hwdesc_phys[1];
> +	priv->dma_hwdesc[1]->id = 0xdeadbabe;
> +
>  	ret = devm_add_action_or_reset(dev, ingenic_drm_free_dma_hwdesc, priv);
>  	if (ret)
>  		return ret;
>  
> -	priv->dma_hwdesc->next = priv->dma_hwdesc_phys;
> -	priv->dma_hwdesc->id = 0xdeafbead;
> -
> -	drm_plane_helper_add(&priv->primary, &ingenic_drm_plane_helper_funcs);
> +	drm_plane_helper_add(&priv->f1, &ingenic_drm_plane_helper_funcs);
>  
> -	ret = drm_universal_plane_init(drm, &priv->primary,
> -				       0, &ingenic_drm_primary_plane_funcs,
> +	ret = drm_universal_plane_init(drm, &priv->f1, 1,
> +				       &ingenic_drm_primary_plane_funcs,
>  				       ingenic_drm_primary_formats,
>  				       ARRAY_SIZE(ingenic_drm_primary_formats),
>  				       NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
> @@ -576,13 +718,30 @@ static int ingenic_drm_probe(struct platform_device *pdev)
>  
>  	drm_crtc_helper_add(&priv->crtc, &ingenic_drm_crtc_helper_funcs);
>  
> -	ret = drm_crtc_init_with_planes(drm, &priv->crtc, &priv->primary,
> +	ret = drm_crtc_init_with_planes(drm, &priv->crtc, &priv->f1,
>  					NULL, &ingenic_drm_crtc_funcs, NULL);
>  	if (ret) {
>  		dev_err(dev, "Failed to init CRTC: %i\n", ret);
>  		return ret;
>  	}
>  
> +	if (soc_info->has_osd) {
> +		drm_plane_helper_add(&priv->f0,
> +				     &ingenic_drm_plane_helper_funcs);
> +
> +		ret = drm_universal_plane_init(drm, &priv->f0, 1,
> +					       &ingenic_drm_primary_plane_funcs,
> +					       ingenic_drm_primary_formats,
> +					       ARRAY_SIZE(ingenic_drm_primary_formats),
> +					       NULL, DRM_PLANE_TYPE_OVERLAY,
> +					       NULL);
> +		if (ret) {
> +			dev_err(dev, "Failed to register overlay plane: %i\n",
> +				ret);
> +			return ret;
> +		}
> +	}
> +
>  	priv->encoder.possible_crtcs = 1;
>  
>  	drm_encoder_helper_add(&priv->encoder,
> @@ -644,7 +803,12 @@ static int ingenic_drm_probe(struct platform_device *pdev)
>  	}
>  
>  	/* Set address of our DMA descriptor chain */
> -	regmap_write(priv->map, JZ_REG_LCD_DA0, priv->dma_hwdesc_phys);
> +	regmap_write(priv->map, JZ_REG_LCD_DA0, priv->dma_hwdesc_phys[0]);
> +	regmap_write(priv->map, JZ_REG_LCD_DA1, priv->dma_hwdesc_phys[1]);
> +
> +	/* Enable OSD if available */
> +	if (soc_info->has_osd)
> +		regmap_write(priv->map, JZ_REG_LCD_OSDC, JZ_LCD_OSDC_OSDEN);
>  
>  	ret = drm_dev_register(drm, 0);
>  	if (ret) {
> @@ -680,18 +844,21 @@ static int ingenic_drm_remove(struct platform_device *pdev)
>  
>  static const struct jz_soc_info jz4740_soc_info = {
>  	.needs_dev_clk = true,
> +	.has_osd = false,
>  	.max_width = 800,
>  	.max_height = 600,
>  };
>  
>  static const struct jz_soc_info jz4725b_soc_info = {
>  	.needs_dev_clk = false,
> +	.has_osd = true,
>  	.max_width = 800,
>  	.max_height = 600,
>  };
>  
>  static const struct jz_soc_info jz4770_soc_info = {
>  	.needs_dev_clk = false,
> +	.has_osd = true,
>  	.max_width = 1280,
>  	.max_height = 720,
>  };
> diff --git a/drivers/gpu/drm/ingenic/ingenic-drm.h b/drivers/gpu/drm/ingenic/ingenic-drm.h
> index cb578cff7bb1..d0b827a9fe83 100644
> --- a/drivers/gpu/drm/ingenic/ingenic-drm.h
> +++ b/drivers/gpu/drm/ingenic/ingenic-drm.h
> @@ -30,6 +30,18 @@
>  #define JZ_REG_LCD_SA1				0x54
>  #define JZ_REG_LCD_FID1				0x58
>  #define JZ_REG_LCD_CMD1				0x5C
> +#define JZ_REG_LCD_OSDC				0x100
> +#define JZ_REG_LCD_OSDCTRL			0x104
> +#define JZ_REG_LCD_OSDS				0x108
> +#define JZ_REG_LCD_BGC				0x10c
> +#define JZ_REG_LCD_KEY0				0x110
> +#define JZ_REG_LCD_KEY1				0x114
> +#define JZ_REG_LCD_ALPHA			0x118
> +#define JZ_REG_LCD_IPUR				0x11c
> +#define JZ_REG_LCD_XYP0				0x120
> +#define JZ_REG_LCD_XYP1				0x124
> +#define JZ_REG_LCD_SIZE0			0x128
> +#define JZ_REG_LCD_SIZE1			0x12c
>  
>  #define JZ_LCD_CFG_SLCD				BIT(31)
>  #define JZ_LCD_CFG_PS_DISABLE			BIT(23)
> @@ -123,4 +135,27 @@
>  #define JZ_LCD_STATE_SOF_IRQ			BIT(4)
>  #define JZ_LCD_STATE_DISABLED			BIT(0)
>  
> +#define JZ_LCD_OSDC_OSDEN			BIT(0)
> +#define JZ_LCD_OSDC_F0EN			BIT(3)
> +#define JZ_LCD_OSDC_F1EN			BIT(4)
> +
> +#define JZ_LCD_OSDCTRL_IPU			BIT(15)
> +#define JZ_LCD_OSDCTRL_RGB555			BIT(4)
> +#define JZ_LCD_OSDCTRL_CHANGE			BIT(3)
> +#define JZ_LCD_OSDCTRL_BPP_15_16		0x4
> +#define JZ_LCD_OSDCTRL_BPP_18_24		0x5
> +#define JZ_LCD_OSDCTRL_BPP_30			0x7
> +#define JZ_LCD_OSDCTRL_BPP_MASK			(JZ_LCD_OSDCTRL_RGB555 | 0x7)
> +
> +#define JZ_LCD_OSDS_READY			BIT(0)
> +
> +#define JZ_LCD_IPUR_IPUREN			BIT(31)
> +#define JZ_LCD_IPUR_IPUR_LSB			0
> +
> +#define JZ_LCD_XYP01_XPOS_LSB			0
> +#define JZ_LCD_XYP01_YPOS_LSB			16
> +
> +#define JZ_LCD_SIZE01_WIDTH_LSB			0
> +#define JZ_LCD_SIZE01_HEIGHT_LSB		16
> +
>  #endif /* DRIVERS_GPU_DRM_INGENIC_INGENIC_DRM_H */
> -- 
> 2.27.0
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel


More information about the dri-devel mailing list