[PATCH v3] Separate display's pixel configuration from video mode

Guennadi Liakhovetski g.liakhovetski at gmx.de
Wed Sep 22 12:15:06 EDT 2010


On Wed, 22 Sep 2010, Michael Grzeschik wrote:

> From: Juergen Beisert <jbe at pengutronix.de>
> 
> Currently the pixel mapping to the display depends on the video mode. This
> seems not true as the IPU transfers the data read from the video memory in an
> internal 32 bit bus to the DI unit. The DI mapping only depends on the settings
> the IPU should read the data from video memory. If all these settings do it in
> the same byte order, only one DI mapping per display is required.
> 
> There are three locations where we can mix the colour components:
>  - in the video mode description, colour offsets
>  - in the IPU while reading pixel data from memory
>  - in the DI unit while mapping it to the connected display
> 
> If one of these settings are incorrect, the displayed colours are broken.
> 
> With this patch the platform describes the display connection and the driver
> uses this information independently from the selected video mode.
> 
> Signed-off-by: Juergen Beisert <jbe at pengutronix.de>
> Signed-off-by: Michael Grzeschik <m.grzeschik at pengutronix.de>

Tested-by: Guennadi Liakhovetski <g.liakhovetski at gmx.de>

> ---
>  v2 - v3:
> 	changed to multiline comment
> 	added a generic set_di_bus_mapping function
> 
>  v1 - v2:
>         added default fallback ipu fb_bitfield values
>         for the case the platform doesn't define these.
> 
>  arch/arm/plat-mxc/include/mach/mx3fb.h |    5 ++
>  drivers/video/mx3fb.c                  |   81 ++++++++++++++++----------------
>  2 files changed, 45 insertions(+), 41 deletions(-)
> 
> diff --git a/arch/arm/plat-mxc/include/mach/mx3fb.h b/arch/arm/plat-mxc/include/mach/mx3fb.h
> index ac24c5c..93bd032 100644
> --- a/arch/arm/plat-mxc/include/mach/mx3fb.h
> +++ b/arch/arm/plat-mxc/include/mach/mx3fb.h
> @@ -33,6 +33,11 @@ struct mx3fb_platform_data {
>  	const char			*name;
>  	const struct fb_videomode	*mode;
>  	int				num_modes;
> +
> +	/* display's mapping description */
> +	struct fb_bitfield red;
> +	struct fb_bitfield green;
> +	struct fb_bitfield blue;
>  };
>  
>  #endif
> diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c
> index 658f10a..ca20da8 100644
> --- a/drivers/video/mx3fb.c
> +++ b/drivers/video/mx3fb.c
> @@ -286,13 +286,6 @@ static void mx3fb_write_reg(struct mx3fb_data *mx3fb, u32 value, unsigned long r
>  	__raw_writel(value, mx3fb->reg_base + reg);
>  }
>  
> -static const uint32_t di_mappings[] = {
> -	0x1600AAAA, 0x00E05555, 0x00070000, 3,	/* RGB888 */
> -	0x0005000F, 0x000B000F, 0x0011000F, 1,	/* RGB666 */
> -	0x0011000F, 0x000B000F, 0x0005000F, 1,	/* BGR666 */
> -	0x0004003F, 0x000A000F, 0x000F003F, 1	/* RGB565 */
> -};
> -
>  static void sdc_fb_init(struct mx3fb_info *fbi)
>  {
>  	struct mx3fb_data *mx3fb = fbi->mx3fb;
> @@ -414,6 +407,17 @@ static int sdc_set_window_pos(struct mx3fb_data *mx3fb, enum ipu_channel channel
>  	return 0;
>  }
>  
> +static void set_di_bus_mapping(struct mx3fb_data *mx3fb, struct fb_bitfield *bf,
> +			      unsigned long reg)
> +{
> +	u32 val = 0xffff;
> +
> +	val &= ~(((1 << (bf->length * 2)) - 1) << (16 - (bf->length * 2)));
> +	val |= ((bf->offset + bf->length - 1)) << 16;
> +	pr_debug("b: %d %d 0x%08x\n", bf->offset, bf->length, val);
> +	mx3fb_write_reg(mx3fb, val, reg);
> +}
> +
>  /**
>   * sdc_init_panel() - initialize a synchronous LCD panel.
>   * @mx3fb:		mx3fb context.
> @@ -421,7 +425,6 @@ static int sdc_set_window_pos(struct mx3fb_data *mx3fb, enum ipu_channel channel
>   * @pixel_clk:		desired pixel clock frequency in Hz.
>   * @width:		width of panel in pixels.
>   * @height:		height of panel in pixels.
> - * @pixel_fmt:		pixel format of buffer as FOURCC ASCII code.
>   * @h_start_width:	number of pixel clocks between the HSYNC signal pulse
>   *			and the start of valid data.
>   * @h_sync_width:	width of the HSYNC signal in units of pixel clocks.
> @@ -438,7 +441,6 @@ static int sdc_set_window_pos(struct mx3fb_data *mx3fb, enum ipu_channel channel
>  static int sdc_init_panel(struct mx3fb_data *mx3fb, enum ipu_panel panel,
>  			  uint32_t pixel_clk,
>  			  uint16_t width, uint16_t height,
> -			  enum pixel_fmt pixel_fmt,
>  			  uint16_t h_start_width, uint16_t h_sync_width,
>  			  uint16_t h_end_width, uint16_t v_start_width,
>  			  uint16_t v_sync_width, uint16_t v_end_width,
> @@ -450,6 +452,9 @@ static int sdc_init_panel(struct mx3fb_data *mx3fb, enum ipu_panel panel,
>  	uint32_t div;
>  	struct clk *ipu_clk;
>  
> +	struct device *dev = mx3fb->dev;
> +	struct mx3fb_platform_data *mx3fb_pdata = dev->platform_data;
> +
>  	dev_dbg(mx3fb->dev, "panel size = %d x %d", width, height);
>  
>  	if (v_sync_width == 0 || h_sync_width == 0)
> @@ -536,36 +541,18 @@ static int sdc_init_panel(struct mx3fb_data *mx3fb, enum ipu_panel panel,
>  		sig.Vsync_pol << DI_D3_VSYNC_POL_SHIFT;
>  	mx3fb_write_reg(mx3fb, old_conf, DI_DISP_SIG_POL);
>  
> -	switch (pixel_fmt) {
> -	case IPU_PIX_FMT_RGB24:
> -		mx3fb_write_reg(mx3fb, di_mappings[0], DI_DISP3_B0_MAP);
> -		mx3fb_write_reg(mx3fb, di_mappings[1], DI_DISP3_B1_MAP);
> -		mx3fb_write_reg(mx3fb, di_mappings[2], DI_DISP3_B2_MAP);
> -		mx3fb_write_reg(mx3fb, mx3fb_read_reg(mx3fb, DI_DISP_ACC_CC) |
> -			     ((di_mappings[3] - 1) << 12), DI_DISP_ACC_CC);
> -		break;
> -	case IPU_PIX_FMT_RGB666:
> -		mx3fb_write_reg(mx3fb, di_mappings[4], DI_DISP3_B0_MAP);
> -		mx3fb_write_reg(mx3fb, di_mappings[5], DI_DISP3_B1_MAP);
> -		mx3fb_write_reg(mx3fb, di_mappings[6], DI_DISP3_B2_MAP);
> -		mx3fb_write_reg(mx3fb, mx3fb_read_reg(mx3fb, DI_DISP_ACC_CC) |
> -			     ((di_mappings[7] - 1) << 12), DI_DISP_ACC_CC);
> -		break;
> -	case IPU_PIX_FMT_BGR666:
> -		mx3fb_write_reg(mx3fb, di_mappings[8], DI_DISP3_B0_MAP);
> -		mx3fb_write_reg(mx3fb, di_mappings[9], DI_DISP3_B1_MAP);
> -		mx3fb_write_reg(mx3fb, di_mappings[10], DI_DISP3_B2_MAP);
> -		mx3fb_write_reg(mx3fb, mx3fb_read_reg(mx3fb, DI_DISP_ACC_CC) |
> -			     ((di_mappings[11] - 1) << 12), DI_DISP_ACC_CC);
> -		break;
> -	default:
> -		mx3fb_write_reg(mx3fb, di_mappings[12], DI_DISP3_B0_MAP);
> -		mx3fb_write_reg(mx3fb, di_mappings[13], DI_DISP3_B1_MAP);
> -		mx3fb_write_reg(mx3fb, di_mappings[14], DI_DISP3_B2_MAP);
> -		mx3fb_write_reg(mx3fb, mx3fb_read_reg(mx3fb, DI_DISP_ACC_CC) |
> -			     ((di_mappings[15] - 1) << 12), DI_DISP_ACC_CC);
> -		break;
> -	}
> +	/*
> +	 * setup the pixel mapping to the display. This seems independent
> +	 * from the internal video mode in use
> +	 */
> +	set_di_bus_mapping(mx3fb, &mx3fb_pdata->blue, DI_DISP3_B0_MAP);
> +	set_di_bus_mapping(mx3fb, &mx3fb_pdata->green, DI_DISP3_B1_MAP);
> +	set_di_bus_mapping(mx3fb, &mx3fb_pdata->red, DI_DISP3_B2_MAP);
> +
> +	/* the TFT displays expecting one pixel per clock */
> +	reg = mx3fb_read_reg(mx3fb, DI_DISP_ACC_CC) & ~(3 << 12);
> +	reg |= 0 << 12;	/* 0 means one clock */
> +	mx3fb_write_reg(mx3fb, reg, DI_DISP_ACC_CC);
>  
>  	spin_unlock_irqrestore(&mx3fb->lock, lock_flags);
>  
> @@ -776,8 +763,6 @@ static int __set_par(struct fb_info *fbi, bool lock)
>  		if (sdc_init_panel(mx3fb, mode,
>  				   (PICOS2KHZ(fbi->var.pixclock)) * 1000UL,
>  				   fbi->var.xres, fbi->var.yres,
> -				   (fbi->var.sync & FB_SYNC_SWAP_RGB) ?
> -				   IPU_PIX_FMT_BGR666 : IPU_PIX_FMT_RGB666,
>  				   fbi->var.left_margin,
>  				   fbi->var.hsync_len,
>  				   fbi->var.right_margin +
> @@ -1367,6 +1352,20 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan)
>  		goto emode;
>  	}
>  
> +	if (mx3fb_pdata->red.length == 0 &&
> +	    mx3fb_pdata->green.length == 0 &&
> +	    mx3fb_pdata->blue.length == 0) {
> +
> +		mx3fb_pdata->red.length = 6;
> +		mx3fb_pdata->red.offset = 12;
> +
> +		mx3fb_pdata->green.length = 6;
> +		mx3fb_pdata->green.offset = 6;
> +
> +		mx3fb_pdata->blue.length = 6;
> +		mx3fb_pdata->blue.offset = 0;
> +	}
> +
>  	fb_videomode_to_modelist(mode, num_modes, &fbi->modelist);
>  
>  	/* Default Y virtual size is 2x panel size */
> -- 
> 1.7.2.3
> 
> 

---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/



More information about the linux-arm-kernel mailing list