Linux Framebuffer Layer development
 help / color / mirror / Atom feed
* Re: [PATCH 1/8] video: atmel_lcdfb: fix platform data struct
From: Nicolas Ferre @ 2013-04-16 12:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1365692422-9565-1-git-send-email-plagnioj@jcrosoft.com>

On 04/11/2013 05:00 PM, Jean-Christophe PLAGNIOL-VILLARD :
> Today we mix pdata and drivers data in the struct atmel_lcdfb_info
> Fix it and introduce a new struct atmel_lcdfb_pdata for platform data only
> 
> Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
> Cc: linux-fbdev@vger.kernel.org
> Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: Hans-Christian Egtvedt <egtvedt@samfundet.no>
> ---
>  arch/arm/mach-at91/at91sam9261_devices.c    |    6 +-
>  arch/arm/mach-at91/at91sam9263_devices.c    |    6 +-
>  arch/arm/mach-at91/at91sam9g45_devices.c    |    6 +-
>  arch/arm/mach-at91/at91sam9rl_devices.c     |    6 +-
>  arch/arm/mach-at91/board-sam9261ek.c        |    6 +-
>  arch/arm/mach-at91/board-sam9263ek.c        |    4 +-
>  arch/arm/mach-at91/board-sam9m10g45ek.c     |    4 +-
>  arch/arm/mach-at91/board-sam9rlek.c         |    4 +-
>  arch/arm/mach-at91/board.h                  |    4 +-
>  arch/avr32/boards/atngw100/evklcd10x.c      |    6 +-
>  arch/avr32/boards/atngw100/mrmt.c           |    4 +-
>  arch/avr32/boards/atstk1000/atstk1000.h     |    2 +-
>  arch/avr32/boards/atstk1000/setup.c         |    2 +-
>  arch/avr32/boards/favr-32/setup.c           |    2 +-
>  arch/avr32/boards/hammerhead/setup.c        |    2 +-
>  arch/avr32/boards/merisc/display.c          |    2 +-
>  arch/avr32/boards/mimc200/setup.c           |    4 +-
>  arch/avr32/mach-at32ap/at32ap700x.c         |    8 +--
>  arch/avr32/mach-at32ap/include/mach/board.h |    4 +-
>  drivers/video/atmel_lcdfb.c                 |  104 +++++++++++++++++----------
>  include/video/atmel_lcdc.h                  |   24 +------
>  21 files changed, 109 insertions(+), 101 deletions(-)
> 
> diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
> index 629ea5f..b2a3474 100644
> --- a/arch/arm/mach-at91/at91sam9261_devices.c
> +++ b/arch/arm/mach-at91/at91sam9261_devices.c
> @@ -465,7 +465,7 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
>  
>  #if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
>  static u64 lcdc_dmamask = DMA_BIT_MASK(32);
> -static struct atmel_lcdfb_info lcdc_data;
> +static struct atmel_lcdfb_pdata lcdc_data;
>  
>  static struct resource lcdc_resources[] = {
>  	[0] = {
> @@ -498,7 +498,7 @@ static struct platform_device at91_lcdc_device = {
>  	.num_resources	= ARRAY_SIZE(lcdc_resources),
>  };
>  
> -void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
> +void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data)
>  {
>  	if (!data) {
>  		return;
> @@ -559,7 +559,7 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
>  	platform_device_register(&at91_lcdc_device);
>  }
>  #else
> -void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
> +void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data) {}
>  #endif
>  
>  
> diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
> index 858c8aa..4aeaddd 100644
> --- a/arch/arm/mach-at91/at91sam9263_devices.c
> +++ b/arch/arm/mach-at91/at91sam9263_devices.c
> @@ -832,7 +832,7 @@ void __init at91_add_device_can(struct at91_can_data *data) {}
>  
>  #if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
>  static u64 lcdc_dmamask = DMA_BIT_MASK(32);
> -static struct atmel_lcdfb_info lcdc_data;
> +static struct atmel_lcdfb_pdata lcdc_data;
>  
>  static struct resource lcdc_resources[] = {
>  	[0] = {
> @@ -859,7 +859,7 @@ static struct platform_device at91_lcdc_device = {
>  	.num_resources	= ARRAY_SIZE(lcdc_resources),
>  };
>  
> -void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
> +void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data)
>  {
>  	if (!data)
>  		return;
> @@ -891,7 +891,7 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
>  	platform_device_register(&at91_lcdc_device);
>  }
>  #else
> -void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
> +void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data) {}
>  #endif
>  
>  
> diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
> index fe626d4..82636c7 100644
> --- a/arch/arm/mach-at91/at91sam9g45_devices.c
> +++ b/arch/arm/mach-at91/at91sam9g45_devices.c
> @@ -965,7 +965,7 @@ void __init at91_add_device_isi(struct isi_platform_data *data,
>  
>  #if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
>  static u64 lcdc_dmamask = DMA_BIT_MASK(32);
> -static struct atmel_lcdfb_info lcdc_data;
> +static struct atmel_lcdfb_pdata lcdc_data;
>  
>  static struct resource lcdc_resources[] = {
>  	[0] = {
> @@ -991,7 +991,7 @@ static struct platform_device at91_lcdc_device = {
>  	.num_resources	= ARRAY_SIZE(lcdc_resources),
>  };
>  
> -void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
> +void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data)
>  {
>  	if (!data)
>  		return;
> @@ -1037,7 +1037,7 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
>  	platform_device_register(&at91_lcdc_device);
>  }
>  #else
> -void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
> +void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data) {}
>  #endif
>  
>  
> diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
> index 352468f..a698bda 100644
> --- a/arch/arm/mach-at91/at91sam9rl_devices.c
> +++ b/arch/arm/mach-at91/at91sam9rl_devices.c
> @@ -498,7 +498,7 @@ void __init at91_add_device_ac97(struct ac97c_platform_data *data) {}
>  
>  #if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
>  static u64 lcdc_dmamask = DMA_BIT_MASK(32);
> -static struct atmel_lcdfb_info lcdc_data;
> +static struct atmel_lcdfb_pdata lcdc_data;
>  
>  static struct resource lcdc_resources[] = {
>  	[0] = {
> @@ -525,7 +525,7 @@ static struct platform_device at91_lcdc_device = {
>  	.num_resources	= ARRAY_SIZE(lcdc_resources),
>  };
>  
> -void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
> +void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data)
>  {
>  	if (!data) {
>  		return;
> @@ -557,7 +557,7 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
>  	platform_device_register(&at91_lcdc_device);
>  }
>  #else
> -void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
> +void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data) {}
>  #endif
>  
>  
> diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
> index b446645..c819e29 100644
> --- a/arch/arm/mach-at91/board-sam9261ek.c
> +++ b/arch/arm/mach-at91/board-sam9261ek.c
> @@ -405,7 +405,7 @@ static void at91_lcdc_stn_power_control(int on)
>  	}
>  }
>  
> -static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
> +static struct atmel_lcdfb_pdata __initdata ek_lcdc_data = {
>  	.default_bpp			= 1,
>  	.default_dmacon			= ATMEL_LCDC_DMAEN,
>  	.default_lcdcon2		= AT91SAM9261_DEFAULT_STN_LCDCON2,
> @@ -460,7 +460,7 @@ static void at91_lcdc_tft_power_control(int on)
>  		at91_set_gpio_value(AT91_PIN_PA12, 1);	/* power down */
>  }
>  
> -static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
> +static struct atmel_lcdfb_pdata __initdata ek_lcdc_data = {
>  	.lcdcon_is_backlight		= true,
>  	.default_bpp			= 16,
>  	.default_dmacon			= ATMEL_LCDC_DMAEN,
> @@ -475,7 +475,7 @@ static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
>  #endif
>  
>  #else
> -static struct atmel_lcdfb_info __initdata ek_lcdc_data;
> +static struct atmel_lcdfb_pdata __initdata ek_lcdc_data;
>  #endif
>  
>  
> diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
> index 3284df0..0fdae3f 100644
> --- a/arch/arm/mach-at91/board-sam9263ek.c
> +++ b/arch/arm/mach-at91/board-sam9263ek.c
> @@ -281,7 +281,7 @@ static void at91_lcdc_power_control(int on)
>  }
>  
>  /* Driver datas */
> -static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
> +static struct atmel_lcdfb_pdata __initdata ek_lcdc_data = {
>  	.lcdcon_is_backlight		= true,
>  	.default_bpp			= 16,
>  	.default_dmacon			= ATMEL_LCDC_DMAEN,
> @@ -292,7 +292,7 @@ static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
>  };
>  
>  #else
> -static struct atmel_lcdfb_info __initdata ek_lcdc_data;
> +static struct atmel_lcdfb_pdata __initdata ek_lcdc_data;
>  #endif
>  
>  
> diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
> index 2a94896..ef39078 100644
> --- a/arch/arm/mach-at91/board-sam9m10g45ek.c
> +++ b/arch/arm/mach-at91/board-sam9m10g45ek.c
> @@ -284,7 +284,7 @@ static struct fb_monspecs at91fb_default_monspecs = {
>  					| ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
>  
>  /* Driver datas */
> -static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
> +static struct atmel_lcdfb_pdata __initdata ek_lcdc_data = {
>  	.lcdcon_is_backlight		= true,
>  	.default_bpp			= 32,
>  	.default_dmacon			= ATMEL_LCDC_DMAEN,
> @@ -295,7 +295,7 @@ static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
>  };
>  
>  #else
> -static struct atmel_lcdfb_info __initdata ek_lcdc_data;
> +static struct atmel_lcdfb_pdata __initdata ek_lcdc_data;
>  #endif
>  
>  
> diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c
> index aa265dc..b77d7a9 100644
> --- a/arch/arm/mach-at91/board-sam9rlek.c
> +++ b/arch/arm/mach-at91/board-sam9rlek.c
> @@ -179,7 +179,7 @@ static void at91_lcdc_power_control(int on)
>  }
>  
>  /* Driver datas */
> -static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
> +static struct atmel_lcdfb_pdata __initdata ek_lcdc_data = {
>  	.lcdcon_is_backlight            = true,
>  	.default_bpp			= 16,
>  	.default_dmacon			= ATMEL_LCDC_DMAEN,
> @@ -191,7 +191,7 @@ static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
>  };
>  
>  #else
> -static struct atmel_lcdfb_info __initdata ek_lcdc_data;
> +static struct atmel_lcdfb_pdata __initdata ek_lcdc_data;
>  #endif
>  
>  
> diff --git a/arch/arm/mach-at91/board.h b/arch/arm/mach-at91/board.h
> index 4a234fb..6c08b34 100644
> --- a/arch/arm/mach-at91/board.h
> +++ b/arch/arm/mach-at91/board.h
> @@ -107,8 +107,8 @@ extern void __init at91_add_device_pwm(u32 mask);
>  extern void __init at91_add_device_ssc(unsigned id, unsigned pins);
>  
>   /* LCD Controller */
> -struct atmel_lcdfb_info;
> -extern void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data);
> +struct atmel_lcdfb_pdata;
> +extern void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data);
>  
>   /* AC97 */
>  extern void __init at91_add_device_ac97(struct ac97c_platform_data *data);
> diff --git a/arch/avr32/boards/atngw100/evklcd10x.c b/arch/avr32/boards/atngw100/evklcd10x.c
> index 2038875..dc42804 100644
> --- a/arch/avr32/boards/atngw100/evklcd10x.c
> +++ b/arch/avr32/boards/atngw100/evklcd10x.c
> @@ -58,7 +58,7 @@ static struct fb_monspecs __initdata atevklcd10x_default_monspecs = {
>  	.dclkmax		= 28330000,
>  };
>  
> -static struct atmel_lcdfb_info __initdata atevklcd10x_lcdc_data = {
> +static struct atmel_lcdfb_pdata __initdata atevklcd10x_lcdc_data = {
>  	.default_bpp		= 16,
>  	.default_dmacon		= ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
>  	.default_lcdcon2	= (ATMEL_LCDC_DISTYPE_TFT
> @@ -96,7 +96,7 @@ static struct fb_monspecs __initdata atevklcd10x_default_monspecs = {
>  	.dclkmax		= 7000000,
>  };
>  
> -static struct atmel_lcdfb_info __initdata atevklcd10x_lcdc_data = {
> +static struct atmel_lcdfb_pdata __initdata atevklcd10x_lcdc_data = {
>  	.default_bpp		= 16,
>  	.default_dmacon		= ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
>  	.default_lcdcon2	= (ATMEL_LCDC_DISTYPE_TFT
> @@ -134,7 +134,7 @@ static struct fb_monspecs __initdata atevklcd10x_default_monspecs = {
>  	.dclkmax		= 6400000,
>  };
>  
> -static struct atmel_lcdfb_info __initdata atevklcd10x_lcdc_data = {
> +static struct atmel_lcdfb_pdata __initdata atevklcd10x_lcdc_data = {
>  	.default_bpp		= 16,
>  	.default_dmacon		= ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
>  	.default_lcdcon2	= (ATMEL_LCDC_DISTYPE_TFT
> diff --git a/arch/avr32/boards/atngw100/mrmt.c b/arch/avr32/boards/atngw100/mrmt.c
> index f914319..ccc9599 100644
> --- a/arch/avr32/boards/atngw100/mrmt.c
> +++ b/arch/avr32/boards/atngw100/mrmt.c
> @@ -83,7 +83,7 @@ static struct fb_monspecs __initdata lcd_fb_default_monspecs = {
>  	.dclkmax		= 9260000,
>  };
>  
> -static struct atmel_lcdfb_info __initdata rmt_lcdc_data = {
> +static struct atmel_lcdfb_pdata __initdata rmt_lcdc_data = {
>  	.default_bpp		= 24,
>  	.default_dmacon		= ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
>  	.default_lcdcon2	= (ATMEL_LCDC_DISTYPE_TFT
> @@ -126,7 +126,7 @@ static struct fb_monspecs __initdata lcd_fb_default_monspecs = {
>  	.dclkmax		= 9260000,
>  };
>  
> -static struct atmel_lcdfb_info __initdata rmt_lcdc_data = {
> +static struct atmel_lcdfb_pdata __initdata rmt_lcdc_data = {
>  	.default_bpp		= 24,
>  	.default_dmacon		= ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
>  	.default_lcdcon2	= (ATMEL_LCDC_DISTYPE_TFT
> diff --git a/arch/avr32/boards/atstk1000/atstk1000.h b/arch/avr32/boards/atstk1000/atstk1000.h
> index 9392d32..653cc09 100644
> --- a/arch/avr32/boards/atstk1000/atstk1000.h
> +++ b/arch/avr32/boards/atstk1000/atstk1000.h
> @@ -10,7 +10,7 @@
>  #ifndef __ARCH_AVR32_BOARDS_ATSTK1000_ATSTK1000_H
>  #define __ARCH_AVR32_BOARDS_ATSTK1000_ATSTK1000_H
>  
> -extern struct atmel_lcdfb_info atstk1000_lcdc_data;
> +extern struct atmel_lcdfb_pdata atstk1000_lcdc_data;
>  
>  void atstk1000_setup_j2_leds(void);
>  
> diff --git a/arch/avr32/boards/atstk1000/setup.c b/arch/avr32/boards/atstk1000/setup.c
> index 2d6b560..b6b88f5 100644
> --- a/arch/avr32/boards/atstk1000/setup.c
> +++ b/arch/avr32/boards/atstk1000/setup.c
> @@ -55,7 +55,7 @@ static struct fb_monspecs __initdata atstk1000_default_monspecs = {
>  	.dclkmax		= 30000000,
>  };
>  
> -struct atmel_lcdfb_info __initdata atstk1000_lcdc_data = {
> +struct atmel_lcdfb_pdata __initdata atstk1000_lcdc_data = {
>  	.default_bpp		= 24,
>  	.default_dmacon		= ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
>  	.default_lcdcon2	= (ATMEL_LCDC_DISTYPE_TFT
> diff --git a/arch/avr32/boards/favr-32/setup.c b/arch/avr32/boards/favr-32/setup.c
> index 27bd6fb..7b1f2cd 100644
> --- a/arch/avr32/boards/favr-32/setup.c
> +++ b/arch/avr32/boards/favr-32/setup.c
> @@ -125,7 +125,7 @@ static struct fb_monspecs __initdata favr32_default_monspecs = {
>  	.dclkmax		= 28000000,
>  };
>  
> -struct atmel_lcdfb_info __initdata favr32_lcdc_data = {
> +struct atmel_lcdfb_pdata __initdata favr32_lcdc_data = {
>  	.default_bpp		= 16,
>  	.default_dmacon		= ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
>  	.default_lcdcon2	= (ATMEL_LCDC_DISTYPE_TFT
> diff --git a/arch/avr32/boards/hammerhead/setup.c b/arch/avr32/boards/hammerhead/setup.c
> index 9d1efd1..dc0e317 100644
> --- a/arch/avr32/boards/hammerhead/setup.c
> +++ b/arch/avr32/boards/hammerhead/setup.c
> @@ -77,7 +77,7 @@ static struct fb_monspecs __initdata hammerhead_hda350t_monspecs = {
>  	.dclkmax		= 10000000,
>  };
>  
> -struct atmel_lcdfb_info __initdata hammerhead_lcdc_data = {
> +struct atmel_lcdfb_pdata __initdata hammerhead_lcdc_data = {
>  	.default_bpp		= 24,
>  	.default_dmacon		= ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
>  	.default_lcdcon2	= (ATMEL_LCDC_DISTYPE_TFT
> diff --git a/arch/avr32/boards/merisc/display.c b/arch/avr32/boards/merisc/display.c
> index 85a543c..e7683ee 100644
> --- a/arch/avr32/boards/merisc/display.c
> +++ b/arch/avr32/boards/merisc/display.c
> @@ -45,7 +45,7 @@ static struct fb_monspecs merisc_fb_monspecs = {
>  	.dclkmax	= 30000000,
>  };
>  
> -struct atmel_lcdfb_info merisc_lcdc_data = {
> +struct atmel_lcdfb_pdata merisc_lcdc_data = {
>  	.default_bpp		= 24,
>  	.default_dmacon		= ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
>  	.default_lcdcon2	= (ATMEL_LCDC_DISTYPE_TFT
> diff --git a/arch/avr32/boards/mimc200/setup.c b/arch/avr32/boards/mimc200/setup.c
> index 05358aa..1cb8e9c 100644
> --- a/arch/avr32/boards/mimc200/setup.c
> +++ b/arch/avr32/boards/mimc200/setup.c
> @@ -8,7 +8,7 @@
>   * published by the Free Software Foundation.
>   */
>  
> -extern struct atmel_lcdfb_info mimc200_lcdc_data;
> +extern struct atmel_lcdfb_pdata mimc200_lcdc_data;
>  
>  #include <linux/clk.h>
>  #include <linux/etherdevice.h>
> @@ -71,7 +71,7 @@ static struct fb_monspecs __initdata mimc200_default_monspecs = {
>  	.dclkmax		= 25200000,
>  };
>  
> -struct atmel_lcdfb_info __initdata mimc200_lcdc_data = {
> +struct atmel_lcdfb_pdata __initdata mimc200_lcdc_data = {
>  	.default_bpp		= 16,
>  	.default_dmacon		= ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
>  	.default_lcdcon2	= (ATMEL_LCDC_DISTYPE_TFT
> diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
> index 7c2f668..0badb05 100644
> --- a/arch/avr32/mach-at32ap/at32ap700x.c
> +++ b/arch/avr32/mach-at32ap/at32ap700x.c
> @@ -1437,7 +1437,7 @@ fail:
>   *  LCDC
>   * -------------------------------------------------------------------- */
>  #if defined(CONFIG_CPU_AT32AP7000) || defined(CONFIG_CPU_AT32AP7002)
> -static struct atmel_lcdfb_info atmel_lcdfb0_data;
> +static struct atmel_lcdfb_pdata atmel_lcdfb0_data;
>  static struct resource atmel_lcdfb0_resource[] = {
>  	{
>  		.start		= 0xff000000,
> @@ -1465,12 +1465,12 @@ static struct clk atmel_lcdfb0_pixclk = {
>  };
>  
>  struct platform_device *__init
> -at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
> +at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_pdata *data,
>  		     unsigned long fbmem_start, unsigned long fbmem_len,
>  		     u64 pin_mask)
>  {
>  	struct platform_device *pdev;
> -	struct atmel_lcdfb_info *info;
> +	struct atmel_lcdfb_pdata *info;
>  	struct fb_monspecs *monspecs;
>  	struct fb_videomode *modedb;
>  	unsigned int modedb_size;
> @@ -1527,7 +1527,7 @@ at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
>  	}
>  
>  	info = pdev->dev.platform_data;
> -	memcpy(info, data, sizeof(struct atmel_lcdfb_info));
> +	memcpy(info, data, sizeof(struct atmel_lcdfb_pdata));
>  	info->default_monspecs = monspecs;
>  
>  	pdev->name = "at32ap-lcdfb";
> diff --git a/arch/avr32/mach-at32ap/include/mach/board.h b/arch/avr32/mach-at32ap/include/mach/board.h
> index d485b03..f1a316d 100644
> --- a/arch/avr32/mach-at32ap/include/mach/board.h
> +++ b/arch/avr32/mach-at32ap/include/mach/board.h
> @@ -44,9 +44,9 @@ struct platform_device *
>  at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n);
>  void at32_spi_setup_slaves(unsigned int bus_num, struct spi_board_info *b, unsigned int n);
>  
> -struct atmel_lcdfb_info;
> +struct atmel_lcdfb_pdata;
>  struct platform_device *
> -at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
> +at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_pdata *data,
>  		     unsigned long fbmem_start, unsigned long fbmem_len,
>  		     u64 pin_mask);
>  
> diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
> index c1a2914..98733cd4 100644
> --- a/drivers/video/atmel_lcdfb.c
> +++ b/drivers/video/atmel_lcdfb.c
> @@ -20,12 +20,45 @@
>  #include <linux/gfp.h>
>  #include <linux/module.h>
>  #include <linux/platform_data/atmel.h>
> +#include <video/of_display_timing.h>

I am not sure this one is useful for this patch, maybe place it in the
4/8 one.


>  #include <mach/cpu.h>
>  #include <asm/gpio.h>
>  
>  #include <video/atmel_lcdc.h>
>  
> +struct atmel_lcdfb_config {
> +	bool have_alt_pixclock;
> +	bool have_hozval;
> +	bool have_intensity_bit;
> +};
> +
> + /* LCD Controller info data structure, stored in device platform_data */

Is comment still relevant?

> +struct atmel_lcdfb_info {
> +	spinlock_t		lock;
> +	struct fb_info		*info;
> +	void __iomem		*mmio;
> +	int			irq_base;
> +	struct work_struct	task;
> +
> +	unsigned int		smem_len;
> +	struct platform_device	*pdev;
> +	struct clk		*bus_clk;
> +	struct clk		*lcdc_clk;
> +
> +	struct backlight_device	*backlight;
> +	u8			bl_power;
> +	bool			lcdcon_pol_negative;
> +	u8			saved_lcdcon;
> +
> +	u32			pseudo_palette[16];
> +	bool			have_intensity_bit;
> +
> +	struct atmel_lcdfb_pdata pdata;
> +
> +	struct atmel_lcdfb_config *config;
> +};
> +
>  #define lcdc_readl(sinfo, reg)		__raw_readl((sinfo)->mmio+(reg))
>  #define lcdc_writel(sinfo, reg, val)	__raw_writel((val), (sinfo)->mmio+(reg))
>  
> @@ -34,12 +67,6 @@
>  #define ATMEL_LCDC_DMA_BURST_LEN	8	/* words */
>  #define ATMEL_LCDC_FIFO_SIZE		512	/* words */
>  
> -struct atmel_lcdfb_config {
> -	bool have_alt_pixclock;
> -	bool have_hozval;
> -	bool have_intensity_bit;
> -};
> -
>  static struct atmel_lcdfb_config at91sam9261_config = {
>  	.have_hozval		= true,
>  	.have_intensity_bit	= true,
> @@ -242,6 +269,8 @@ static void exit_backlight(struct atmel_lcdfb_info *sinfo)
>  
>  static void init_contrast(struct atmel_lcdfb_info *sinfo)
>  {
> +	struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
> +
>  	/* contrast pwm can be 'inverted' */
>  	if (sinfo->lcdcon_pol_negative)
>  			contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE);
> @@ -250,7 +279,7 @@ static void init_contrast(struct atmel_lcdfb_info *sinfo)
>  	lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
>  	lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
>  
> -	if (sinfo->lcdcon_is_backlight)
> +	if (pdata->lcdcon_is_backlight)
>  		init_backlight(sinfo);
>  }
>  
> @@ -293,9 +322,11 @@ static unsigned long compute_hozval(struct atmel_lcdfb_info *sinfo,
>  
>  static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo)
>  {
> +	struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
> +
>  	/* Turn off the LCD controller and the DMA controller */
>  	lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
> -			sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
> +			pdata->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
>  
>  	/* Wait for the LCDC core to become idle */
>  	while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
> @@ -315,9 +346,11 @@ static void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo)
>  
>  static void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
>  {
> -	lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
> +	struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
> +
> +	lcdc_writel(sinfo, ATMEL_LCDC_DMACON, pdata->default_dmacon);
>  	lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
> -		(sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
> +		(pdata->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
>  		| ATMEL_LCDC_PWR);
>  }
>  
> @@ -418,6 +451,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
>  {
>  	struct device *dev = info->device;
>  	struct atmel_lcdfb_info *sinfo = info->par;
> +	struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
>  	unsigned long clk_value_khz;
>  
>  	clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
> @@ -501,7 +535,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
>  		else
>  			var->green.length = 6;
>  
> -		if (sinfo->lcd_wiring_mode = ATMEL_LCDC_WIRING_RGB) {
> +		if (pdata->lcd_wiring_mode = ATMEL_LCDC_WIRING_RGB) {
>  			/* RGB:5X5 mode */
>  			var->red.offset = var->green.length + 5;
>  			var->blue.offset = 0;
> @@ -518,7 +552,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
>  		var->transp.length = 8;
>  		/* fall through */
>  	case 24:
> -		if (sinfo->lcd_wiring_mode = ATMEL_LCDC_WIRING_RGB) {
> +		if (pdata->lcd_wiring_mode = ATMEL_LCDC_WIRING_RGB) {
>  			/* RGB:888 mode */
>  			var->red.offset = 16;
>  			var->blue.offset = 0;
> @@ -567,6 +601,7 @@ static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo)
>  static int atmel_lcdfb_set_par(struct fb_info *info)
>  {
>  	struct atmel_lcdfb_info *sinfo = info->par;
> +	struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
>  	unsigned long hozval_linesz;
>  	unsigned long value;
>  	unsigned long clk_value_khz;
> @@ -628,7 +663,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
>  
>  
>  	/* Initialize control register 2 */
> -	value = sinfo->default_lcdcon2;
> +	value = pdata->default_lcdcon2;
>  
>  	if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
>  		value |= ATMEL_LCDC_INVLINE_INVERTED;
> @@ -732,6 +767,7 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
>  			     unsigned int transp, struct fb_info *info)
>  {
>  	struct atmel_lcdfb_info *sinfo = info->par;
> +	struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
>  	unsigned int val;
>  	u32 *pal;
>  	int ret = 1;
> @@ -768,8 +804,7 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
>  				 */
>  			} else {
>  				/* new style BGR:565 / RGB:565 */
> -				if (sinfo->lcd_wiring_mode =
> -				    ATMEL_LCDC_WIRING_RGB) {
> +				if (pdata->lcd_wiring_mode = ATMEL_LCDC_WIRING_RGB) {
>  					val  = ((blue >> 11) & 0x001f);
>  					val |= ((red  >>  0) & 0xf800);
>  				} else {
> @@ -909,7 +944,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
>  	struct device *dev = &pdev->dev;
>  	struct fb_info *info;
>  	struct atmel_lcdfb_info *sinfo;
> -	struct atmel_lcdfb_info *pdata_sinfo;
> +	struct atmel_lcdfb_pdata *pdata;
>  	struct fb_videomode fbmode;
>  	struct resource *regs = NULL;
>  	struct resource *map = NULL;
> @@ -927,17 +962,8 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
>  	sinfo = info->par;
>  
>  	if (dev->platform_data) {
> -		pdata_sinfo = (struct atmel_lcdfb_info *)dev->platform_data;
> -		sinfo->default_bpp = pdata_sinfo->default_bpp;
> -		sinfo->default_dmacon = pdata_sinfo->default_dmacon;
> -		sinfo->default_lcdcon2 = pdata_sinfo->default_lcdcon2;
> -		sinfo->default_monspecs = pdata_sinfo->default_monspecs;
> -		sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control;
> -		sinfo->guard_time = pdata_sinfo->guard_time;
> -		sinfo->smem_len = pdata_sinfo->smem_len;
> -		sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight;
> -		sinfo->lcdcon_pol_negative = pdata_sinfo->lcdcon_pol_negative;
> -		sinfo->lcd_wiring_mode = pdata_sinfo->lcd_wiring_mode;
> +		pdata = (struct atmel_lcdfb_pdata *)dev->platform_data;
> +		sinfo->pdata = *pdata;
>  	} else {
>  		dev_err(dev, "cannot get default configuration\n");
>  		goto free_info;
> @@ -953,7 +979,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
>  	info->pseudo_palette = sinfo->pseudo_palette;
>  	info->fbops = &atmel_lcdfb_ops;
>  
> -	memcpy(&info->monspecs, sinfo->default_monspecs, sizeof(info->monspecs));
> +	memcpy(&info->monspecs, pdata->default_monspecs, sizeof(info->monspecs));
>  	info->fix = atmel_lcdfb_fix;
>  
>  	/* Enable LCDC Clocks */
> @@ -971,7 +997,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
>  
>  	ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb,
>  			info->monspecs.modedb_len, info->monspecs.modedb,
> -			sinfo->default_bpp);
> +			pdata->default_bpp);
>  	if (!ret) {
>  		dev_err(dev, "no suitable video mode found\n");
>  		goto stop_clk;
> @@ -1088,8 +1114,8 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
>  	fb_add_videomode(&fbmode, &info->modelist);
>  
>  	/* Power up the LCDC screen */
> -	if (sinfo->atmel_lcdfb_power_control)
> -		sinfo->atmel_lcdfb_power_control(1);
> +	if (pdata->atmel_lcdfb_power_control)
> +		pdata->atmel_lcdfb_power_control(1);
>  
>  	dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %d\n",
>  		       info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base);
> @@ -1134,15 +1160,17 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
>  	struct device *dev = &pdev->dev;
>  	struct fb_info *info = dev_get_drvdata(dev);
>  	struct atmel_lcdfb_info *sinfo;
> +	struct atmel_lcdfb_pdata *pdata;
>  
>  	if (!info || !info->par)
>  		return 0;
>  	sinfo = info->par;
> +	pdata = &sinfo->pdata;
>  
>  	cancel_work_sync(&sinfo->task);
>  	exit_backlight(sinfo);
> -	if (sinfo->atmel_lcdfb_power_control)
> -		sinfo->atmel_lcdfb_power_control(0);
> +	if (pdata->atmel_lcdfb_power_control)
> +		pdata->atmel_lcdfb_power_control(0);
>  	unregister_framebuffer(info);
>  	atmel_lcdfb_stop_clock(sinfo);
>  	clk_put(sinfo->lcdc_clk);
> @@ -1170,6 +1198,7 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
>  {
>  	struct fb_info *info = platform_get_drvdata(pdev);
>  	struct atmel_lcdfb_info *sinfo = info->par;
> +	struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
>  
>  	/*
>  	 * We don't want to handle interrupts while the clock is
> @@ -1179,8 +1208,8 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
>  
>  	sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_CTR);
>  	lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0);
> -	if (sinfo->atmel_lcdfb_power_control)
> -		sinfo->atmel_lcdfb_power_control(0);
> +	if (pdata->atmel_lcdfb_power_control)
> +		pdata->atmel_lcdfb_power_control(0);
>  
>  	atmel_lcdfb_stop(sinfo);
>  	atmel_lcdfb_stop_clock(sinfo);
> @@ -1192,11 +1221,12 @@ static int atmel_lcdfb_resume(struct platform_device *pdev)
>  {
>  	struct fb_info *info = platform_get_drvdata(pdev);
>  	struct atmel_lcdfb_info *sinfo = info->par;
> +	struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
>  
>  	atmel_lcdfb_start_clock(sinfo);
>  	atmel_lcdfb_start(sinfo);
> -	if (sinfo->atmel_lcdfb_power_control)
> -		sinfo->atmel_lcdfb_power_control(1);
> +	if (pdata->atmel_lcdfb_power_control)
> +		pdata->atmel_lcdfb_power_control(1);
>  	lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon);
>  
>  	/* Enable FIFO & DMA errors */
> diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
> index 0f5a2fc..2eb601c 100644
> --- a/include/video/atmel_lcdc.h
> +++ b/include/video/atmel_lcdc.h
> @@ -31,39 +31,17 @@
>  #define ATMEL_LCDC_WIRING_BGR	0
>  #define ATMEL_LCDC_WIRING_RGB	1
>  
> -struct atmel_lcdfb_config;
>  
>   /* LCD Controller info data structure, stored in device platform_data */

Wrong comment: it is not the "info" data structure, this time.

> -struct atmel_lcdfb_info {
> -	spinlock_t		lock;
> -	struct fb_info		*info;
> -	void __iomem		*mmio;
> -	int			irq_base;
> -	struct work_struct	task;
> -
> +struct atmel_lcdfb_pdata {
>  	unsigned int		guard_time;
> -	unsigned int 		smem_len;
> -	struct platform_device	*pdev;
> -	struct clk		*bus_clk;
> -	struct clk		*lcdc_clk;
> -
> -#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
> -	struct backlight_device	*backlight;
> -	u8			bl_power;
> -#endif
>  	bool			lcdcon_is_backlight;
> -	bool			lcdcon_pol_negative;
> -	u8			saved_lcdcon;
> -
>  	u8			default_bpp;
>  	u8			lcd_wiring_mode;
>  	unsigned int		default_lcdcon2;
>  	unsigned int		default_dmacon;
>  	void (*atmel_lcdfb_power_control)(int on);
>  	struct fb_monspecs	*default_monspecs;
> -	u32			pseudo_palette[16];
> -
> -	struct atmel_lcdfb_config *config;
>  };
>  
>  #define ATMEL_LCDC_DMABADDR1	0x00
> 


-- 
Nicolas Ferre

^ permalink raw reply

* Re: [PATCH 2/8] video: atmel_lcdfb: introduce atmel_lcdfb_power_control
From: Nicolas Ferre @ 2013-04-16 12:35 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1365692422-9565-2-git-send-email-plagnioj@jcrosoft.com>

On 04/11/2013 05:00 PM, Jean-Christophe PLAGNIOL-VILLARD :
> to simplify the check on the presence of the callback
> 
> Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
> Cc: linux-fbdev@vger.kernel.org
> Cc: Nicolas Ferre <nicolas.ferre@atmel.com>

Simple and nice

Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>


> Cc: Andrew Morton <akpm@linux-foundation.org>
> ---
>  drivers/video/atmel_lcdfb.c |   22 +++++++++++-----------
>  1 file changed, 11 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
> index 98733cd4..9574c47 100644
> --- a/drivers/video/atmel_lcdfb.c
> +++ b/drivers/video/atmel_lcdfb.c
> @@ -283,6 +283,13 @@ static void init_contrast(struct atmel_lcdfb_info *sinfo)
>  		init_backlight(sinfo);
>  }
>  
> +static inline void atmel_lcdfb_power_control(struct atmel_lcdfb_info *sinfo, int on)
> +{
> +	struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
> +
> +	if (pdata->atmel_lcdfb_power_control)
> +		pdata->atmel_lcdfb_power_control(on);
> +}
>  
>  static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
>  	.type		= FB_TYPE_PACKED_PIXELS,
> @@ -1114,8 +1121,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
>  	fb_add_videomode(&fbmode, &info->modelist);
>  
>  	/* Power up the LCDC screen */
> -	if (pdata->atmel_lcdfb_power_control)
> -		pdata->atmel_lcdfb_power_control(1);
> +	atmel_lcdfb_power_control(sinfo, 1);
>  
>  	dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %d\n",
>  		       info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base);
> @@ -1169,8 +1175,7 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
>  
>  	cancel_work_sync(&sinfo->task);
>  	exit_backlight(sinfo);
> -	if (pdata->atmel_lcdfb_power_control)
> -		pdata->atmel_lcdfb_power_control(0);
> +	atmel_lcdfb_power_control(sinfo, 0);
>  	unregister_framebuffer(info);
>  	atmel_lcdfb_stop_clock(sinfo);
>  	clk_put(sinfo->lcdc_clk);
> @@ -1198,7 +1203,6 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
>  {
>  	struct fb_info *info = platform_get_drvdata(pdev);
>  	struct atmel_lcdfb_info *sinfo = info->par;
> -	struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
>  
>  	/*
>  	 * We don't want to handle interrupts while the clock is
> @@ -1208,9 +1212,7 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
>  
>  	sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_CTR);
>  	lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0);
> -	if (pdata->atmel_lcdfb_power_control)
> -		pdata->atmel_lcdfb_power_control(0);
> -
> +	atmel_lcdfb_power_control(sinfo, 0);
>  	atmel_lcdfb_stop(sinfo);
>  	atmel_lcdfb_stop_clock(sinfo);
>  
> @@ -1221,12 +1223,10 @@ static int atmel_lcdfb_resume(struct platform_device *pdev)
>  {
>  	struct fb_info *info = platform_get_drvdata(pdev);
>  	struct atmel_lcdfb_info *sinfo = info->par;
> -	struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
>  
>  	atmel_lcdfb_start_clock(sinfo);
>  	atmel_lcdfb_start(sinfo);
> -	if (pdata->atmel_lcdfb_power_control)
> -		pdata->atmel_lcdfb_power_control(1);
> +	atmel_lcdfb_power_control(sinfo, 1);
>  	lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon);
>  
>  	/* Enable FIFO & DMA errors */
> 


-- 
Nicolas Ferre

^ permalink raw reply

* Re: [PATCH 3/8] video: atmel_lcdfb: pass the pdata as params
From: Nicolas Ferre @ 2013-04-16 12:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1365692422-9565-3-git-send-email-plagnioj@jcrosoft.com>

On 04/11/2013 05:00 PM, Jean-Christophe PLAGNIOL-VILLARD :
> so we can use have list gpio as example (probe via DT)

Please refine the commit message: I do not understand.

After reading the patch, it seems obvious that more explanations are
needed in the message.

> Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
> Cc: linux-fbdev@vger.kernel.org
> Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> ---
>  arch/arm/mach-at91/board-sam9261ek.c   |    4 ++--
>  arch/arm/mach-at91/board-sam9263ek.c   |    2 +-
>  arch/arm/mach-at91/board-sam9rlek.c    |    2 +-
>  arch/avr32/boards/atngw100/evklcd10x.c |    2 +-
>  drivers/video/atmel_lcdfb.c            |    2 +-
>  include/video/atmel_lcdc.h             |    4 +++-
>  6 files changed, 9 insertions(+), 7 deletions(-)
> 
> diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
> index c819e29..9a6618a 100644
> --- a/arch/arm/mach-at91/board-sam9261ek.c
> +++ b/arch/arm/mach-at91/board-sam9261ek.c
> @@ -393,7 +393,7 @@ static struct fb_monspecs at91fb_default_stn_monspecs = {
>  					| ATMEL_LCDC_IFWIDTH_4 \
>  					| ATMEL_LCDC_SCANMOD_SINGLE)
>  
> -static void at91_lcdc_stn_power_control(int on)
> +static void at91_lcdc_stn_power_control(struct atmel_lcdfb_pdata *pdata, int on)
>  {
>  	/* backlight */
>  	if (on) {	/* power up */
> @@ -452,7 +452,7 @@ static struct fb_monspecs at91fb_default_tft_monspecs = {
>  					| ATMEL_LCDC_DISTYPE_TFT    \
>  					| ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
>  
> -static void at91_lcdc_tft_power_control(int on)
> +static void at91_lcdc_tft_power_control(struct atmel_lcdfb_pdata *pdata, int on)
>  {
>  	if (on)
>  		at91_set_gpio_value(AT91_PIN_PA12, 0);	/* power up */
> diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
> index 0fdae3f..8b4942c 100644
> --- a/arch/arm/mach-at91/board-sam9263ek.c
> +++ b/arch/arm/mach-at91/board-sam9263ek.c
> @@ -275,7 +275,7 @@ static struct fb_monspecs at91fb_default_monspecs = {
>  					| ATMEL_LCDC_DISTYPE_TFT \
>  					| ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
>  
> -static void at91_lcdc_power_control(int on)
> +static void at91_lcdc_power_control(struct atmel_lcdfb_pdata *pdata, int on)
>  {
>  	at91_set_gpio_value(AT91_PIN_PA30, on);
>  }
> diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c
> index b77d7a9..604eecf 100644
> --- a/arch/arm/mach-at91/board-sam9rlek.c
> +++ b/arch/arm/mach-at91/board-sam9rlek.c
> @@ -170,7 +170,7 @@ static struct fb_monspecs at91fb_default_monspecs = {
>  					| ATMEL_LCDC_DISTYPE_TFT \
>  					| ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
>  
> -static void at91_lcdc_power_control(int on)
> +static void at91_lcdc_power_control(struct atmel_lcdfb_pdata *pdata, int on)
>  {
>  	if (on)
>  		at91_set_gpio_value(AT91_PIN_PC1, 0);	/* power up */
> diff --git a/arch/avr32/boards/atngw100/evklcd10x.c b/arch/avr32/boards/atngw100/evklcd10x.c
> index dc42804..64919b0 100644
> --- a/arch/avr32/boards/atngw100/evklcd10x.c
> +++ b/arch/avr32/boards/atngw100/evklcd10x.c
> @@ -145,7 +145,7 @@ static struct atmel_lcdfb_pdata __initdata atevklcd10x_lcdc_data = {
>  };
>  #endif
>  
> -static void atevklcd10x_lcdc_power_control(int on)
> +static void atevklcd10x_lcdc_power_control(struct atmel_lcdfb_pdata *pdata, int on)
>  {
>  	gpio_set_value(GPIO_PIN_PB(15), on);
>  }
> diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
> index 9574c47..f67e226 100644
> --- a/drivers/video/atmel_lcdfb.c
> +++ b/drivers/video/atmel_lcdfb.c
> @@ -288,7 +288,7 @@ static inline void atmel_lcdfb_power_control(struct atmel_lcdfb_info *sinfo, int
>  	struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
>  
>  	if (pdata->atmel_lcdfb_power_control)
> -		pdata->atmel_lcdfb_power_control(on);
> +		pdata->atmel_lcdfb_power_control(pdata, on);
>  }
>  
>  static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
> diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
> index 2eb601c..f624c51 100644
> --- a/include/video/atmel_lcdc.h
> +++ b/include/video/atmel_lcdc.h
> @@ -40,8 +40,10 @@ struct atmel_lcdfb_pdata {
>  	u8			lcd_wiring_mode;
>  	unsigned int		default_lcdcon2;
>  	unsigned int		default_dmacon;
> -	void (*atmel_lcdfb_power_control)(int on);
> +	void (*atmel_lcdfb_power_control)(struct atmel_lcdfb_pdata *pdata, int on);
>  	struct fb_monspecs	*default_monspecs;
> +
> +	struct list_head	pwr_gpios;
>  };
>  
>  #define ATMEL_LCDC_DMABADDR1	0x00
> 


-- 
Nicolas Ferre

^ permalink raw reply

* Re: [PATCH 4/8] video: atmel_lcdfb: add device tree suport
From: Nicolas Ferre @ 2013-04-16 13:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1365692422-9565-4-git-send-email-plagnioj@jcrosoft.com>

On 04/11/2013 05:00 PM, Jean-Christophe PLAGNIOL-VILLARD :
> get display timings from device tree
> Use videomode helpers to get display timings and configurations from
> device tree

2 sentences? Simply elaborate the 2nd one and it will be good.

> Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
> Cc: linux-fbdev@vger.kernel.org
> Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> ---
>  .../devicetree/bindings/video/atmel,lcdc.txt       |   75 ++++++
>  drivers/video/Kconfig                              |    2 +
>  drivers/video/atmel_lcdfb.c                        |  244 +++++++++++++++++---
>  3 files changed, 289 insertions(+), 32 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/video/atmel,lcdc.txt
> 
> diff --git a/Documentation/devicetree/bindings/video/atmel,lcdc.txt b/Documentation/devicetree/bindings/video/atmel,lcdc.txt
> new file mode 100644
> index 0000000..1ec175e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/video/atmel,lcdc.txt

Why lcdc? I would have preferred atmel,lcdfb, like the driver's name: it
is even more self-explanatory...

> @@ -0,0 +1,75 @@
> +Atmel LCDC Framebuffer
> +-----------------------------------------------------
> +
> +Required properties:
> +- compatible :
> +	"atmel,at91sam9261-lcdc" , 
> +	"atmel,at91sam9263-lcdc" ,
> +	"atmel,at91sam9g10-lcdc" ,
> +	"atmel,at91sam9g45-lcdc" ,
> +	"atmel,at91sam9g45es-lcdc" ,
> +	"atmel,at91sam9rl-lcdc" ,
> +	"atmel,at32ap-lcdc"
> +- reg : Should contain 1 register ranges(address and length)
> +- interrupts : framebuffer controller interrupt
> +- display: a phandle pointing to the display node
> +
> +Required nodes:
> +- display: a display node is required to initialize the lcd panel
> +	This should be in the board dts.
> +- default-mode: a videomode within the display with timing parameters
> +	as specified below.
> +
> +Example:
> +
> +	fb0: fb@0x00500000 {
> +		compatible = "atmel,at91sam9g45-lcdc";
> +		reg = <0x00500000 0x1000>;
> +		interrupts = <23 3 0>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&pinctrl_fb>;
> +		display = <&display0>;
> +		status = "okay";
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +
> +	};
> +
> +Atmel LCDC Display
> +-----------------------------------------------------
> +Required properties (as per of_videomode_helper):

Can you please point somewhere to the documentation:
Documentation/devicetree/bindings/video/display-timing.txt

> + - atmel,dmacon: dma controler configuration

Typo: controller.

> + - atmel,lcdcon2: lcd controler configuration

Ditto

> + - atmel,guard-time: lcd guard time (Delay in frame periods)

periods -> period, no?

> + - bits-per-pixel: lcd panel bit-depth.
> +
> +Optional properties (as per of_videomode_helper):
> + - atmel,lcdcon-backlight: enable backlight
> + - atmel,lcd-wiring-mode: lcd wiring mode "RGB" or "BRG"

Is it a sting, or a number (as seen below)? If it is a number, please
tell how to choose the index.


> + - atmel,power-control-gpio: gpio to power on or off the LCD (as many as needed)
> +
> +Example:
> +	display0: display {
> +		bits-per-pixel = <32>;
> +		atmel,lcdcon-backlight;
> +		atmel,dmacon = <0x1>;
> +		atmel,lcdcon2 = <0x80008002>;
> +		atmel,guard-time = <9>;
> +		atmel,lcd-wiring-mode = <1>;
> +
> +		display-timings {
> +			native-mode = <&timing0>;
> +			timing0: timing0 {
> +				clock-frequency = <9000000>;
> +				hactive = <480>;
> +				vactive = <272>;
> +				hback-porch = <1>;
> +				hfront-porch = <1>;
> +				vback-porch = <40>;
> +				vfront-porch = <1>;
> +				hsync-len = <45>;
> +				vsync-len = <1>;
> +			};
> +		};
> +	};
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index 4c1546f..0687482 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -1018,6 +1018,8 @@ config FB_ATMEL
>  	select FB_CFB_FILLRECT
>  	select FB_CFB_COPYAREA
>  	select FB_CFB_IMAGEBLIT
> +	select FB_MODE_HELPERS
> +	select OF_VIDEOMODE
>  	help
>  	  This enables support for the AT91/AT32 LCD Controller.
>  
> diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
> index f67e226..4a31570 100644
> --- a/drivers/video/atmel_lcdfb.c
> +++ b/drivers/video/atmel_lcdfb.c
> @@ -20,7 +20,11 @@
>  #include <linux/gfp.h>
>  #include <linux/module.h>
>  #include <linux/platform_data/atmel.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/of_gpio.h>
>  #include <video/of_display_timing.h>

As said in patch 1/8, this one belongs to this 4/8 patch.

> +#include <video/videomode.h>
>  
>  #include <mach/cpu.h>
>  #include <asm/gpio.h>
> @@ -59,6 +63,13 @@ struct atmel_lcdfb_info {
>  	struct atmel_lcdfb_config *config;
>  };
>  
> +struct atmel_lcdfb_power_ctrl_gpio {
> +	int gpio;
> +	int active_low;
> +
> +	struct list_head list;
> +};
> +
>  #define lcdc_readl(sinfo, reg)		__raw_readl((sinfo)->mmio+(reg))
>  #define lcdc_writel(sinfo, reg, val)	__raw_writel((val), (sinfo)->mmio+(reg))
>  
> @@ -945,16 +956,187 @@ static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo)
>  	clk_disable(sinfo->lcdc_clk);
>  }
>  
> +#ifdef CONFIG_OF
> +static const struct of_device_id atmel_lcdfb_dt_ids[] = {
> +	{ .compatible = "atmel,at91sam9261-lcdc" , .data = &at91sam9261_config, },
> +	{ .compatible = "atmel,at91sam9263-lcdc" , .data = &at91sam9263_config, },
> +	{ .compatible = "atmel,at91sam9g10-lcdc" , .data = &at91sam9g10_config, },
> +	{ .compatible = "atmel,at91sam9g45-lcdc" , .data = &at91sam9g45_config, },
> +	{ .compatible = "atmel,at91sam9g45es-lcdc" , .data = &at91sam9g45es_config, },
> +	{ .compatible = "atmel,at91sam9rl-lcdc" , .data = &at91sam9rl_config, },
> +	{ .compatible = "atmel,at32ap-lcdc" , .data = &at32ap_config, },
> +	{ /* sentinel */ }
> +};
> +
> +MODULE_DEVICE_TABLE(of, atmel_lcdfb_dt_ids);
> +
> +static const char *atmel_lcdfb_wiring_modes[] = {
> +	[ATMEL_LCDC_WIRING_BGR]	= "BRG",
> +	[ATMEL_LCDC_WIRING_RGB]	= "RGB",
> +};
> +
> +const int atmel_lcdfb_get_of_wiring_modes(struct device_node *np)
> +{
> +	const char *mode;
> +	int err, i;
> +
> +	err = of_property_read_string(np, "atmel,lcd-wiring-mode", &mode);
> +	if (err < 0)
> +		return ATMEL_LCDC_WIRING_BGR;
> +
> +	for (i = 0; i < ARRAY_SIZE(atmel_lcdfb_wiring_modes); i++)
> +		if (!strcasecmp(mode, atmel_lcdfb_wiring_modes[i]))
> +			return i;
> +
> +	return -ENODEV;
> +}
> +
> +static void atmel_lcdfb_power_control_gpio(struct atmel_lcdfb_pdata *pdata, int on)
> +{
> +	struct atmel_lcdfb_power_ctrl_gpio *og;
> +
> +	list_for_each_entry(og, &pdata->pwr_gpios, list)
> +		gpio_set_value(og->gpio, on);
> +}
> +
> +static int atmel_lcdfb_of_init(struct atmel_lcdfb_info *sinfo)
> +{
> +	struct fb_info *info = sinfo->info;
> +	struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
> +	struct fb_var_screeninfo *var = &info->var;
> +	struct device *dev = &sinfo->pdev->dev;
> +	struct device_node *np Þv->of_node;
> +	struct device_node *display_np;
> +	struct device_node *timings_np;
> +	struct display_timings *timings;
> +	enum of_gpio_flags flags;
> +	struct atmel_lcdfb_power_ctrl_gpio *og;
> +	bool is_gpio_power = false;
> +	int ret = -ENOENT;
> +	int i, gpio;
> +
> +	sinfo->config = (struct atmel_lcdfb_config*)
> +		of_match_device(atmel_lcdfb_dt_ids, dev)->data;

Please split it in 2 steps, otherwise the day that the drivers doesn't
find the device in dt_ids table, it hangs here with an Oops.

> +
> +	display_np = of_parse_phandle(np, "display", 0);
> +	if (!display_np) {
> +		dev_err(dev, "failed to find display phandle\n");
> +		return -ENOENT;
> +	}
> +
> +	ret = of_property_read_u32(display_np, "bits-per-pixel", &var->bits_per_pixel);
> +	if (ret < 0) {
> +		dev_err(dev, "failed to get property bits-per-pixel\n");
> +		goto put_display_node;
> +	}
> +
> +	ret = of_property_read_u32(display_np, "atmel,guard-time", &pdata->guard_time);
> +	if (ret < 0) {
> +		dev_err(dev, "failed to get property atmel,guard-time\n");
> +		goto put_display_node;
> +	}
> +
> +	ret = of_property_read_u32(display_np, "atmel,lcdcon2", &pdata->default_lcdcon2);
> +	if (ret < 0) {
> +		dev_err(dev, "failed to get property atmel,lcdcon2\n");
> +		goto put_display_node;
> +	}
> +
> +	ret = of_property_read_u32(display_np, "atmel,dmacon", &pdata->default_dmacon);
> +	if (ret < 0) {
> +		dev_err(dev, "failed to get property bits-per-pixel\n");

No, wrong error message.

> +		goto put_display_node;
> +	}
> +
> +	ret = -ENOMEM;
> +	for (i = 0; i < of_gpio_named_count(display_np, "atmel,power-control-gpio"); i++) {
> +		gpio = of_get_named_gpio_flags(display_np, "atmel,power-control-gpio",
> +					       i, &flags);
> +		if (gpio < 0)
> +			continue;
> +
> +		og = devm_kzalloc(dev, sizeof(*og), GFP_KERNEL);
> +		if (!og)
> +			goto put_display_node;
> +
> +		og->gpio = gpio;
> +		og->active_low = flags & OF_GPIO_ACTIVE_LOW;
> +		is_gpio_power = true;
> +		ret = devm_gpio_request(dev, gpio, "lcd-power-control-gpio");
> +		if (ret) {
> +			dev_err(dev, "request gpio %d failed\n", gpio);
> +			goto put_display_node;
> +		}
> +
> +		ret = gpio_direction_output(gpio, og->active_low);
> +		if (ret) {
> +			dev_err(dev, "set direction output gpio %d failed\n", gpio);
> +			goto put_display_node;
> +		}
> +	}
> +
> +	if (is_gpio_power)
> +		pdata->atmel_lcdfb_power_control = atmel_lcdfb_power_control_gpio;
> +
> +	ret = atmel_lcdfb_get_of_wiring_modes(display_np);
> +	if (ret < 0) {
> +		dev_err(dev, "invalid atmel,lcd-wiring-mode\n");
> +		goto put_display_node;
> +	}
> +	pdata->lcd_wiring_mode = ret;
> +
> +	pdata->lcdcon_is_backlight = of_property_read_bool(display_np, "atmel,lcdcon-backlight");
> +
> +	timings = of_get_display_timings(display_np);
> +	if (!timings) {
> +		dev_err(dev, "failed to get display timings\n");
> +		goto put_display_node;
> +	}
> +
> +	timings_np = of_find_node_by_name(display_np, "display-timings");
> +	if (!timings_np) {
> +		dev_err(dev, "failed to find display-timings node\n");
> +		goto put_display_node;
> +	}
> +
> +	for (i = 0; i < of_get_child_count(timings_np); i++) {
> +		struct videomode vm;
> +		struct fb_videomode fb_vm;
> +
> +		ret = videomode_from_timing(timings, &vm, i);
> +		if (ret < 0)
> +			goto put_timings_node;
> +		ret = fb_videomode_from_videomode(&vm, &fb_vm);
> +		if (ret < 0)
> +			goto put_timings_node;
> +
> +		fb_add_videomode(&fb_vm, &info->modelist);
> +	}
> +
> +	return 0;
> +
> +put_timings_node:
> +	of_node_put(timings_np);
> +put_display_node:
> +	of_node_put(display_np);
> +	return ret;
> +}
> +#else
> +static int atmel_lcdfb_of_init(struct atmel_lcdfb_info *sinfo)
> +{
> +	return 0;
> +}
> +#endif
>  
>  static int __init atmel_lcdfb_probe(struct platform_device *pdev)
>  {
>  	struct device *dev = &pdev->dev;
>  	struct fb_info *info;
>  	struct atmel_lcdfb_info *sinfo;
> -	struct atmel_lcdfb_pdata *pdata;
> -	struct fb_videomode fbmode;
> +	struct atmel_lcdfb_pdata *pdata = NULL;
>  	struct resource *regs = NULL;
>  	struct resource *map = NULL;
> +	struct fb_modelist *modelist;
>  	int ret;
>  
>  	dev_dbg(dev, "%s BEGIN\n", __func__);
> @@ -967,17 +1149,35 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
>  	}
>  
>  	sinfo = info->par;
> +	sinfo->pdev = pdev;
> +	sinfo->info = info;
> +
> +	INIT_LIST_HEAD(&info->modelist);
>  
> -	if (dev->platform_data) {
> -		pdata = (struct atmel_lcdfb_pdata *)dev->platform_data;
> +	if (pdev->dev.of_node) {
> +		ret = atmel_lcdfb_of_init(sinfo);
> +		if (ret)
> +			goto free_info;
> +	} else if (dev->platform_data) {
> +		struct fb_monspecs *monspecs;
> +		int i;
> +
> +		pdata = dev->platform_data;
> +		monspecs = pdata->default_monspecs;
>  		sinfo->pdata = *pdata;
> +
> +		for (i = 0; i < monspecs->modedb_len; i++)
> +			fb_add_videomode(&monspecs->modedb[i], &info->modelist);
> +
> +		sinfo->config = atmel_lcdfb_get_config(pdev);
> +
> +		info->var.bits_per_pixel = pdata->default_bpp ? pdata->default_bpp : 16;
> +		memcpy(&info->monspecs, pdata->default_monspecs, sizeof(info->monspecs));
>  	} else {
>  		dev_err(dev, "cannot get default configuration\n");
>  		goto free_info;
>  	}
> -	sinfo->info = info;
> -	sinfo->pdev = pdev;
> -	sinfo->config = atmel_lcdfb_get_config(pdev);
> +
>  	if (!sinfo->config)
>  		goto free_info;
>  
> @@ -986,7 +1186,6 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
>  	info->pseudo_palette = sinfo->pseudo_palette;
>  	info->fbops = &atmel_lcdfb_ops;
>  
> -	memcpy(&info->monspecs, pdata->default_monspecs, sizeof(info->monspecs));
>  	info->fix = atmel_lcdfb_fix;
>  
>  	/* Enable LCDC Clocks */
> @@ -1002,14 +1201,11 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
>  	}
>  	atmel_lcdfb_start_clock(sinfo);
>  
> -	ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb,
> -			info->monspecs.modedb_len, info->monspecs.modedb,
> -			pdata->default_bpp);
> -	if (!ret) {
> -		dev_err(dev, "no suitable video mode found\n");
> -		goto stop_clk;
> -	}
> +	modelist = list_first_entry(&info->modelist,
> +			struct fb_modelist, list);
> +	fb_videomode_to_var(&info->var, &modelist->mode);
>  
> +	atmel_lcdfb_check_var(&info->var, info);
>  
>  	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	if (!regs) {
> @@ -1093,18 +1289,6 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
>  		goto unregister_irqs;
>  	}
>  
> -	/*
> -	 * This makes sure that our colour bitfield
> -	 * descriptors are correctly initialised.
> -	 */
> -	atmel_lcdfb_check_var(&info->var, info);
> -
> -	ret = fb_set_var(info, &info->var);
> -	if (ret) {
> -		dev_warn(dev, "unable to set display parameters\n");
> -		goto free_cmap;
> -	}
> -
>  	dev_set_drvdata(dev, info);
>  
>  	/*
> @@ -1116,10 +1300,6 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
>  		goto reset_drvdata;
>  	}
>  
> -	/* add selected videomode to modelist */
> -	fb_var_to_videomode(&fbmode, &info->var);
> -	fb_add_videomode(&fbmode, &info->modelist);
> -
>  	/* Power up the LCDC screen */
>  	atmel_lcdfb_power_control(sinfo, 1);
>  
> @@ -1130,7 +1310,6 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
>  
>  reset_drvdata:
>  	dev_set_drvdata(dev, NULL);
> -free_cmap:
>  	fb_dealloc_cmap(&info->cmap);
>  unregister_irqs:
>  	cancel_work_sync(&sinfo->task);
> @@ -1249,6 +1428,7 @@ static struct platform_driver atmel_lcdfb_driver = {
>  	.driver		= {
>  		.name	= "atmel_lcdfb",
>  		.owner	= THIS_MODULE,
> +		.of_match_table	= of_match_ptr(atmel_lcdfb_dt_ids),
>  	},
>  };
>  
> 


-- 
Nicolas Ferre

^ permalink raw reply

* Re: [PATCH 4/8] video: atmel_lcdfb: add device tree suport
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-04-16 13:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <516D554C.1090909@atmel.com>

On 15:42 Tue 16 Apr     , Nicolas Ferre wrote:
> On 04/11/2013 05:00 PM, Jean-Christophe PLAGNIOL-VILLARD :
> > get display timings from device tree
> > Use videomode helpers to get display timings and configurations from
> > device tree
> 
> 2 sentences? Simply elaborate the 2nd one and it will be good.
> 
> > Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
> > Cc: linux-fbdev@vger.kernel.org
> > Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
> > Cc: Andrew Morton <akpm@linux-foundation.org>
> > ---
> >  .../devicetree/bindings/video/atmel,lcdc.txt       |   75 ++++++
> >  drivers/video/Kconfig                              |    2 +
> >  drivers/video/atmel_lcdfb.c                        |  244 +++++++++++++++++---
> >  3 files changed, 289 insertions(+), 32 deletions(-)
> >  create mode 100644 Documentation/devicetree/bindings/video/atmel,lcdc.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/video/atmel,lcdc.txt b/Documentation/devicetree/bindings/video/atmel,lcdc.txt
> > new file mode 100644
> > index 0000000..1ec175e
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/video/atmel,lcdc.txt
> 
> Why lcdc? I would have preferred atmel,lcdfb, like the driver's name: it
> is even more self-explanatory...
we do not describe drivers but IP
> 
> > @@ -0,0 +1,75 @@
> > +Atmel LCDC Framebuffer
> > +-----------------------------------------------------
> > +
> > +Required properties:
> > +- compatible :
> > +	"atmel,at91sam9261-lcdc" , 
> > +	"atmel,at91sam9263-lcdc" ,
> > +	"atmel,at91sam9g10-lcdc" ,
> > +	"atmel,at91sam9g45-lcdc" ,
> > +	"atmel,at91sam9g45es-lcdc" ,
> > +	"atmel,at91sam9rl-lcdc" ,
> > +	"atmel,at32ap-lcdc"
> > +- reg : Should contain 1 register ranges(address and length)
> > +- interrupts : framebuffer controller interrupt
> > +- display: a phandle pointing to the display node
> > +
> > +Required nodes:
> > +- display: a display node is required to initialize the lcd panel
> > +	This should be in the board dts.
> > +- default-mode: a videomode within the display with timing parameters
> > +	as specified below.
> > +
> > +Example:
> > +
> > +	fb0: fb@0x00500000 {
> > +		compatible = "atmel,at91sam9g45-lcdc";
> > +		reg = <0x00500000 0x1000>;
> > +		interrupts = <23 3 0>;
> > +		pinctrl-names = "default";
> > +		pinctrl-0 = <&pinctrl_fb>;
> > +		display = <&display0>;
> > +		status = "okay";
> > +		#address-cells = <1>;
> > +		#size-cells = <1>;
> > +
> > +	};
> > +
> > +Atmel LCDC Display
> > +-----------------------------------------------------
> > +Required properties (as per of_videomode_helper):
> 
> Can you please point somewhere to the documentation:
> Documentation/devicetree/bindings/video/display-timing.txt
> 
> > + - atmel,dmacon: dma controler configuration
> 
> Typo: controller.
> 
> > + - atmel,lcdcon2: lcd controler configuration
> 
> Ditto
> 
> > + - atmel,guard-time: lcd guard time (Delay in frame periods)
> 
> periods -> period, no?
no it's periods even in the datasheet
> 
> > + - bits-per-pixel: lcd panel bit-depth.
> > +
> > +Optional properties (as per of_videomode_helper):
> > + - atmel,lcdcon-backlight: enable backlight
> > + - atmel,lcd-wiring-mode: lcd wiring mode "RGB" or "BRG"
> 
> Is it a sting, or a number (as seen below)? If it is a number, please
> tell how to choose the index.
String
> 
> 
> > + - atmel,power-control-gpio: gpio to power on or off the LCD (as many as needed)
> > +
> > +Example:
> > +	display0: display {
> > +		bits-per-pixel = <32>;
> > +		atmel,lcdcon-backlight;
> > +		atmel,dmacon = <0x1>;
> > +		atmel,lcdcon2 = <0x80008002>;
> > +		atmel,guard-time = <9>;
> > +		atmel,lcd-wiring-mode = <1>;
> > +
> > +		display-timings {
> > +			native-mode = <&timing0>;
> > +			timing0: timing0 {
> > +				clock-frequency = <9000000>;
> > +				hactive = <480>;
> > +				vactive = <272>;
> > +				hback-porch = <1>;
> > +				hfront-porch = <1>;
> > +				vback-porch = <40>;
> > +				vfront-porch = <1>;
> > +				hsync-len = <45>;
> > +				vsync-len = <1>;
> > +			};
> > +		};
> > +	};
> > diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> > index 4c1546f..0687482 100644
> > --- a/drivers/video/Kconfig
> > +++ b/drivers/video/Kconfig
> > @@ -1018,6 +1018,8 @@ config FB_ATMEL
> >  	select FB_CFB_FILLRECT
> >  	select FB_CFB_COPYAREA
> >  	select FB_CFB_IMAGEBLIT
> > +	select FB_MODE_HELPERS
> > +	select OF_VIDEOMODE
> >  	help
> >  	  This enables support for the AT91/AT32 LCD Controller.
> >  
> > diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
> > index f67e226..4a31570 100644
> > --- a/drivers/video/atmel_lcdfb.c
> > +++ b/drivers/video/atmel_lcdfb.c
> > @@ -20,7 +20,11 @@
> >  #include <linux/gfp.h>
> >  #include <linux/module.h>
> >  #include <linux/platform_data/atmel.h>
> > +#include <linux/of.h>
> > +#include <linux/of_device.h>
> > +#include <linux/of_gpio.h>
> >  #include <video/of_display_timing.h>
> 
> As said in patch 1/8, this one belongs to this 4/8 patch.
> 
> > +#include <video/videomode.h>
> >  
> >  #include <mach/cpu.h>
> >  #include <asm/gpio.h>
> > @@ -59,6 +63,13 @@ struct atmel_lcdfb_info {
> >  	struct atmel_lcdfb_config *config;
> >  };
> >  
> > +struct atmel_lcdfb_power_ctrl_gpio {
> > +	int gpio;
> > +	int active_low;
> > +
> > +	struct list_head list;
> > +};
> > +
> >  #define lcdc_readl(sinfo, reg)		__raw_readl((sinfo)->mmio+(reg))
> >  #define lcdc_writel(sinfo, reg, val)	__raw_writel((val), (sinfo)->mmio+(reg))
> >  
> > @@ -945,16 +956,187 @@ static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo)
> >  	clk_disable(sinfo->lcdc_clk);
> >  }
> >  
> > +#ifdef CONFIG_OF
> > +static const struct of_device_id atmel_lcdfb_dt_ids[] = {
> > +	{ .compatible = "atmel,at91sam9261-lcdc" , .data = &at91sam9261_config, },
> > +	{ .compatible = "atmel,at91sam9263-lcdc" , .data = &at91sam9263_config, },
> > +	{ .compatible = "atmel,at91sam9g10-lcdc" , .data = &at91sam9g10_config, },
> > +	{ .compatible = "atmel,at91sam9g45-lcdc" , .data = &at91sam9g45_config, },
> > +	{ .compatible = "atmel,at91sam9g45es-lcdc" , .data = &at91sam9g45es_config, },
> > +	{ .compatible = "atmel,at91sam9rl-lcdc" , .data = &at91sam9rl_config, },
> > +	{ .compatible = "atmel,at32ap-lcdc" , .data = &at32ap_config, },
> > +	{ /* sentinel */ }
> > +};
> > +
> > +MODULE_DEVICE_TABLE(of, atmel_lcdfb_dt_ids);
> > +
> > +static const char *atmel_lcdfb_wiring_modes[] = {
> > +	[ATMEL_LCDC_WIRING_BGR]	= "BRG",
> > +	[ATMEL_LCDC_WIRING_RGB]	= "RGB",
> > +};
> > +
> > +const int atmel_lcdfb_get_of_wiring_modes(struct device_node *np)
> > +{
> > +	const char *mode;
> > +	int err, i;
> > +
> > +	err = of_property_read_string(np, "atmel,lcd-wiring-mode", &mode);
> > +	if (err < 0)
> > +		return ATMEL_LCDC_WIRING_BGR;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(atmel_lcdfb_wiring_modes); i++)
> > +		if (!strcasecmp(mode, atmel_lcdfb_wiring_modes[i]))
> > +			return i;
> > +
> > +	return -ENODEV;
> > +}
> > +
> > +static void atmel_lcdfb_power_control_gpio(struct atmel_lcdfb_pdata *pdata, int on)
> > +{
> > +	struct atmel_lcdfb_power_ctrl_gpio *og;
> > +
> > +	list_for_each_entry(og, &pdata->pwr_gpios, list)
> > +		gpio_set_value(og->gpio, on);
> > +}
> > +
> > +static int atmel_lcdfb_of_init(struct atmel_lcdfb_info *sinfo)
> > +{
> > +	struct fb_info *info = sinfo->info;
> > +	struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
> > +	struct fb_var_screeninfo *var = &info->var;
> > +	struct device *dev = &sinfo->pdev->dev;
> > +	struct device_node *np Þv->of_node;
> > +	struct device_node *display_np;
> > +	struct device_node *timings_np;
> > +	struct display_timings *timings;
> > +	enum of_gpio_flags flags;
> > +	struct atmel_lcdfb_power_ctrl_gpio *og;
> > +	bool is_gpio_power = false;
> > +	int ret = -ENOENT;
> > +	int i, gpio;
> > +
> > +	sinfo->config = (struct atmel_lcdfb_config*)
> > +		of_match_device(atmel_lcdfb_dt_ids, dev)->data;
> 
> Please split it in 2 steps, otherwise the day that the drivers doesn't
> find the device in dt_ids table, it hangs here with an Oops.
no as you will never end here in this case
> 
> > +
> > +	display_np = of_parse_phandle(np, "display", 0);
> > +	if (!display_np) {
> > +		dev_err(dev, "failed to find display phandle\n");
> > +		return -ENOENT;
> > +	}
> > +
> > +	ret = of_property_read_u32(display_np, "bits-per-pixel", &var->bits_per_pixel);
> > +	if (ret < 0) {
> > +		dev_err(dev, "failed to get property bits-per-pixel\n");
> > +		goto put_display_node;
> > +	}
> > +
> > +	ret = of_property_read_u32(display_np, "atmel,guard-time", &pdata->guard_time);
> > +	if (ret < 0) {
> > +		dev_err(dev, "failed to get property atmel,guard-time\n");
> > +		goto put_display_node;
> > +	}
> > +
> > +	ret = of_property_read_u32(display_np, "atmel,lcdcon2", &pdata->default_lcdcon2);
> > +	if (ret < 0) {
> > +		dev_err(dev, "failed to get property atmel,lcdcon2\n");
> > +		goto put_display_node;
> > +	}
> > +
> > +	ret = of_property_read_u32(display_np, "atmel,dmacon", &pdata->default_dmacon);
> > +	if (ret < 0) {
> > +		dev_err(dev, "failed to get property bits-per-pixel\n");
> 
> No, wrong error message.
> 
> > +		goto put_display_node;
> > +	}
> > +
> > +	ret = -ENOMEM;
> > +	for (i = 0; i < of_gpio_named_count(display_np, "atmel,power-control-gpio"); i++) {
> > +		gpio = of_get_named_gpio_flags(display_np, "atmel,power-control-gpio",
> > +					       i, &flags);
> > +		if (gpio < 0)
> > +			continue;
> > +
> > +		og = devm_kzalloc(dev, sizeof(*og), GFP_KERNEL);
> > +		if (!og)
> > +			goto put_display_node;
> > +
> > +		og->gpio = gpio;
> > +		og->active_low = flags & OF_GPIO_ACTIVE_LOW;
> > +		is_gpio_power = true;
> > +		ret = devm_gpio_request(dev, gpio, "lcd-power-control-gpio");
> > +		if (ret) {
> > +			dev_err(dev, "request gpio %d failed\n", gpio);
> > +			goto put_display_node;
> > +		}
> > +
> > +		ret = gpio_direction_output(gpio, og->active_low);
> > +		if (ret) {
> > +			dev_err(dev, "set direction output gpio %d failed\n", gpio);
> > +			goto put_display_node;
> > +		}
> > +	}
> > +
> > +	if (is_gpio_power)
> > +		pdata->atmel_lcdfb_power_control = atmel_lcdfb_power_control_gpio;
> > +
> > +	ret = atmel_lcdfb_get_of_wiring_modes(display_np);
> > +	if (ret < 0) {
> > +		dev_err(dev, "invalid atmel,lcd-wiring-mode\n");
> > +		goto put_display_node;
> > +	}
> > +	pdata->lcd_wiring_mode = ret;
> > +
> > +	pdata->lcdcon_is_backlight = of_property_read_bool(display_np, "atmel,lcdcon-backlight");
> > +
> > +	timings = of_get_display_timings(display_np);
> > +	if (!timings) {
> > +		dev_err(dev, "failed to get display timings\n");
> > +		goto put_display_node;
> > +	}
> > +
> > +	timings_np = of_find_node_by_name(display_np, "display-timings");
> > +	if (!timings_np) {
> > +		dev_err(dev, "failed to find display-timings node\n");
> > +		goto put_display_node;
> > +	}
> > +
> > +	for (i = 0; i < of_get_child_count(timings_np); i++) {
> > +		struct videomode vm;
> > +		struct fb_videomode fb_vm;
> > +
> > +		ret = videomode_from_timing(timings, &vm, i);
> > +		if (ret < 0)
> > +			goto put_timings_node;
> > +		ret = fb_videomode_from_videomode(&vm, &fb_vm);
> > +		if (ret < 0)
> > +			goto put_timings_node;
> > +
> > +		fb_add_videomode(&fb_vm, &info->modelist);
> > +	}
> > +
> > +	return 0;
> > +
> > +put_timings_node:
> > +	of_node_put(timings_np);
> > +put_display_node:
> > +	of_node_put(display_np);
> > +	return ret;
> > +}
> > +#else
> > +static int atmel_lcdfb_of_init(struct atmel_lcdfb_info *sinfo)
> > +{
> > +	return 0;
> > +}
> > +#endif
> >  
> >  static int __init atmel_lcdfb_probe(struct platform_device *pdev)
> >  {
> >  	struct device *dev = &pdev->dev;
> >  	struct fb_info *info;
> >  	struct atmel_lcdfb_info *sinfo;
> > -	struct atmel_lcdfb_pdata *pdata;
> > -	struct fb_videomode fbmode;
> > +	struct atmel_lcdfb_pdata *pdata = NULL;
> >  	struct resource *regs = NULL;
> >  	struct resource *map = NULL;
> > +	struct fb_modelist *modelist;
> >  	int ret;
> >  
> >  	dev_dbg(dev, "%s BEGIN\n", __func__);
> > @@ -967,17 +1149,35 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
> >  	}
> >  
> >  	sinfo = info->par;
> > +	sinfo->pdev = pdev;
> > +	sinfo->info = info;
> > +
> > +	INIT_LIST_HEAD(&info->modelist);
> >  
> > -	if (dev->platform_data) {
> > -		pdata = (struct atmel_lcdfb_pdata *)dev->platform_data;
> > +	if (pdev->dev.of_node) {
> > +		ret = atmel_lcdfb_of_init(sinfo);
> > +		if (ret)
> > +			goto free_info;
> > +	} else if (dev->platform_data) {
> > +		struct fb_monspecs *monspecs;
> > +		int i;
> > +
> > +		pdata = dev->platform_data;
> > +		monspecs = pdata->default_monspecs;
> >  		sinfo->pdata = *pdata;
> > +
> > +		for (i = 0; i < monspecs->modedb_len; i++)
> > +			fb_add_videomode(&monspecs->modedb[i], &info->modelist);
> > +
> > +		sinfo->config = atmel_lcdfb_get_config(pdev);
> > +
> > +		info->var.bits_per_pixel = pdata->default_bpp ? pdata->default_bpp : 16;
> > +		memcpy(&info->monspecs, pdata->default_monspecs, sizeof(info->monspecs));
> >  	} else {
> >  		dev_err(dev, "cannot get default configuration\n");
> >  		goto free_info;
> >  	}
> > -	sinfo->info = info;
> > -	sinfo->pdev = pdev;
> > -	sinfo->config = atmel_lcdfb_get_config(pdev);
> > +
> >  	if (!sinfo->config)
> >  		goto free_info;
> >  
> > @@ -986,7 +1186,6 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
> >  	info->pseudo_palette = sinfo->pseudo_palette;
> >  	info->fbops = &atmel_lcdfb_ops;
> >  
> > -	memcpy(&info->monspecs, pdata->default_monspecs, sizeof(info->monspecs));
> >  	info->fix = atmel_lcdfb_fix;
> >  
> >  	/* Enable LCDC Clocks */
> > @@ -1002,14 +1201,11 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
> >  	}
> >  	atmel_lcdfb_start_clock(sinfo);
> >  
> > -	ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb,
> > -			info->monspecs.modedb_len, info->monspecs.modedb,
> > -			pdata->default_bpp);
> > -	if (!ret) {
> > -		dev_err(dev, "no suitable video mode found\n");
> > -		goto stop_clk;
> > -	}
> > +	modelist = list_first_entry(&info->modelist,
> > +			struct fb_modelist, list);
> > +	fb_videomode_to_var(&info->var, &modelist->mode);
> >  
> > +	atmel_lcdfb_check_var(&info->var, info);
> >  
> >  	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >  	if (!regs) {
> > @@ -1093,18 +1289,6 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
> >  		goto unregister_irqs;
> >  	}
> >  
> > -	/*
> > -	 * This makes sure that our colour bitfield
> > -	 * descriptors are correctly initialised.
> > -	 */
> > -	atmel_lcdfb_check_var(&info->var, info);
> > -
> > -	ret = fb_set_var(info, &info->var);
> > -	if (ret) {
> > -		dev_warn(dev, "unable to set display parameters\n");
> > -		goto free_cmap;
> > -	}
> > -
> >  	dev_set_drvdata(dev, info);
> >  
> >  	/*
> > @@ -1116,10 +1300,6 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
> >  		goto reset_drvdata;
> >  	}
> >  
> > -	/* add selected videomode to modelist */
> > -	fb_var_to_videomode(&fbmode, &info->var);
> > -	fb_add_videomode(&fbmode, &info->modelist);
> > -
> >  	/* Power up the LCDC screen */
> >  	atmel_lcdfb_power_control(sinfo, 1);
> >  
> > @@ -1130,7 +1310,6 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
> >  
> >  reset_drvdata:
> >  	dev_set_drvdata(dev, NULL);
> > -free_cmap:
> >  	fb_dealloc_cmap(&info->cmap);
> >  unregister_irqs:
> >  	cancel_work_sync(&sinfo->task);
> > @@ -1249,6 +1428,7 @@ static struct platform_driver atmel_lcdfb_driver = {
> >  	.driver		= {
> >  		.name	= "atmel_lcdfb",
> >  		.owner	= THIS_MODULE,
> > +		.of_match_table	= of_match_ptr(atmel_lcdfb_dt_ids),
> >  	},
> >  };
> >  
> > 
> 
> 
> -- 
> Nicolas Ferre

^ permalink raw reply

* Re: [PATCH v3 2/2] video: imxfb: Add DT support
From: Markus Pargmann @ 2013-04-16 14:17 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130415132322.GC15139@game.jcrosoft.org>

On Mon, Apr 15, 2013 at 03:23:22PM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote:
> On 15:13 Mon 15 Apr     , Eric Bénard wrote:
> > Hi,
> > 
> > Le Mon, 15 Apr 2013 14:43:21 +0200,
> > Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> a écrit :
> > 
> > > On 16:31 Sun 14 Apr     , Markus Pargmann wrote:
> > > > On Mon, Apr 08, 2013 at 09:57:42AM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote:
> > > > > On 12:31 Fri 05 Apr     , Markus Pargmann wrote:
> > > > > > Add devicetree support for imx framebuffer driver. It uses the generic
> > > > > > display bindings and helper functions.
> > > > > > 
> > > > > > Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
> > > > > > Cc: Fabio Estevam <festevam@gmail.com>
> > > > > > Cc: Mark Rutland <mark.rutland@arm.com>
> > > > > > ---
> > > > > >  .../devicetree/bindings/video/fsl,imx-fb.txt       |  49 ++++++
> > > > > >  drivers/video/imxfb.c                              | 192 +++++++++++++++++----
> > > > > >  2 files changed, 207 insertions(+), 34 deletions(-)
> > > > > >  create mode 100644 Documentation/devicetree/bindings/video/fsl,imx-fb.txt
> > > > > > 
> > > > > > diff --git a/Documentation/devicetree/bindings/video/fsl,imx-fb.txt b/Documentation/devicetree/bindings/video/fsl,imx-fb.txt
> > > > > > new file mode 100644
> > > > > > index 0000000..bde9c77
> > > > > > --- /dev/null
> > > > > > +++ b/Documentation/devicetree/bindings/video/fsl,imx-fb.txt
> > > > > > @@ -0,0 +1,49 @@
> > > > > > +Freescale imx21 Framebuffer
> > > > > > +
> > > > > > +This framebuffer driver supports devices imx1, imx21, imx25, and imx27.
> > > > > > +
> > > > > > +Required properties:
> > > > > > +- compatible : "fsl,<chip>-fb", chip should be imx1 or imx21
> > > > > > +- reg : Should contain 1 register ranges(address and length)
> > > > > > +- interrupts : One interrupt of the fb dev
> > > > > > +
> > > > > > +Required nodes:
> > > > > > +- display: Phandle to a display node as described in
> > > > > > +	Documentation/devicetree/bindings/video/display-timing.txt
> > > > > > +	Additional, the display node has to define properties:
> > > > > > +	- fsl,bpp: Bits per pixel
> > > > > > +	- fsl,pcr: LCDC PCR value
> > > > > > +
> > > > > > +Optional properties:
> > > > > > +- dmacr-eukrea: Should be set for eukrea boards.
> > > > > why ?
> > > > 
> > > > Because eukrea boards have a different dmacr then all other boards using
> > > > imxfb. The dmacr address is hardcoded as defaults in the code. I could
> > > > also search for the board name in the DT, but there are no eukrea boards
> > > > with DT at the moment, so I thought a bool property may be better for
> > > > the moment.
> > > so no if an other board come will have an other property no
> > > 
> > > add an optionnal option to pass the dmacr
> > 
> > I didn't follow the thread but dmacr is not specific to our boards :
> > $ grep -rn dmacr arch/arm/mach-imx/
> > arch/arm/mach-imx/mach-mx27_3ds.c:446:	.dmacr		= 0x00020010,
> > arch/arm/mach-imx/mach-mx21ads.c:231:	.dmacr		= 0x00020008,
> > arch/arm/mach-imx/mach-mxt_td60.c:210:	.dmacr		= 0x00020010,
> > arch/arm/mach-imx/eukrea_mbimx27-baseboard.c:192:	.dmacr		= 0x00040060,
> > arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c:165:	.dmacr		= 0x00040060,
> > arch/arm/mach-imx/mach-mx27ads.c:241:	.dmacr		= 0x00020010,
> > arch/arm/mach-imx/mach-pca100.c:351:	.dmacr		= 0x00020010,
> > arch/arm/mach-imx/pcm970-baseboard.c:185:	.dmacr		= 0x00020010,
> > arch/arm/mach-imx/mach-mx25_3ds.c:173:	.dmacr		= 0x00020010,
> 
> with this it even more clear nack on the dmacr-eukrea property
> 
> use an optional property where we can specify the value to use
> 
> Best Regsrds,
> J.
> 

v4 will contain a optional fsl,dmacr property now. By default the reset
value of dmacr register is not changed.

Regards,

Markus

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply

* Re: [PATCH 4/8] video: atmel_lcdfb: add device tree suport
From: Nicolas Ferre @ 2013-04-16 15:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130416134404.GA4998@game.jcrosoft.org>

On 04/16/2013 03:44 PM, Jean-Christophe PLAGNIOL-VILLARD :
> On 15:42 Tue 16 Apr     , Nicolas Ferre wrote:
>> On 04/11/2013 05:00 PM, Jean-Christophe PLAGNIOL-VILLARD :
>>> get display timings from device tree
>>> Use videomode helpers to get display timings and configurations from
>>> device tree
>>
>> 2 sentences? Simply elaborate the 2nd one and it will be good.
>>
>>> Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
>>> Cc: linux-fbdev@vger.kernel.org
>>> Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
>>> Cc: Andrew Morton <akpm@linux-foundation.org>
>>> ---
>>>  .../devicetree/bindings/video/atmel,lcdc.txt       |   75 ++++++
>>>  drivers/video/Kconfig                              |    2 +
>>>  drivers/video/atmel_lcdfb.c                        |  244 +++++++++++++++++---
>>>  3 files changed, 289 insertions(+), 32 deletions(-)
>>>  create mode 100644 Documentation/devicetree/bindings/video/atmel,lcdc.txt
>>>
>>> diff --git a/Documentation/devicetree/bindings/video/atmel,lcdc.txt b/Documentation/devicetree/bindings/video/atmel,lcdc.txt
>>> new file mode 100644
>>> index 0000000..1ec175e
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/video/atmel,lcdc.txt
>>
>> Why lcdc? I would have preferred atmel,lcdfb, like the driver's name: it
>> is even more self-explanatory...
> we do not describe drivers but IP

fine, but in
static const struct platform_device_id atmel_lcdfb_devtypes, we use
"xxx-lcdfb" type...

>>
>>> @@ -0,0 +1,75 @@
>>> +Atmel LCDC Framebuffer
>>> +-----------------------------------------------------
>>> +
>>> +Required properties:
>>> +- compatible :
>>> +	"atmel,at91sam9261-lcdc" , 
>>> +	"atmel,at91sam9263-lcdc" ,
>>> +	"atmel,at91sam9g10-lcdc" ,
>>> +	"atmel,at91sam9g45-lcdc" ,
>>> +	"atmel,at91sam9g45es-lcdc" ,
>>> +	"atmel,at91sam9rl-lcdc" ,
>>> +	"atmel,at32ap-lcdc"
>>> +- reg : Should contain 1 register ranges(address and length)
>>> +- interrupts : framebuffer controller interrupt
>>> +- display: a phandle pointing to the display node
>>> +
>>> +Required nodes:
>>> +- display: a display node is required to initialize the lcd panel
>>> +	This should be in the board dts.
>>> +- default-mode: a videomode within the display with timing parameters
>>> +	as specified below.
>>> +
>>> +Example:
>>> +
>>> +	fb0: fb@0x00500000 {
>>> +		compatible = "atmel,at91sam9g45-lcdc";
>>> +		reg = <0x00500000 0x1000>;
>>> +		interrupts = <23 3 0>;
>>> +		pinctrl-names = "default";
>>> +		pinctrl-0 = <&pinctrl_fb>;
>>> +		display = <&display0>;
>>> +		status = "okay";
>>> +		#address-cells = <1>;
>>> +		#size-cells = <1>;
>>> +
>>> +	};
>>> +
>>> +Atmel LCDC Display
>>> +-----------------------------------------------------
>>> +Required properties (as per of_videomode_helper):
>>
>> Can you please point somewhere to the documentation:
>> Documentation/devicetree/bindings/video/display-timing.txt
>>
>>> + - atmel,dmacon: dma controler configuration
>>
>> Typo: controller.
>>
>>> + - atmel,lcdcon2: lcd controler configuration
>>
>> Ditto
>>
>>> + - atmel,guard-time: lcd guard time (Delay in frame periods)
>>
>> periods -> period, no?
> no it's periods even in the datasheet
>>
>>> + - bits-per-pixel: lcd panel bit-depth.
>>> +
>>> +Optional properties (as per of_videomode_helper):
>>> + - atmel,lcdcon-backlight: enable backlight
>>> + - atmel,lcd-wiring-mode: lcd wiring mode "RGB" or "BRG"
>>
>> Is it a sting, or a number (as seen below)? If it is a number, please
>> tell how to choose the index.
> String

Okay: so tell it in the description and correct the example below.


>>> + - atmel,power-control-gpio: gpio to power on or off the LCD (as many as needed)
>>> +
>>> +Example:
>>> +	display0: display {
>>> +		bits-per-pixel = <32>;
>>> +		atmel,lcdcon-backlight;
>>> +		atmel,dmacon = <0x1>;
>>> +		atmel,lcdcon2 = <0x80008002>;
>>> +		atmel,guard-time = <9>;
>>> +		atmel,lcd-wiring-mode = <1>;

Here ----------------------------------^^^^

>>> +
>>> +		display-timings {
>>> +			native-mode = <&timing0>;
>>> +			timing0: timing0 {
>>> +				clock-frequency = <9000000>;
>>> +				hactive = <480>;
>>> +				vactive = <272>;
>>> +				hback-porch = <1>;
>>> +				hfront-porch = <1>;
>>> +				vback-porch = <40>;
>>> +				vfront-porch = <1>;
>>> +				hsync-len = <45>;
>>> +				vsync-len = <1>;
>>> +			};
>>> +		};
>>> +	};
>>> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
>>> index 4c1546f..0687482 100644
>>> --- a/drivers/video/Kconfig
>>> +++ b/drivers/video/Kconfig
>>> @@ -1018,6 +1018,8 @@ config FB_ATMEL
>>>  	select FB_CFB_FILLRECT
>>>  	select FB_CFB_COPYAREA
>>>  	select FB_CFB_IMAGEBLIT
>>> +	select FB_MODE_HELPERS
>>> +	select OF_VIDEOMODE
>>>  	help
>>>  	  This enables support for the AT91/AT32 LCD Controller.
>>>  
>>> diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
>>> index f67e226..4a31570 100644
>>> --- a/drivers/video/atmel_lcdfb.c
>>> +++ b/drivers/video/atmel_lcdfb.c
>>> @@ -20,7 +20,11 @@
>>>  #include <linux/gfp.h>
>>>  #include <linux/module.h>
>>>  #include <linux/platform_data/atmel.h>
>>> +#include <linux/of.h>
>>> +#include <linux/of_device.h>
>>> +#include <linux/of_gpio.h>
>>>  #include <video/of_display_timing.h>
>>
>> As said in patch 1/8, this one belongs to this 4/8 patch.
>>
>>> +#include <video/videomode.h>
>>>  
>>>  #include <mach/cpu.h>
>>>  #include <asm/gpio.h>
>>> @@ -59,6 +63,13 @@ struct atmel_lcdfb_info {
>>>  	struct atmel_lcdfb_config *config;
>>>  };
>>>  
>>> +struct atmel_lcdfb_power_ctrl_gpio {
>>> +	int gpio;
>>> +	int active_low;
>>> +
>>> +	struct list_head list;
>>> +};
>>> +
>>>  #define lcdc_readl(sinfo, reg)		__raw_readl((sinfo)->mmio+(reg))
>>>  #define lcdc_writel(sinfo, reg, val)	__raw_writel((val), (sinfo)->mmio+(reg))
>>>  
>>> @@ -945,16 +956,187 @@ static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo)
>>>  	clk_disable(sinfo->lcdc_clk);
>>>  }
>>>  
>>> +#ifdef CONFIG_OF
>>> +static const struct of_device_id atmel_lcdfb_dt_ids[] = {
>>> +	{ .compatible = "atmel,at91sam9261-lcdc" , .data = &at91sam9261_config, },
>>> +	{ .compatible = "atmel,at91sam9263-lcdc" , .data = &at91sam9263_config, },
>>> +	{ .compatible = "atmel,at91sam9g10-lcdc" , .data = &at91sam9g10_config, },
>>> +	{ .compatible = "atmel,at91sam9g45-lcdc" , .data = &at91sam9g45_config, },
>>> +	{ .compatible = "atmel,at91sam9g45es-lcdc" , .data = &at91sam9g45es_config, },
>>> +	{ .compatible = "atmel,at91sam9rl-lcdc" , .data = &at91sam9rl_config, },
>>> +	{ .compatible = "atmel,at32ap-lcdc" , .data = &at32ap_config, },
>>> +	{ /* sentinel */ }
>>> +};
>>> +
>>> +MODULE_DEVICE_TABLE(of, atmel_lcdfb_dt_ids);
>>> +
>>> +static const char *atmel_lcdfb_wiring_modes[] = {
>>> +	[ATMEL_LCDC_WIRING_BGR]	= "BRG",
>>> +	[ATMEL_LCDC_WIRING_RGB]	= "RGB",
>>> +};
>>> +
>>> +const int atmel_lcdfb_get_of_wiring_modes(struct device_node *np)
>>> +{
>>> +	const char *mode;
>>> +	int err, i;
>>> +
>>> +	err = of_property_read_string(np, "atmel,lcd-wiring-mode", &mode);
>>> +	if (err < 0)
>>> +		return ATMEL_LCDC_WIRING_BGR;
>>> +
>>> +	for (i = 0; i < ARRAY_SIZE(atmel_lcdfb_wiring_modes); i++)
>>> +		if (!strcasecmp(mode, atmel_lcdfb_wiring_modes[i]))
>>> +			return i;
>>> +
>>> +	return -ENODEV;
>>> +}
>>> +
>>> +static void atmel_lcdfb_power_control_gpio(struct atmel_lcdfb_pdata *pdata, int on)
>>> +{
>>> +	struct atmel_lcdfb_power_ctrl_gpio *og;
>>> +
>>> +	list_for_each_entry(og, &pdata->pwr_gpios, list)
>>> +		gpio_set_value(og->gpio, on);
>>> +}
>>> +
>>> +static int atmel_lcdfb_of_init(struct atmel_lcdfb_info *sinfo)
>>> +{
>>> +	struct fb_info *info = sinfo->info;
>>> +	struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
>>> +	struct fb_var_screeninfo *var = &info->var;
>>> +	struct device *dev = &sinfo->pdev->dev;
>>> +	struct device_node *np Þv->of_node;
>>> +	struct device_node *display_np;
>>> +	struct device_node *timings_np;
>>> +	struct display_timings *timings;
>>> +	enum of_gpio_flags flags;
>>> +	struct atmel_lcdfb_power_ctrl_gpio *og;
>>> +	bool is_gpio_power = false;
>>> +	int ret = -ENOENT;
>>> +	int i, gpio;
>>> +
>>> +	sinfo->config = (struct atmel_lcdfb_config*)
>>> +		of_match_device(atmel_lcdfb_dt_ids, dev)->data;
>>
>> Please split it in 2 steps, otherwise the day that the drivers doesn't
>> find the device in dt_ids table, it hangs here with an Oops.
> no as you will never end here in this case

Ok, I see.

>>
>>> +
>>> +	display_np = of_parse_phandle(np, "display", 0);
>>> +	if (!display_np) {
>>> +		dev_err(dev, "failed to find display phandle\n");
>>> +		return -ENOENT;
>>> +	}
>>> +
>>> +	ret = of_property_read_u32(display_np, "bits-per-pixel", &var->bits_per_pixel);
>>> +	if (ret < 0) {
>>> +		dev_err(dev, "failed to get property bits-per-pixel\n");
>>> +		goto put_display_node;
>>> +	}
>>> +
>>> +	ret = of_property_read_u32(display_np, "atmel,guard-time", &pdata->guard_time);
>>> +	if (ret < 0) {
>>> +		dev_err(dev, "failed to get property atmel,guard-time\n");
>>> +		goto put_display_node;
>>> +	}
>>> +
>>> +	ret = of_property_read_u32(display_np, "atmel,lcdcon2", &pdata->default_lcdcon2);
>>> +	if (ret < 0) {
>>> +		dev_err(dev, "failed to get property atmel,lcdcon2\n");
>>> +		goto put_display_node;
>>> +	}
>>> +
>>> +	ret = of_property_read_u32(display_np, "atmel,dmacon", &pdata->default_dmacon);
>>> +	if (ret < 0) {
>>> +		dev_err(dev, "failed to get property bits-per-pixel\n");
>>
>> No, wrong error message.
>>
>>> +		goto put_display_node;
>>> +	}
>>> +
>>> +	ret = -ENOMEM;
>>> +	for (i = 0; i < of_gpio_named_count(display_np, "atmel,power-control-gpio"); i++) {
>>> +		gpio = of_get_named_gpio_flags(display_np, "atmel,power-control-gpio",
>>> +					       i, &flags);
>>> +		if (gpio < 0)
>>> +			continue;
>>> +
>>> +		og = devm_kzalloc(dev, sizeof(*og), GFP_KERNEL);
>>> +		if (!og)
>>> +			goto put_display_node;
>>> +
>>> +		og->gpio = gpio;
>>> +		og->active_low = flags & OF_GPIO_ACTIVE_LOW;
>>> +		is_gpio_power = true;
>>> +		ret = devm_gpio_request(dev, gpio, "lcd-power-control-gpio");
>>> +		if (ret) {
>>> +			dev_err(dev, "request gpio %d failed\n", gpio);
>>> +			goto put_display_node;
>>> +		}
>>> +
>>> +		ret = gpio_direction_output(gpio, og->active_low);
>>> +		if (ret) {
>>> +			dev_err(dev, "set direction output gpio %d failed\n", gpio);
>>> +			goto put_display_node;
>>> +		}
>>> +	}
>>> +
>>> +	if (is_gpio_power)
>>> +		pdata->atmel_lcdfb_power_control = atmel_lcdfb_power_control_gpio;
>>> +
>>> +	ret = atmel_lcdfb_get_of_wiring_modes(display_np);
>>> +	if (ret < 0) {
>>> +		dev_err(dev, "invalid atmel,lcd-wiring-mode\n");
>>> +		goto put_display_node;
>>> +	}
>>> +	pdata->lcd_wiring_mode = ret;
>>> +
>>> +	pdata->lcdcon_is_backlight = of_property_read_bool(display_np, "atmel,lcdcon-backlight");
>>> +
>>> +	timings = of_get_display_timings(display_np);
>>> +	if (!timings) {
>>> +		dev_err(dev, "failed to get display timings\n");
>>> +		goto put_display_node;
>>> +	}
>>> +
>>> +	timings_np = of_find_node_by_name(display_np, "display-timings");
>>> +	if (!timings_np) {
>>> +		dev_err(dev, "failed to find display-timings node\n");
>>> +		goto put_display_node;
>>> +	}
>>> +
>>> +	for (i = 0; i < of_get_child_count(timings_np); i++) {
>>> +		struct videomode vm;
>>> +		struct fb_videomode fb_vm;
>>> +
>>> +		ret = videomode_from_timing(timings, &vm, i);
>>> +		if (ret < 0)
>>> +			goto put_timings_node;
>>> +		ret = fb_videomode_from_videomode(&vm, &fb_vm);
>>> +		if (ret < 0)
>>> +			goto put_timings_node;
>>> +
>>> +		fb_add_videomode(&fb_vm, &info->modelist);
>>> +	}
>>> +
>>> +	return 0;
>>> +
>>> +put_timings_node:
>>> +	of_node_put(timings_np);
>>> +put_display_node:
>>> +	of_node_put(display_np);
>>> +	return ret;
>>> +}
>>> +#else
>>> +static int atmel_lcdfb_of_init(struct atmel_lcdfb_info *sinfo)
>>> +{
>>> +	return 0;
>>> +}
>>> +#endif
>>>  
>>>  static int __init atmel_lcdfb_probe(struct platform_device *pdev)
>>>  {
>>>  	struct device *dev = &pdev->dev;
>>>  	struct fb_info *info;
>>>  	struct atmel_lcdfb_info *sinfo;
>>> -	struct atmel_lcdfb_pdata *pdata;
>>> -	struct fb_videomode fbmode;
>>> +	struct atmel_lcdfb_pdata *pdata = NULL;
>>>  	struct resource *regs = NULL;
>>>  	struct resource *map = NULL;
>>> +	struct fb_modelist *modelist;
>>>  	int ret;
>>>  
>>>  	dev_dbg(dev, "%s BEGIN\n", __func__);
>>> @@ -967,17 +1149,35 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
>>>  	}
>>>  
>>>  	sinfo = info->par;
>>> +	sinfo->pdev = pdev;
>>> +	sinfo->info = info;
>>> +
>>> +	INIT_LIST_HEAD(&info->modelist);
>>>  
>>> -	if (dev->platform_data) {
>>> -		pdata = (struct atmel_lcdfb_pdata *)dev->platform_data;
>>> +	if (pdev->dev.of_node) {
>>> +		ret = atmel_lcdfb_of_init(sinfo);
>>> +		if (ret)
>>> +			goto free_info;
>>> +	} else if (dev->platform_data) {
>>> +		struct fb_monspecs *monspecs;
>>> +		int i;
>>> +
>>> +		pdata = dev->platform_data;
>>> +		monspecs = pdata->default_monspecs;
>>>  		sinfo->pdata = *pdata;
>>> +
>>> +		for (i = 0; i < monspecs->modedb_len; i++)
>>> +			fb_add_videomode(&monspecs->modedb[i], &info->modelist);
>>> +
>>> +		sinfo->config = atmel_lcdfb_get_config(pdev);
>>> +
>>> +		info->var.bits_per_pixel = pdata->default_bpp ? pdata->default_bpp : 16;
>>> +		memcpy(&info->monspecs, pdata->default_monspecs, sizeof(info->monspecs));
>>>  	} else {
>>>  		dev_err(dev, "cannot get default configuration\n");
>>>  		goto free_info;
>>>  	}
>>> -	sinfo->info = info;
>>> -	sinfo->pdev = pdev;
>>> -	sinfo->config = atmel_lcdfb_get_config(pdev);
>>> +
>>>  	if (!sinfo->config)
>>>  		goto free_info;
>>>  
>>> @@ -986,7 +1186,6 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
>>>  	info->pseudo_palette = sinfo->pseudo_palette;
>>>  	info->fbops = &atmel_lcdfb_ops;
>>>  
>>> -	memcpy(&info->monspecs, pdata->default_monspecs, sizeof(info->monspecs));
>>>  	info->fix = atmel_lcdfb_fix;
>>>  
>>>  	/* Enable LCDC Clocks */
>>> @@ -1002,14 +1201,11 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
>>>  	}
>>>  	atmel_lcdfb_start_clock(sinfo);
>>>  
>>> -	ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb,
>>> -			info->monspecs.modedb_len, info->monspecs.modedb,
>>> -			pdata->default_bpp);
>>> -	if (!ret) {
>>> -		dev_err(dev, "no suitable video mode found\n");
>>> -		goto stop_clk;
>>> -	}
>>> +	modelist = list_first_entry(&info->modelist,
>>> +			struct fb_modelist, list);
>>> +	fb_videomode_to_var(&info->var, &modelist->mode);
>>>  
>>> +	atmel_lcdfb_check_var(&info->var, info);
>>>  
>>>  	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>  	if (!regs) {
>>> @@ -1093,18 +1289,6 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
>>>  		goto unregister_irqs;
>>>  	}
>>>  
>>> -	/*
>>> -	 * This makes sure that our colour bitfield
>>> -	 * descriptors are correctly initialised.
>>> -	 */
>>> -	atmel_lcdfb_check_var(&info->var, info);
>>> -
>>> -	ret = fb_set_var(info, &info->var);
>>> -	if (ret) {
>>> -		dev_warn(dev, "unable to set display parameters\n");
>>> -		goto free_cmap;
>>> -	}
>>> -
>>>  	dev_set_drvdata(dev, info);
>>>  
>>>  	/*
>>> @@ -1116,10 +1300,6 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
>>>  		goto reset_drvdata;
>>>  	}
>>>  
>>> -	/* add selected videomode to modelist */
>>> -	fb_var_to_videomode(&fbmode, &info->var);
>>> -	fb_add_videomode(&fbmode, &info->modelist);
>>> -
>>>  	/* Power up the LCDC screen */
>>>  	atmel_lcdfb_power_control(sinfo, 1);
>>>  
>>> @@ -1130,7 +1310,6 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
>>>  
>>>  reset_drvdata:
>>>  	dev_set_drvdata(dev, NULL);
>>> -free_cmap:
>>>  	fb_dealloc_cmap(&info->cmap);
>>>  unregister_irqs:
>>>  	cancel_work_sync(&sinfo->task);
>>> @@ -1249,6 +1428,7 @@ static struct platform_driver atmel_lcdfb_driver = {
>>>  	.driver		= {
>>>  		.name	= "atmel_lcdfb",
>>>  		.owner	= THIS_MODULE,
>>> +		.of_match_table	= of_match_ptr(atmel_lcdfb_dt_ids),
>>>  	},
>>>  };
>>>  
>>>
>>
>>
>> -- 
>> Nicolas Ferre
> 
> 


-- 
Nicolas Ferre

^ permalink raw reply

* [RFC 00/10] Versatile Express CLCD DVI output support
From: Pawel Moll @ 2013-04-17 15:17 UTC (permalink / raw)
  To: linux-fbdev, linux-media, dri-devel, devicetree-discuss,
	linux-arm-kernel
  Cc: Laurent Pinchart, Linus Walleij, Russell King - ARM Linux,
	Pawel Moll

Hello All,

This series implements support for the Versatile Express
video output pipeline, which is not the simplest one available...

It is meant as a RFC only and I'm hoping to attract all possible
feedback (*including* naming ;-).

The VE's "MultiMedia Bus" [1] comprises three video signal sources
(motherboard's CLCD cell and a implementation-specific driver
on each of the daugtherboards) and a FPGA multiplexer routing
data from one of the sources to DVI/HDMI formatter chip (Sii9022).

+-----+
| DB1 |>--+                         DVI connector
+-----+   |   +------+                   +--+
          +-->|      |                   |oo|
+-----+       | mux  |    +---------+    |oo|
| DB2 |>----->|      |>-->| sii9022 |>-->|oo|
+-----+       | FPGA |    +---------+    |oo|
          +-->|      |                   |oo|
+-----+   |   +------+                   +--+
| MB  |>--+
+-----+

The series is based on Laurent Pinchart's Common Display Framework
patch (not in mainline yet, v2 discussed here: [2]) and extends it
by adding DT bindings and basic support for TFT panels.

The CLCD driver has been adapted to work with the framework and
the Device Tree information.

Also a set of drivers for the VE-specific components is included
(note that the sii9022 is now driven via the moterboard firmware;
this is intended to be replaced by a proper I2C driver for the
chip).

It is worth mentioning that the CDF caters for both fbdev and DRM
so the solution should be suitable for all potential DRM-driven
display controllers.

[1] http://infocenter.arm.com/help/topic/com.arm.doc.dui0447h/CHDEHEAA.html#CACGIGGC
[2] http://thread.gmane.org/gmane.linux.drivers.video-input-infrastructure/57298


Laurent Pinchart (1):
  video: Add generic display entity core

Pawel Moll (9):
  video: display: Update the display with the video mode data
  video: display: Add Device Tree bindings
  video: display: Add generic TFT display type
  fbmon: Add extra video helper
  video: ARM CLCD: Add DT & CDF support
  mfd: vexpress: Allow external drivers to parse site ids
  video: Versatile Express MUXFPGA driver
  video: Versatile Express DVI mode driver
  ARM: vexpress: Add CLCD Device Tree properties

 .../testing/sysfs-driver-video-vexpress-muxfpga    |    5 +
 .../devicetree/bindings/video/arm,pl11x.txt        |   35 ++
 .../devicetree/bindings/video/display-bindings.txt |   75 ++++
 arch/arm/boot/dts/vexpress-v2m-rs1.dtsi            |   17 +-
 arch/arm/boot/dts/vexpress-v2m.dtsi                |   17 +-
 arch/arm/boot/dts/vexpress-v2p-ca9.dts             |    5 +
 drivers/mfd/vexpress-sysreg.c                      |    5 +
 drivers/video/Kconfig                              |    2 +
 drivers/video/Makefile                             |    5 +
 drivers/video/amba-clcd.c                          |  244 +++++++++++
 drivers/video/display/Kconfig                      |    4 +
 drivers/video/display/Makefile                     |    1 +
 drivers/video/display/display-core.c               |  447 ++++++++++++++++++++
 drivers/video/fbmon.c                              |   29 ++
 drivers/video/vexpress-dvimode.c                   |  158 +++++++
 drivers/video/vexpress-muxfpga.c                   |  228 ++++++++++
 include/linux/amba/clcd.h                          |    2 +
 include/linux/fb.h                                 |    3 +
 include/linux/vexpress.h                           |    2 +
 include/video/display.h                            |  172 ++++++++
 20 files changed, 1448 insertions(+), 8 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-driver-video-vexpress-muxfpga
 create mode 100644 Documentation/devicetree/bindings/video/arm,pl11x.txt
 create mode 100644 Documentation/devicetree/bindings/video/display-bindings.txt
 create mode 100644 drivers/video/display/Kconfig
 create mode 100644 drivers/video/display/Makefile
 create mode 100644 drivers/video/display/display-core.c
 create mode 100644 drivers/video/vexpress-dvimode.c
 create mode 100644 drivers/video/vexpress-muxfpga.c
 create mode 100644 include/video/display.h

-- 
1.7.10.4



^ permalink raw reply

* [RFC 01/10] video: Add generic display entity core
From: Pawel Moll @ 2013-04-17 15:17 UTC (permalink / raw)
  To: linux-fbdev, linux-media, dri-devel, devicetree-discuss,
	linux-arm-kernel
  Cc: Laurent Pinchart, Linus Walleij, Russell King - ARM Linux,
	Laurent Pinchart
In-Reply-To: <1366211842-21497-1-git-send-email-pawel.moll@arm.com>

From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/Kconfig                |    1 +
 drivers/video/Makefile               |    1 +
 drivers/video/display/Kconfig        |    4 +
 drivers/video/display/Makefile       |    1 +
 drivers/video/display/display-core.c |  362 ++++++++++++++++++++++++++++++++++
 include/video/display.h              |  150 ++++++++++++++
 6 files changed, 519 insertions(+)
 create mode 100644 drivers/video/display/Kconfig
 create mode 100644 drivers/video/display/Makefile
 create mode 100644 drivers/video/display/display-core.c
 create mode 100644 include/video/display.h

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 4c1546f..281e548 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2456,6 +2456,7 @@ source "drivers/video/omap2/Kconfig"
 source "drivers/video/exynos/Kconfig"
 source "drivers/video/mmp/Kconfig"
 source "drivers/video/backlight/Kconfig"
+source "drivers/video/display/Kconfig"
 
 if VT
 	source "drivers/video/console/Kconfig"
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 9df3873..b989e8e 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -15,6 +15,7 @@ fb-objs                           := $(fb-y)
 obj-$(CONFIG_VT)		  += console/
 obj-$(CONFIG_LOGO)		  += logo/
 obj-y				  += backlight/
+obj-y				  += display/
 
 obj-$(CONFIG_EXYNOS_VIDEO)     += exynos/
 
diff --git a/drivers/video/display/Kconfig b/drivers/video/display/Kconfig
new file mode 100644
index 0000000..1d533e7
--- /dev/null
+++ b/drivers/video/display/Kconfig
@@ -0,0 +1,4 @@
+menuconfig DISPLAY_CORE
+	tristate "Display Core"
+	---help---
+	  Support common display framework for graphics devices.
diff --git a/drivers/video/display/Makefile b/drivers/video/display/Makefile
new file mode 100644
index 0000000..bd93496
--- /dev/null
+++ b/drivers/video/display/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_DISPLAY_CORE) += display-core.o
diff --git a/drivers/video/display/display-core.c b/drivers/video/display/display-core.c
new file mode 100644
index 0000000..d2daa15
--- /dev/null
+++ b/drivers/video/display/display-core.c
@@ -0,0 +1,362 @@
+/*
+ * Display Core
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+
+#include <video/display.h>
+#include <video/videomode.h>
+
+static LIST_HEAD(display_entity_list);
+static LIST_HEAD(display_entity_notifiers);
+static DEFINE_MUTEX(display_entity_mutex);
+
+/* -----------------------------------------------------------------------------
+ * Control operations
+ */
+
+/**
+ * display_entity_set_state - Set the display entity operation state
+ * @entity: The display entity
+ * @state: Display entity operation state
+ *
+ * See &enum display_entity_state for information regarding the entity states.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+int display_entity_set_state(struct display_entity *entity,
+			     enum display_entity_state state)
+{
+	int ret;
+
+	if (entity->state == state)
+		return 0;
+
+	if (!entity->ops.ctrl || !entity->ops.ctrl->set_state)
+		return 0;
+
+	ret = entity->ops.ctrl->set_state(entity, state);
+	if (ret < 0)
+		return ret;
+
+	entity->state = state;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(display_entity_set_state);
+
+/**
+ * display_entity_update - Update the display
+ * @entity: The display entity
+ *
+ * Make the display entity ready to receive pixel data and start frame transfer.
+ * This operation can only be called if the display entity is in STANDBY or ON
+ * state.
+ *
+ * The display entity will call the upstream entity in the video chain to start
+ * the video stream.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+int display_entity_update(struct display_entity *entity)
+{
+	if (!entity->ops.ctrl || !entity->ops.ctrl->update)
+		return 0;
+
+	return entity->ops.ctrl->update(entity);
+}
+EXPORT_SYMBOL_GPL(display_entity_update);
+
+/**
+ * display_entity_get_modes - Get video modes supported by the display entity
+ * @entity The display entity
+ * @modes: Pointer to an array of modes
+ *
+ * Fill the modes argument with a pointer to an array of video modes. The array
+ * is owned by the display entity.
+ *
+ * Return the number of supported modes on success (including 0 if no mode is
+ * supported) or a negative error code otherwise.
+ */
+int display_entity_get_modes(struct display_entity *entity,
+			     const struct videomode **modes)
+{
+	if (!entity->ops.ctrl || !entity->ops.ctrl->get_modes)
+		return 0;
+
+	return entity->ops.ctrl->get_modes(entity, modes);
+}
+EXPORT_SYMBOL_GPL(display_entity_get_modes);
+
+/**
+ * display_entity_get_size - Get display entity physical size
+ * @entity: The display entity
+ * @width: Physical width in millimeters
+ * @height: Physical height in millimeters
+ *
+ * When applicable, for instance for display panels, retrieve the display
+ * physical size in millimeters.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+int display_entity_get_size(struct display_entity *entity,
+			    unsigned int *width, unsigned int *height)
+{
+	if (!entity->ops.ctrl || !entity->ops.ctrl->get_size)
+		return -EOPNOTSUPP;
+
+	return entity->ops.ctrl->get_size(entity, width, height);
+}
+EXPORT_SYMBOL_GPL(display_entity_get_size);
+
+/**
+ * display_entity_get_params - Get display entity interface parameters
+ * @entity: The display entity
+ * @params: Pointer to interface parameters
+ *
+ * Fill the parameters structure pointed to by the params argument with display
+ * entity interface parameters.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+int display_entity_get_params(struct display_entity *entity,
+			      struct display_entity_interface_params *params)
+{
+	if (!entity->ops.ctrl || !entity->ops.ctrl->get_modes)
+		return -EOPNOTSUPP;
+
+	return entity->ops.ctrl->get_params(entity, params);
+}
+EXPORT_SYMBOL_GPL(display_entity_get_params);
+
+/* -----------------------------------------------------------------------------
+ * Video operations
+ */
+
+/**
+ * display_entity_set_stream - Control the video stream state
+ * @entity: The display entity
+ * @state: Display video stream state
+ *
+ * Control the video stream state at the entity video output.
+ *
+ * See &enum display_entity_stream_state for information regarding the stream
+ * states.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+int display_entity_set_stream(struct display_entity *entity,
+			      enum display_entity_stream_state state)
+{
+	if (!entity->ops.video || !entity->ops.video->set_stream)
+		return 0;
+
+	return entity->ops.video->set_stream(entity, state);
+}
+EXPORT_SYMBOL_GPL(display_entity_set_stream);
+
+/* -----------------------------------------------------------------------------
+ * Connections
+ */
+
+/**
+ * display_entity_connect - Connect two entities through a video stream
+ * @source: The video stream source
+ * @sink: The video stream sink
+ *
+ * Set the sink entity source field to the source entity.
+ */
+
+/**
+ * display_entity_disconnect - Disconnect two previously connected entities
+ * @source: The video stream source
+ * @sink: The video stream sink
+ *
+ * Break a connection between two previously connected entities. The source
+ * entity source field is reset to NULL.
+ */
+
+/* -----------------------------------------------------------------------------
+ * Registration and notification
+ */
+
+static void display_entity_release(struct kref *ref)
+{
+	struct display_entity *entity =
+		container_of(ref, struct display_entity, ref);
+
+	if (entity->release)
+		entity->release(entity);
+}
+
+/**
+ * display_entity_get - get a reference to a display entity
+ * @display_entity: the display entity
+ *
+ * Return the display entity pointer.
+ */
+struct display_entity *display_entity_get(struct display_entity *entity)
+{
+	if (entity == NULL)
+		return NULL;
+
+	kref_get(&entity->ref);
+	return entity;
+}
+EXPORT_SYMBOL_GPL(display_entity_get);
+
+/**
+ * display_entity_put - release a reference to a display entity
+ * @display_entity: the display entity
+ *
+ * Releasing the last reference to a display entity releases the display entity
+ * itself.
+ */
+void display_entity_put(struct display_entity *entity)
+{
+	kref_put(&entity->ref, display_entity_release);
+}
+EXPORT_SYMBOL_GPL(display_entity_put);
+
+static int display_entity_notifier_match(struct display_entity *entity,
+				struct display_entity_notifier *notifier)
+{
+	return notifier->dev == NULL || notifier->dev == entity->dev;
+}
+
+/**
+ * display_entity_register_notifier - register a display entity notifier
+ * @notifier: display entity notifier structure we want to register
+ *
+ * Display entity notifiers are called to notify drivers of display
+ * entity-related events for matching display_entitys.
+ *
+ * Notifiers and display_entitys are matched through the device they correspond
+ * to. If the notifier dev field is equal to the display entity dev field the
+ * notifier will be called when an event is reported. Notifiers with a NULL dev
+ * field act as catch-all and will be called for all display_entitys.
+ *
+ * Supported events are
+ *
+ * - DISPLAY_ENTITY_NOTIFIER_CONNECT reports display entity connection and is
+ *   sent at display entity or notifier registration time
+ * - DISPLAY_ENTITY_NOTIFIER_DISCONNECT reports display entity disconnection and
+ *   is sent at display entity unregistration time
+ *
+ * Registering a notifier sends DISPLAY_ENTITY_NOTIFIER_CONNECT events for all
+ * previously registered display_entitys that match the notifiers.
+ *
+ * Return 0 on success.
+ */
+int display_entity_register_notifier(struct display_entity_notifier *notifier)
+{
+	struct display_entity *entity;
+
+	mutex_lock(&display_entity_mutex);
+	list_add_tail(&notifier->list, &display_entity_notifiers);
+
+	list_for_each_entry(entity, &display_entity_list, list) {
+		if (!display_entity_notifier_match(entity, notifier))
+			continue;
+
+		if (notifier->notify(notifier, entity,
+				     DISPLAY_ENTITY_NOTIFIER_CONNECT))
+			break;
+	}
+	mutex_unlock(&display_entity_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(display_entity_register_notifier);
+
+/**
+ * display_entity_unregister_notifier - unregister a display entity notifier
+ * @notifier: display entity notifier to be unregistered
+ *
+ * Unregistration guarantees that the notifier will never be called upon return
+ * of this function.
+ */
+void display_entity_unregister_notifier(struct display_entity_notifier *notifier)
+{
+	mutex_lock(&display_entity_mutex);
+	list_del(&notifier->list);
+	mutex_unlock(&display_entity_mutex);
+}
+EXPORT_SYMBOL_GPL(display_entity_unregister_notifier);
+
+/**
+ * display_entity_register - register a display entity
+ * @display_entity: display entity to be registered
+ *
+ * Register the display entity and send the DISPLAY_ENTITY_NOTIFIER_CONNECT
+ * event to all matching registered notifiers.
+ *
+ * Return 0 on success.
+ */
+int __must_check __display_entity_register(struct display_entity *entity,
+					   struct module *owner)
+{
+	struct display_entity_notifier *notifier;
+
+	kref_init(&entity->ref);
+	entity->owner = owner;
+	entity->state = DISPLAY_ENTITY_STATE_OFF;
+
+	mutex_lock(&display_entity_mutex);
+	list_add(&entity->list, &display_entity_list);
+
+	list_for_each_entry(notifier, &display_entity_notifiers, list) {
+		if (!display_entity_notifier_match(entity, notifier))
+			continue;
+
+		if (notifier->notify(notifier, entity,
+				     DISPLAY_ENTITY_NOTIFIER_CONNECT))
+			break;
+	}
+	mutex_unlock(&display_entity_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(__display_entity_register);
+
+/**
+ * display_entity_unregister - unregister a display entity
+ * @display_entity: display entity to be unregistered
+ *
+ * Unregister the display entity and send the DISPLAY_ENTITY_NOTIFIER_DISCONNECT
+ * event to all matching registered notifiers.
+ */
+void display_entity_unregister(struct display_entity *entity)
+{
+	struct display_entity_notifier *notifier;
+
+	mutex_lock(&display_entity_mutex);
+	list_for_each_entry(notifier, &display_entity_notifiers, list) {
+		if (!display_entity_notifier_match(entity, notifier))
+			continue;
+
+		notifier->notify(notifier, entity,
+				 DISPLAY_ENTITY_NOTIFIER_DISCONNECT);
+	}
+
+	list_del(&entity->list);
+	mutex_unlock(&display_entity_mutex);
+
+	display_entity_put(entity);
+}
+EXPORT_SYMBOL_GPL(display_entity_unregister);
+
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_DESCRIPTION("Display Core");
+MODULE_LICENSE("GPL");
diff --git a/include/video/display.h b/include/video/display.h
new file mode 100644
index 0000000..90d18ca
--- /dev/null
+++ b/include/video/display.h
@@ -0,0 +1,150 @@
+/*
+ * Display Core
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __DISPLAY_H__
+#define __DISPLAY_H__
+
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/module.h>
+
+/* -----------------------------------------------------------------------------
+ * Display Entity
+ */
+
+struct display_entity;
+struct videomode;
+
+#define DISPLAY_ENTITY_NOTIFIER_CONNECT		1
+#define DISPLAY_ENTITY_NOTIFIER_DISCONNECT	2
+
+struct display_entity_notifier {
+	int (*notify)(struct display_entity_notifier *, struct display_entity *,
+		      int);
+	struct device *dev;
+	struct list_head list;
+};
+
+/**
+ * enum display_entity_state - State of a display entity
+ * @DISPLAY_ENTITY_STATE_OFF: The entity is turned off completely, possibly
+ *	including its power supplies. Communication with a display entity in
+ *	that state is not possible.
+ * @DISPLAY_ENTITY_STATE_STANDBY: The entity is in a low-power state. Full
+ *	communication with the display entity is supported, including pixel data
+ *	transfer, but the output is kept blanked.
+ * @DISPLAY_ENTITY_STATE_ON: The entity is fully operational.
+ */
+enum display_entity_state {
+	DISPLAY_ENTITY_STATE_OFF,
+	DISPLAY_ENTITY_STATE_STANDBY,
+	DISPLAY_ENTITY_STATE_ON,
+};
+
+/**
+ * enum display_entity_stream_state - State of a video stream
+ * @DISPLAY_ENTITY_STREAM_STOPPED: The video stream is stopped, no frames are
+ *	transferred.
+ * @DISPLAY_ENTITY_STREAM_SINGLE_SHOT: The video stream has been started for
+ *      single shot operation. The source entity will transfer a single frame
+ *      and then stop.
+ * @DISPLAY_ENTITY_STREAM_CONTINUOUS: The video stream is running, frames are
+ *	transferred continuously by the source entity.
+ */
+enum display_entity_stream_state {
+	DISPLAY_ENTITY_STREAM_STOPPED,
+	DISPLAY_ENTITY_STREAM_SINGLE_SHOT,
+	DISPLAY_ENTITY_STREAM_CONTINUOUS,
+};
+
+enum display_entity_interface_type {
+	DISPLAY_ENTITY_INTERFACE_DPI,
+};
+
+struct display_entity_interface_params {
+	enum display_entity_interface_type type;
+};
+
+struct display_entity_control_ops {
+	int (*set_state)(struct display_entity *ent,
+			 enum display_entity_state state);
+	int (*update)(struct display_entity *ent);
+	int (*get_modes)(struct display_entity *ent,
+			 const struct videomode **modes);
+	int (*get_params)(struct display_entity *ent,
+			  struct display_entity_interface_params *params);
+	int (*get_size)(struct display_entity *ent,
+			unsigned int *width, unsigned int *height);
+};
+
+struct display_entity_video_ops {
+	int (*set_stream)(struct display_entity *ent,
+			  enum display_entity_stream_state state);
+};
+
+struct display_entity {
+	struct list_head list;
+	struct device *dev;
+	struct module *owner;
+	struct kref ref;
+
+	struct display_entity *source;
+
+	struct {
+		const struct display_entity_control_ops *ctrl;
+		const struct display_entity_video_ops *video;
+	} ops;
+
+	void(*release)(struct display_entity *ent);
+
+	enum display_entity_state state;
+};
+
+int display_entity_set_state(struct display_entity *entity,
+			     enum display_entity_state state);
+int display_entity_update(struct display_entity *entity);
+int display_entity_get_modes(struct display_entity *entity,
+			     const struct videomode **modes);
+int display_entity_get_params(struct display_entity *entity,
+			      struct display_entity_interface_params *params);
+int display_entity_get_size(struct display_entity *entity,
+			    unsigned int *width, unsigned int *height);
+
+int display_entity_set_stream(struct display_entity *entity,
+			      enum display_entity_stream_state state);
+
+static inline void display_entity_connect(struct display_entity *source,
+					  struct display_entity *sink)
+{
+	sink->source = source;
+}
+
+static inline void display_entity_disconnect(struct display_entity *source,
+					     struct display_entity *sink)
+{
+	sink->source = NULL;
+}
+
+struct display_entity *display_entity_get(struct display_entity *entity);
+void display_entity_put(struct display_entity *entity);
+
+int __must_check __display_entity_register(struct display_entity *entity,
+					   struct module *owner);
+void display_entity_unregister(struct display_entity *entity);
+
+int display_entity_register_notifier(struct display_entity_notifier *notifier);
+void display_entity_unregister_notifier(struct display_entity_notifier *notifier);
+
+#define display_entity_register(display_entity) \
+	__display_entity_register(display_entity, THIS_MODULE)
+
+#endif /* __DISPLAY_H__ */
-- 
1.7.10.4



^ permalink raw reply related

* [RFC 02/10] video: display: Update the display with the video mode data
From: Pawel Moll @ 2013-04-17 15:17 UTC (permalink / raw)
  To: linux-fbdev, linux-media, dri-devel, devicetree-discuss,
	linux-arm-kernel
  Cc: Laurent Pinchart, Linus Walleij, Russell King - ARM Linux,
	Pawel Moll
In-Reply-To: <1366211842-21497-1-git-send-email-pawel.moll@arm.com>

The display entity (sink) may need to know about the mode being
changed, eg. to update timings.

Alternatively there could be a separate set_mode() operation...

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
 drivers/video/display/display-core.c |    5 +++--
 include/video/display.h              |    6 ++++--
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/video/display/display-core.c b/drivers/video/display/display-core.c
index d2daa15..4b8e45a 100644
--- a/drivers/video/display/display-core.c
+++ b/drivers/video/display/display-core.c
@@ -69,12 +69,13 @@ EXPORT_SYMBOL_GPL(display_entity_set_state);
  *
  * Return 0 on success or a negative error code otherwise.
  */
-int display_entity_update(struct display_entity *entity)
+int display_entity_update(struct display_entity *entity,
+			     const struct videomode *mode)
 {
 	if (!entity->ops.ctrl || !entity->ops.ctrl->update)
 		return 0;
 
-	return entity->ops.ctrl->update(entity);
+	return entity->ops.ctrl->update(entity, mode);
 }
 EXPORT_SYMBOL_GPL(display_entity_update);
 
diff --git a/include/video/display.h b/include/video/display.h
index 90d18ca..64f84d5 100644
--- a/include/video/display.h
+++ b/include/video/display.h
@@ -77,7 +77,8 @@ struct display_entity_interface_params {
 struct display_entity_control_ops {
 	int (*set_state)(struct display_entity *ent,
 			 enum display_entity_state state);
-	int (*update)(struct display_entity *ent);
+	int (*update)(struct display_entity *ent,
+			 const struct videomode *mode);
 	int (*get_modes)(struct display_entity *ent,
 			 const struct videomode **modes);
 	int (*get_params)(struct display_entity *ent,
@@ -111,7 +112,8 @@ struct display_entity {
 
 int display_entity_set_state(struct display_entity *entity,
 			     enum display_entity_state state);
-int display_entity_update(struct display_entity *entity);
+int display_entity_update(struct display_entity *entity,
+			     const struct videomode *mode);
 int display_entity_get_modes(struct display_entity *entity,
 			     const struct videomode **modes);
 int display_entity_get_params(struct display_entity *entity,
-- 
1.7.10.4



^ permalink raw reply related

* [RFC 03/10] video: display: Add Device Tree bindings
From: Pawel Moll @ 2013-04-17 15:17 UTC (permalink / raw)
  To: linux-fbdev, linux-media, dri-devel, devicetree-discuss,
	linux-arm-kernel
  Cc: Laurent Pinchart, Linus Walleij, Russell King - ARM Linux,
	Pawel Moll
In-Reply-To: <1366211842-21497-1-git-send-email-pawel.moll@arm.com>

Modelled after the common clock solution, the bindings
are based on the idea of display entity "providers" and
"consumers".

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
 .../devicetree/bindings/video/display-bindings.txt |   75 +++++++++++++++++
 drivers/video/display/display-core.c               |   84 ++++++++++++++++++++
 include/video/display.h                            |   11 +++
 3 files changed, 170 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/video/display-bindings.txt

diff --git a/Documentation/devicetree/bindings/video/display-bindings.txt b/Documentation/devicetree/bindings/video/display-bindings.txt
new file mode 100644
index 0000000..6d8b888
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/display-bindings.txt
@@ -0,0 +1,75 @@
+[this is an RFC]
+
+Common Display Framework define a display entity (eg. LCD panel),
+being a sink for video data generated by a video signal generator
+(eg.  LCD controller/driver).
+
+This set of bindings allow to represent connections between them
+in the Device Tree.
+
+Devices nodes representing display sinks are called "display
+providers" and nodes representing display sources are called
+"display consumers".
+
+Notice that in both cases a device represented by a node can
+provide or consume more than one display entity. For example
+a LCD controller can be able to driver more than one LCD
+panel at the same time, while a panel (or a special signal
+multiplexer) may have more than one input (sink) and switch
+between them.
+
+== Display provider ==
+
+Required properties:
+
+* #clock-cells:	Number of cells in the display specifier. Typically
+		0 for nodes providing single display entity and 1
+		for nodes providing multiple displays.
+
+Example:
+			dvi-output: dvi-output@0 {
+				#display-cells = <0>;
+			};
+
+== Display consumer ==
+
+Required properties:
+
+* display:	List of phandle and clock specifier pairs, one pair
+		for each display (sink). Note: if the display provider
+		specifies '0' for #display-cells, then only the phandle
+		portion of the pair will appear.
+
+Example:
+
+			display-driver {
+				display = <&dvi-output>;
+			};
+
+== Larger example ==
+
+			clcd@10020000 {
+				compatible = "arm,pl111", "arm,primecell";
+				reg = <0x10020000 0x1000>;
+				interrupts = <0 44 4>;
+				clocks = <&oscclk1>, <&oscclk2>;
+				clock-names = "clcdclk", "apb_pclk";
+				label = "V2P-CA9 CLCD";
+				display = <&v2m_muxfpga 0xf>;
+				max-hactive = <1024>;
+				max-vactive = <768>;
+				max-bpp = <16>;
+			};
+
+			v2m_muxfpga: muxfpga@0 {
+				compatible = "arm,vexpress-muxfpga";
+				arm,vexpress-sysreg,func = <7 0>;
+				#display-cells = <1>;
+				display = <&v2m_dvimode>;
+			};
+
+			v2m_dvimode: dvimode@0 {
+				compatible = "arm,vexpress-dvimode";
+				arm,vexpress-sysreg,func = <11 0>;
+				#display-cells = <0>;
+			};
diff --git a/drivers/video/display/display-core.c b/drivers/video/display/display-core.c
index 4b8e45a..9827a5d 100644
--- a/drivers/video/display/display-core.c
+++ b/drivers/video/display/display-core.c
@@ -15,6 +15,7 @@
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/slab.h>
 
 #include <video/display.h>
 #include <video/videomode.h>
@@ -230,6 +231,89 @@ void display_entity_put(struct display_entity *entity)
 }
 EXPORT_SYMBOL_GPL(display_entity_put);
 
+#if defined(CONFIG_OF)
+struct of_display_entity_provider {
+	struct list_head list;
+	struct device_node *node;
+	struct display_entity *(*get)(struct of_phandle_args *spec, void *data);
+	void *data;
+};
+
+static LIST_HEAD(of_display_entity_providers);
+static DEFINE_MUTEX(of_display_entity_providers_lock);
+
+int of_display_entity_add_provider(struct device_node *node,
+		struct display_entity *(*get)(struct of_phandle_args *spec,
+		void *data), void *data)
+{
+	struct of_display_entity_provider *provider =
+			kzalloc(sizeof(*provider), GFP_KERNEL);
+
+	if (!provider)
+		return -ENOMEM;
+
+	provider->node = of_node_get(node);
+	provider->get = get;
+	provider->data = data;
+
+	mutex_lock(&of_display_entity_providers_lock);
+	list_add(&provider->list, &of_display_entity_providers);
+	mutex_unlock(&of_display_entity_providers_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(of_display_entity_add_provider);
+
+struct display_entity *of_display_entity_provider_simple_get(
+		struct of_phandle_args *spec, void *data)
+{
+	return data;
+}
+EXPORT_SYMBOL_GPL(of_display_entity_provider_simple_get);
+
+void of_display_entity_remove_provider(struct device_node *node)
+{
+	struct of_display_entity_provider *provider, *p;
+
+	mutex_lock(&of_display_entity_providers_lock);
+	list_for_each_entry_safe(provider, p, &of_display_entity_providers,
+			list) {
+		if (provider->node == node) {
+			list_del(&provider->list);
+			of_node_put(provider->node);
+			kfree(node);
+			break;
+		}
+	}
+	mutex_unlock(&of_display_entity_providers_lock);
+}
+EXPORT_SYMBOL_GPL(of_display_entity_remove_provider);
+
+struct display_entity *of_display_entity_get(struct device_node *node,
+		int index)
+{
+	struct of_phandle_args spec;
+	struct of_display_entity_provider *provider;
+	struct display_entity *entity = NULL;
+
+	if (of_parse_phandle_with_args(node, "display", "#display-cells",
+			index, &spec) != 0)
+		return NULL;
+
+	mutex_lock(&of_display_entity_providers_lock);
+	list_for_each_entry(provider, &of_display_entity_providers, list) {
+		if (provider->node == spec.np) {
+			entity = provider->get(&spec, provider->data);
+			break;
+		}
+	}
+	mutex_unlock(&of_display_entity_providers_lock);
+
+	return entity;
+}
+EXPORT_SYMBOL_GPL(of_display_entity_get);
+#endif
+
 static int display_entity_notifier_match(struct display_entity *entity,
 				struct display_entity_notifier *notifier)
 {
diff --git a/include/video/display.h b/include/video/display.h
index 64f84d5..7fe8b2f 100644
--- a/include/video/display.h
+++ b/include/video/display.h
@@ -16,6 +16,7 @@
 #include <linux/kref.h>
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/of.h>
 
 /* -----------------------------------------------------------------------------
  * Display Entity
@@ -149,4 +150,14 @@ void display_entity_unregister_notifier(struct display_entity_notifier *notifier
 #define display_entity_register(display_entity) \
 	__display_entity_register(display_entity, THIS_MODULE)
 
+struct display_entity *of_display_entity_get(struct device_node *node,
+		int index);
+
+int of_display_entity_add_provider(struct device_node *node,
+		struct display_entity *(*get)(struct of_phandle_args *spec,
+		void *data), void *data);
+void of_display_entity_remove_provider(struct device_node *node);
+struct display_entity *of_display_entity_provider_simple_get(
+		struct of_phandle_args *spec, void *data);
+
 #endif /* __DISPLAY_H__ */
-- 
1.7.10.4



^ permalink raw reply related

* [RFC 04/10] video: display: Add generic TFT display type
From: Pawel Moll @ 2013-04-17 15:17 UTC (permalink / raw)
  To: linux-fbdev, linux-media, dri-devel, devicetree-discuss,
	linux-arm-kernel
  Cc: Laurent Pinchart, Linus Walleij, Russell King - ARM Linux,
	Pawel Moll
In-Reply-To: <1366211842-21497-1-git-send-email-pawel.moll@arm.com>

TFT panels may be interfaced via a simple parallel interface
carrying RGB data, pixel clock and synchronisation signals.
From the video generator point of view the width of the data
channels (number of bits per R/G/B components) may be an
important factor in setting up the display model.

Above information is based on the presentations by Dave Anders
available here: http://elinux.org/Elc-lcd

This patch adds the parallel TFT display type and basic parameters
structure. Maybe it should be split into a separate header, eg.
include/video/tft.h? Or maybe it's just the INTERFACE_DPI I'm
talking about?

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
 include/video/display.h |    9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/include/video/display.h b/include/video/display.h
index 7fe8b2f..875e230 100644
--- a/include/video/display.h
+++ b/include/video/display.h
@@ -69,10 +69,19 @@ enum display_entity_stream_state {
 
 enum display_entity_interface_type {
 	DISPLAY_ENTITY_INTERFACE_DPI,
+	DISPLAY_ENTITY_INTERFACE_TFT_PARALLEL,
+};
+
+struct tft_parallel_interface_params {
+	int r_bits, g_bits, b_bits;
+	int r_b_swapped;
 };
 
 struct display_entity_interface_params {
 	enum display_entity_interface_type type;
+	union {
+		struct tft_parallel_interface_params tft_parallel;
+	} p;
 };
 
 struct display_entity_control_ops {
-- 
1.7.10.4



^ permalink raw reply related

* [RFC 05/10] fbmon: Add extra video helper
From: Pawel Moll @ 2013-04-17 15:17 UTC (permalink / raw)
  To: linux-fbdev, linux-media, dri-devel, devicetree-discuss,
	linux-arm-kernel
  Cc: Laurent Pinchart, Linus Walleij, Russell King - ARM Linux,
	Pawel Moll
In-Reply-To: <1366211842-21497-1-git-send-email-pawel.moll@arm.com>

This function converts the fb_var_screeninfo to the videomode
structure, to be used in fbdev drivers working with the
Common Display Framework.

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
 drivers/video/fbmon.c |   29 +++++++++++++++++++++++++++++
 include/linux/fb.h    |    3 +++
 2 files changed, 32 insertions(+)

diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
index 7f67099..f0ff2bf 100644
--- a/drivers/video/fbmon.c
+++ b/drivers/video/fbmon.c
@@ -1424,6 +1424,35 @@ int fb_videomode_from_videomode(const struct videomode *vm,
 	return 0;
 }
 EXPORT_SYMBOL_GPL(fb_videomode_from_videomode);
+
+void videomode_from_fb_var_screeninfo(const struct fb_var_screeninfo *var,
+				      struct videomode *vm)
+{
+	vm->pixelclock = PICOS2KHZ(var->pixclock) * 1000;
+
+	vm->hactive = var->xres;
+	vm->hfront_porch = var->right_margin;
+	vm->hback_porch = var->left_margin;
+	vm->hsync_len = var->hsync_len;
+
+	vm->vactive = var->yres;
+	vm->vfront_porch = var->lower_margin;
+	vm->vback_porch = var->upper_margin;
+	vm->vsync_len = var->vsync_len;
+
+	vm->dmt_flags = 0;
+	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+		vm->dmt_flags |= VESA_DMT_HSYNC_HIGH;
+	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+		vm->dmt_flags |= VESA_DMT_VSYNC_HIGH;
+
+	vm->data_flags = 0;
+	if (var->vmode & FB_VMODE_INTERLACED)
+		vm->data_flags |= DISPLAY_FLAGS_INTERLACED;
+	if (var->vmode & FB_VMODE_DOUBLE)
+		vm->data_flags |= DISPLAY_FLAGS_DOUBLESCAN;
+}
+EXPORT_SYMBOL_GPL(videomode_from_fb_var_screeninfo);
 #endif
 
 #if IS_ENABLED(CONFIG_OF_VIDEOMODE)
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 58b9860..aae2ed3 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -721,6 +721,9 @@ extern int of_get_fb_videomode(struct device_node *np,
 			       int index);
 extern int fb_videomode_from_videomode(const struct videomode *vm,
 				       struct fb_videomode *fbmode);
+extern void videomode_from_fb_var_screeninfo(
+				const struct fb_var_screeninfo *var,
+				struct videomode *vm);
 
 /* drivers/video/modedb.c */
 #define VESA_MODEDB_SIZE 34
-- 
1.7.10.4



^ permalink raw reply related

* [RFC 06/10] video: ARM CLCD: Add DT & CDF support
From: Pawel Moll @ 2013-04-17 15:17 UTC (permalink / raw)
  To: linux-fbdev, linux-media, dri-devel, devicetree-discuss,
	linux-arm-kernel
  Cc: Laurent Pinchart, Linus Walleij, Russell King - ARM Linux,
	Pawel Moll
In-Reply-To: <1366211842-21497-1-git-send-email-pawel.moll@arm.com>

This patch adds basic DT bindings for the PL11x CLCD cells
and make their fbdev driver use them, together with the
Common Display Framework.

The DT provides information about the hardware configuration
and limitations (eg. the largest supported resolution)
but the video modes come exclusively from the Common
Display Framework drivers, referenced to by the standard CDF
binding.

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
 .../devicetree/bindings/video/arm,pl11x.txt        |   35 +++
 drivers/video/Kconfig                              |    1 +
 drivers/video/amba-clcd.c                          |  244 ++++++++++++++++++++
 include/linux/amba/clcd.h                          |    2 +
 4 files changed, 282 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/video/arm,pl11x.txt

diff --git a/Documentation/devicetree/bindings/video/arm,pl11x.txt b/Documentation/devicetree/bindings/video/arm,pl11x.txt
new file mode 100644
index 0000000..ee9534a
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/arm,pl11x.txt
@@ -0,0 +1,35 @@
+* ARM PrimeCell Color LCD Controller (CLCD) PL110/PL111
+
+Required properties:
+
+- compatible : must be one of:
+			"arm,pl110", "arm,primecell"
+			"arm,pl111", "arm,primecell"
+- reg : base address and size of the control registers block
+- interrupts : the combined interrupt
+- clocks : phandles to the CLCD (pixel) clock and the APB clocks
+- clock-names : "clcdclk", "apb_pclk"
+- display : phandle to the display entity connected to the controller
+
+Optional properties:
+
+- label : string describing the controller location and/or usage
+- video-ram : phandle to DT node of the specialized video RAM to be used
+- max-hactive : maximum frame buffer width in pixels
+- max-vactive : maximum frame buffer height in pixels
+- max-bpp : maximum number of bits per pixel
+- big-endian-pixels : defining this property makes the pixel bytes being
+			accessed in Big Endian organization
+
+Example:
+
+			clcd@1f0000 {
+				compatible = "arm,pl111", "arm,primecell";
+				reg = <0x1f0000 0x1000>;
+				interrupts = <14>;
+				clocks = <&v2m_oscclk1>, <&smbclk>;
+				clock-names = "clcdclk", "apb_pclk";
+				label = "IOFPGA CLCD";
+				video-ram = <&v2m_vram>;
+				display = <&v2m_muxfpga>;
+			};
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 281e548..bad8166 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -340,6 +340,7 @@ config FB_ARMCLCD
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
+	select FB_MODE_HELPERS if OF
 	help
 	  This framebuffer device driver is for the ARM PrimeCell PL110
 	  Colour LCD controller.  ARM PrimeCells provide the building
diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c
index 0a2cce7..778dc03 100644
--- a/drivers/video/amba-clcd.c
+++ b/drivers/video/amba-clcd.c
@@ -25,6 +25,11 @@
 #include <linux/amba/clcd.h>
 #include <linux/clk.h>
 #include <linux/hardirq.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <video/display.h>
+#include <video/videomode.h>
 
 #include <asm/sizes.h>
 
@@ -62,6 +67,10 @@ static void clcdfb_disable(struct clcd_fb *fb)
 {
 	u32 val;
 
+	if (fb->panel->display)
+		display_entity_set_state(fb->panel->display,
+				DISPLAY_ENTITY_STATE_OFF);
+
 	if (fb->board->disable)
 		fb->board->disable(fb);
 
@@ -115,6 +124,11 @@ static void clcdfb_enable(struct clcd_fb *fb, u32 cntl)
 	 */
 	if (fb->board->enable)
 		fb->board->enable(fb);
+
+	if (fb->panel->display)
+		display_entity_set_state(fb->panel->display,
+				DISPLAY_ENTITY_STATE_ON);
+
 }
 
 static int
@@ -304,6 +318,13 @@ static int clcdfb_set_par(struct fb_info *info)
 
 	clcdfb_enable(fb, regs.cntl);
 
+	if (fb->panel->display) {
+		struct videomode mode;
+
+		videomode_from_fb_var_screeninfo(&fb->fb.var, &mode);
+		display_entity_update(fb->panel->display, &mode);
+	}
+
 #ifdef DEBUG
 	printk(KERN_INFO
 	       "CLCD: Registers set to\n"
@@ -542,6 +563,226 @@ static int clcdfb_register(struct clcd_fb *fb)
 	return ret;
 }
 
+#if defined(CONFIG_OF)
+static int clcdfb_of_get_tft_parallel_panel(struct clcd_panel *panel,
+		struct display_entity_interface_params *params)
+{
+	int r = params->p.tft_parallel.r_bits;
+	int g = params->p.tft_parallel.g_bits;
+	int b = params->p.tft_parallel.b_bits;
+
+	/* Bypass pixel clock divider, data output on the falling edge */
+	panel->tim2 = TIM2_BCD | TIM2_IPC;
+
+	/* TFT display, vert. comp. interrupt at the start of the back porch */
+	panel->cntl |= CNTL_LCDTFT | CNTL_LCDVCOMP(1);
+
+	if (params->p.tft_parallel.r_b_swapped)
+		panel->cntl |= CNTL_BGR;
+
+	if (r >= 4 && g >= 4 && b >= 4)
+		panel->caps |= CLCD_CAP_444;
+	if (r >= 5 && g >= 5 && b >= 5)
+		panel->caps |= CLCD_CAP_5551;
+	if (r >= 5 && g >= 6 && b >= 5)
+		panel->caps |= CLCD_CAP_565;
+	if (r >= 8 && g >= 8 && b >= 8)
+		panel->caps |= CLCD_CAP_888;
+
+	return 0;
+}
+
+static int clcdfb_of_init_display(struct clcd_fb *fb)
+{
+	struct device_node *node = fb->dev->dev.of_node;
+	struct display_entity_interface_params params;
+	const struct videomode *modes;
+	int modes_num;
+	int best_mode = -1;
+	u32 max_bpp = 32;
+	u32 max_hactive = (u32)~0UL;
+	u32 max_vactive = (u32)~0UL;
+	unsigned int width, height;
+	char *mode_name;
+	int i, err;
+
+	fb->panel = devm_kzalloc(&fb->dev->dev, sizeof(*fb->panel), GFP_KERNEL);
+	if (!fb->panel)
+		return -ENOMEM;
+
+	fb->panel->display = of_display_entity_get(node, 0);
+	if (!fb->panel->display)
+		return -EPROBE_DEFER;
+
+	modes_num = display_entity_get_modes(fb->panel->display, &modes);
+	if (modes_num < 0)
+		return modes_num;
+
+	/* Pick the "best" (the widest, then the highest) mode from the list */
+	of_property_read_u32(node, "max-hactive", &max_hactive);
+	of_property_read_u32(node, "max-vactive", &max_vactive);
+	for (i = 0; i < modes_num; i++) {
+		if (modes[i].hactive > max_hactive ||
+				modes[i].vactive > max_vactive)
+			continue;
+		if (best_mode < 0 ||
+				(modes[i].hactive >= modes[best_mode].hactive &&
+				modes[i].vactive > modes[best_mode].vactive))
+			best_mode = i;
+	}
+	if (best_mode < 0)
+		return -ENODEV;
+
+	err = fb_videomode_from_videomode(&modes[best_mode], &fb->panel->mode);
+	if (err)
+		return err;
+
+	i = snprintf(NULL, 0, "%ux%u@%u", fb->panel->mode.xres,
+			fb->panel->mode.yres, fb->panel->mode.refresh);
+	mode_name = devm_kzalloc(&fb->dev->dev, i + 1, GFP_KERNEL);
+	snprintf(mode_name, i + 1, "%ux%u@%u", fb->panel->mode.xres,
+			fb->panel->mode.yres, fb->panel->mode.refresh);
+	fb->panel->mode.name = mode_name;
+
+	of_property_read_u32(node, "max-bpp", &max_bpp);
+	fb->panel->bpp = max_bpp;
+
+	if (of_property_read_bool(node, "big-endian-pixels"))
+		fb->panel->cntl |= CNTL_BEBO;
+
+	if (display_entity_get_size(fb->panel->display, &width, &height) != 0)
+		width = height = -1;
+	fb->panel->width = width;
+	fb->panel->height = height;
+
+	err = display_entity_get_params(fb->panel->display, &params);
+	if (err)
+		return err;
+
+	switch (params.type) {
+	case DISPLAY_ENTITY_INTERFACE_TFT_PARALLEL:
+		return clcdfb_of_get_tft_parallel_panel(fb->panel, &params);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int clcdfb_of_vram_setup(struct clcd_fb *fb)
+{
+	const __be32 *prop = of_get_property(fb->dev->dev.of_node, "video-ram",
+			NULL);
+	struct device_node *node = of_find_node_by_phandle(be32_to_cpup(prop));
+	u64 size;
+	int err;
+
+	if (!node)
+		return -ENODEV;
+
+	err = clcdfb_of_init_display(fb);
+	if (err)
+		return err;
+
+	fb->fb.screen_base = of_iomap(node, 0);
+	if (!fb->fb.screen_base)
+		return -ENOMEM;
+
+	fb->fb.fix.smem_start = of_translate_address(node,
+			of_get_address(node, 0, &size, NULL));
+	fb->fb.fix.smem_len = size;
+
+	return 0;
+}
+
+static int clcdfb_of_vram_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
+{
+	unsigned long off, user_size, kernel_size;
+
+	off = vma->vm_pgoff << PAGE_SHIFT;
+	user_size = vma->vm_end - vma->vm_start;
+	kernel_size = fb->fb.fix.smem_len;
+
+	if (off >= kernel_size || user_size > (kernel_size - off))
+		return -ENXIO;
+
+	return remap_pfn_range(vma, vma->vm_start,
+			__phys_to_pfn(fb->fb.fix.smem_start) + vma->vm_pgoff,
+			user_size,
+			pgprot_writecombine(vma->vm_page_prot));
+}
+
+static void clcdfb_of_vram_remove(struct clcd_fb *fb)
+{
+	iounmap(fb->fb.screen_base);
+}
+
+static int clcdfb_of_dma_setup(struct clcd_fb *fb)
+{
+	unsigned long framesize;
+	dma_addr_t dma;
+	int err;
+
+	err = clcdfb_of_init_display(fb);
+	if (err)
+		return err;
+
+	framesize = fb->panel->mode.xres * fb->panel->mode.yres *
+			fb->panel->bpp / 8;
+	fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize,
+			&dma, GFP_KERNEL);
+	if (!fb->fb.screen_base)
+		return -ENOMEM;
+
+	fb->fb.fix.smem_start = dma;
+	fb->fb.fix.smem_len = framesize;
+
+	return 0;
+}
+
+static int clcdfb_of_dma_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
+{
+	return dma_mmap_writecombine(&fb->dev->dev, vma, fb->fb.screen_base,
+			fb->fb.fix.smem_start, fb->fb.fix.smem_len);
+}
+
+static void clcdfb_of_dma_remove(struct clcd_fb *fb)
+{
+	dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
+			fb->fb.screen_base, fb->fb.fix.smem_start);
+}
+
+static struct clcd_board *clcdfb_of_get_board(struct amba_device *dev)
+{
+	struct clcd_board *board = devm_kzalloc(&dev->dev, sizeof(*board),
+			GFP_KERNEL);
+	struct device_node *node = dev->dev.of_node;
+
+	if (!board)
+		return NULL;
+
+	board->name = of_get_property(node, "label", NULL);
+	if (!board->name)
+		board->name = of_node_full_name(node);
+	board->check = clcdfb_check;
+	board->decode = clcdfb_decode;
+	if (of_find_property(node, "video-ram", NULL)) {
+		board->setup = clcdfb_of_vram_setup;
+		board->mmap = clcdfb_of_vram_mmap;
+		board->remove = clcdfb_of_vram_remove;
+	} else {
+		board->setup = clcdfb_of_dma_setup;
+		board->mmap = clcdfb_of_dma_mmap;
+		board->remove = clcdfb_of_dma_remove;
+	}
+
+	return board;
+}
+#else
+static struct clcd_board *clcdfb_of_get_board(struct amba_dev *dev)
+{
+	return NULL;
+}
+#endif
+
 static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
 {
 	struct clcd_board *board = dev->dev.platform_data;
@@ -549,6 +790,9 @@ static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
 	int ret;
 
 	if (!board)
+		board = clcdfb_of_get_board(dev);
+
+	if (!board)
 		return -EINVAL;
 
 	ret = amba_request_regions(dev, NULL);
diff --git a/include/linux/amba/clcd.h b/include/linux/amba/clcd.h
index e82e3ee..73b199b 100644
--- a/include/linux/amba/clcd.h
+++ b/include/linux/amba/clcd.h
@@ -10,6 +10,7 @@
  * for more details.
  */
 #include <linux/fb.h>
+#include <video/display.h>
 
 /*
  * CLCD Controller Internal Register addresses
@@ -105,6 +106,7 @@ struct clcd_panel {
 				fixedtimings:1,
 				grayscale:1;
 	unsigned int		connector;
+	struct display_entity	*display;
 };
 
 struct clcd_regs {
-- 
1.7.10.4



^ permalink raw reply related

* [RFC 07/10] mfd: vexpress: Allow external drivers to parse site ids
From: Pawel Moll @ 2013-04-17 15:17 UTC (permalink / raw)
  To: linux-fbdev, linux-media, dri-devel, devicetree-discuss,
	linux-arm-kernel
  Cc: Laurent Pinchart, Linus Walleij, Russell King - ARM Linux,
	Pawel Moll
In-Reply-To: <1366211842-21497-1-git-send-email-pawel.moll@arm.com>

... by providing a function translating the MASTER
value into the currently valid site number and
a _LAST constant providing all possible site id values.

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
 drivers/mfd/vexpress-sysreg.c |    5 +++++
 include/linux/vexpress.h      |    2 ++
 2 files changed, 7 insertions(+)

diff --git a/drivers/mfd/vexpress-sysreg.c b/drivers/mfd/vexpress-sysreg.c
index bf75e96..4158e26 100644
--- a/drivers/mfd/vexpress-sysreg.c
+++ b/drivers/mfd/vexpress-sysreg.c
@@ -81,6 +81,11 @@ void vexpress_flags_set(u32 data)
 	writel(data, vexpress_sysreg_base + SYS_FLAGSSET);
 }
 
+u32 vexpress_get_site(int site)
+{
+	return site == VEXPRESS_SITE_MASTER ? vexpress_master_site : site;
+}
+
 u32 vexpress_get_procid(int site)
 {
 	if (site == VEXPRESS_SITE_MASTER)
diff --git a/include/linux/vexpress.h b/include/linux/vexpress.h
index 7581874..1ebbcf5 100644
--- a/include/linux/vexpress.h
+++ b/include/linux/vexpress.h
@@ -19,6 +19,7 @@
 #define VEXPRESS_SITE_MB		0
 #define VEXPRESS_SITE_DB1		1
 #define VEXPRESS_SITE_DB2		2
+#define __VEXPRESS_SITE_LAST		3
 #define VEXPRESS_SITE_MASTER		0xf
 
 #define VEXPRESS_CONFIG_STATUS_DONE	0
@@ -103,6 +104,7 @@ int vexpress_config_write(struct vexpress_config_func *func, int offset,
 
 /* Platform control */
 
+u32 vexpress_get_site(int site);
 u32 vexpress_get_procid(int site);
 u32 vexpress_get_hbi(int site);
 void *vexpress_get_24mhz_clock_base(void);
-- 
1.7.10.4



^ permalink raw reply related

* [RFC 08/10] video: Versatile Express MUXFPGA driver
From: Pawel Moll @ 2013-04-17 15:17 UTC (permalink / raw)
  To: linux-fbdev, linux-media, dri-devel, devicetree-discuss,
	linux-arm-kernel
  Cc: Laurent Pinchart, Linus Walleij, Russell King - ARM Linux,
	Pawel Moll
In-Reply-To: <1366211842-21497-1-git-send-email-pawel.moll@arm.com>

Versatile Express' DVI video output can be connected to one the three
sources - motherboard's CLCD controller or a video signal generated
by one of the daughterboards.

This driver provides a Common Display Framework driver for the
muxer FPGA, which acts as a switch selecting one of the video data
sources. The default source is selected basing on the priority
list (which itself can be modified via module paramter), but
the user can make his own decision about it using the device's
sysfs "source" attribute.

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
 .../testing/sysfs-driver-video-vexpress-muxfpga    |    5 +
 drivers/video/Makefile                             |    3 +
 drivers/video/vexpress-muxfpga.c                   |  228 ++++++++++++++++++++
 3 files changed, 236 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-driver-video-vexpress-muxfpga
 create mode 100644 drivers/video/vexpress-muxfpga.c

diff --git a/Documentation/ABI/testing/sysfs-driver-video-vexpress-muxfpga b/Documentation/ABI/testing/sysfs-driver-video-vexpress-muxfpga
new file mode 100644
index 0000000..bfd568d
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-video-vexpress-muxfpga
@@ -0,0 +1,5 @@
+What:		/sys/bus/platform/drivers/vexpress-muxfpga/<muxfpga device>/source
+Date:		April 2013
+Contant:	Pawel Moll <pawel.moll@arm.com>
+Description:	This file stores the id of the video signal source
+		supposed to be routed to the board's DVI output.
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index b989e8e..84c6083 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -176,3 +176,6 @@ obj-$(CONFIG_DISPLAY_TIMING) += display_timing.o
 obj-$(CONFIG_OF_DISPLAY_TIMING) += of_display_timing.o
 obj-$(CONFIG_VIDEOMODE) += videomode.o
 obj-$(CONFIG_OF_VIDEOMODE) += of_videomode.o
+
+# platform specific output drivers
+obj-$(CONFIG_VEXPRESS_CONFIG)	  += vexpress-muxfpga.o
diff --git a/drivers/video/vexpress-muxfpga.c b/drivers/video/vexpress-muxfpga.c
new file mode 100644
index 0000000..1731ad0
--- /dev/null
+++ b/drivers/video/vexpress-muxfpga.c
@@ -0,0 +1,228 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Copyright (C) 2013 ARM Limited
+ */
+
+#define pr_fmt(fmt) "vexpress-muxfpga: " fmt
+
+#include <linux/fb.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/vexpress.h>
+#include <video/display.h>
+#include <video/videomode.h>
+
+
+static struct vexpress_config_func *vexpress_muxfpga_func;
+static struct display_entity *vexpress_muxfpga_output;
+
+
+static struct vexpress_muxfpga_source {
+	struct display_entity display;
+	struct videomode mode;
+	bool updated;
+} vexpress_muxfpga_sources[__VEXPRESS_SITE_LAST];
+static u32 vexpress_muxfpga_source_site = VEXPRESS_SITE_MB;
+static bool vexpress_muxfpga_source_stored;
+
+
+static int vexpress_muxfpga_set_site(u32 site)
+{
+	int err;
+
+	if (site >= ARRAY_SIZE(vexpress_muxfpga_sources))
+		return -EINVAL;
+
+	err = vexpress_config_write(vexpress_muxfpga_func, 0, site);
+	if (!err) {
+		pr_debug("Selected site %d as source\n", site);
+		vexpress_muxfpga_source_site = site;
+	} else {
+		pr_warn("Failed to select site %d as source! (%d)\n",
+				site, err);
+	}
+
+	return err;
+}
+
+static unsigned int vexpress_muxfpga_preferred_sites[] = {
+	VEXPRESS_SITE_MASTER,
+	VEXPRESS_SITE_DB1,
+	VEXPRESS_SITE_DB2,
+	VEXPRESS_SITE_MB,
+};
+static unsigned int vexpress_muxfpga_preferred_sites_num =
+		ARRAY_SIZE(vexpress_muxfpga_preferred_sites);
+module_param_array_named(preferred_sites, vexpress_muxfpga_preferred_sites,
+		uint, &vexpress_muxfpga_preferred_sites_num, S_IRUGO);
+MODULE_PARM_DESC(preferred_sites, "Preferred order of MUXFPGA (DVI output) "
+		"sources; values can be a daughterboard site ID (1-2), the "
+		"motherboard ID (0) or a value describing the master site "
+		"(0xf).");
+
+static int vexpress_muxfpga_get_priority(u32 site)
+{
+	int i;
+
+	for (i = 0; i < vexpress_muxfpga_preferred_sites_num; i++) {
+		u32 preference = vexpress_muxfpga_preferred_sites[i];
+
+		if (site == vexpress_get_site(preference))
+			return i;
+	}
+
+	return INT_MAX;
+}
+
+static void vexpress_muxfpga_set_preffered_site(u32 site)
+{
+	int current_priority = vexpress_muxfpga_get_priority(
+			vexpress_muxfpga_source_site);
+	int new_priority = vexpress_muxfpga_get_priority(site);
+
+	if (new_priority <= current_priority)
+		vexpress_muxfpga_set_site(site);
+}
+
+
+static int vexpress_muxfpga_display_update(struct display_entity *display,
+		const struct videomode *mode)
+{
+	int err = display_entity_update(vexpress_muxfpga_output, mode);
+
+	if (!err) {
+		struct vexpress_muxfpga_source *source = container_of(display,
+				struct vexpress_muxfpga_source, display);
+
+		source->updated = true;
+		source->mode = *mode;
+	}
+
+	return err;
+}
+
+static int vexpress_muxfpga_display_get_modes(struct display_entity *display,
+		const struct videomode **modes)
+{
+	return display_entity_get_modes(vexpress_muxfpga_output, modes);
+}
+
+static int vexpress_muxfpga_display_get_params(struct display_entity *display,
+		struct display_entity_interface_params *params)
+{
+	return display_entity_get_params(vexpress_muxfpga_output, params);
+}
+
+static const struct display_entity_control_ops vexpress_muxfpga_display_ops = {
+	.update = vexpress_muxfpga_display_update,
+	.get_modes = vexpress_muxfpga_display_get_modes,
+	.get_params = vexpress_muxfpga_display_get_params,
+};
+
+
+static ssize_t vexpress_muxfpga_show_source(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+
+	return sprintf(buf, "%u\n", vexpress_muxfpga_source_site);
+}
+
+static ssize_t vexpress_muxfpga_store_source(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	u32 site;
+	int err = kstrtou32(buf, 0, &site);
+
+	if (!err) {
+		site = vexpress_get_site(site);
+		err = vexpress_muxfpga_set_site(site);
+	}
+
+	if (!err)
+		vexpress_muxfpga_source_stored = true;
+
+	if (!err && vexpress_muxfpga_sources[site].updated)
+		vexpress_muxfpga_display_update(
+				&vexpress_muxfpga_sources[site].display,
+				&vexpress_muxfpga_sources[site].mode);
+
+	return err ? err : count;
+}
+
+DEVICE_ATTR(source, S_IRUGO | S_IWUSR, vexpress_muxfpga_show_source,
+		vexpress_muxfpga_store_source);
+
+static struct display_entity *vexpress_muxfpga_display_get(
+		struct of_phandle_args *spec, void *data)
+{
+	u32 site = vexpress_get_site(spec->args[0]);
+
+	if (WARN_ON(spec->args_count != 1 ||
+			site >= ARRAY_SIZE(vexpress_muxfpga_sources)))
+		return NULL;
+
+	/* Skip source selection if the user made his choice */
+	if (!vexpress_muxfpga_source_stored)
+		vexpress_muxfpga_set_preffered_site(site);
+
+	return &vexpress_muxfpga_sources[site].display;
+}
+
+
+static struct of_device_id vexpress_muxfpga_of_match[] = {
+	{ .compatible = "arm,vexpress-muxfpga", },
+	{}
+};
+
+static int vexpress_muxfpga_probe(struct platform_device *pdev)
+{
+	struct display_entity_interface_params params;
+	int i;
+
+	vexpress_muxfpga_output = of_display_entity_get(pdev->dev.of_node, 0);
+	if (!vexpress_muxfpga_output)
+		return -EPROBE_DEFER;
+
+	if (display_entity_get_params(vexpress_muxfpga_output, &params) != 0 ||
+			params.type != DISPLAY_ENTITY_INTERFACE_TFT_PARALLEL)
+		return -EINVAL;
+
+	vexpress_muxfpga_func = vexpress_config_func_get_by_dev(&pdev->dev);
+
+	for (i = 0; i < ARRAY_SIZE(vexpress_muxfpga_sources); i++) {
+		struct vexpress_muxfpga_source *source =
+			&vexpress_muxfpga_sources[i];
+
+		source->display.dev = &pdev->dev;
+		source->display.ops.ctrl = &vexpress_muxfpga_display_ops;
+		WARN_ON(display_entity_register(&source->display));
+		of_display_entity_add_provider(pdev->dev.of_node,
+				vexpress_muxfpga_display_get, NULL);
+	}
+
+	device_create_file(&pdev->dev, &dev_attr_source);
+
+	return 0;
+}
+
+static struct platform_driver vexpress_muxfpga_driver = {
+	.probe = vexpress_muxfpga_probe,
+	.driver = {
+		.name = "vexpress-muxfpga",
+		.of_match_table = vexpress_muxfpga_of_match,
+	},
+};
+
+static int __init vexpress_muxfpga_init(void)
+{
+	return platform_driver_register(&vexpress_muxfpga_driver);
+}
+device_initcall(vexpress_muxfpga_init);
-- 
1.7.10.4



^ permalink raw reply related

* [RFC 09/10] video: Versatile Express DVI mode driver
From: Pawel Moll @ 2013-04-17 15:17 UTC (permalink / raw)
  To: linux-fbdev, linux-media, dri-devel, devicetree-discuss,
	linux-arm-kernel
  Cc: Laurent Pinchart, Linus Walleij, Russell King - ARM Linux,
	Pawel Moll
In-Reply-To: <1366211842-21497-1-git-send-email-pawel.moll@arm.com>

Versatile Express DVI output is driven by a Sii9022 chip. It can be
controller to a limited extend by the Motherboard Config Controller,
and that's what the driver is doing now. It is a temporary measure
till there's a full I2C driver for the chip.

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
 drivers/video/Makefile           |    1 +
 drivers/video/vexpress-dvimode.c |  158 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 159 insertions(+)
 create mode 100644 drivers/video/vexpress-dvimode.c

diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 84c6083..9347e00 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -179,3 +179,4 @@ obj-$(CONFIG_OF_VIDEOMODE) += of_videomode.o
 
 # platform specific output drivers
 obj-$(CONFIG_VEXPRESS_CONFIG)	  += vexpress-muxfpga.o
+obj-$(CONFIG_VEXPRESS_CONFIG)	  += vexpress-dvimode.o
diff --git a/drivers/video/vexpress-dvimode.c b/drivers/video/vexpress-dvimode.c
new file mode 100644
index 0000000..85d5608
--- /dev/null
+++ b/drivers/video/vexpress-dvimode.c
@@ -0,0 +1,158 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Copyright (C) 2013 ARM Limited
+ */
+
+#define pr_fmt(fmt) "vexpress-dvimode: " fmt
+
+#include <linux/fb.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/vexpress.h>
+#include <video/display.h>
+#include <video/videomode.h>
+
+
+static struct vexpress_config_func *vexpress_dvimode_func;
+
+
+static int vexpress_dvimode_display_update(struct display_entity *display,
+		const struct videomode *mode)
+{
+	static const struct {
+		u32 hactive, vactive, dvimode;
+	} dvimodes[] = {
+		{ 640, 480, 0 }, /* VGA */
+		{ 800, 600, 1 }, /* SVGA */
+		{ 1024, 768, 2 }, /* XGA */
+		{ 1280, 1024, 3 }, /* SXGA */
+		{ 1600, 1200, 4 }, /* UXGA */
+		{ 1920, 1080, 5 }, /* HD1080 */
+	};
+	int err = -ENOENT;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(dvimodes); i++) {
+		if (dvimodes[i].hactive == mode->hactive &&
+				dvimodes[i].vactive == mode->vactive) {
+			pr_debug("mode: %ux%u = %d\n", mode->hactive,
+					mode->vactive, dvimodes[i].dvimode);
+			err = vexpress_config_write(vexpress_dvimode_func, 0,
+					dvimodes[i].dvimode);
+			break;
+		}
+	}
+
+	if (err)
+		pr_warn("Failed to set %ux%u mode! (%d)\n", mode->hactive,
+				mode->vactive, err);
+
+	return err;
+}
+
+static int vexpress_dvimode_display_get_modes(struct display_entity *display,
+		const struct videomode **modes)
+{
+	static const struct videomode m[] = {
+		{
+			/* VGA */
+			.pixelclock	= 25175000,
+			.hactive	= 640,
+			.hback_porch	= 40,
+			.hfront_porch	= 24,
+			.vfront_porch	= 11,
+			.hsync_len	= 96,
+			.vactive	= 480,
+			.vback_porch	= 32,
+			.vsync_len	= 2,
+		}, {
+			/* XGA */
+			.pixelclock	= 63500127,
+			.hactive	= 1024,
+			.hback_porch	= 152,
+			.hfront_porch	= 48,
+			.hsync_len	= 104,
+			.vactive	= 768,
+			.vback_porch	= 23,
+			.vfront_porch	= 3,
+			.vsync_len	= 4,
+		}, {
+			/* SXGA */
+			.pixelclock	= 108000000,
+			.hactive	= 1280,
+			.hback_porch	= 248,
+			.hfront_porch	= 48,
+			.hsync_len	= 112,
+			.vactive	= 1024,
+			.vback_porch	= 38,
+			.vfront_porch	= 1,
+			.vsync_len	= 3,
+		},
+	};
+
+	*modes = m;
+
+	return ARRAY_SIZE(m);
+}
+
+static int vexpress_dvimode_display_get_params(struct display_entity *display,
+		struct display_entity_interface_params *params)
+{
+	params->type = DISPLAY_ENTITY_INTERFACE_TFT_PARALLEL;
+	params->p.tft_parallel.r_bits = 8;
+	params->p.tft_parallel.g_bits = 8;
+	params->p.tft_parallel.b_bits = 8;
+	params->p.tft_parallel.r_b_swapped = 0;
+
+	return 0;
+}
+
+static const struct display_entity_control_ops vexpress_dvimode_display_ops = {
+	.update = vexpress_dvimode_display_update,
+	.get_modes = vexpress_dvimode_display_get_modes,
+	.get_params = vexpress_dvimode_display_get_params,
+};
+
+static struct display_entity vexpress_dvimode_display = {
+	.ops.ctrl = &vexpress_dvimode_display_ops,
+};
+
+static struct of_device_id vexpress_dvimode_of_match[] = {
+	{ .compatible = "arm,vexpress-dvimode", },
+	{}
+};
+
+static int vexpress_dvimode_probe(struct platform_device *pdev)
+{
+	vexpress_dvimode_func = vexpress_config_func_get_by_dev(&pdev->dev);
+
+	vexpress_dvimode_display.dev = &pdev->dev;
+	display_entity_register(&vexpress_dvimode_display);
+	of_display_entity_add_provider(pdev->dev.of_node,
+			of_display_entity_provider_simple_get,
+			&vexpress_dvimode_display);
+
+	return 0;
+}
+
+static struct platform_driver vexpress_dvimode_driver = {
+	.probe = vexpress_dvimode_probe,
+	.driver = {
+		.name = "vexpress-dvimode",
+		.of_match_table = vexpress_dvimode_of_match,
+	},
+};
+
+static int __init vexpress_dvimode_init(void)
+{
+	return platform_driver_register(&vexpress_dvimode_driver);
+}
+device_initcall(vexpress_dvimode_init);
-- 
1.7.10.4



^ permalink raw reply related

* [RFC 10/10] ARM: vexpress: Add CLCD Device Tree properties
From: Pawel Moll @ 2013-04-17 15:17 UTC (permalink / raw)
  To: linux-fbdev, linux-media, dri-devel, devicetree-discuss,
	linux-arm-kernel
  Cc: Laurent Pinchart, Linus Walleij, Russell King - ARM Linux,
	Pawel Moll
In-Reply-To: <1366211842-21497-1-git-send-email-pawel.moll@arm.com>

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
 arch/arm/boot/dts/vexpress-v2m-rs1.dtsi |   17 +++++++++++++----
 arch/arm/boot/dts/vexpress-v2m.dtsi     |   17 +++++++++++++----
 arch/arm/boot/dts/vexpress-v2p-ca9.dts  |    5 +++++
 3 files changed, 31 insertions(+), 8 deletions(-)

diff --git a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
index ac870fb..aac9459 100644
--- a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
+++ b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
@@ -41,7 +41,7 @@
 			bank-width = <4>;
 		};
 
-		vram@2,00000000 {
+		v2m_vram: vram@2,00000000 {
 			compatible = "arm,vexpress-vram";
 			reg = <2 0x00000000 0x00800000>;
 		};
@@ -233,6 +233,12 @@
 				interrupts = <14>;
 				clocks = <&v2m_oscclk1>, <&smbclk>;
 				clock-names = "clcdclk", "apb_pclk";
+				label = "IOFPGA CLCD";
+				video-ram = <&v2m_vram>;
+				display = <&v2m_muxfpga 0>;
+				max-hactive = <640>;
+				max-vactive = <480>;
+				max-bpp = <16>;
 			};
 		};
 
@@ -282,7 +288,7 @@
 				/* CLCD clock */
 				compatible = "arm,vexpress-osc";
 				arm,vexpress-sysreg,func = <1 1>;
-				freq-range = <23750000 63500000>;
+				freq-range = <23750000 65000000>;
 				#clock-cells = <0>;
 				clock-output-names = "v2m:oscclk1";
 			};
@@ -317,9 +323,11 @@
 				arm,vexpress-sysreg,func = <5 0>;
 			};
 
-			muxfpga@0 {
+			v2m_muxfpga: muxfpga@0 {
 				compatible = "arm,vexpress-muxfpga";
 				arm,vexpress-sysreg,func = <7 0>;
+				#display-cells = <1>;
+				display = <&v2m_dvimode>;
 			};
 
 			shutdown@0 {
@@ -332,9 +340,10 @@
 				arm,vexpress-sysreg,func = <9 0>;
 			};
 
-			dvimode@0 {
+			v2m_dvimode: dvimode@0 {
 				compatible = "arm,vexpress-dvimode";
 				arm,vexpress-sysreg,func = <11 0>;
+				#display-cells = <0>;
 			};
 		};
 	};
diff --git a/arch/arm/boot/dts/vexpress-v2m.dtsi b/arch/arm/boot/dts/vexpress-v2m.dtsi
index f142036..4d080d0 100644
--- a/arch/arm/boot/dts/vexpress-v2m.dtsi
+++ b/arch/arm/boot/dts/vexpress-v2m.dtsi
@@ -40,7 +40,7 @@
 			bank-width = <4>;
 		};
 
-		vram@3,00000000 {
+		v2m_vram: vram@3,00000000 {
 			compatible = "arm,vexpress-vram";
 			reg = <3 0x00000000 0x00800000>;
 		};
@@ -232,6 +232,12 @@
 				interrupts = <14>;
 				clocks = <&v2m_oscclk1>, <&smbclk>;
 				clock-names = "clcdclk", "apb_pclk";
+				label = "IOFPGA CLCD";
+				video-ram = <&v2m_vram>;
+				display = <&v2m_muxfpga 0>;
+				max-hactive = <640>;
+				max-vactive = <480>;
+				max-bpp = <16>;
 			};
 		};
 
@@ -281,7 +287,7 @@
 				/* CLCD clock */
 				compatible = "arm,vexpress-osc";
 				arm,vexpress-sysreg,func = <1 1>;
-				freq-range = <23750000 63500000>;
+				freq-range = <23750000 65000000>;
 				#clock-cells = <0>;
 				clock-output-names = "v2m:oscclk1";
 			};
@@ -316,9 +322,11 @@
 				arm,vexpress-sysreg,func = <5 0>;
 			};
 
-			muxfpga@0 {
+			v2m_muxfpga: muxfpga@0 {
 				compatible = "arm,vexpress-muxfpga";
 				arm,vexpress-sysreg,func = <7 0>;
+				#display-cells = <1>;
+				display = <&v2m_dvimode>;
 			};
 
 			shutdown@0 {
@@ -331,9 +339,10 @@
 				arm,vexpress-sysreg,func = <9 0>;
 			};
 
-			dvimode@0 {
+			v2m_dvimode: dvimode@0 {
 				compatible = "arm,vexpress-dvimode";
 				arm,vexpress-sysreg,func = <11 0>;
+				#display-cells = <0>;
 			};
 		};
 	};
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca9.dts b/arch/arm/boot/dts/vexpress-v2p-ca9.dts
index 1420bb1..2a63510 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca9.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca9.dts
@@ -73,6 +73,11 @@
 		interrupts = <0 44 4>;
 		clocks = <&oscclk1>, <&oscclk2>;
 		clock-names = "clcdclk", "apb_pclk";
+		label = "V2P-CA9 CLCD";
+		display = <&v2m_muxfpga 0xf>;
+		max-hactive = <1024>;
+		max-vactive = <768>;
+		max-bpp = <16>;
 	};
 
 	memory-controller@100e0000 {
-- 
1.7.10.4



^ permalink raw reply related

* Re: [PATCH 00/33] OMAPDSS: platform_enable/disable callback removal from panel drivers
From: Tony Lindgren @ 2013-04-18  0:34 UTC (permalink / raw)
  To: Tomi Valkeinen; +Cc: Archit Taneja, linux-omap, linux-fbdev
In-Reply-To: <516CD17A.5050403@ti.com>

* Tomi Valkeinen <tomi.valkeinen@ti.com> [130415 21:25]:
> On 2013-04-16 00:20, Tony Lindgren wrote:
> 
> >> So, to recap, the common header changes are located in:
> >>
> >> git://gitorious.org/linux-omap-dss2/linux.git 3.10/0-dss-headers
> >>
> >> And the branch for linux-omap is:
> >>
> >> git://gitorious.org/linux-omap-dss2/linux.git 3.10-lo/board-cleanup
> >>
> >> After merging those, some displays won't start anymore until the omapdss
> >> changes are in, but things should still compile.
> > 
> > Sounds like it's best that you merge those branches via your
> > tree as the conflicts have been already resolved in linux next.
> 
> The dss changes are going through drm tree this time, as there are some
> drm dependencies also, and I've already sent the pull request for those.
> And when I asked Dave Airlie if he can merge the dss changes, I didn't
> talk about a big chunk of arch file changes getting included.

OK sorry I did not know that and was assuming you will be sending
a pull request to Linus.
 
> Also, the whole division to two independent branches was done only to
> make it possible for the arch changes to go through l-o tree.

Yup. That probably caused you to fix up few other things while doing
it though ;)
 
> There will probably be more these kind of changes in the future, so I
> think we should agree how to handle those and stick to the plan.
> Dividing the arch file changes to a separate branch is often quite
> laborious, and I'd rather not do that for nothing.

Thanks for doing all that. And yes, let's plan on always separating
driver changes from arch/arm changes to cut away the dependencies.

Just one request: Let's do branches like this early on before -rc6,
not what might be five days before the merge window potentially
opens..

I've pulled them into omap-for-v3.10/dss and will send a pull
request for Arnd and Olof.

Regards,

Tony

^ permalink raw reply

* Re: [PATCH 00/33] OMAPDSS: platform_enable/disable callback removal from panel drivers
From: Tomi Valkeinen @ 2013-04-18  3:40 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: Archit Taneja, linux-omap, linux-fbdev
In-Reply-To: <20130418003419.GB10155@atomide.com>

[-- Attachment #1: Type: text/plain, Size: 641 bytes --]

On 2013-04-18 03:34, Tony Lindgren wrote:

> Just one request: Let's do branches like this early on before -rc6,
> not what might be five days before the merge window potentially
> opens..

Agreed, it got a bit late. But the branch itself has been stable and in
linux-next for some time.

Perhaps it would've been better to merge it to l-o earlier, instead of
me pushing it to linux-next via my tree. Any possible found problems
(there weren't any this time) could've been fixed with a new fixes branch.

> I've pulled them into omap-for-v3.10/dss and will send a pull
> request for Arnd and Olof.

Ok, thanks!

 Tomi



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 899 bytes --]

^ permalink raw reply

* [PATCH] video: mxsfb: Fix colors display on lower color depth
From: Maxime Ripard @ 2013-04-18  9:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <516EBCA4.1020609@free-electrons.com>

The current code always registers as a 32 bits display, and uses the
hardware to drop the MSB of each color to abjust to the interface width
used by the panel.

This results on 18 bits (and probably 16 bits display as well) in colors
being displayed poorly, because the MSB are obviously the most important
bits for each color definition.

The default controller behaviour when using an interface width smaller
than the color depth is to drop the LSBs of each color, which makes more
sense because you lose the least important part of the color definition.

So, to fix the colors display, just get back to the default controller
behaviour.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/video/mxsfb.c |    5 -----
 1 file changed, 5 deletions(-)

diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
index 755556c..2cfaf8b 100644
--- a/drivers/video/mxsfb.c
+++ b/drivers/video/mxsfb.c
@@ -424,11 +424,6 @@ static int mxsfb_set_par(struct fb_info *fb_info)
 			return -EINVAL;
 		case STMLCDIF_16BIT:
 		case STMLCDIF_18BIT:
-			/* 24 bit to 18 bit mapping */
-			ctrl |= CTRL_DF24; /* ignore the upper 2 bits in
-					    *  each colour component
-					    */
-			break;
 		case STMLCDIF_24BIT:
 			/* real 24 bit */
 			break;
-- 
1.7.10.4


^ permalink raw reply related

* Re: [RFC 06/10] video: ARM CLCD: Add DT & CDF support
From: Russell King - ARM Linux @ 2013-04-18 10:24 UTC (permalink / raw)
  To: Pawel Moll
  Cc: linux-fbdev, linux-media, dri-devel, devicetree-discuss,
	linux-arm-kernel, Laurent Pinchart, Linus Walleij
In-Reply-To: <1366211842-21497-7-git-send-email-pawel.moll@arm.com>

On Wed, Apr 17, 2013 at 04:17:18PM +0100, Pawel Moll wrote:
> +#if defined(CONFIG_OF)
> +static int clcdfb_of_get_tft_parallel_panel(struct clcd_panel *panel,
> +		struct display_entity_interface_params *params)
> +{
> +	int r = params->p.tft_parallel.r_bits;
> +	int g = params->p.tft_parallel.g_bits;
> +	int b = params->p.tft_parallel.b_bits;
> +
> +	/* Bypass pixel clock divider, data output on the falling edge */
> +	panel->tim2 = TIM2_BCD | TIM2_IPC;
> +
> +	/* TFT display, vert. comp. interrupt at the start of the back porch */
> +	panel->cntl |= CNTL_LCDTFT | CNTL_LCDVCOMP(1);
> +
> +	if (params->p.tft_parallel.r_b_swapped)
> +		panel->cntl |= CNTL_BGR;

NAK.  Do not set this explicitly.  Note the driver talks about this being
"the old way" - this should not be used with the panel capabilities - and
in fact it will be overwritten.

Instead, you need to encode this into the capabilities by masking the
below with CLCD_CAP_RGB or CLCD_CAP_BGR depending on the ordering.

^ permalink raw reply

* [PATCH v4 0/2] video: imxfb DT support
From: Markus Pargmann @ 2013-04-18 13:03 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

This series adds DT support for imxfb. Changes are listed in the notes section
of each patch.

Regards,

Markus


Christian Hemp (1):
      imxfb: Set alpha value of the framebuffer

Markus Pargmann (1):
      video: imxfb: Add DT support

 Documentation/devicetree/bindings/video/fsl,imx-fb.txt |  51 ++++++++++++++++++
 drivers/video/imxfb.c                                  | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
 include/linux/platform_data/video-imxfb.h              |   3 ++
 3 files changed, 248 insertions(+), 35 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/video/fsl,imx-fb.txt


^ permalink raw reply

* [PATCH v4 1/2] imxfb: Set alpha value of the framebuffer
From: Markus Pargmann @ 2013-04-18 13:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1366290183-367-1-git-send-email-mpa@pengutronix.de>

From: Christian Hemp <c.hemp@phytec.de>

Based on Sascha Hauer's patch i.MX27 clock: Do not disable lcd clocks during
startup.
This patch gives a interface to chance the alphavalue of the framebuffer.

Signed-off-by: Christian Hemp <c.hemp@phytec.de>

rebased to 3.7
Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
---
 drivers/video/imxfb.c                     | 35 +++++++++++++++++++++++++++++++
 include/linux/platform_data/video-imxfb.h |  3 +++
 2 files changed, 38 insertions(+)

diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c
index 0abf2bf..ef2b587 100644
--- a/drivers/video/imxfb.c
+++ b/drivers/video/imxfb.c
@@ -31,6 +31,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/io.h>
 #include <linux/math64.h>
+#include <linux/uaccess.h>
 
 #include <linux/platform_data/video-imxfb.h>
 
@@ -112,6 +113,10 @@
 #define LCDISR_EOF	(1<<1)
 #define LCDISR_BOF	(1<<0)
 
+#define LCDC_LGWCR	0x64
+#define LGWCR_GWAV(alpha)	(((alpha) & 0xff) << 24)
+#define LGWCR_GWE	(1 << 22)
+
 /* Used fb-mode. Can be set on kernel command line, therefore file-static. */
 static const char *fb_mode;
 
@@ -610,6 +615,35 @@ static int imxfb_blank(int blank, struct fb_info *info)
 	return 0;
 }
 
+static int imxfb_ioctl(struct fb_info *info, unsigned int cmd,
+			unsigned long arg)
+{
+	struct imxfb_info *fbi = info->par;
+	int alpha, ret = 0;
+	unsigned int tmp;
+
+	switch (cmd) {
+	case IMXFB_ALPHA:
+		if (get_user(alpha, (int __user *)arg)) {
+			ret = -EFAULT;
+		} else {
+			tmp = readl(fbi->regs + LCDC_LGWCR);
+			tmp &= ~LGWCR_GWAV(0xff);
+			tmp |= LGWCR_GWAV(alpha);
+			if (!alpha)
+				tmp &= ~LGWCR_GWE;
+			else
+				tmp |= LGWCR_GWE;
+			writel(tmp , fbi->regs + LCDC_LGWCR);
+		}
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
 static struct fb_ops imxfb_ops = {
 	.owner		= THIS_MODULE,
 	.fb_check_var	= imxfb_check_var,
@@ -619,6 +653,7 @@ static struct fb_ops imxfb_ops = {
 	.fb_copyarea	= cfb_copyarea,
 	.fb_imageblit	= cfb_imageblit,
 	.fb_blank	= imxfb_blank,
+	.fb_ioctl	= imxfb_ioctl,
 };
 
 /*
diff --git a/include/linux/platform_data/video-imxfb.h b/include/linux/platform_data/video-imxfb.h
index 9de8f06..ce3875f 100644
--- a/include/linux/platform_data/video-imxfb.h
+++ b/include/linux/platform_data/video-imxfb.h
@@ -51,6 +51,9 @@
 #define DMACR_HM(x)	(((x) & 0xf) << 16)
 #define DMACR_TM(x)	((x) & 0xf)
 
+#define IMXFB_IOW(num, dtype)	_IOW('I', num, dtype)
+#define IMXFB_ALPHA		IMXFB_IOW(31, int)
+
 struct imx_fb_videomode {
 	struct fb_videomode mode;
 	u32 pcr;
-- 
1.8.1.5


^ permalink raw reply related

* [PATCH v4 2/2] video: imxfb: Add DT support
From: Markus Pargmann @ 2013-04-18 13:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1366290183-367-1-git-send-email-mpa@pengutronix.de>

Add devicetree support for imx framebuffer driver. It uses the generic
display bindings and helper functions.

Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Mark Rutland <mark.rutland@arm.com>
---

Notes:
    Changes in v4:
    - Remove eukrea specific dmacr property.
    - Add optional dmacr property. If not present, the dmacr reset value is not
      changed.
    
    Changes in v3:
    - Fix returncodes of of_read_mode function and print error messages
    - Introduce a lower bound check for bits per pixel
    - Calculate correct bytes per pixel value before using it for the calculation of
    	memory size
    - Change DT property names
    
    Changes in v2:
    - Removed pwmr register property
    - Cleanup of devicetree binding documentation
    - Use default values for pwmr and lscr1

 .../devicetree/bindings/video/fsl,imx-fb.txt       |  51 ++++++
 drivers/video/imxfb.c                              | 194 +++++++++++++++++----
 2 files changed, 210 insertions(+), 35 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/video/fsl,imx-fb.txt

diff --git a/Documentation/devicetree/bindings/video/fsl,imx-fb.txt b/Documentation/devicetree/bindings/video/fsl,imx-fb.txt
new file mode 100644
index 0000000..aff16a4
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/fsl,imx-fb.txt
@@ -0,0 +1,51 @@
+Freescale imx21 Framebuffer
+
+This framebuffer driver supports devices imx1, imx21, imx25, and imx27.
+
+Required properties:
+- compatible : "fsl,<chip>-fb", chip should be imx1 or imx21
+- reg : Should contain 1 register ranges(address and length)
+- interrupts : One interrupt of the fb dev
+
+Required nodes:
+- display: Phandle to a display node as described in
+	Documentation/devicetree/bindings/video/display-timing.txt
+	Additional, the display node has to define properties:
+	- fsl,bpp: Bits per pixel
+	- fsl,pcr: LCDC PCR value
+
+Optional properties:
+- fsl,dmacr: DMA Control Register value. This is optional. By default, the
+	register is not modified as recommended by the datasheet.
+- fsl,lscr1: LCDC Sharp Configuration Register value.
+
+Example:
+
+	imxfb: fb@10021000 {
+		compatible = "fsl,imx27-fb", "fsl,imx21-fb";
+		interrupts = <61>;
+		reg = <0x10021000 0x1000>;
+		display = <&display0>;
+	};
+
+	...
+
+	display0: display0 {
+		model = "Primeview-PD050VL1";
+		native-mode = <&timing_disp0>;
+		fsl,bpp = <16>;		/* non-standard but required */
+		fsl,pcr = <0xf0c88080>;	/* non-standard but required */
+		display-timings {
+			timing_disp0: 640x480 {
+				hactive = <640>;
+				vactive = <480>;
+				hback-porch = <112>;
+				hfront-porch = <36>;
+				hsync-len = <32>;
+				vback-porch = <33>;
+				vfront-porch = <33>;
+				vsync-len = <2>;
+				clock-frequency = <25000000>;
+			};
+		};
+	};
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c
index ef2b587..e0230f8 100644
--- a/drivers/video/imxfb.c
+++ b/drivers/video/imxfb.c
@@ -32,6 +32,12 @@
 #include <linux/io.h>
 #include <linux/math64.h>
 #include <linux/uaccess.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include <video/of_display_timing.h>
+#include <video/of_videomode.h>
+#include <video/videomode.h>
 
 #include <linux/platform_data/video-imxfb.h>
 
@@ -117,10 +123,11 @@
 #define LGWCR_GWAV(alpha)	(((alpha) & 0xff) << 24)
 #define LGWCR_GWE	(1 << 22)
 
+#define IMXFB_LSCR1_DEFAULT 0x00120300
+
 /* Used fb-mode. Can be set on kernel command line, therefore file-static. */
 static const char *fb_mode;
 
-
 /*
  * These are the bitfields for each
  * display depth that we support.
@@ -192,6 +199,19 @@ static struct platform_device_id imxfb_devtype[] = {
 };
 MODULE_DEVICE_TABLE(platform, imxfb_devtype);
 
+static struct of_device_id imxfb_of_dev_id[] = {
+	{
+		.compatible = "fsl,imx1-fb",
+		.data = &imxfb_devtype[IMX1_FB],
+	}, {
+		.compatible = "fsl,imx21-fb",
+		.data = &imxfb_devtype[IMX21_FB],
+	}, {
+		/* sentinel */
+	}
+};
+MODULE_DEVICE_TABLE(of, imxfb_of_dev_id);
+
 static inline int is_imx1_fb(struct imxfb_info *fbi)
 {
 	return fbi->devtype = IMX1_FB;
@@ -324,6 +344,9 @@ static const struct imx_fb_videomode *imxfb_find_mode(struct imxfb_info *fbi)
 	struct imx_fb_videomode *m;
 	int i;
 
+	if (!fb_mode)
+		return &fbi->mode[0];
+
 	for (i = 0, m = &fbi->mode[0]; i < fbi->num_modes; i++, m++) {
 		if (!strcmp(m->mode.name, fb_mode))
 			return m;
@@ -479,6 +502,9 @@ static int imxfb_bl_update_status(struct backlight_device *bl)
 	struct imxfb_info *fbi = bl_get_data(bl);
 	int brightness = bl->props.brightness;
 
+	if (!fbi->pwmr)
+		return 0;
+
 	if (bl->props.power != FB_BLANK_UNBLANK)
 		brightness = 0;
 	if (bl->props.fb_blank != FB_BLANK_UNBLANK)
@@ -719,10 +745,14 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf
 
 	writel(fbi->pcr, fbi->regs + LCDC_PCR);
 #ifndef PWMR_BACKLIGHT_AVAILABLE
-	writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
+	if (fbi->pwmr)
+		writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
 #endif
 	writel(fbi->lscr1, fbi->regs + LCDC_LSCR1);
-	writel(fbi->dmacr, fbi->regs + LCDC_DMACR);
+
+	/* dmacr = 0 is no valid value, as we need DMA control marks. */
+	if (fbi->dmacr)
+		writel(fbi->dmacr, fbi->regs + LCDC_DMACR);
 
 	return 0;
 }
@@ -758,13 +788,12 @@ static int imxfb_resume(struct platform_device *dev)
 #define imxfb_resume	NULL
 #endif
 
-static int __init imxfb_init_fbinfo(struct platform_device *pdev)
+static int imxfb_init_fbinfo(struct platform_device *pdev)
 {
 	struct imx_fb_platform_data *pdata = pdev->dev.platform_data;
 	struct fb_info *info = dev_get_drvdata(&pdev->dev);
 	struct imxfb_info *fbi = info->par;
-	struct imx_fb_videomode *m;
-	int i;
+	struct device_node *np;
 
 	pr_debug("%s\n",__func__);
 
@@ -795,41 +824,95 @@ static int __init imxfb_init_fbinfo(struct platform_device *pdev)
 	info->fbops			= &imxfb_ops;
 	info->flags			= FBINFO_FLAG_DEFAULT |
 					  FBINFO_READS_FAST;
-	info->var.grayscale		= pdata->cmap_greyscale;
-	fbi->cmap_inverse		= pdata->cmap_inverse;
-	fbi->cmap_static		= pdata->cmap_static;
-	fbi->lscr1			= pdata->lscr1;
-	fbi->dmacr			= pdata->dmacr;
-	fbi->pwmr			= pdata->pwmr;
-	fbi->lcd_power			= pdata->lcd_power;
-	fbi->backlight_power		= pdata->backlight_power;
-
-	for (i = 0, m = &pdata->mode[0]; i < pdata->num_modes; i++, m++)
-		info->fix.smem_len = max_t(size_t, info->fix.smem_len,
-				m->mode.xres * m->mode.yres * m->bpp / 8);
+	if (pdata) {
+		info->var.grayscale		= pdata->cmap_greyscale;
+		fbi->cmap_inverse		= pdata->cmap_inverse;
+		fbi->cmap_static		= pdata->cmap_static;
+		fbi->lscr1			= pdata->lscr1;
+		fbi->dmacr			= pdata->dmacr;
+		fbi->pwmr			= pdata->pwmr;
+		fbi->lcd_power			= pdata->lcd_power;
+		fbi->backlight_power		= pdata->backlight_power;
+	} else {
+		np = pdev->dev.of_node;
+		info->var.grayscale = of_property_read_bool(np,
+						"cmap-greyscale");
+		fbi->cmap_inverse = of_property_read_bool(np, "cmap-inverse");
+		fbi->cmap_static = of_property_read_bool(np, "cmap-static");
+
+		fbi->lscr1 = IMXFB_LSCR1_DEFAULT;
+		of_property_read_u32(np, "fsl,lscr1", &fbi->lscr1);
+
+		of_property_read_u32(np, "fsl,dmacr", &fbi->dmacr);
+
+		/* These two function pointers could be used by some specific
+		 * platforms. */
+		fbi->lcd_power = NULL;
+		fbi->backlight_power = NULL;
+	}
+
+	return 0;
+}
+
+static int imxfb_of_read_mode(struct device *dev, struct device_node *np,
+		struct imx_fb_videomode *imxfb_mode)
+{
+	int ret;
+	struct fb_videomode *of_mode = &imxfb_mode->mode;
+	u32 bpp;
+	u32 pcr;
+
+	ret = of_property_read_string(np, "model", &of_mode->name);
+	if (ret)
+		of_mode->name = NULL;
+
+	ret = of_get_fb_videomode(np, of_mode, OF_USE_NATIVE_MODE);
+	if (ret) {
+		dev_err(dev, "Failed to get videomode from DT\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(np, "fsl,bpp", &bpp);
+	ret |= of_property_read_u32(np, "fsl,pcr", &pcr);
+
+	if (ret) {
+		dev_err(dev, "Failed to read bpp and pcr from DT\n");
+		return -EINVAL;
+	}
+
+	if (bpp < 1 || bpp > 255) {
+		dev_err(dev, "Bits per pixel have to be between 1 and 255\n");
+		return -EINVAL;
+	}
+
+	imxfb_mode->bpp = bpp;
+	imxfb_mode->pcr = pcr;
 
 	return 0;
 }
 
-static int __init imxfb_probe(struct platform_device *pdev)
+static int imxfb_probe(struct platform_device *pdev)
 {
 	struct imxfb_info *fbi;
 	struct fb_info *info;
 	struct imx_fb_platform_data *pdata;
 	struct resource *res;
+	struct imx_fb_videomode *m;
+	const struct of_device_id *of_id;
 	int ret, i;
+	int bytes_per_pixel;
 
 	dev_info(&pdev->dev, "i.MX Framebuffer driver\n");
 
+	of_id = of_match_device(imxfb_of_dev_id, &pdev->dev);
+	if (of_id)
+		pdev->id_entry = of_id->data;
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res)
 		return -ENODEV;
 
 	pdata = pdev->dev.platform_data;
-	if (!pdata) {
-		dev_err(&pdev->dev,"No platform_data available\n");
-		return -ENOMEM;
-	}
 
 	info = framebuffer_alloc(sizeof(struct imxfb_info), &pdev->dev);
 	if (!info)
@@ -837,15 +920,55 @@ static int __init imxfb_probe(struct platform_device *pdev)
 
 	fbi = info->par;
 
-	if (!fb_mode)
-		fb_mode = pdata->mode[0].mode.name;
-
 	platform_set_drvdata(pdev, info);
 
 	ret = imxfb_init_fbinfo(pdev);
 	if (ret < 0)
 		goto failed_init;
 
+	if (pdata) {
+		if (!fb_mode)
+			fb_mode = pdata->mode[0].mode.name;
+
+		fbi->mode = pdata->mode;
+		fbi->num_modes = pdata->num_modes;
+	} else {
+		struct device_node *display_np;
+		fb_mode = NULL;
+
+		display_np = of_parse_phandle(pdev->dev.of_node, "display", 0);
+		if (!display_np) {
+			dev_err(&pdev->dev, "No display defined in devicetree\n");
+			ret = -EINVAL;
+			goto failed_of_parse;
+		}
+
+		/*
+		 * imxfb does not support more modes, we choose only the native
+		 * mode.
+		 */
+		fbi->num_modes = 1;
+
+		fbi->mode = devm_kzalloc(&pdev->dev,
+				sizeof(struct imx_fb_videomode), GFP_KERNEL);
+		if (!fbi->mode) {
+			ret = -ENOMEM;
+			goto failed_of_parse;
+		}
+
+		ret = imxfb_of_read_mode(&pdev->dev, display_np, fbi->mode);
+		if (ret)
+			goto failed_of_parse;
+	}
+
+	/* Calculate maximum bytes used per pixel. In most cases this should
+	 * be the same as m->bpp/8 */
+	m = &fbi->mode[0];
+	bytes_per_pixel = (m->bpp + 7) / 8;
+	for (i = 0; i < fbi->num_modes; i++, m++)
+		info->fix.smem_len = max_t(size_t, info->fix.smem_len,
+				m->mode.xres * m->mode.yres * bytes_per_pixel);
+
 	res = request_mem_region(res->start, resource_size(res),
 				DRIVER_NAME);
 	if (!res) {
@@ -878,7 +1001,8 @@ static int __init imxfb_probe(struct platform_device *pdev)
 		goto failed_ioremap;
 	}
 
-	if (!pdata->fixed_screen_cpu) {
+	/* Seems not being used by anyone, so no support for oftree */
+	if (!pdata || !pdata->fixed_screen_cpu) {
 		fbi->map_size = PAGE_ALIGN(info->fix.smem_len);
 		fbi->map_cpu = dma_alloc_writecombine(&pdev->dev,
 				fbi->map_size, &fbi->map_dma, GFP_KERNEL);
@@ -903,18 +1027,16 @@ static int __init imxfb_probe(struct platform_device *pdev)
 		info->fix.smem_start = fbi->screen_dma;
 	}
 
-	if (pdata->init) {
+	if (pdata && pdata->init) {
 		ret = pdata->init(fbi->pdev);
 		if (ret)
 			goto failed_platform_init;
 	}
 
-	fbi->mode = pdata->mode;
-	fbi->num_modes = pdata->num_modes;
 
 	INIT_LIST_HEAD(&info->modelist);
-	for (i = 0; i < pdata->num_modes; i++)
-		fb_add_videomode(&pdata->mode[i].mode, &info->modelist);
+	for (i = 0; i < fbi->num_modes; i++)
+		fb_add_videomode(&fbi->mode[i].mode, &info->modelist);
 
 	/*
 	 * This makes sure that our colour bitfield
@@ -944,10 +1066,10 @@ static int __init imxfb_probe(struct platform_device *pdev)
 failed_register:
 	fb_dealloc_cmap(&info->cmap);
 failed_cmap:
-	if (pdata->exit)
+	if (pdata && pdata->exit)
 		pdata->exit(fbi->pdev);
 failed_platform_init:
-	if (!pdata->fixed_screen_cpu)
+	if (pdata && !pdata->fixed_screen_cpu)
 		dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu,
 			fbi->map_dma);
 failed_map:
@@ -956,6 +1078,7 @@ failed_ioremap:
 failed_getclock:
 	release_mem_region(res->start, resource_size(res));
 failed_req:
+failed_of_parse:
 	kfree(info->pseudo_palette);
 failed_init:
 	platform_set_drvdata(pdev, NULL);
@@ -980,7 +1103,7 @@ static int imxfb_remove(struct platform_device *pdev)
 	unregister_framebuffer(info);
 
 	pdata = pdev->dev.platform_data;
-	if (pdata->exit)
+	if (pdata && pdata->exit)
 		pdata->exit(fbi->pdev);
 
 	fb_dealloc_cmap(&info->cmap);
@@ -1009,6 +1132,7 @@ static struct platform_driver imxfb_driver = {
 	.shutdown	= imxfb_shutdown,
 	.driver		= {
 		.name	= DRIVER_NAME,
+		.of_match_table = imxfb_of_dev_id,
 	},
 	.id_table	= imxfb_devtype,
 };
-- 
1.8.1.5


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox