* RE: [PATCH v3 4/4] ARM: Samsung: Rework platform data of s3c-fb driver
From: Jingoo Han @ 2012-03-28 10:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1332606528-32338-5-git-send-email-thomas.abraham@linaro.org>
On 25 March 2012 01:29, Thomas Abraham < thomas.abraham@linaro.org> wrote:
> Subject: [PATCH v3 4/4] ARM: Samsung: Rework platform data of s3c-fb driver
>
> For all the Samsung SoC based boards which have the platform data for
> s3c-fb driver, the 'default_win' element in the platform data is removed
> and the lcd panel video timing values are moved out of individual window
> configuration data.
>
> Cc: Jingoo Han <jg1.han@samsung.com>
It looks good for SMDK boards.
Acked-by: Jingoo Han <jg1.han@samsung.com>
> Cc: Kyungmin Park <kyungmin.park@samsung.com>
> Cc: JeongHyeon Kim <jhkim@insignal.co.kr>
> Cc: Kukjin Kim <kgene.kim@samsung.com>
> Cc: Heiko Stuebner <heiko@sntech.de>
> Cc: Ben Dooks <ben-linux@fluff.org>
> Cc: Kwangwoo Lee <kwangwoo.lee@gmail.com>
> Cc: Mark Brown <broonie@opensource.wolfsonmicro.com>
> Cc: Peter Korsgaard <jacmet@sunsite.dk>
> Cc: Darius Augulis <augulis.darius@gmail.com>
> Cc: Maurus Cuelenaere <mcuelenaere@gmail.com>
> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
> ---
> arch/arm/mach-exynos/mach-nuri.c | 26 ++++++++------
> arch/arm/mach-exynos/mach-origen.c | 24 +++++++-----
> arch/arm/mach-exynos/mach-smdkv310.c | 28 ++++++++------
> arch/arm/mach-exynos/mach-universal_c210.c | 26 ++++++++------
> arch/arm/mach-s3c24xx/mach-smdk2416.c | 27 ++++++++------
> arch/arm/mach-s3c64xx/mach-anw6410.c | 25 +++++++------
> arch/arm/mach-s3c64xx/mach-crag6410.c | 25 +++++++------
> arch/arm/mach-s3c64xx/mach-hmt.c | 24 +++++++-----
> arch/arm/mach-s3c64xx/mach-mini6410.c | 54 ++++++++++++++++-----------
> arch/arm/mach-s3c64xx/mach-real6410.c | 52 +++++++++++++++-----------
> arch/arm/mach-s3c64xx/mach-smartq5.c | 26 ++++++++------
> arch/arm/mach-s3c64xx/mach-smartq7.c | 26 ++++++++------
> arch/arm/mach-s3c64xx/mach-smdk6410.c | 25 +++++++------
> arch/arm/mach-s5p64x0/mach-smdk6440.c | 24 +++++++-----
> arch/arm/mach-s5p64x0/mach-smdk6450.c | 24 +++++++-----
> arch/arm/mach-s5pc100/mach-smdkc100.c | 27 ++++++++------
> arch/arm/mach-s5pv210/mach-aquila.c | 36 ++++++++----------
> arch/arm/mach-s5pv210/mach-goni.c | 26 ++++++++------
> arch/arm/mach-s5pv210/mach-smdkv210.c | 24 +++++++-----
> 19 files changed, 311 insertions(+), 238 deletions(-)
>
> diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c
> index 7ac81ce..a7e6731 100644
> --- a/arch/arm/mach-exynos/mach-nuri.c
> +++ b/arch/arm/mach-exynos/mach-nuri.c
> @@ -212,25 +212,29 @@ static struct platform_device nuri_gpio_keys = {
>
> /* Frame Buffer */
> static struct s3c_fb_pd_win nuri_fb_win0 = {
> - .win_mode = {
> - .left_margin = 64,
> - .right_margin = 16,
> - .upper_margin = 64,
> - .lower_margin = 1,
> - .hsync_len = 48,
> - .vsync_len = 3,
> - .xres = 1024,
> - .yres = 600,
> - .refresh = 60,
> - },
> .max_bpp = 24,
> .default_bpp = 16,
> + .xres = 1024,
> + .yres = 600,
> .virtual_x = 1024,
> .virtual_y = 2 * 600,
> };
>
> +static struct fb_videomode nuri_lcd_timing = {
> + .left_margin = 64,
> + .right_margin = 16,
> + .upper_margin = 64,
> + .lower_margin = 1,
> + .hsync_len = 48,
> + .vsync_len = 3,
> + .xres = 1024,
> + .yres = 600,
> + .refresh = 60,
> +};
> +
> static struct s3c_fb_platdata nuri_fb_pdata __initdata = {
> .win[0] = &nuri_fb_win0,
> + .vtiming = &nuri_lcd_timing,
> .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB |
> VIDCON0_CLKSEL_LCD,
> .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
> diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c
> index 25c9b46..de71237 100644
> --- a/arch/arm/mach-exynos/mach-origen.c
> +++ b/arch/arm/mach-exynos/mach-origen.c
> @@ -583,22 +583,26 @@ static struct platform_device origen_lcd_hv070wsa = {
> };
>
> static struct s3c_fb_pd_win origen_fb_win0 = {
> - .win_mode = {
> - .left_margin = 64,
> - .right_margin = 16,
> - .upper_margin = 64,
> - .lower_margin = 16,
> - .hsync_len = 48,
> - .vsync_len = 3,
> - .xres = 1024,
> - .yres = 600,
> - },
> + .xres = 1024,
> + .yres = 600,
> .max_bpp = 32,
> .default_bpp = 24,
> };
>
> +static struct fb_videomode origen_lcd_timing = {
> + .left_margin = 64,
> + .right_margin = 16,
> + .upper_margin = 64,
> + .lower_margin = 16,
> + .hsync_len = 48,
> + .vsync_len = 3,
> + .xres = 1024,
> + .yres = 600,
> +};
> +
> static struct s3c_fb_platdata origen_lcd_pdata __initdata = {
> .win[0] = &origen_fb_win0,
> + .vtiming = &origen_lcd_timing,
> .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
> .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC |
> VIDCON1_INV_VCLK,
> diff --git a/arch/arm/mach-exynos/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c
> index f08529f..6c00fa6 100644
> --- a/arch/arm/mach-exynos/mach-smdkv310.c
> +++ b/arch/arm/mach-exynos/mach-smdkv310.c
> @@ -157,22 +157,26 @@ static struct platform_device smdkv310_lcd_lte480wv = {
> };
>
> static struct s3c_fb_pd_win smdkv310_fb_win0 = {
> - .win_mode = {
> - .left_margin = 13,
> - .right_margin = 8,
> - .upper_margin = 7,
> - .lower_margin = 5,
> - .hsync_len = 3,
> - .vsync_len = 1,
> - .xres = 800,
> - .yres = 480,
> - },
> - .max_bpp = 32,
> - .default_bpp = 24,
> + .max_bpp = 32,
> + .default_bpp = 24,
> + .xres = 800,
> + .yres = 480,
> +};
> +
> +static struct fb_videomode smdkv310_lcd_timing = {
> + .left_margin = 13,
> + .right_margin = 8,
> + .upper_margin = 7,
> + .lower_margin = 5,
> + .hsync_len = 3,
> + .vsync_len = 1,
> + .xres = 800,
> + .yres = 480,
> };
>
> static struct s3c_fb_platdata smdkv310_lcd0_pdata __initdata = {
> .win[0] = &smdkv310_fb_win0,
> + .vtiming = &smdkv310_lcd_timing,
> .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
> .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
> .setup_gpio = exynos4_fimd0_gpio_setup_24bpp,
> diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c
> index 57e4418..67a9547 100644
> --- a/arch/arm/mach-exynos/mach-universal_c210.c
> +++ b/arch/arm/mach-exynos/mach-universal_c210.c
> @@ -813,25 +813,29 @@ static struct i2c_board_info i2c1_devs[] __initdata = {
>
> /* Frame Buffer */
> static struct s3c_fb_pd_win universal_fb_win0 = {
> - .win_mode = {
> - .left_margin = 16,
> - .right_margin = 16,
> - .upper_margin = 2,
> - .lower_margin = 28,
> - .hsync_len = 2,
> - .vsync_len = 1,
> - .xres = 480,
> - .yres = 800,
> - .refresh = 55,
> - },
> .max_bpp = 32,
> .default_bpp = 16,
> + .xres = 480,
> + .yres = 800,
> .virtual_x = 480,
> .virtual_y = 2 * 800,
> };
>
> +static struct fb_videomode universal_lcd_timing = {
> + .left_margin = 16,
> + .right_margin = 16,
> + .upper_margin = 2,
> + .lower_margin = 28,
> + .hsync_len = 2,
> + .vsync_len = 1,
> + .xres = 480,
> + .yres = 800,
> + .refresh = 55,
> +};
> +
> static struct s3c_fb_platdata universal_lcd_pdata __initdata = {
> .win[0] = &universal_fb_win0,
> + .vtiming = &universal_lcd_timing,
> .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB |
> VIDCON0_CLKSEL_LCD,
> .vidcon1 = VIDCON1_INV_VCLK | VIDCON1_INV_VDEN
> diff --git a/arch/arm/mach-s3c24xx/mach-smdk2416.c b/arch/arm/mach-s3c24xx/mach-smdk2416.c
> index 30a44f8..c3100a0 100644
> --- a/arch/arm/mach-s3c24xx/mach-smdk2416.c
> +++ b/arch/arm/mach-s3c24xx/mach-smdk2416.c
> @@ -148,23 +148,25 @@ static struct s3c24xx_hsudc_platdata smdk2416_hsudc_platdata = {
>
> static struct s3c_fb_pd_win smdk2416_fb_win[] = {
> [0] = {
> - /* think this is the same as the smdk6410 */
> - .win_mode = {
> - .pixclock = 41094,
> - .left_margin = 8,
> - .right_margin = 13,
> - .upper_margin = 7,
> - .lower_margin = 5,
> - .hsync_len = 3,
> - .vsync_len = 1,
> - .xres = 800,
> - .yres = 480,
> - },
> .default_bpp = 16,
> .max_bpp = 32,
> + .xres = 800,
> + .yres = 480,
> },
> };
>
> +static struct fb_videomode smdk2416_lcd_timing = {
> + .pixclock = 41094,
> + .left_margin = 8,
> + .right_margin = 13,
> + .upper_margin = 7,
> + .lower_margin = 5,
> + .hsync_len = 3,
> + .vsync_len = 1,
> + .xres = 800,
> + .yres = 480,
> +};
> +
> static void s3c2416_fb_gpio_setup_24bpp(void)
> {
> unsigned int gpio;
> @@ -187,6 +189,7 @@ static void s3c2416_fb_gpio_setup_24bpp(void)
>
> static struct s3c_fb_platdata smdk2416_fb_platdata = {
> .win[0] = &smdk2416_fb_win[0],
> + .vtiming = &smdk2416_lcd_timing,
> .setup_gpio = s3c2416_fb_gpio_setup_24bpp,
> .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
> .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
> diff --git a/arch/arm/mach-s3c64xx/mach-anw6410.c b/arch/arm/mach-s3c64xx/mach-anw6410.c
> index b86f277..58fd0e3 100644
> --- a/arch/arm/mach-s3c64xx/mach-anw6410.c
> +++ b/arch/arm/mach-s3c64xx/mach-anw6410.c
> @@ -134,24 +134,27 @@ static struct platform_device anw6410_lcd_powerdev = {
> };
>
> static struct s3c_fb_pd_win anw6410_fb_win0 = {
> - /* this is to ensure we use win0 */
> - .win_mode = {
> - .left_margin = 8,
> - .right_margin = 13,
> - .upper_margin = 7,
> - .lower_margin = 5,
> - .hsync_len = 3,
> - .vsync_len = 1,
> - .xres = 800,
> - .yres = 480,
> - },
> .max_bpp = 32,
> .default_bpp = 16,
> + .xres = 800,
> + .yres = 480,
> +};
> +
> +static struct fb_videomode anw6410_lcd_timing = {
> + .left_margin = 8,
> + .right_margin = 13,
> + .upper_margin = 7,
> + .lower_margin = 5,
> + .hsync_len = 3,
> + .vsync_len = 1,
> + .xres = 800,
> + .yres = 480,
> };
>
> /* 405566 clocks per frame => 60Hz refresh requires 24333960Hz clock */
> static struct s3c_fb_platdata anw6410_lcd_pdata __initdata = {
> .setup_gpio = s3c64xx_fb_gpio_setup_24bpp,
> + .vtiming = &anw6410_lcd_timing,
> .win[0] = &anw6410_fb_win0,
> .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
> .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
> diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c
> index e20bf58..c1ef57e 100644
> --- a/arch/arm/mach-s3c64xx/mach-crag6410.c
> +++ b/arch/arm/mach-s3c64xx/mach-crag6410.c
> @@ -151,26 +151,29 @@ static struct platform_device crag6410_lcd_powerdev = {
>
> /* 640x480 URT */
> static struct s3c_fb_pd_win crag6410_fb_win0 = {
> - /* this is to ensure we use win0 */
> - .win_mode = {
> - .left_margin = 150,
> - .right_margin = 80,
> - .upper_margin = 40,
> - .lower_margin = 5,
> - .hsync_len = 40,
> - .vsync_len = 5,
> - .xres = 640,
> - .yres = 480,
> - },
> .max_bpp = 32,
> .default_bpp = 16,
> + .xres = 640,
> + .yres = 480,
> .virtual_y = 480 * 2,
> .virtual_x = 640,
> };
>
> +static struct fb_videomode crag6410_lcd_timing = {
> + .left_margin = 150,
> + .right_margin = 80,
> + .upper_margin = 40,
> + .lower_margin = 5,
> + .hsync_len = 40,
> + .vsync_len = 5,
> + .xres = 640,
> + .yres = 480,
> +};
> +
> /* 405566 clocks per frame => 60Hz refresh requires 24333960Hz clock */
> static struct s3c_fb_platdata crag6410_lcd_pdata __initdata = {
> .setup_gpio = s3c64xx_fb_gpio_setup_24bpp,
> + .vtiming = &crag6410_lcd_timing,
> .win[0] = &crag6410_fb_win0,
> .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
> .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
> diff --git a/arch/arm/mach-s3c64xx/mach-hmt.c b/arch/arm/mach-s3c64xx/mach-hmt.c
> index 521e07b..4e9b1ac 100644
> --- a/arch/arm/mach-s3c64xx/mach-hmt.c
> +++ b/arch/arm/mach-s3c64xx/mach-hmt.c
> @@ -129,23 +129,27 @@ static struct platform_device hmt_backlight_device = {
> };
>
> static struct s3c_fb_pd_win hmt_fb_win0 = {
> - .win_mode = {
> - .left_margin = 8,
> - .right_margin = 13,
> - .upper_margin = 7,
> - .lower_margin = 5,
> - .hsync_len = 3,
> - .vsync_len = 1,
> - .xres = 800,
> - .yres = 480,
> - },
> .max_bpp = 32,
> .default_bpp = 16,
> + .xres = 800,
> + .yres = 480,
> +};
> +
> +static struct fb_videomode hmt_lcd_timing = {
> + .left_margin = 8,
> + .right_margin = 13,
> + .upper_margin = 7,
> + .lower_margin = 5,
> + .hsync_len = 3,
> + .vsync_len = 1,
> + .xres = 800,
> + .yres = 480,
> };
>
> /* 405566 clocks per frame => 60Hz refresh requires 24333960Hz clock */
> static struct s3c_fb_platdata hmt_lcd_pdata __initdata = {
> .setup_gpio = s3c64xx_fb_gpio_setup_24bpp,
> + .vtiming = &hmt_lcd_timing,
> .win[0] = &hmt_fb_win0,
> .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
> .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
> diff --git a/arch/arm/mach-s3c64xx/mach-mini6410.c b/arch/arm/mach-s3c64xx/mach-mini6410.c
> index 34f5195..2f425d5 100644
> --- a/arch/arm/mach-s3c64xx/mach-mini6410.c
> +++ b/arch/arm/mach-s3c64xx/mach-mini6410.c
> @@ -152,43 +152,53 @@ static struct s3c2410_platform_nand mini6410_nand_info = {
> };
>
> static struct s3c_fb_pd_win mini6410_lcd_type0_fb_win = {
> - .win_mode = { /* 4.3" 480x272 */
> - .left_margin = 3,
> - .right_margin = 2,
> - .upper_margin = 1,
> - .lower_margin = 1,
> - .hsync_len = 40,
> - .vsync_len = 1,
> - .xres = 480,
> - .yres = 272,
> - },
> .max_bpp = 32,
> .default_bpp = 16,
> + .xres = 480,
> + .yres = 272,
> +};
> +
> +static struct fb_videomode mini6410_lcd_type0_timing = {
> + /* 4.3" 480x272 */
> + .left_margin = 3,
> + .right_margin = 2,
> + .upper_margin = 1,
> + .lower_margin = 1,
> + .hsync_len = 40,
> + .vsync_len = 1,
> + .xres = 480,
> + .yres = 272,
> };
>
> static struct s3c_fb_pd_win mini6410_lcd_type1_fb_win = {
> - .win_mode = { /* 7.0" 800x480 */
> - .left_margin = 8,
> - .right_margin = 13,
> - .upper_margin = 7,
> - .lower_margin = 5,
> - .hsync_len = 3,
> - .vsync_len = 1,
> - .xres = 800,
> - .yres = 480,
> - },
> .max_bpp = 32,
> .default_bpp = 16,
> + .xres = 800,
> + .yres = 480,
> +};
> +
> +static struct fb_videomode mini6410_lcd_type1_timing = {
> + /* 7.0" 800x480 */
> + .left_margin = 8,
> + .right_margin = 13,
> + .upper_margin = 7,
> + .lower_margin = 5,
> + .hsync_len = 3,
> + .vsync_len = 1,
> + .xres = 800,
> + .yres = 480,
> };
>
> static struct s3c_fb_platdata mini6410_lcd_pdata[] __initdata = {
> {
> .setup_gpio = s3c64xx_fb_gpio_setup_24bpp,
> + .vtiming = &mini6410_lcd_type0_timing,
> .win[0] = &mini6410_lcd_type0_fb_win,
> .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
> .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
> }, {
> .setup_gpio = s3c64xx_fb_gpio_setup_24bpp,
> + .vtiming = &mini6410_lcd_type1_timing,
> .win[0] = &mini6410_lcd_type1_fb_win,
> .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
> .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
> @@ -316,8 +326,8 @@ static void __init mini6410_machine_init(void)
> mini6410_parse_features(&features, mini6410_features_str);
>
> printk(KERN_INFO "MINI6410: selected LCD display is %dx%d\n",
> - mini6410_lcd_pdata[features.lcd_index].win[0]->win_mode.xres,
> - mini6410_lcd_pdata[features.lcd_index].win[0]->win_mode.yres);
> + mini6410_lcd_pdata[features.lcd_index].win[0]->xres,
> + mini6410_lcd_pdata[features.lcd_index].win[0]->yres);
>
> s3c_nand_set_platdata(&mini6410_nand_info);
> s3c_fb_set_platdata(&mini6410_lcd_pdata[features.lcd_index]);
> diff --git a/arch/arm/mach-s3c64xx/mach-real6410.c b/arch/arm/mach-s3c64xx/mach-real6410.c
> index 21f91e5..0fbd32c 100644
> --- a/arch/arm/mach-s3c64xx/mach-real6410.c
> +++ b/arch/arm/mach-s3c64xx/mach-real6410.c
> @@ -118,43 +118,51 @@ static struct platform_device real6410_device_eth = {
> };
>
> static struct s3c_fb_pd_win real6410_lcd_type0_fb_win = {
> - .win_mode = { /* 4.3" 480x272 */
> - .left_margin = 3,
> - .right_margin = 2,
> - .upper_margin = 1,
> - .lower_margin = 1,
> - .hsync_len = 40,
> - .vsync_len = 1,
> - .xres = 480,
> - .yres = 272,
> - },
> .max_bpp = 32,
> .default_bpp = 16,
> + .xres = 480,
> + .yres = 272,
> +};
> +
> +static struct fb_videomode real6410_lcd_type0_timing = {
> + /* 4.3" 480x272 */
> + .left_margin = 3,
> + .right_margin = 2,
> + .upper_margin = 1,
> + .lower_margin = 1,
> + .hsync_len = 40,
> + .vsync_len = 1,
> };
>
> static struct s3c_fb_pd_win real6410_lcd_type1_fb_win = {
> - .win_mode = { /* 7.0" 800x480 */
> - .left_margin = 8,
> - .right_margin = 13,
> - .upper_margin = 7,
> - .lower_margin = 5,
> - .hsync_len = 3,
> - .vsync_len = 1,
> - .xres = 800,
> - .yres = 480,
> - },
> .max_bpp = 32,
> .default_bpp = 16,
> + .xres = 800,
> + .yres = 480,
> +};
> +
> +static struct fb_videomode real6410_lcd_type1_timing = {
> + /* 7.0" 800x480 */
> + .left_margin = 8,
> + .right_margin = 13,
> + .upper_margin = 7,
> + .lower_margin = 5,
> + .hsync_len = 3,
> + .vsync_len = 1,
> + .xres = 800,
> + .yres = 480,
> };
>
> static struct s3c_fb_platdata real6410_lcd_pdata[] __initdata = {
> {
> .setup_gpio = s3c64xx_fb_gpio_setup_24bpp,
> + .vtiming = &real6410_lcd_type0_timing,
> .win[0] = &real6410_lcd_type0_fb_win,
> .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
> .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
> }, {
> .setup_gpio = s3c64xx_fb_gpio_setup_24bpp,
> + .vtiming = &real6410_lcd_type1_timing,
> .win[0] = &real6410_lcd_type1_fb_win,
> .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
> .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
> @@ -297,8 +305,8 @@ static void __init real6410_machine_init(void)
> real6410_parse_features(&features, real6410_features_str);
>
> printk(KERN_INFO "REAL6410: selected LCD display is %dx%d\n",
> - real6410_lcd_pdata[features.lcd_index].win[0]->win_mode.xres,
> - real6410_lcd_pdata[features.lcd_index].win[0]->win_mode.yres);
> + real6410_lcd_pdata[features.lcd_index].win[0]->xres,
> + real6410_lcd_pdata[features.lcd_index].win[0]->yres);
>
> s3c_fb_set_platdata(&real6410_lcd_pdata[features.lcd_index]);
> s3c_nand_set_platdata(&real6410_nand_info);
> diff --git a/arch/arm/mach-s3c64xx/mach-smartq5.c b/arch/arm/mach-s3c64xx/mach-smartq5.c
> index 3f42431..03a2f88 100644
> --- a/arch/arm/mach-s3c64xx/mach-smartq5.c
> +++ b/arch/arm/mach-s3c64xx/mach-smartq5.c
> @@ -108,23 +108,27 @@ static struct platform_device smartq5_buttons_device = {
> };
>
> static struct s3c_fb_pd_win smartq5_fb_win0 = {
> - .win_mode = {
> - .left_margin = 216,
> - .right_margin = 40,
> - .upper_margin = 35,
> - .lower_margin = 10,
> - .hsync_len = 1,
> - .vsync_len = 1,
> - .xres = 800,
> - .yres = 480,
> - .refresh = 80,
> - },
> .max_bpp = 32,
> .default_bpp = 16,
> + .xres = 800,
> + .yres = 480,
> +};
> +
> +static struct fb_videomode smartq5_lcd_timing = {
> + .left_margin = 216,
> + .right_margin = 40,
> + .upper_margin = 35,
> + .lower_margin = 10,
> + .hsync_len = 1,
> + .vsync_len = 1,
> + .xres = 800,
> + .yres = 480,
> + .refresh = 80,
> };
>
> static struct s3c_fb_platdata smartq5_lcd_pdata __initdata = {
> .setup_gpio = s3c64xx_fb_gpio_setup_24bpp,
> + .vtiming = &smartq5_lcd_timing,
> .win[0] = &smartq5_fb_win0,
> .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
> .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC |
> diff --git a/arch/arm/mach-s3c64xx/mach-smartq7.c b/arch/arm/mach-s3c64xx/mach-smartq7.c
> index e5c09b6..4e3b038 100644
> --- a/arch/arm/mach-s3c64xx/mach-smartq7.c
> +++ b/arch/arm/mach-s3c64xx/mach-smartq7.c
> @@ -124,23 +124,27 @@ static struct platform_device smartq7_buttons_device = {
> };
>
> static struct s3c_fb_pd_win smartq7_fb_win0 = {
> - .win_mode = {
> - .left_margin = 3,
> - .right_margin = 5,
> - .upper_margin = 1,
> - .lower_margin = 20,
> - .hsync_len = 10,
> - .vsync_len = 3,
> - .xres = 800,
> - .yres = 480,
> - .refresh = 80,
> - },
> .max_bpp = 32,
> .default_bpp = 16,
> + .xres = 800,
> + .yres = 480,
> +};
> +
> +static struct fb_videomode smartq7_lcd_timing = {
> + .left_margin = 3,
> + .right_margin = 5,
> + .upper_margin = 1,
> + .lower_margin = 20,
> + .hsync_len = 10,
> + .vsync_len = 3,
> + .xres = 800,
> + .yres = 480,
> + .refresh = 80,
> };
>
> static struct s3c_fb_platdata smartq7_lcd_pdata __initdata = {
> .setup_gpio = s3c64xx_fb_gpio_setup_24bpp,
> + .vtiming = &smartq7_lcd_timing,
> .win[0] = &smartq7_fb_win0,
> .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
> .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC |
> diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c
> index d55bc96..3cfc90f 100644
> --- a/arch/arm/mach-s3c64xx/mach-smdk6410.c
> +++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c
> @@ -146,26 +146,29 @@ static struct platform_device smdk6410_lcd_powerdev = {
> };
>
> static struct s3c_fb_pd_win smdk6410_fb_win0 = {
> - /* this is to ensure we use win0 */
> - .win_mode = {
> - .left_margin = 8,
> - .right_margin = 13,
> - .upper_margin = 7,
> - .lower_margin = 5,
> - .hsync_len = 3,
> - .vsync_len = 1,
> - .xres = 800,
> - .yres = 480,
> - },
> .max_bpp = 32,
> .default_bpp = 16,
> + .xres = 800,
> + .yres = 480,
> .virtual_y = 480 * 2,
> .virtual_x = 800,
> };
>
> +static struct fb_videomode smdk6410_lcd_timing = {
> + .left_margin = 8,
> + .right_margin = 13,
> + .upper_margin = 7,
> + .lower_margin = 5,
> + .hsync_len = 3,
> + .vsync_len = 1,
> + .xres = 800,
> + .yres = 480,
> +};
> +
> /* 405566 clocks per frame => 60Hz refresh requires 24333960Hz clock */
> static struct s3c_fb_platdata smdk6410_lcd_pdata __initdata = {
> .setup_gpio = s3c64xx_fb_gpio_setup_24bpp,
> + .vtiming = &smdk6410_lcd_timing,
> .win[0] = &smdk6410_fb_win0,
> .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
> .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
> diff --git a/arch/arm/mach-s5p64x0/mach-smdk6440.c b/arch/arm/mach-s5p64x0/mach-smdk6440.c
> index a40e325..92fefad 100644
> --- a/arch/arm/mach-s5p64x0/mach-smdk6440.c
> +++ b/arch/arm/mach-s5p64x0/mach-smdk6440.c
> @@ -103,22 +103,26 @@ static struct s3c2410_uartcfg smdk6440_uartcfgs[] __initdata = {
>
> /* Frame Buffer */
> static struct s3c_fb_pd_win smdk6440_fb_win0 = {
> - .win_mode = {
> - .left_margin = 8,
> - .right_margin = 13,
> - .upper_margin = 7,
> - .lower_margin = 5,
> - .hsync_len = 3,
> - .vsync_len = 1,
> - .xres = 800,
> - .yres = 480,
> - },
> .max_bpp = 32,
> .default_bpp = 24,
> + .xres = 800,
> + .yres = 480,
> +};
> +
> +static struct fb_videomode smdk6440_lcd_timing = {
> + .left_margin = 8,
> + .right_margin = 13,
> + .upper_margin = 7,
> + .lower_margin = 5,
> + .hsync_len = 3,
> + .vsync_len = 1,
> + .xres = 800,
> + .yres = 480,
> };
>
> static struct s3c_fb_platdata smdk6440_lcd_pdata __initdata = {
> .win[0] = &smdk6440_fb_win0,
> + .vtiming = &smdk6440_lcd_timing,
> .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
> .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
> .setup_gpio = s5p64x0_fb_gpio_setup_24bpp,
> diff --git a/arch/arm/mach-s5p64x0/mach-smdk6450.c b/arch/arm/mach-s5p64x0/mach-smdk6450.c
> index efb69e2..e2335ec 100644
> --- a/arch/arm/mach-s5p64x0/mach-smdk6450.c
> +++ b/arch/arm/mach-s5p64x0/mach-smdk6450.c
> @@ -121,22 +121,26 @@ static struct s3c2410_uartcfg smdk6450_uartcfgs[] __initdata = {
>
> /* Frame Buffer */
> static struct s3c_fb_pd_win smdk6450_fb_win0 = {
> - .win_mode = {
> - .left_margin = 8,
> - .right_margin = 13,
> - .upper_margin = 7,
> - .lower_margin = 5,
> - .hsync_len = 3,
> - .vsync_len = 1,
> - .xres = 800,
> - .yres = 480,
> - },
> .max_bpp = 32,
> .default_bpp = 24,
> + .xres = 800,
> + .yres = 480,
> +};
> +
> +static struct fb_videomode smdk6450_lcd_timing = {
> + .left_margin = 8,
> + .right_margin = 13,
> + .upper_margin = 7,
> + .lower_margin = 5,
> + .hsync_len = 3,
> + .vsync_len = 1,
> + .xres = 800,
> + .yres = 480,
> };
>
> static struct s3c_fb_platdata smdk6450_lcd_pdata __initdata = {
> .win[0] = &smdk6450_fb_win0,
> + .vtiming = &smdk6450_lcd_timing,
> .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
> .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
> .setup_gpio = s5p64x0_fb_gpio_setup_24bpp,
> diff --git a/arch/arm/mach-s5pc100/mach-smdkc100.c b/arch/arm/mach-s5pc100/mach-smdkc100.c
> index 674d229..0c3ae38 100644
> --- a/arch/arm/mach-s5pc100/mach-smdkc100.c
> +++ b/arch/arm/mach-s5pc100/mach-smdkc100.c
> @@ -136,24 +136,27 @@ static struct platform_device smdkc100_lcd_powerdev = {
>
> /* Frame Buffer */
> static struct s3c_fb_pd_win smdkc100_fb_win0 = {
> - /* this is to ensure we use win0 */
> - .win_mode = {
> - .left_margin = 8,
> - .right_margin = 13,
> - .upper_margin = 7,
> - .lower_margin = 5,
> - .hsync_len = 3,
> - .vsync_len = 1,
> - .xres = 800,
> - .yres = 480,
> - .refresh = 80,
> - },
> .max_bpp = 32,
> .default_bpp = 16,
> + .xres = 800,
> + .yres = 480,
> +};
> +
> +static struct fb_videomode smdkc100_lcd_timing = {
> + .left_margin = 8,
> + .right_margin = 13,
> + .upper_margin = 7,
> + .lower_margin = 5,
> + .hsync_len = 3,
> + .vsync_len = 1,
> + .xres = 800,
> + .yres = 480,
> + .refresh = 80,
> };
>
> static struct s3c_fb_platdata smdkc100_lcd_pdata __initdata = {
> .win[0] = &smdkc100_fb_win0,
> + .vtiming = &smdkc100_lcd_timing,
> .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
> .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
> .setup_gpio = s5pc100_fb_gpio_setup_24bpp,
> diff --git a/arch/arm/mach-s5pv210/mach-aquila.c b/arch/arm/mach-s5pv210/mach-aquila.c
> index a9ea64e..7b91bbf 100644
> --- a/arch/arm/mach-s5pv210/mach-aquila.c
> +++ b/arch/arm/mach-s5pv210/mach-aquila.c
> @@ -96,38 +96,34 @@ static struct s3c2410_uartcfg aquila_uartcfgs[] __initdata = {
>
> /* Frame Buffer */
> static struct s3c_fb_pd_win aquila_fb_win0 = {
> - .win_mode = {
> - .left_margin = 16,
> - .right_margin = 16,
> - .upper_margin = 3,
> - .lower_margin = 28,
> - .hsync_len = 2,
> - .vsync_len = 2,
> - .xres = 480,
> - .yres = 800,
> - },
> .max_bpp = 32,
> .default_bpp = 16,
> + .xres = 480,
> + .yres = 800,
> };
>
> static struct s3c_fb_pd_win aquila_fb_win1 = {
> - .win_mode = {
> - .left_margin = 16,
> - .right_margin = 16,
> - .upper_margin = 3,
> - .lower_margin = 28,
> - .hsync_len = 2,
> - .vsync_len = 2,
> - .xres = 480,
> - .yres = 800,
> - },
> .max_bpp = 32,
> .default_bpp = 16,
> + .xres = 480,
> + .yres = 800,
> +};
> +
> +static struct fb_videomode aquila_lcd_timing = {
> + .left_margin = 16,
> + .right_margin = 16,
> + .upper_margin = 3,
> + .lower_margin = 28,
> + .hsync_len = 2,
> + .vsync_len = 2,
> + .xres = 480,
> + .yres = 800,
> };
>
> static struct s3c_fb_platdata aquila_lcd_pdata __initdata = {
> .win[0] = &aquila_fb_win0,
> .win[1] = &aquila_fb_win1,
> + .vtiming = &aquila_lcd_timing,
> .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
> .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC |
> VIDCON1_INV_VCLK | VIDCON1_INV_VDEN,
> diff --git a/arch/arm/mach-s5pv210/mach-goni.c b/arch/arm/mach-s5pv210/mach-goni.c
> index 2cf5ed7..07a840d 100644
> --- a/arch/arm/mach-s5pv210/mach-goni.c
> +++ b/arch/arm/mach-s5pv210/mach-goni.c
> @@ -105,25 +105,29 @@ static struct s3c2410_uartcfg goni_uartcfgs[] __initdata = {
>
> /* Frame Buffer */
> static struct s3c_fb_pd_win goni_fb_win0 = {
> - .win_mode = {
> - .left_margin = 16,
> - .right_margin = 16,
> - .upper_margin = 2,
> - .lower_margin = 28,
> - .hsync_len = 2,
> - .vsync_len = 1,
> - .xres = 480,
> - .yres = 800,
> - .refresh = 55,
> - },
> .max_bpp = 32,
> .default_bpp = 16,
> + .xres = 480,
> + .yres = 800,
> .virtual_x = 480,
> .virtual_y = 2 * 800,
> };
>
> +static struct fb_videomode goni_lcd_timing = {
> + .left_margin = 16,
> + .right_margin = 16,
> + .upper_margin = 2,
> + .lower_margin = 28,
> + .hsync_len = 2,
> + .vsync_len = 1,
> + .xres = 480,
> + .yres = 800,
> + .refresh = 55,
> +};
> +
> static struct s3c_fb_platdata goni_lcd_pdata __initdata = {
> .win[0] = &goni_fb_win0,
> + .vtiming = &goni_lcd_timing,
> .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB |
> VIDCON0_CLKSEL_LCD,
> .vidcon1 = VIDCON1_INV_VCLK | VIDCON1_INV_VDEN
> diff --git a/arch/arm/mach-s5pv210/mach-smdkv210.c b/arch/arm/mach-s5pv210/mach-smdkv210.c
> index 91d4ad8..5e0c955 100644
> --- a/arch/arm/mach-s5pv210/mach-smdkv210.c
> +++ b/arch/arm/mach-s5pv210/mach-smdkv210.c
> @@ -189,22 +189,26 @@ static struct platform_device smdkv210_lcd_lte480wv = {
> };
>
> static struct s3c_fb_pd_win smdkv210_fb_win0 = {
> - .win_mode = {
> - .left_margin = 13,
> - .right_margin = 8,
> - .upper_margin = 7,
> - .lower_margin = 5,
> - .hsync_len = 3,
> - .vsync_len = 1,
> - .xres = 800,
> - .yres = 480,
> - },
> .max_bpp = 32,
> .default_bpp = 24,
> + .xres = 800,
> + .yres = 480,
> +};
> +
> +static struct fb_videomode smdkv210_lcd_timing = {
> + .left_margin = 13,
> + .right_margin = 8,
> + .upper_margin = 7,
> + .lower_margin = 5,
> + .hsync_len = 3,
> + .vsync_len = 1,
> + .xres = 800,
> + .yres = 480,
> };
>
> static struct s3c_fb_platdata smdkv210_lcd0_pdata __initdata = {
> .win[0] = &smdkv210_fb_win0,
> + .vtiming = &smdkv210_lcd_timing,
> .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
> .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
> .setup_gpio = s5pv210_fb_gpio_setup_24bpp,
> --
> 1.6.6.rc2
^ permalink raw reply
* Re: [PATCH v3 3/4] ARM: s3c64xx: Decouple lcd type from display controller window data
From: Jingoo Han @ 2012-03-28 10:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1332606528-32338-4-git-send-email-thomas.abraham@linaro.org>
On 25 March 2012 01:29, Thomas Abraham < thomas.abraham@linaro.org> wrote:
> Subject: [PATCH v3 3/4] ARM: s3c64xx: Decouple lcd type from display controller window data
>
> The display controller window data should contain window configuration data
> for only one type of lcd panel. So, for real6410 and mini6410 boards, split
> the existing display controller window data, which contains window
> configuration data for two different types of lcd panels, into two seperate
> instances and register one of them depending on the type of the lcd panel
> detected at runtime.
>
> This is a prerequisite change for a subsequent commit that reorders the
> platform data of display controller by moving video interface timing out
> of window setup data.
>
> Cc: Darius Augulis <augulis.darius@gmail.com>
> Cc: Jingoo Han <jg1.han@samsung.com>
It looks good.
Acked-by: Jingoo Han <jg1.han@samsung.com>
> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
> ---
> arch/arm/mach-s3c64xx/mach-mini6410.c | 82 +++++++++++++++++---------------
> arch/arm/mach-s3c64xx/mach-real6410.c | 82 +++++++++++++++++---------------
> 2 files changed, 88 insertions(+), 76 deletions(-)
>
> diff --git a/arch/arm/mach-s3c64xx/mach-mini6410.c b/arch/arm/mach-s3c64xx/mach-mini6410.c
> index c34c2ab..34f5195 100644
> --- a/arch/arm/mach-s3c64xx/mach-mini6410.c
> +++ b/arch/arm/mach-s3c64xx/mach-mini6410.c
> @@ -151,41 +151,49 @@ static struct s3c2410_platform_nand mini6410_nand_info = {
> .sets = mini6410_nand_sets,
> };
>
> -static struct s3c_fb_pd_win mini6410_fb_win[] = {
> - {
> - .win_mode = { /* 4.3" 480x272 */
> - .left_margin = 3,
> - .right_margin = 2,
> - .upper_margin = 1,
> - .lower_margin = 1,
> - .hsync_len = 40,
> - .vsync_len = 1,
> - .xres = 480,
> - .yres = 272,
> - },
> - .max_bpp = 32,
> - .default_bpp = 16,
> - }, {
> - .win_mode = { /* 7.0" 800x480 */
> - .left_margin = 8,
> - .right_margin = 13,
> - .upper_margin = 7,
> - .lower_margin = 5,
> - .hsync_len = 3,
> - .vsync_len = 1,
> - .xres = 800,
> - .yres = 480,
> - },
> - .max_bpp = 32,
> - .default_bpp = 16,
> +static struct s3c_fb_pd_win mini6410_lcd_type0_fb_win = {
> + .win_mode = { /* 4.3" 480x272 */
> + .left_margin = 3,
> + .right_margin = 2,
> + .upper_margin = 1,
> + .lower_margin = 1,
> + .hsync_len = 40,
> + .vsync_len = 1,
> + .xres = 480,
> + .yres = 272,
> },
> + .max_bpp = 32,
> + .default_bpp = 16,
> };
>
> -static struct s3c_fb_platdata mini6410_lcd_pdata __initdata = {
> - .setup_gpio = s3c64xx_fb_gpio_setup_24bpp,
> - .win[0] = &mini6410_fb_win[0],
> - .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
> - .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
> +static struct s3c_fb_pd_win mini6410_lcd_type1_fb_win = {
> + .win_mode = { /* 7.0" 800x480 */
> + .left_margin = 8,
> + .right_margin = 13,
> + .upper_margin = 7,
> + .lower_margin = 5,
> + .hsync_len = 3,
> + .vsync_len = 1,
> + .xres = 800,
> + .yres = 480,
> + },
> + .max_bpp = 32,
> + .default_bpp = 16,
> +};
> +
> +static struct s3c_fb_platdata mini6410_lcd_pdata[] __initdata = {
> + {
> + .setup_gpio = s3c64xx_fb_gpio_setup_24bpp,
> + .win[0] = &mini6410_lcd_type0_fb_win,
> + .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
> + .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
> + }, {
> + .setup_gpio = s3c64xx_fb_gpio_setup_24bpp,
> + .win[0] = &mini6410_lcd_type1_fb_win,
> + .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
> + .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
> + },
> + { },
> };
>
> static void mini6410_lcd_power_set(struct plat_lcd_data *pd,
> @@ -283,7 +291,7 @@ static void mini6410_parse_features(
> "screen type already set\n", f);
> } else {
> int li = f - '0';
> - if (li >= ARRAY_SIZE(mini6410_fb_win))
> + if (li >= ARRAY_SIZE(mini6410_lcd_pdata))
> printk(KERN_INFO "MINI6410: '%c' out "
> "of range LCD mode\n", f);
> else {
> @@ -307,14 +315,12 @@ static void __init mini6410_machine_init(void)
> /* Parse the feature string */
> mini6410_parse_features(&features, mini6410_features_str);
>
> - mini6410_lcd_pdata.win[0] = &mini6410_fb_win[features.lcd_index];
> -
> printk(KERN_INFO "MINI6410: selected LCD display is %dx%d\n",
> - mini6410_lcd_pdata.win[0]->win_mode.xres,
> - mini6410_lcd_pdata.win[0]->win_mode.yres);
> + mini6410_lcd_pdata[features.lcd_index].win[0]->win_mode.xres,
> + mini6410_lcd_pdata[features.lcd_index].win[0]->win_mode.yres);
>
> s3c_nand_set_platdata(&mini6410_nand_info);
> - s3c_fb_set_platdata(&mini6410_lcd_pdata);
> + s3c_fb_set_platdata(&mini6410_lcd_pdata[features.lcd_index]);
> s3c24xx_ts_set_platdata(NULL);
>
> /* configure nCS1 width to 16 bits */
> diff --git a/arch/arm/mach-s3c64xx/mach-real6410.c b/arch/arm/mach-s3c64xx/mach-real6410.c
> index be2a9a2..21f91e5 100644
> --- a/arch/arm/mach-s3c64xx/mach-real6410.c
> +++ b/arch/arm/mach-s3c64xx/mach-real6410.c
> @@ -117,41 +117,49 @@ static struct platform_device real6410_device_eth = {
> },
> };
>
> -static struct s3c_fb_pd_win real6410_fb_win[] = {
> - {
> - .win_mode = { /* 4.3" 480x272 */
> - .left_margin = 3,
> - .right_margin = 2,
> - .upper_margin = 1,
> - .lower_margin = 1,
> - .hsync_len = 40,
> - .vsync_len = 1,
> - .xres = 480,
> - .yres = 272,
> - },
> - .max_bpp = 32,
> - .default_bpp = 16,
> - }, {
> - .win_mode = { /* 7.0" 800x480 */
> - .left_margin = 8,
> - .right_margin = 13,
> - .upper_margin = 7,
> - .lower_margin = 5,
> - .hsync_len = 3,
> - .vsync_len = 1,
> - .xres = 800,
> - .yres = 480,
> - },
> - .max_bpp = 32,
> - .default_bpp = 16,
> +static struct s3c_fb_pd_win real6410_lcd_type0_fb_win = {
> + .win_mode = { /* 4.3" 480x272 */
> + .left_margin = 3,
> + .right_margin = 2,
> + .upper_margin = 1,
> + .lower_margin = 1,
> + .hsync_len = 40,
> + .vsync_len = 1,
> + .xres = 480,
> + .yres = 272,
> },
> + .max_bpp = 32,
> + .default_bpp = 16,
> };
>
> -static struct s3c_fb_platdata real6410_lcd_pdata __initdata = {
> - .setup_gpio = s3c64xx_fb_gpio_setup_24bpp,
> - .win[0] = &real6410_fb_win[0],
> - .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
> - .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
> +static struct s3c_fb_pd_win real6410_lcd_type1_fb_win = {
> + .win_mode = { /* 7.0" 800x480 */
> + .left_margin = 8,
> + .right_margin = 13,
> + .upper_margin = 7,
> + .lower_margin = 5,
> + .hsync_len = 3,
> + .vsync_len = 1,
> + .xres = 800,
> + .yres = 480,
> + },
> + .max_bpp = 32,
> + .default_bpp = 16,
> +};
> +
> +static struct s3c_fb_platdata real6410_lcd_pdata[] __initdata = {
> + {
> + .setup_gpio = s3c64xx_fb_gpio_setup_24bpp,
> + .win[0] = &real6410_lcd_type0_fb_win,
> + .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
> + .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
> + }, {
> + .setup_gpio = s3c64xx_fb_gpio_setup_24bpp,
> + .win[0] = &real6410_lcd_type1_fb_win,
> + .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
> + .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
> + },
> + { },
> };
>
> static struct mtd_partition real6410_nand_part[] = {
> @@ -264,7 +272,7 @@ static void real6410_parse_features(
> "screen type already set\n", f);
> } else {
> int li = f - '0';
> - if (li >= ARRAY_SIZE(real6410_fb_win))
> + if (li >= ARRAY_SIZE(real6410_lcd_pdata))
> printk(KERN_INFO "REAL6410: '%c' out "
> "of range LCD mode\n", f);
> else {
> @@ -288,13 +296,11 @@ static void __init real6410_machine_init(void)
> /* Parse the feature string */
> real6410_parse_features(&features, real6410_features_str);
>
> - real6410_lcd_pdata.win[0] = &real6410_fb_win[features.lcd_index];
> -
> printk(KERN_INFO "REAL6410: selected LCD display is %dx%d\n",
> - real6410_lcd_pdata.win[0]->win_mode.xres,
> - real6410_lcd_pdata.win[0]->win_mode.yres);
> + real6410_lcd_pdata[features.lcd_index].win[0]->win_mode.xres,
> + real6410_lcd_pdata[features.lcd_index].win[0]->win_mode.yres);
>
> - s3c_fb_set_platdata(&real6410_lcd_pdata);
> + s3c_fb_set_platdata(&real6410_lcd_pdata[features.lcd_index]);
> s3c_nand_set_platdata(&real6410_nand_info);
> s3c24xx_ts_set_platdata(NULL);
>
> --
> 1.6.6.rc2
^ permalink raw reply
* Re: [PATCH] video:uvesafb: Fix oops that uvesafb try to execute NX-protected page
From: Hein_Tibosch @ 2012-03-28 15:36 UTC (permalink / raw)
To: Alan Cox
Cc: Wang YanQing, FlorianSchandinat, linux-fbdev, linux-kernel, spock
In-Reply-To: <20120327143243.015ecff6@pyramind.ukuu.org.uk>
On 3/27/2012 9:32 PM, Alan Cox wrote:
> On Tue, 27 Mar 2012 18:01:36 +0800
> Wang YanQing <udknight@gmail.com> wrote:
>
>> Ok! I try to check pcibios_enabled first, but get some opposition by Alan Cox,
>> but I want to make thing work and fix the oops, so I choice the simple way to
>> check the (__supported_pte_mask & _PAGE_NX) instead of to check this variable plus
>> pci kernel boot parameter, pci mmconfig works or not, and more, and more. It is not
>> the best method, but it works and maybe all will feel happy.
> Okay let me ask the obvious question - why is it not the best method ?
>
> Apart from adding a helper in the includes for the arch code of
>
> static inline is_nx_enabled(void)
> {
> return !!(__supported_pte_mask & _PAGE_NX);
> }
>
> is there anything else it lacks ?
maybe giving this inline function a return type ?
^ permalink raw reply
* [PATCH 0/4] video: add support for the AUO-K190X epd controllers
From: Heiko Stübner @ 2012-03-28 17:32 UTC (permalink / raw)
To: linux-fbdev
This series adds basic support for the AUO-K190X family of epaper
controllers which consists at the moment of the K1900 and K1901.
These controllers are used mostly in the OEM line of Qisda ebook readers
sold under different brands worldwide. Among those are the Medion/Thalia
Oyo 1 + 2, the bq Avant and Avant 3, the Asus eeeReader DR-900, BenQ K60
and dozens more.
The _dpy_update, _dpy_update_pages and _need_refresh functions are
intentional duplicated. Currently they do the same, but as the
controllers emit a greatly different runtime behaviour there is a lot
of room for future controller-specific performance improvements.
The series also includes the patch which adds a first_io callback to
defio. This creates a nice way to parallelise the wakup when it is known
that the controller is needed at the end of the defio cycle.
Heiko Stuebner (4):
fb_defio: add first_io callback
video: auo_k190x: add code shared by controller drivers
video: auo_k190x: add driver for AUO-K1900 variant
video: auo_k190x: add driver for the AUO-K1901 variant
drivers/video/Kconfig | 28 ++
drivers/video/Makefile | 3 +
drivers/video/auo_k1900fb.c | 198 ++++++++
drivers/video/auo_k1901fb.c | 251 +++++++++++
drivers/video/auo_k190x.c | 1038 +++++++++++++++++++++++++++++++++++++++++++
drivers/video/auo_k190x.h | 129 ++++++
drivers/video/fb_defio.c | 4 +
include/linux/fb.h | 1 +
include/video/auo_k190xfb.h | 106 +++++
9 files changed, 1758 insertions(+), 0 deletions(-)
create mode 100644 drivers/video/auo_k1900fb.c
create mode 100644 drivers/video/auo_k1901fb.c
create mode 100644 drivers/video/auo_k190x.c
create mode 100644 drivers/video/auo_k190x.h
create mode 100644 include/video/auo_k190xfb.h
--
1.7.5.4
^ permalink raw reply
* [PATCH 1/4] fb_defio: add first_io callback
From: Heiko Stübner @ 2012-03-28 17:33 UTC (permalink / raw)
To: linux-fbdev
With this optional callback the driver is notified when the first page
is entered into the pagelist and a new deferred_io call is scheduled.
A possible use-case for this is runtime-pm. In the first_io call
pm_runtime_get()
could be called, which starts an asynchronous runtime_resume of the
device. In the deferred_io callback a call to
pm_runtime_barrier()
makes the sure, the device is resumed by then and a
pm_runtime_put()
may put the device back to sleep.
Also, some SoCs may use the runtime-pm system to determine if they
are able to enter deeper idle states. Therefore it is necessary to
keep the use-count from the first written page until the conclusion
of the screen update, to prevent the system from going to sleep before
completing the pending update.
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
drivers/video/fb_defio.c | 4 ++++
include/linux/fb.h | 1 +
2 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c
index c27e153..070f26f 100644
--- a/drivers/video/fb_defio.c
+++ b/drivers/video/fb_defio.c
@@ -107,6 +107,10 @@ static int fb_deferred_io_mkwrite(struct vm_area_struct *vma,
/* protect against the workqueue changing the page list */
mutex_lock(&fbdefio->lock);
+ /* first write in this cycle, notify the driver */
+ if (fbdefio->first_io && list_empty(&fbdefio->pagelist))
+ fbdefio->first_io(info);
+
/*
* We want the page to remain locked from ->page_mkwrite until
* the PTE is marked dirty to avoid page_mkclean() being called
diff --git a/include/linux/fb.h b/include/linux/fb.h
index d31cb68..c10e71e 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -607,6 +607,7 @@ struct fb_deferred_io {
struct mutex lock; /* mutex that protects the page list */
struct list_head pagelist; /* list of touched pages */
/* callback */
+ void (*first_io)(struct fb_info *info);
void (*deferred_io)(struct fb_info *info, struct list_head *pagelist);
};
#endif
--
1.7.5.4
^ permalink raw reply related
* [PATCH 2/4] video: auo_k190x: add code shared by controller drivers
From: Heiko Stübner @ 2012-03-28 17:34 UTC (permalink / raw)
To: linux-fbdev
The AUO-K190X controllers share a very similar set of commands and
can therefore also share most of the driver code.
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
drivers/video/Kconfig | 10 +
drivers/video/Makefile | 1 +
drivers/video/auo_k190x.c | 1038 +++++++++++++++++++++++++++++++++++++++++++
drivers/video/auo_k190x.h | 129 ++++++
include/video/auo_k190xfb.h | 106 +++++
5 files changed, 1284 insertions(+), 0 deletions(-)
create mode 100644 drivers/video/auo_k190x.c
create mode 100644 drivers/video/auo_k190x.h
create mode 100644 include/video/auo_k190xfb.h
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index a290be5..89c7394 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2382,6 +2382,16 @@ config FB_BROADSHEET
and could also have been called by other names when coupled with
a bridge adapter.
+config FB_AUO_K190X
+ tristate
+ select FB_SYS_FILLRECT
+ select FB_SYS_COPYAREA
+ select FB_SYS_IMAGEBLIT
+ select FB_SYS_FOPS
+ select FB_DEFERRED_IO
+ help
+ Internal config node for K190X common code
+
config FB_JZ4740
tristate "JZ4740 LCD framebuffer support"
depends on FB && MACH_JZ4740
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 9356add..d5406f2 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -118,6 +118,7 @@ obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o
obj-$(CONFIG_FB_MAXINE) += maxinefb.o
obj-$(CONFIG_FB_METRONOME) += metronomefb.o
obj-$(CONFIG_FB_BROADSHEET) += broadsheetfb.o
+obj-$(CONFIG_FB_AUO_K190X) += auo_k190x.o
obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o
obj-$(CONFIG_FB_SH7760) += sh7760fb.o
obj-$(CONFIG_FB_IMX) += imxfb.o
diff --git a/drivers/video/auo_k190x.c b/drivers/video/auo_k190x.c
new file mode 100644
index 0000000..d317137
--- /dev/null
+++ b/drivers/video/auo_k190x.c
@@ -0,0 +1,1038 @@
+/*
+ * Common code for AUO-K190X framebuffer drivers
+ *
+ * Copyright (C) 2012 Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/pm_runtime.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/auo_k190xfb.h>
+
+#include "auo_k190x.h"
+
+struct panel_info {
+ int w;
+ int h;
+};
+
+/* table of panel specific parameters to be indexed into by the board drivers */
+static struct panel_info panel_table[] = {
+ /* standard 6" */
+ [AUOK190X_RESOLUTION_800_600] = {
+ .w = 800,
+ .h = 600,
+ },
+ /* standard 9" */
+ [AUOK190X_RESOLUTION_1024_768] = {
+ .w = 1024,
+ .h = 768,
+ },
+};
+
+/*
+ * private I80 interface to the board driver
+ */
+
+static void auok190x_issue_data(struct auok190xfb_par *par, u16 data)
+{
+ par->board->set_ctl(par, AUOK190X_I80_WR, 0);
+ par->board->set_hdb(par, data);
+ par->board->set_ctl(par, AUOK190X_I80_WR, 1);
+}
+
+static void auok190x_issue_cmd(struct auok190xfb_par *par, u16 data)
+{
+ par->board->set_ctl(par, AUOK190X_I80_DC, 0);
+ auok190x_issue_data(par, data);
+ par->board->set_ctl(par, AUOK190X_I80_DC, 1);
+}
+
+static int auok190x_issue_pixels(struct auok190xfb_par *par, int size,
+ u16 *data)
+{
+ struct device *dev = par->info->device;
+ int i;
+ u16 tmp;
+
+ if (size & 3) {
+ dev_err(dev, "issue_pixels: size %d must be a multiple of 4\n",
+ size);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < (size >> 1); i++) {
+ par->board->set_ctl(par, AUOK190X_I80_WR, 0);
+
+ /* simple reduction of 8bit staticgray to 4bit gray
+ * combines 4 * 4bit pixel values into a 16bit value
+ */
+ tmp = (data[2*i] & 0xF0) >> 4;
+ tmp |= (data[2*i] & 0xF000) >> 8;
+ tmp |= (data[2*i+1] & 0xF0) << 4;
+ tmp |= (data[2*i+1] & 0xF000);
+
+ par->board->set_hdb(par, tmp);
+ par->board->set_ctl(par, AUOK190X_I80_WR, 1);
+ }
+
+ return 0;
+}
+
+static u16 auok190x_read_data(struct auok190xfb_par *par)
+{
+ u16 data;
+
+ par->board->set_ctl(par, AUOK190X_I80_OE, 0);
+ data = par->board->get_hdb(par);
+ par->board->set_ctl(par, AUOK190X_I80_OE, 1);
+
+ return data;
+}
+
+/*
+ * Command interface for the controller drivers
+ */
+
+void auok190x_send_command_nowait(struct auok190xfb_par *par, u16 data)
+{
+ par->board->set_ctl(par, AUOK190X_I80_CS, 0);
+ auok190x_issue_cmd(par, data);
+ par->board->set_ctl(par, AUOK190X_I80_CS, 1);
+}
+EXPORT_SYMBOL_GPL(auok190x_send_command_nowait);
+
+void auok190x_send_cmdargs_nowait(struct auok190xfb_par *par, u16 cmd,
+ int argc, u16 *argv)
+{
+ int i;
+
+ par->board->set_ctl(par, AUOK190X_I80_CS, 0);
+ auok190x_issue_cmd(par, cmd);
+
+ for (i = 0; i < argc; i++)
+ auok190x_issue_data(par, argv[i]);
+ par->board->set_ctl(par, AUOK190X_I80_CS, 1);
+}
+EXPORT_SYMBOL_GPL(auok190x_send_cmdargs_nowait);
+
+int auok190x_send_command(struct auok190xfb_par *par, u16 data)
+{
+ int ret;
+
+ ret = par->board->wait_for_rdy(par);
+ if (ret)
+ return ret;
+
+ auok190x_send_command_nowait(par, data);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(auok190x_send_command);
+
+int auok190x_send_cmdargs(struct auok190xfb_par *par, u16 cmd,
+ int argc, u16 *argv)
+{
+ int ret;
+
+ ret = par->board->wait_for_rdy(par);
+ if (ret)
+ return ret;
+
+ auok190x_send_cmdargs_nowait(par, cmd, argc, argv);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(auok190x_send_cmdargs);
+
+int auok190x_read_cmdargs(struct auok190xfb_par *par, u16 cmd,
+ int argc, u16 *argv)
+{
+ int i, ret;
+
+ ret = par->board->wait_for_rdy(par);
+ if (ret)
+ return ret;
+
+ par->board->set_ctl(par, AUOK190X_I80_CS, 0);
+ auok190x_issue_cmd(par, cmd);
+
+ for (i = 0; i < argc; i++)
+ argv[i] = auok190x_read_data(par);
+ par->board->set_ctl(par, AUOK190X_I80_CS, 1);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(auok190x_read_cmdargs);
+
+void auok190x_send_cmdargs_pixels_nowait(struct auok190xfb_par *par, u16 cmd,
+ int argc, u16 *argv, int size, u16 *data)
+{
+ int i;
+
+ par->board->set_ctl(par, AUOK190X_I80_CS, 0);
+
+ auok190x_issue_cmd(par, cmd);
+
+ for (i = 0; i < argc; i++)
+ auok190x_issue_data(par, argv[i]);
+
+ auok190x_issue_pixels(par, size, data);
+
+ par->board->set_ctl(par, AUOK190X_I80_CS, 1);
+}
+EXPORT_SYMBOL_GPL(auok190x_send_cmdargs_pixels_nowait);
+
+int auok190x_send_cmdargs_pixels(struct auok190xfb_par *par, u16 cmd,
+ int argc, u16 *argv, int size, u16 *data)
+{
+ int ret;
+
+ ret = par->board->wait_for_rdy(par);
+ if (ret)
+ return ret;
+
+ auok190x_send_cmdargs_pixels_nowait(par, cmd, argc, argv, size, data);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(auok190x_send_cmdargs_pixels);
+
+/*
+ * fbdefio callbacks - common on both controllers.
+ */
+
+static void auok190xfb_dpy_first_io(struct fb_info *info)
+{
+ /* tell runtime-pm that we wish to use the device in a short time */
+ pm_runtime_get(info->device);
+}
+
+/* this is called back from the deferred io workqueue */
+static void auok190xfb_dpy_deferred_io(struct fb_info *info,
+ struct list_head *pagelist)
+{
+ struct fb_deferred_io *fbdefio = info->fbdefio;
+ struct auok190xfb_par *par = info->par;
+ u16 yres = info->var.yres;
+ u16 xres = info->var.xres;
+ u16 y1 = 0, h = 0;
+ int prev_index = -1;
+ struct page *cur;
+ int h_inc;
+ int threshold;
+
+ /* the device resume should be requested through first_io,
+ * if the resume did not finish until now, wait for it */
+ pm_runtime_barrier(info->device);
+
+ /* Do a full screen update every n updates to prevent
+ * excessive darkening of the Sipix display.
+ * If we do this, there is no need to walk the pages.
+ */
+ if (par->need_refresh(par)) {
+ par->update_all(par);
+ goto out;
+ }
+
+ /* height increment is fixed per page */
+ h_inc = DIV_ROUND_UP(PAGE_SIZE , xres);
+
+ /* calculate number of pages from pixel height */
+ threshold = par->consecutive_threshold / h_inc;
+ if (threshold < 1)
+ threshold = 1;
+
+ /* walk the written page list and swizzle the data */
+ list_for_each_entry(cur, &fbdefio->pagelist, lru) {
+ if (prev_index < 0) {
+ /* just starting so assign first page */
+ y1 = (cur->index << PAGE_SHIFT) / xres;
+ h = h_inc;
+ } else if ((cur->index - prev_index) <= threshold) {
+ /* page is within our threshold for single updates */
+ h += h_inc * (cur->index - prev_index);
+ } else {
+ /* page not consecutive, issue previous update first */
+ par->update_partial(par, y1, y1 + h);
+
+ /* start over with our non consecutive page */
+ y1 = (cur->index << PAGE_SHIFT) / xres;
+ h = h_inc;
+ }
+ prev_index = cur->index;
+ }
+
+ /* if we still have any pages to update we do so now */
+ if (h >= yres)
+ /* its a full screen update, just do it */
+ par->update_all(par);
+ else
+ par->update_partial(par, y1, min((u16) (y1 + h), yres));
+
+out:
+ pm_runtime_mark_last_busy(info->device);
+ pm_runtime_put_autosuspend(info->device);
+}
+
+/*
+ * framebuffer operations
+ */
+
+/*
+ * this is the slow path from userspace. they can seek and write to
+ * the fb. it's inefficient to do anything less than a full screen draw
+ */
+static ssize_t auok190xfb_write(struct fb_info *info, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct auok190xfb_par *par = info->par;
+ unsigned long p = *ppos;
+ void *dst;
+ int err = 0;
+ unsigned long total_size;
+
+ if (info->state != FBINFO_STATE_RUNNING)
+ return -EPERM;
+
+ total_size = info->fix.smem_len;
+
+ if (p > total_size)
+ return -EFBIG;
+
+ if (count > total_size) {
+ err = -EFBIG;
+ count = total_size;
+ }
+
+ if (count + p > total_size) {
+ if (!err)
+ err = -ENOSPC;
+
+ count = total_size - p;
+ }
+
+ dst = (void *)(info->screen_base + p);
+
+ if (copy_from_user(dst, buf, count))
+ err = -EFAULT;
+
+ if (!err)
+ *ppos += count;
+
+ par->update_all(par);
+
+ return (err) ? err : count;
+}
+
+static void auok190xfb_fillrect(struct fb_info *info,
+ const struct fb_fillrect *rect)
+{
+ struct auok190xfb_par *par = info->par;
+
+ sys_fillrect(info, rect);
+
+ par->update_all(par);
+}
+
+static void auok190xfb_copyarea(struct fb_info *info,
+ const struct fb_copyarea *area)
+{
+ struct auok190xfb_par *par = info->par;
+
+ sys_copyarea(info, area);
+
+ par->update_all(par);
+}
+
+static void auok190xfb_imageblit(struct fb_info *info,
+ const struct fb_image *image)
+{
+ struct auok190xfb_par *par = info->par;
+
+ sys_imageblit(info, image);
+
+ par->update_all(par);
+}
+
+static int auok190xfb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ if (info->var.xres != var->xres || info->var.yres != var->yres ||
+ info->var.xres_virtual != var->xres_virtual ||
+ info->var.yres_virtual != var->yres_virtual) {
+ pr_info("%s: Resolution not supported: X%u x Y%u\n",
+ __func__, var->xres, var->yres);
+ return -EINVAL;
+ }
+
+ /*
+ * Memory limit
+ */
+
+ if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) {
+ pr_info("%s: Memory Limit requested yres_virtual = %u\n",
+ __func__, var->yres_virtual);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static struct fb_ops auok190xfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_read = fb_sys_read,
+ .fb_write = auok190xfb_write,
+ .fb_fillrect = auok190xfb_fillrect,
+ .fb_copyarea = auok190xfb_copyarea,
+ .fb_imageblit = auok190xfb_imageblit,
+ .fb_check_var = auok190xfb_check_var,
+};
+
+/*
+ * Controller-functions common to both K1900 and K1901
+ */
+
+static int auok190x_read_temperature(struct auok190xfb_par *par)
+{
+ struct device *dev = par->info->device;
+ u16 data[4];
+ int temp;
+
+ pm_runtime_get_sync(dev);
+
+ mutex_lock(&(par->io_lock));
+
+ auok190x_read_cmdargs(par, AUOK190X_CMD_READ_VERSION, 4, data);
+
+ mutex_unlock(&(par->io_lock));
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
+ /* sanitize and split of half-degrees for now */
+ temp = ((data[0] & AUOK190X_VERSION_TEMP_MASK) >> 1);
+
+ /* handle positive and negative temperatures */
+ if (temp >= 201)
+ return (255 - temp + 1) * (-1);
+ else
+ return temp;
+}
+
+static void auok190x_identify(struct auok190xfb_par *par)
+{
+ struct device *dev = par->info->device;
+ u16 data[4];
+
+ pm_runtime_get_sync(dev);
+
+ mutex_lock(&(par->io_lock));
+
+ auok190x_read_cmdargs(par, AUOK190X_CMD_READ_VERSION, 4, data);
+
+ mutex_unlock(&(par->io_lock));
+
+ par->epd_type = data[1] & AUOK190X_VERSION_TEMP_MASK;
+
+ par->panel_size_int = AUOK190X_VERSION_SIZE_INT(data[2]);
+ par->panel_size_float = AUOK190X_VERSION_SIZE_FLOAT(data[2]);
+ par->panel_model = AUOK190X_VERSION_MODEL(data[2]);
+
+ par->tcon_version = AUOK190X_VERSION_TCON(data[3]);
+ par->lut_version = AUOK190X_VERSION_LUT(data[3]);
+
+ dev_dbg(dev, "panel %d.%din, model 0x%x, EPD 0x%x TCON-rev 0x%x, LUT-rev 0x%x",
+ par->panel_size_int, par->panel_size_float, par->panel_model,
+ par->epd_type, par->tcon_version, par->lut_version);
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+}
+
+/*
+ * Sysfs functions
+ */
+
+static ssize_t update_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct auok190xfb_par *par = info->par;
+
+ return sprintf(buf, "%d\n", par->update_mode);
+}
+
+static ssize_t update_mode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct auok190xfb_par *par = info->par;
+ int mode, ret;
+
+ ret = kstrtoint(buf, 10, &mode);
+ if (ret)
+ return ret;
+
+ par->update_mode = mode;
+
+ /* if we enter a better mode, do a full update */
+ if (par->last_mode > 1 && mode < par->last_mode)
+ par->update_all(par);
+
+ return count;
+}
+
+static ssize_t flash_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct auok190xfb_par *par = info->par;
+
+ return sprintf(buf, "%d\n", par->flash);
+}
+
+static ssize_t flash_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct auok190xfb_par *par = info->par;
+ int flash, ret;
+
+ ret = kstrtoint(buf, 10, &flash);
+ if (ret)
+ return ret;
+
+ if (flash > 0)
+ par->flash = 1;
+ else
+ par->flash = 0;
+
+ return count;
+}
+
+static ssize_t temp_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct auok190xfb_par *par = info->par;
+ int temp;
+
+ temp = auok190x_read_temperature(par);
+ return sprintf(buf, "%d\n", temp);
+}
+
+static DEVICE_ATTR(update_mode, 0644, update_mode_show, update_mode_store);
+static DEVICE_ATTR(flash, 0644, flash_show, flash_store);
+static DEVICE_ATTR(temp, 0644, temp_show, NULL);
+
+static struct attribute *auok190x_attributes[] = {
+ &dev_attr_update_mode.attr,
+ &dev_attr_flash.attr,
+ &dev_attr_temp.attr,
+ NULL
+};
+
+static const struct attribute_group auok190x_attr_group = {
+ .attrs = auok190x_attributes,
+};
+
+static int auok190x_power(struct auok190xfb_par *par, bool on)
+{
+ struct auok190x_board *board = par->board;
+ int ret;
+
+ if (on) {
+ /* We should maintain POWER up for at least 80ms before set
+ * RST_N and SLP_N to high (TCONÂ spec 20100803_v35 p59)
+ */
+ ret = regulator_enable(par->regulator);
+ if (ret)
+ return ret;
+
+ msleep(200);
+ gpio_set_value(board->gpio_nrst, 1);
+ gpio_set_value(board->gpio_nsleep, 1);
+ msleep(200);
+ } else {
+ regulator_disable(par->regulator);
+ gpio_set_value(board->gpio_nrst, 0);
+ gpio_set_value(board->gpio_nsleep, 0);
+ }
+
+ return 0;
+}
+
+/*
+ * Recovery - powercycle the controller
+ */
+
+static void auok190x_recover(struct auok190xfb_par *par)
+{
+ auok190x_power(par, 0);
+ msleep(100);
+ auok190x_power(par, 1);
+
+ par->init(par);
+
+ /* wait for init to complete */
+ par->board->wait_for_rdy(par);
+}
+
+/*
+ * Power-management
+ */
+
+#ifdef CONFIG_PM
+static int auok190x_runtime_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fb_info *info = platform_get_drvdata(pdev);
+ struct auok190xfb_par *par = info->par;
+ struct auok190x_board *board = par->board;
+ u16 standby_param;
+
+ /* take and keep the lock until we are resumed, as the controller
+ * will never reach the non-busy state when in standby mode
+ */
+ mutex_lock(&(par->io_lock));
+
+ if (par->standby) {
+ dev_warn(dev, "already in standby, runtime-pm pairing mismatch\n");
+ mutex_unlock(&(par->io_lock));
+ return 0;
+ }
+
+ /* according to runtime_pm.txt runtime_suspend only means, that the
+ * device will not process data and will not communicate with the CPU
+ * As we hold the lock, this stays true even without standby
+ */
+ if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) {
+ dev_dbg(dev, "runtime suspend without standby\n");
+ goto finish;
+ } else if (board->quirks & AUOK190X_QUIRK_STANDBYPARAM) {
+ /* for some TCON versions STANDBY expects a parameter (0) but
+ * it seems the real tcon version has to be determined yet.
+ */
+ dev_dbg(dev, "runtime suspend with additional empty param\n");
+ standby_param = 0;
+ auok190x_send_cmdargs(par, AUOK190X_CMD_STANDBY, 1,
+ &standby_param);
+ } else {
+ dev_dbg(dev, "runtime suspend without param\n");
+ auok190x_send_command(par, AUOK190X_CMD_STANDBY);
+ }
+
+ msleep(64);
+
+finish:
+ par->standby = 1;
+
+ return 0;
+}
+
+static int auok190x_runtime_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fb_info *info = platform_get_drvdata(pdev);
+ struct auok190xfb_par *par = info->par;
+ struct auok190x_board *board = par->board;
+
+ if (!par->standby) {
+ dev_warn(dev, "not in standby, runtime-pm pairing mismatch\n");
+ return 0;
+ }
+
+ if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) {
+ dev_dbg(dev, "runtime resume without standby\n");
+ } else {
+ /* when in standby, controller is always busy
+ * and only accepts the wakeup command
+ */
+ dev_dbg(dev, "runtime resume from standby\n");
+ auok190x_send_command_nowait(par, AUOK190X_CMD_WAKEUP);
+
+ msleep(160);
+
+ /* wait for the controller to be ready and release the lock */
+ board->wait_for_rdy(par);
+ }
+
+ par->standby = 0;
+
+ mutex_unlock(&(par->io_lock));
+
+ return 0;
+}
+
+static int auok190x_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fb_info *info = platform_get_drvdata(pdev);
+ struct auok190xfb_par *par = info->par;
+ struct auok190x_board *board = par->board;
+ int ret;
+
+ dev_dbg(dev, "suspend\n");
+ if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) {
+ /* suspend via powering off the ic */
+ dev_dbg(dev, "suspend with broken standby\n");
+
+ auok190x_power(par, 0);
+ } else {
+ dev_dbg(dev, "suspend using sleep\n");
+
+ /* the sleep state can only be entered from the standby state.
+ * pm_runtime_get_noresume gets called before the suspend call.
+ * So the devices usage count is >0 but it is not necessarily
+ * active.
+ */
+ if (!pm_runtime_status_suspended(dev)) {
+ ret = auok190x_runtime_suspend(dev);
+ if (ret < 0) {
+ dev_err(dev, "auok190x_runtime_suspend failed with %d\n",
+ ret);
+ return ret;
+ }
+ par->manual_standby = 1;
+ }
+
+ gpio_direction_output(board->gpio_nsleep, 0);
+ }
+
+ msleep(100);
+
+ return 0;
+}
+
+static int auok190x_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fb_info *info = platform_get_drvdata(pdev);
+ struct auok190xfb_par *par = info->par;
+ struct auok190x_board *board = par->board;
+
+ dev_dbg(dev, "resume\n");
+ if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) {
+ dev_dbg(dev, "resume with broken standby\n");
+
+ auok190x_power(par, 1);
+
+ par->init(par);
+ } else {
+ dev_dbg(dev, "resume from sleep\n");
+
+ /* device should be in runtime suspend when we were suspended
+ * and pm_runtime_put_sync gets called after this function.
+ * So there is no need to touch the standby mode here at all.
+ */
+ gpio_direction_output(board->gpio_nsleep, 1);
+ msleep(100);
+
+ /* an additional init call seems to be necessary after sleep */
+ auok190x_runtime_resume(dev);
+ par->init(par);
+
+ /* if we were runtime-suspended before, suspend again*/
+ if (!par->manual_standby)
+ auok190x_runtime_suspend(dev);
+ else
+ par->manual_standby = 0;
+ }
+
+ return 0;
+}
+#endif
+
+const struct dev_pm_ops auok190x_pm = {
+ SET_RUNTIME_PM_OPS(auok190x_runtime_suspend, auok190x_runtime_resume,
+ NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(auok190x_suspend, auok190x_resume)
+};
+EXPORT_SYMBOL_GPL(auok190x_pm);
+
+/*
+ * Common probe and remove code
+ */
+
+int __devinit auok190x_common_probe(struct platform_device *pdev,
+ struct auok190x_init_data *init)
+{
+ struct auok190x_board *board = init->board;
+ struct auok190xfb_par *par;
+ struct fb_info *info;
+ struct panel_info *panel;
+ int videomemorysize, ret;
+ unsigned char *videomemory;
+
+ /* check board contents */
+ if (!board->init || !board->cleanup || !board->wait_for_rdy
+ || !board->set_ctl || !board->set_hdb || !board->get_hdb
+ || !board->setup_irq)
+ return -EINVAL;
+
+ info = framebuffer_alloc(sizeof(struct auok190xfb_par), &pdev->dev);
+ if (!info)
+ return -ENOMEM;
+
+ par = info->par;
+ par->info = info;
+ par->board = board;
+ par->recover = auok190x_recover;
+ par->update_partial = init->update_partial;
+ par->update_all = init->update_all;
+ par->need_refresh = init->need_refresh;
+ par->init = init->init;
+
+ /* init update modes */
+ par->update_cnt = 0;
+ par->update_mode = -1;
+ par->last_mode = -1;
+ par->flash = 0;
+
+ par->regulator = regulator_get(info->device, "vdd");
+ if (IS_ERR(par->regulator)) {
+ ret = PTR_ERR(par->regulator);
+ dev_err(info->device, "Failed to get regulator: %d\n", ret);
+ goto err_reg;
+ }
+
+ ret = board->init(par);
+ if (ret) {
+ dev_err(info->device, "board init failed, %d\n", ret);
+ goto err_board;
+ }
+
+ ret = gpio_request(board->gpio_nsleep, "AUOK190x sleep");
+ if (ret) {
+ dev_err(info->device, "could not request sleep gpio, %d\n",
+ ret);
+ goto err_gpio1;
+ }
+
+ ret = gpio_direction_output(board->gpio_nsleep, 0);
+ if (ret) {
+ dev_err(info->device, "could not set sleep gpio, %d\n", ret);
+ goto err_gpio2;
+ }
+
+ ret = gpio_request(board->gpio_nrst, "AUOK190x reset");
+ if (ret) {
+ dev_err(info->device, "could not request reset gpio, %d\n",
+ ret);
+ goto err_gpio2;
+ }
+
+ ret = gpio_direction_output(board->gpio_nrst, 0);
+ if (ret) {
+ dev_err(info->device, "could not set reset gpio, %d\n", ret);
+ goto err_gpio3;
+ }
+
+ ret = auok190x_power(par, 1);
+ if (ret) {
+ dev_err(info->device, "could not power on the device, %d\n",
+ ret);
+ goto err_gpio3;
+ }
+
+ mutex_init(&par->io_lock);
+
+ init_waitqueue_head(&par->waitq);
+
+ ret = par->board->setup_irq(par->info);
+ if (ret) {
+ dev_err(info->device, "could not setup ready-irq, %d\n", ret);
+ goto err_irq;
+ }
+
+ /* wait for init to complete */
+ par->board->wait_for_rdy(par);
+
+ /*
+ * From here on the controller can talk to us
+ */
+
+ /* initialise fix, var, resolution and rotation */
+
+ strlcpy(info->fix.id, init->id, 16);
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
+ info->fix.xpanstep = 0;
+ info->fix.ypanstep = 0;
+ info->fix.ywrapstep = 0;
+ info->fix.accel = FB_ACCEL_NONE;
+
+ info->var.bits_per_pixel = 8;
+ info->var.grayscale = 1;
+ info->var.red.length = 8;
+ info->var.green.length = 8;
+ info->var.blue.length = 8;
+
+ panel = &panel_table[board->resolution];
+
+ /* if 90 degree rotation, switch width and height */
+ if (board->rotation & 1) {
+ info->var.xres = panel->h;
+ info->var.yres = panel->w;
+ info->var.xres_virtual = panel->h;
+ info->var.yres_virtual = panel->w;
+ info->fix.line_length = panel->h;
+ } else {
+ info->var.xres = panel->w;
+ info->var.yres = panel->h;
+ info->var.xres_virtual = panel->w;
+ info->var.yres_virtual = panel->h;
+ info->fix.line_length = panel->w;
+ }
+
+ par->resolution = board->resolution;
+ par->rotation = board->rotation;
+
+ /* videomemory handling */
+
+ videomemorysize = roundup((panel->w * panel->h), PAGE_SIZE);
+ videomemory = vmalloc(videomemorysize);
+ if (!videomemory) {
+ ret = -ENOMEM;
+ goto err_irq;
+ }
+
+ memset(videomemory, 0, videomemorysize);
+ info->screen_base = (char *)videomemory;
+ info->fix.smem_len = videomemorysize;
+
+ info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
+ info->fbops = &auok190xfb_ops;
+
+ /* deferred io init */
+
+ info->fbdefio = devm_kzalloc(info->device,
+ sizeof(struct fb_deferred_io),
+ GFP_KERNEL);
+ if (!info->fbdefio) {
+ dev_err(info->device, "Failed to allocate memory\n");
+ ret = -ENOMEM;
+ goto err_defio;
+ }
+
+ dev_dbg(info->device, "targetting %d frames per second\n", board->fps);
+ info->fbdefio->delay = HZ / board->fps;
+ info->fbdefio->first_io = auok190xfb_dpy_first_io,
+ info->fbdefio->deferred_io = auok190xfb_dpy_deferred_io,
+ fb_deferred_io_init(info);
+
+ /* color map */
+
+ ret = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (ret < 0) {
+ dev_err(info->device, "Failed to allocate colormap\n");
+ goto err_cmap;
+ }
+
+ /* controller init */
+
+ par->consecutive_threshold = 100;
+ par->init(par);
+ auok190x_identify(par);
+
+ platform_set_drvdata(pdev, info);
+
+ ret = register_framebuffer(info);
+ if (ret < 0)
+ goto err_regfb;
+
+ ret = sysfs_create_group(&info->device->kobj, &auok190x_attr_group);
+ if (ret)
+ goto err_sysfs;
+
+ dev_info(info->device, "fb%d: %dx%d using %dK of video memory\n",
+ info->node, info->var.xres, info->var.yres,
+ videomemorysize >> 10);
+
+ /* increase autosuspend_delay when we use alternative methods
+ * for runtime_pm
+ */
+ par->autosuspend_delay = (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN)
+ ? 1000 : 200;
+
+ pm_runtime_set_active(info->device);
+ pm_runtime_enable(info->device);
+ pm_runtime_set_autosuspend_delay(info->device, par->autosuspend_delay);
+ pm_runtime_use_autosuspend(info->device);
+
+ return 0;
+
+err_sysfs:
+ unregister_framebuffer(info);
+err_regfb:
+ fb_dealloc_cmap(&info->cmap);
+err_cmap:
+ fb_deferred_io_cleanup(info);
+ kfree(info->fbdefio);
+err_defio:
+ vfree((void *)info->screen_base);
+err_irq:
+ auok190x_power(par, 0);
+err_gpio3:
+ gpio_free(board->gpio_nrst);
+err_gpio2:
+ gpio_free(board->gpio_nsleep);
+err_gpio1:
+ board->cleanup(par);
+err_board:
+ regulator_put(par->regulator);
+err_reg:
+ framebuffer_release(info);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(auok190x_common_probe);
+
+int __devexit auok190x_common_remove(struct platform_device *pdev)
+{
+ struct fb_info *info = platform_get_drvdata(pdev);
+ struct auok190xfb_par *par = info->par;
+ struct auok190x_board *board = par->board;
+
+ pm_runtime_disable(info->device);
+
+ sysfs_remove_group(&info->device->kobj, &auok190x_attr_group);
+
+ unregister_framebuffer(info);
+
+ fb_dealloc_cmap(&info->cmap);
+
+ fb_deferred_io_cleanup(info);
+ kfree(info->fbdefio);
+
+ vfree((void *)info->screen_base);
+
+ auok190x_power(par, 0);
+
+ gpio_free(board->gpio_nrst);
+ gpio_free(board->gpio_nsleep);
+
+ board->cleanup(par);
+
+ regulator_put(par->regulator);
+
+ framebuffer_release(info);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(auok190x_common_remove);
+
+MODULE_DESCRIPTION("Common code for AUO-K190X controllers");
+MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/auo_k190x.h b/drivers/video/auo_k190x.h
new file mode 100644
index 0000000..e35af1f
--- /dev/null
+++ b/drivers/video/auo_k190x.h
@@ -0,0 +1,129 @@
+/*
+ * Private common definitions for AUO-K190X framebuffer drivers
+ *
+ * Copyright (C) 2012 Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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.
+ */
+
+/*
+ * I80 interface specific defines
+ */
+
+#define AUOK190X_I80_CS 0x01
+#define AUOK190X_I80_DC 0x02
+#define AUOK190X_I80_WR 0x03
+#define AUOK190X_I80_OE 0x04
+
+/*
+ * AUOK190x commands, common to both controllers
+ */
+
+#define AUOK190X_CMD_INIT 0x0000
+#define AUOK190X_CMD_STANDBY 0x0001
+#define AUOK190X_CMD_WAKEUP 0x0002
+#define AUOK190X_CMD_TCON_RESET 0x0003
+#define AUOK190X_CMD_DATA_STOP 0x1002
+#define AUOK190X_CMD_LUT_START 0x1003
+#define AUOK190X_CMD_DISP_REFRESH 0x1004
+#define AUOK190X_CMD_DISP_RESET 0x1005
+#define AUOK190X_CMD_PRE_DISPLAY_START 0x100D
+#define AUOK190X_CMD_PRE_DISPLAY_STOP 0x100F
+#define AUOK190X_CMD_FLASH_W 0x2000
+#define AUOK190X_CMD_FLASH_E 0x2001
+#define AUOK190X_CMD_FLASH_STS 0x2002
+#define AUOK190X_CMD_FRAMERATE 0x3000
+#define AUOK190X_CMD_READ_VERSION 0x4000
+#define AUOK190X_CMD_READ_STATUS 0x4001
+#define AUOK190X_CMD_READ_LUT 0x4003
+#define AUOK190X_CMD_DRIVERTIMING 0x5000
+#define AUOK190X_CMD_LBALANCE 0x5001
+#define AUOK190X_CMD_AGINGMODE 0x6000
+#define AUOK190X_CMD_AGINGEXIT 0x6001
+
+/*
+ * Common settings for AUOK190X_CMD_INIT
+ */
+
+#define AUOK190X_INIT_DATA_FILTER (0 << 12)
+#define AUOK190X_INIT_DATA_BYPASS (1 << 12)
+#define AUOK190X_INIT_INVERSE_WHITE (0 << 9)
+#define AUOK190X_INIT_INVERSE_BLACK (1 << 9)
+#define AUOK190X_INIT_SCAN_DOWN (0 << 1)
+#define AUOK190X_INIT_SCAN_UP (1 << 1)
+#define AUOK190X_INIT_SHIFT_LEFT (0 << 0)
+#define AUOK190X_INIT_SHIFT_RIGHT (1 << 0)
+
+/* Common bits to pixels
+ * Mode 15-12 11-8 7-4 3-0
+ * format0 4 3 2 1
+ * format1 3 4 1 2
+ */
+
+#define AUOK190X_INIT_FORMAT0 0
+#define AUOK190X_INIT_FORMAT1 (1 << 6)
+
+/*
+ * settings for AUOK190X_CMD_RESET
+ */
+
+#define AUOK190X_RESET_TCON (0 << 0)
+#define AUOK190X_RESET_NORMAL (1 << 0)
+#define AUOK190X_RESET_PON (1 << 1)
+
+/*
+ * AUOK190X_CMD_VERSION
+ */
+
+#define AUOK190X_VERSION_TEMP_MASK (0x1ff)
+#define AUOK190X_VERSION_EPD_MASK (0xff)
+#define AUOK190X_VERSION_SIZE_INT(_val) ((_val & 0xfc00) >> 10)
+#define AUOK190X_VERSION_SIZE_FLOAT(_val) ((_val & 0x3c0) >> 6)
+#define AUOK190X_VERSION_MODEL(_val) (_val & 0x3f)
+#define AUOK190X_VERSION_LUT(_val) (_val & 0xff)
+#define AUOK190X_VERSION_TCON(_val) ((_val & 0xff00) >> 8)
+
+/*
+ * update modes for CMD_PARTIALDISP on K1900 and CMD_DDMA on K1901
+ */
+
+#define AUOK190X_UPDATE_MODE(_res) ((_res & 0x7) << 12)
+#define AUOK190X_UPDATE_NONFLASH (1 << 15)
+
+/*
+ * track panel specific parameters for common init
+ */
+
+struct auok190x_init_data {
+ char *id;
+ struct auok190x_board *board;
+
+ void (*update_partial)(struct auok190xfb_par *par, u16 y1, u16 y2);
+ void (*update_all)(struct auok190xfb_par *par);
+ bool (*need_refresh)(struct auok190xfb_par *par);
+ void (*init)(struct auok190xfb_par *par);
+};
+
+
+extern void auok190x_send_command_nowait(struct auok190xfb_par *par, u16 data);
+extern int auok190x_send_command(struct auok190xfb_par *par, u16 data);
+extern void auok190x_send_cmdargs_nowait(struct auok190xfb_par *par, u16 cmd,
+ int argc, u16 *argv);
+extern int auok190x_send_cmdargs(struct auok190xfb_par *par, u16 cmd,
+ int argc, u16 *argv);
+extern void auok190x_send_cmdargs_pixels_nowait(struct auok190xfb_par *par,
+ u16 cmd, int argc, u16 *argv,
+ int size, u16 *data);
+extern int auok190x_send_cmdargs_pixels(struct auok190xfb_par *par, u16 cmd,
+ int argc, u16 *argv, int size,
+ u16 *data);
+extern int auok190x_read_cmdargs(struct auok190xfb_par *par, u16 cmd,
+ int argc, u16 *argv);
+
+extern int auok190x_common_probe(struct platform_device *pdev,
+ struct auok190x_init_data *init);
+extern int auok190x_common_remove(struct platform_device *pdev);
+
+extern const struct dev_pm_ops auok190x_pm;
diff --git a/include/video/auo_k190xfb.h b/include/video/auo_k190xfb.h
new file mode 100644
index 0000000..609efe8
--- /dev/null
+++ b/include/video/auo_k190xfb.h
@@ -0,0 +1,106 @@
+/*
+ * Definitions for AUO-K190X framebuffer drivers
+ *
+ * Copyright (C) 2012 Heiko Stuebner <heiko@sntech.de>
+ *
+ * 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 _LINUX_VIDEO_AUO_K190XFB_H_
+#define _LINUX_VIDEO_AUO_K190XFB_H_
+
+/* Controller standby command needs a param */
+#define AUOK190X_QUIRK_STANDBYPARAM (1 << 0)
+
+/* Controller standby is completely broken */
+#define AUOK190X_QUIRK_STANDBYBROKEN (1 << 1)
+
+/*
+ * Resolutions for the displays
+ */
+#define AUOK190X_RESOLUTION_800_600 0
+#define AUOK190X_RESOLUTION_1024_768 1
+
+/*
+ * struct used by auok190x. board specific stuff comes from *board
+ */
+struct auok190xfb_par {
+ struct fb_info *info;
+ struct auok190x_board *board;
+
+ struct regulator *regulator;
+
+ struct mutex io_lock;
+ struct delayed_work work;
+ wait_queue_head_t waitq;
+ int resolution;
+ int rotation;
+ int consecutive_threshold;
+ int update_cnt;
+
+ /* panel and controller informations */
+ int epd_type;
+ int panel_size_int;
+ int panel_size_float;
+ int panel_model;
+ int tcon_version;
+ int lut_version;
+
+ /* individual controller callbacks */
+ void (*update_partial)(struct auok190xfb_par *par, u16 y1, u16 y2);
+ void (*update_all)(struct auok190xfb_par *par);
+ bool (*need_refresh)(struct auok190xfb_par *par);
+ void (*init)(struct auok190xfb_par *par);
+ void (*recover)(struct auok190xfb_par *par);
+
+ int update_mode; /* mode to use for updates */
+ int last_mode; /* update mode last used */
+ int flash;
+
+ /* power management */
+ int autosuspend_delay;
+ bool standby;
+ bool manual_standby;
+};
+
+/**
+ * Board specific platform-data
+ * @init: initialize the controller interface
+ * @cleanup: cleanup the controller interface
+ * @wait_for_rdy: wait until the controller is not busy anymore
+ * @set_ctl: change an interface control
+ * @set_hdb: write a value to the data register
+ * @get_hdb: read a value from the data register
+ * @setup_irq: method to setup the irq handling on the busy gpio
+ * @gpio_nsleep: sleep gpio
+ * @gpio_nrst: reset gpio
+ * @gpio_nbusy: busy gpio
+ * @resolution: one of the AUOK190X_RESOLUTION constants
+ * @rotation: rotation of the framebuffer
+ * @quirks: controller quirks to honor
+ * @fps: frames per second for defio
+ */
+struct auok190x_board {
+ int (*init)(struct auok190xfb_par *);
+ void (*cleanup)(struct auok190xfb_par *);
+ int (*wait_for_rdy)(struct auok190xfb_par *);
+
+ void (*set_ctl)(struct auok190xfb_par *, unsigned char, u8);
+ void (*set_hdb)(struct auok190xfb_par *, u16);
+ u16 (*get_hdb)(struct auok190xfb_par *);
+
+ int (*setup_irq)(struct fb_info *);
+
+ int gpio_nsleep;
+ int gpio_nrst;
+ int gpio_nbusy;
+
+ int resolution;
+ int rotation;
+ int quirks;
+ int fps;
+};
+
+#endif
--
1.7.5.4
^ permalink raw reply related
* [PATCH 3/4] video: auo_k190x: add driver for AUO-K1900 variant
From: Heiko Stübner @ 2012-03-28 17:35 UTC (permalink / raw)
To: linux-fbdev
This controller only supports smaller resolutions and only serial
updates, i.e. it has to wait for an update to finish before
starting another one.
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
drivers/video/Kconfig | 9 ++
drivers/video/Makefile | 1 +
drivers/video/auo_k1900fb.c | 198 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 208 insertions(+), 0 deletions(-)
create mode 100644 drivers/video/auo_k1900fb.c
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 89c7394..d9d1e44 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2392,6 +2392,15 @@ config FB_AUO_K190X
help
Internal config node for K190X common code
+config FB_AUO_K1900
+ tristate "AUO K1900 controller support for Sipix displays"
+ depends on FB
+ select FB_AUO_K190X
+ help
+ This driver implements support for the AUO K1900 epd-controller.
+ This controller can drive Sipix epaper displays but can only do
+ serial updates, reducing the number of possible frames per second.
+
config FB_JZ4740
tristate "JZ4740 LCD framebuffer support"
depends on FB && MACH_JZ4740
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index d5406f2..e84df73 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -119,6 +119,7 @@ obj-$(CONFIG_FB_MAXINE) += maxinefb.o
obj-$(CONFIG_FB_METRONOME) += metronomefb.o
obj-$(CONFIG_FB_BROADSHEET) += broadsheetfb.o
obj-$(CONFIG_FB_AUO_K190X) += auo_k190x.o
+obj-$(CONFIG_FB_AUO_K1900) += auo_k1900fb.o
obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o
obj-$(CONFIG_FB_SH7760) += sh7760fb.o
obj-$(CONFIG_FB_IMX) += imxfb.o
diff --git a/drivers/video/auo_k1900fb.c b/drivers/video/auo_k1900fb.c
new file mode 100644
index 0000000..c36cf96
--- /dev/null
+++ b/drivers/video/auo_k1900fb.c
@@ -0,0 +1,198 @@
+/*
+ * auok190xfb.c -- FB driver for AUO-K1900 controllers
+ *
+ * Copyright (C) 2011, 2012 Heiko Stuebner <heiko@sntech.de>
+ *
+ * based on broadsheetfb.c
+ *
+ * Copyright (C) 2008, Jaya Kumar
+ *
+ * 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.
+ *
+ * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
+ *
+ * This driver is written to be used with the AUO-K1900 display controller.
+ *
+ * It is intended to be architecture independent. A board specific driver
+ * must be used to perform all the physical IO interactions.
+ *
+ * The controller supports different update modes:
+ * mode0+1 16 step gray (4bit)
+ * mode2 4 step gray (2bit) - FIXME: add strange refresh
+ * mode3 2 step gray (1bit) - FIXME: add strange refresh
+ * mode4 handwriting mode (strange behaviour)
+ * mode5 automatic selection of update mode
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/firmware.h>
+#include <linux/gpio.h>
+#include <linux/pm_runtime.h>
+
+#include <video/auo_k190xfb.h>
+
+#include "auo_k190x.h"
+
+/*
+ * AUO-K1900 specific commands
+ */
+
+#define AUOK1900_CMD_PARTIALDISP 0x1001
+#define AUOK1900_CMD_ROTATION 0x1006
+#define AUOK1900_CMD_LUT_STOP 0x1009
+
+#define AUOK1900_INIT_TEMP_AVERAGE (1 << 13)
+#define AUOK1900_INIT_ROTATE(_x) ((_x & 0x3) << 10)
+#define AUOK1900_INIT_RESOLUTION(_res) ((_res & 0x7) << 2)
+
+static void auok1900_init(struct auok190xfb_par *par)
+{
+ struct auok190x_board *board = par->board;
+ u16 init_param = 0;
+
+ init_param |= AUOK1900_INIT_TEMP_AVERAGE;
+ init_param |= AUOK1900_INIT_ROTATE(par->rotation);
+ init_param |= AUOK190X_INIT_INVERSE_WHITE;
+ init_param |= AUOK190X_INIT_FORMAT0;
+ init_param |= AUOK1900_INIT_RESOLUTION(par->resolution);
+ init_param |= AUOK190X_INIT_SHIFT_RIGHT;
+
+ auok190x_send_cmdargs(par, AUOK190X_CMD_INIT, 1, &init_param);
+
+ /* let the controller finish */
+ board->wait_for_rdy(par);
+}
+
+static void auok1900_update_region(struct auok190xfb_par *par, int mode,
+ u16 y1, u16 y2)
+{
+ struct device *dev = par->info->device;
+ unsigned char *buf = (unsigned char *)par->info->screen_base;
+ int xres = par->info->var.xres;
+ u16 args[4];
+
+ pm_runtime_get_sync(dev);
+
+ mutex_lock(&(par->io_lock));
+
+ /* y1 and y2 must be a multiple of 2 so drop the lowest bit */
+ y1 &= 0xfffe;
+ y2 &= 0xfffe;
+
+ dev_dbg(dev, "update (x,y,w,h,mode)=(%d,%d,%d,%d,%d)\n",
+ 1, y1+1, xres, y2-y1, mode);
+
+ /* to FIX handle different partial update modes */
+ args[0] = mode | 1;
+ args[1] = y1 + 1;
+ args[2] = xres;
+ args[3] = y2 - y1;
+ buf += y1 * xres;
+ auok190x_send_cmdargs_pixels(par, AUOK1900_CMD_PARTIALDISP, 4, args,
+ ((y2 - y1) * xres)/2, (u16 *) buf);
+ auok190x_send_command(par, AUOK190X_CMD_DATA_STOP);
+
+ par->update_cnt++;
+
+ mutex_unlock(&(par->io_lock));
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+}
+
+static void auok1900fb_dpy_update_pages(struct auok190xfb_par *par,
+ u16 y1, u16 y2)
+{
+ int mode;
+
+ if (par->update_mode < 0) {
+ mode = AUOK190X_UPDATE_MODE(1);
+ par->last_mode = -1;
+ } else {
+ mode = AUOK190X_UPDATE_MODE(par->update_mode);
+ par->last_mode = par->update_mode;
+ }
+
+ if (par->flash)
+ mode |= AUOK190X_UPDATE_NONFLASH;
+
+ auok1900_update_region(par, mode, y1, y2);
+}
+
+static void auok1900fb_dpy_update(struct auok190xfb_par *par)
+{
+ int mode;
+
+ if (par->update_mode < 0) {
+ mode = AUOK190X_UPDATE_MODE(0);
+ par->last_mode = -1;
+ } else {
+ mode = AUOK190X_UPDATE_MODE(par->update_mode);
+ par->last_mode = par->update_mode;
+ }
+
+ if (par->flash)
+ mode |= AUOK190X_UPDATE_NONFLASH;
+
+ auok1900_update_region(par, mode, 0, par->info->var.yres);
+ par->update_cnt = 0;
+}
+
+static bool auok1900fb_need_refresh(struct auok190xfb_par *par)
+{
+ return (par->update_cnt > 10);
+}
+
+static int __devinit auok1900fb_probe(struct platform_device *pdev)
+{
+ struct auok190x_init_data init;
+ struct auok190x_board *board;
+
+ /* pick up board specific routines */
+ board = pdev->dev.platform_data;
+ if (!board)
+ return -EINVAL;
+
+ /* fill temporary init struct for common init */
+ init.id = "auo_k1900fb";
+ init.board = board;
+ init.update_partial = auok1900fb_dpy_update_pages;
+ init.update_all = auok1900fb_dpy_update;
+ init.need_refresh = auok1900fb_need_refresh;
+ init.init = auok1900_init;
+
+ return auok190x_common_probe(pdev, &init);
+}
+
+static int __devexit auok1900fb_remove(struct platform_device *pdev)
+{
+ return auok190x_common_remove(pdev);
+}
+
+static struct platform_driver auok1900fb_driver = {
+ .probe = auok1900fb_probe,
+ .remove = __devexit_p(auok1900fb_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "auo_k1900fb",
+ .pm = &auok190x_pm,
+ },
+};
+module_platform_driver(auok1900fb_driver);
+
+MODULE_DESCRIPTION("framebuffer driver for the AUO-K1900 EPD controller");
+MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
+MODULE_LICENSE("GPL");
--
1.7.5.4
^ permalink raw reply related
* [PATCH 4/4] video: auo_k190x: add driver for the AUO-K1901 variant
From: Heiko Stübner @ 2012-03-28 17:36 UTC (permalink / raw)
To: linux-fbdev
This controller not only supports higher resolutions than the K1900
but concurrent updates as well. This results in a generally higher
display speed.
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
drivers/video/Kconfig | 9 ++
drivers/video/Makefile | 1 +
drivers/video/auo_k1901fb.c | 251 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 261 insertions(+), 0 deletions(-)
create mode 100644 drivers/video/auo_k1901fb.c
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index d9d1e44..28f7ca3 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2401,6 +2401,15 @@ config FB_AUO_K1900
This controller can drive Sipix epaper displays but can only do
serial updates, reducing the number of possible frames per second.
+config FB_AUO_K1901
+ tristate "AUO K1901 controller support for Sipix displays"
+ depends on FB
+ select FB_AUO_K190X
+ help
+ This driver implements support for the AUO K1901 epd-controller.
+ This controller can drive Sipix epaper displays and supports
+ concurrent updates, making higher frames per second possible.
+
config FB_JZ4740
tristate "JZ4740 LCD framebuffer support"
depends on FB && MACH_JZ4740
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index e84df73..ee8dafb 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -120,6 +120,7 @@ obj-$(CONFIG_FB_METRONOME) += metronomefb.o
obj-$(CONFIG_FB_BROADSHEET) += broadsheetfb.o
obj-$(CONFIG_FB_AUO_K190X) += auo_k190x.o
obj-$(CONFIG_FB_AUO_K1900) += auo_k1900fb.o
+obj-$(CONFIG_FB_AUO_K1901) += auo_k1901fb.o
obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o
obj-$(CONFIG_FB_SH7760) += sh7760fb.o
obj-$(CONFIG_FB_IMX) += imxfb.o
diff --git a/drivers/video/auo_k1901fb.c b/drivers/video/auo_k1901fb.c
new file mode 100644
index 0000000..1c054c1
--- /dev/null
+++ b/drivers/video/auo_k1901fb.c
@@ -0,0 +1,251 @@
+/*
+ * auok190xfb.c -- FB driver for AUO-K1901 controllers
+ *
+ * Copyright (C) 2011, 2012 Heiko Stuebner <heiko@sntech.de>
+ *
+ * based on broadsheetfb.c
+ *
+ * Copyright (C) 2008, Jaya Kumar
+ *
+ * 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.
+ *
+ * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
+ *
+ * This driver is written to be used with the AUO-K1901 display controller.
+ *
+ * It is intended to be architecture independent. A board specific driver
+ * must be used to perform all the physical IO interactions.
+ *
+ * The controller supports different update modes:
+ * mode0+1 16 step gray (4bit)
+ * mode2+3 4 step gray (2bit)
+ * mode4+5 2 step gray (1bit)
+ * - mode4 is described as "without LUT"
+ * mode7 automatic selection of update mode
+ *
+ * The most interesting difference to the K1900 is the ability to do screen
+ * updates in an asynchronous fashion. Where the K1900 needs to wait for the
+ * current update to complete, the K1901 can process later updates already.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/firmware.h>
+#include <linux/gpio.h>
+#include <linux/pm_runtime.h>
+
+#include <video/auo_k190xfb.h>
+
+#include "auo_k190x.h"
+
+/*
+ * AUO-K1901 specific commands
+ */
+
+#define AUOK1901_CMD_LUT_INTERFACE 0x0005
+#define AUOK1901_CMD_DMA_START 0x1001
+#define AUOK1901_CMD_CURSOR_START 0x1007
+#define AUOK1901_CMD_CURSOR_STOP AUOK190X_CMD_DATA_STOP
+#define AUOK1901_CMD_DDMA_START 0x1009
+
+#define AUOK1901_INIT_GATE_PULSE_LOW (0 << 14)
+#define AUOK1901_INIT_GATE_PULSE_HIGH (1 << 14)
+#define AUOK1901_INIT_SINGLE_GATE (0 << 13)
+#define AUOK1901_INIT_DOUBLE_GATE (1 << 13)
+
+/* Bits to pixels
+ * Mode 15-12 11-8 7-4 3-0
+ * format2 2 T 1 T
+ * format3 1 T 2 T
+ * format4 T 2 T 1
+ * format5 T 1 T 2
+ *
+ * halftone modes:
+ * format6 2 2 1 1
+ * format7 1 1 2 2
+ */
+#define AUOK1901_INIT_FORMAT2 (1 << 7)
+#define AUOK1901_INIT_FORMAT3 ((1 << 7) | (1 << 6))
+#define AUOK1901_INIT_FORMAT4 (1 << 8)
+#define AUOK1901_INIT_FORMAT5 ((1 << 8) | (1 << 6))
+#define AUOK1901_INIT_FORMAT6 ((1 << 8) | (1 << 7))
+#define AUOK1901_INIT_FORMAT7 ((1 << 8) | (1 << 7) | (1 << 6))
+
+/* res[4] to bit 10
+ * res[3-0] to bits 5-2
+ */
+#define AUOK1901_INIT_RESOLUTION(_res) (((_res & (1 << 4)) << 6) \
+ | ((_res & 0xf) << 2))
+
+/*
+ * portrait / landscape orientation in AUOK1901_CMD_DMA_START
+ */
+#define AUOK1901_DMA_ROTATE90(_rot) ((_rot & 1) << 13)
+
+/*
+ * equivalent to 1 << 11, needs the ~ to have same rotation like K1900
+ */
+#define AUOK1901_DDMA_ROTATE180(_rot) ((~_rot & 2) << 10)
+
+static void auok1901_init(struct auok190xfb_par *par)
+{
+ struct auok190x_board *board = par->board;
+ u16 init_param = 0;
+
+ init_param |= AUOK190X_INIT_INVERSE_WHITE;
+ init_param |= AUOK190X_INIT_FORMAT0;
+ init_param |= AUOK1901_INIT_RESOLUTION(par->resolution);
+ init_param |= AUOK190X_INIT_SHIFT_LEFT;
+
+ auok190x_send_cmdargs(par, AUOK190X_CMD_INIT, 1, &init_param);
+
+ /* let the controller finish */
+ board->wait_for_rdy(par);
+}
+
+static void auok1901_update_region(struct auok190xfb_par *par, int mode,
+ u16 y1, u16 y2)
+{
+ struct device *dev = par->info->device;
+ unsigned char *buf = (unsigned char *)par->info->screen_base;
+ int xres = par->info->var.xres;
+ u16 args[5];
+
+ pm_runtime_get_sync(dev);
+
+ mutex_lock(&(par->io_lock));
+
+ /* y1 and y2 must be a multiple of 2 so drop the lowest bit */
+ y1 &= 0xfffe;
+ y2 &= 0xfffe;
+
+ dev_dbg(dev, "update (x,y,w,h,mode)=(%d,%d,%d,%d,%d)\n",
+ 1, y1+1, xres, y2-y1, mode);
+
+ /* K1901: first transfer the region data */
+ args[0] = AUOK1901_DMA_ROTATE90(par->rotation) | 1;
+ args[1] = y1 + 1;
+ args[2] = xres;
+ args[3] = y2 - y1;
+ buf += y1 * xres;
+ auok190x_send_cmdargs_pixels_nowait(par, AUOK1901_CMD_DMA_START, 4,
+ args, ((y2 - y1) * xres)/2,
+ (u16 *) buf);
+ auok190x_send_command_nowait(par, AUOK190X_CMD_DATA_STOP);
+
+ /* K1901: second tell the controller to update the region with mode */
+ args[0] = mode | AUOK1901_DDMA_ROTATE180(par->rotation);
+ args[1] = 1;
+ args[2] = y1 + 1;
+ args[3] = xres;
+ args[4] = y2 - y1;
+ auok190x_send_cmdargs_nowait(par, AUOK1901_CMD_DDMA_START, 5, args);
+
+ par->update_cnt++;
+
+ mutex_unlock(&(par->io_lock));
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+}
+
+static void auok1901fb_dpy_update_pages(struct auok190xfb_par *par,
+ u16 y1, u16 y2)
+{
+ int mode;
+
+ if (par->update_mode < 0) {
+ mode = AUOK190X_UPDATE_MODE(1);
+ par->last_mode = -1;
+ } else {
+ mode = AUOK190X_UPDATE_MODE(par->update_mode);
+ par->last_mode = par->update_mode;
+ }
+
+ if (par->flash)
+ mode |= AUOK190X_UPDATE_NONFLASH;
+
+ auok1901_update_region(par, mode, y1, y2);
+}
+
+static void auok1901fb_dpy_update(struct auok190xfb_par *par)
+{
+ int mode;
+
+ /* When doing full updates, wait for the controller to be ready
+ * This will hopefully catch some hangs of the K1901
+ */
+ par->board->wait_for_rdy(par);
+
+ if (par->update_mode < 0) {
+ mode = AUOK190X_UPDATE_MODE(0);
+ par->last_mode = -1;
+ } else {
+ mode = AUOK190X_UPDATE_MODE(par->update_mode);
+ par->last_mode = par->update_mode;
+ }
+
+ if (par->flash)
+ mode |= AUOK190X_UPDATE_NONFLASH;
+
+ auok1901_update_region(par, mode, 0, par->info->var.yres);
+ par->update_cnt = 0;
+}
+
+static bool auok1901fb_need_refresh(struct auok190xfb_par *par)
+{
+ return (par->update_cnt > 10);
+}
+
+static int __devinit auok1901fb_probe(struct platform_device *pdev)
+{
+ struct auok190x_init_data init;
+ struct auok190x_board *board;
+
+ /* pick up board specific routines */
+ board = pdev->dev.platform_data;
+ if (!board)
+ return -EINVAL;
+
+ /* fill temporary init struct for common init */
+ init.id = "auo_k1901fb";
+ init.board = board;
+ init.update_partial = auok1901fb_dpy_update_pages;
+ init.update_all = auok1901fb_dpy_update;
+ init.need_refresh = auok1901fb_need_refresh;
+ init.init = auok1901_init;
+
+ return auok190x_common_probe(pdev, &init);
+}
+
+static int __devexit auok1901fb_remove(struct platform_device *pdev)
+{
+ return auok190x_common_remove(pdev);
+}
+
+static struct platform_driver auok1901fb_driver = {
+ .probe = auok1901fb_probe,
+ .remove = __devexit_p(auok1901fb_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "auo_k1901fb",
+ .pm = &auok190x_pm,
+ },
+};
+module_platform_driver(auok1901fb_driver);
+
+MODULE_DESCRIPTION("framebuffer driver for the AUO-K1901 EPD controller");
+MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
+MODULE_LICENSE("GPL");
--
1.7.5.4
^ permalink raw reply related
* [PATCH] OMAPDSS: VENC: allow switching venc type at runtime
From: Grazvydas Ignotas @ 2012-03-28 23:45 UTC (permalink / raw)
To: linux-fbdev; +Cc: Tomi Valkeinen, linux-omap, Grazvydas Ignotas
VENC type (composite/svideo) doesn't have to be fixed by board wiring,
it is possible to provide both connectors, which is what pandora does.
Having to recompile the kernel for users who have TV connector types
that's don't match default board setting is very inconvenient, especially
for users of a consumer device, so add support for switching VENC type
at runtime over a new sysfs file venc_type.
Signed-off-by: Grazvydas Ignotas <notasas@gmail.com>
---
Documentation/arm/OMAP/DSS | 1 +
drivers/video/omap2/dss/venc.c | 55 +++++++++++++++++++++++++++++++++++++++-
2 files changed, 55 insertions(+), 1 deletions(-)
diff --git a/Documentation/arm/OMAP/DSS b/Documentation/arm/OMAP/DSS
index 888ae7b..18e2214 100644
--- a/Documentation/arm/OMAP/DSS
+++ b/Documentation/arm/OMAP/DSS
@@ -156,6 +156,7 @@ timings Display timings (pixclock,xres/hfp/hbp/hsw,yres/vfp/vbp/vsw)
"pal" and "ntsc"
panel_name
tear_elim Tearing elimination 0=off, 1=on
+venc_type Output type (video encoder only): "composite" or "svideo"
There are also some debugfs files at <debugfs>/omapdss/ which show information
about clocks and registers.
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
index 9c3daf7..aa2e74a 100644
--- a/drivers/video/omap2/dss/venc.c
+++ b/drivers/video/omap2/dss/venc.c
@@ -485,16 +485,69 @@ unsigned long venc_get_pixel_clock(void)
return 13500000;
}
+static ssize_t display_venc_type_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct omap_dss_device *dssdev = to_dss_device(dev);
+ const char *ret;
+
+ switch (dssdev->phy.venc.type) {
+ case OMAP_DSS_VENC_TYPE_COMPOSITE:
+ ret = "composite";
+ break;
+ case OMAP_DSS_VENC_TYPE_SVIDEO:
+ ret = "svideo";
+ break;
+ default:
+ ret = "unknown";
+ break;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", ret);
+}
+
+static ssize_t display_venc_type_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct omap_dss_device *dssdev = to_dss_device(dev);
+ enum omap_dss_venc_type new_type;
+
+ if (strncmp("composite", buf, 9) = 0)
+ new_type = OMAP_DSS_VENC_TYPE_COMPOSITE;
+ else if (strncmp("svideo", buf, 6) = 0)
+ new_type = OMAP_DSS_VENC_TYPE_SVIDEO;
+ else
+ return -EINVAL;
+
+ mutex_lock(&venc.venc_lock);
+
+ if (dssdev->phy.venc.type != new_type) {
+ dssdev->phy.venc.type = new_type;
+ if (dssdev->state = OMAP_DSS_DISPLAY_ACTIVE) {
+ venc_power_off(dssdev);
+ venc_power_on(dssdev);
+ }
+ }
+
+ mutex_unlock(&venc.venc_lock);
+
+ return size;
+}
+
+static DEVICE_ATTR(venc_type, S_IRUGO | S_IWUSR,
+ display_venc_type_show, display_venc_type_store);
+
/* driver */
static int venc_panel_probe(struct omap_dss_device *dssdev)
{
dssdev->panel.timings = omap_dss_pal_timings;
- return 0;
+ return device_create_file(&dssdev->dev, &dev_attr_venc_type);
}
static void venc_panel_remove(struct omap_dss_device *dssdev)
{
+ device_remove_file(&dssdev->dev, &dev_attr_venc_type);
}
static int venc_panel_enable(struct omap_dss_device *dssdev)
--
1.7.0.4
^ permalink raw reply related
* Re: [PATCH] video/console: Clip the right margin clear to the visible region
From: Florian Tobias Schandinat @ 2012-03-30 1:16 UTC (permalink / raw)
To: Chris Wilson; +Cc: linux-fbdev, linux-kernel
In-Reply-To: <1332793022-29292-1-git-send-email-chris@chris-wilson.co.uk>
Hi Chris,
On 03/26/2012 08:17 PM, Chris Wilson wrote:
> For some unknown reason, yres_virtual was 2x larger the the size specified
> by i915 and so when blit_clear_margins() tried to clear the full virtual
> right-hand margin it tried to write far beyond the end of the buffer.
>
> This limits the clear to only the visible portion of the right-hand
> margin, similar to how the bottom margin is treated.
>
> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id8138
as you also found the root of the problem and posted a patch to fix i915
(or rather all KMS-based framebuffers) by validating the virtual
resolution in check var, I don't see any reason to apply this one. I'm
not sure about it, but changing the behaviour of this function might
cause some undesired changes in user experience and as there is no
problem with this code as is, I'd prefer to not change it.
Best regards,
Florian Tobias Schandinat
> Cc: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> ---
> drivers/video/console/bitblit.c | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c
> index 28b1a83..9f89e5a 100644
> --- a/drivers/video/console/bitblit.c
> +++ b/drivers/video/console/bitblit.c
> @@ -219,9 +219,9 @@ static void bit_clear_margins(struct vc_data *vc, struct fb_info *info,
>
> if (rw && !bottom_only) {
> region.dx = info->var.xoffset + rs;
> - region.dy = 0;
> + region.dy = info->var.yoffset;
> region.width = rw;
> - region.height = info->var.yres_virtual;
> + region.height = info->var.yres;
> info->fbops->fb_fillrect(info, ®ion);
> }
>
^ permalink raw reply
* [PATCH v2] video: s3c-fb: Add device tree support
From: Thomas Abraham @ 2012-03-30 5:49 UTC (permalink / raw)
To: linux-arm-kernel
Add device tree based discovery support for Samsung's display controller
framebuffer driver.
Cc: Jingoo Han <jg1.han@samsung.com>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
---
.../devicetree/bindings/fb/samsung-fb.txt | 148 +++++++++++++
drivers/video/s3c-fb.c | 230 +++++++++++++++++++-
2 files changed, 370 insertions(+), 8 deletions(-)
create mode 100644 Documentation/devicetree/bindings/fb/samsung-fb.txt
diff --git a/Documentation/devicetree/bindings/fb/samsung-fb.txt b/Documentation/devicetree/bindings/fb/samsung-fb.txt
new file mode 100644
index 0000000..612bd9f
--- /dev/null
+++ b/Documentation/devicetree/bindings/fb/samsung-fb.txt
@@ -0,0 +1,148 @@
+* Samsung Display Controller Framebuffer Controller
+
+The display controller is used to transfer image data from memory to a
+external display device such as an RGB interface LCD panel. It supports
+various color formats such as rgb and yuv. It also supports multiple window
+overlays.
+
+Required properties:
+
+ - compatible: should be one of the following
+ - samsung,exynos4210-fimd: for fimd compatible with Exynos4210 fimd
+ - samsung,s5pv210-fimd: for fimd compatible with s5pv210 fimd
+
+ - reg: physical base address of the controller and length of memory
+ mapped region.
+
+ - interrupts: Three interrupts should be specified. The format of the
+ interrupt specifier depends on the interrupt controller. The interrupts
+ should be specified in the following order.
+ - VSYNC (Video Frame) interrupt
+ - Video FIFO level interrupt
+ - FIMD System Interrupt
+
+ - gpios: The gpios used to interface with the external LCD panel. For a
+ panel with rgb interface, the gpio interface consists of video data
+ lines, HSYNC, VSYNC, Pixel Clock and Data Enable. The gpio's used for
+ these interface lines can be listed under this property in any order.
+
+ - samsung,fimd-display: The fimd controller is interfaced with the a
+ display device such as a lcd panel. This property should specify the
+ phandle of the display device node. For a display device node that
+ represents a RGB type display interface, it is expected to specify the
+ video interface timing using the following properties.
+
+ - lcd-htiming: Specifies the horizontal timing for the overlay. The
+ horizontal timing includes four parameters in the following order.
+
+ - horizontal back porch (in number of lcd clocks)
+ - horizontal front porch (in number of lcd clocks)
+ - hsync pulse width (in number of lcd clocks)
+ - Display panels X resolution.
+
+ - lcd-vtiming: Specifies the vertical timing for the overlay. The
+ vertical timing includes four parameters in the following order.
+
+ - vertical back porch (in number of lcd lines)
+ - vertical front porch (in number of lcd lines)
+ - vsync pulse width (in number of lcd clocks)
+ - Y resolution.
+
+ - Overlay/Windows: Multiple overlays/windows can be specified as child
+ nodes. Each window should have the following properties (optional
+ window properties are marked as 'optional').
+
+ - samsung,fimd-win-id: Specifies the window number of the fimd controller.
+
+ - samsung,fimd-win-bpp: Specifies the bits per pixel. Two values should
+ be specified in the following order.
+ - default-bpp: bpp supported by the overlay.
+ - max-bpp: maximum required bpp for the overlay.
+
+ - samsung,fimd-win-res: (OPTIONAL) Specifies the window resolution in
+ pixels. The resolution contains the X and Y pixel values with X being
+ specified first. If this property is not specified, the window
+ resolution is set to be equal to the display panel resolution.
+
+ - samsung,fimd-win-virtres: (OPTIONAL) Specifies the resolution of the
+ virtual frame buffer for the window. The resolution contains the X
+ and Y resolution in pixels with value of X being the specified first.
+
+Optional properties:
+
+ - samsung,fimd-vidout-rgb: Video output format is RGB.
+ - samsung,fimd-inv-hsync: invert hsync pulse polarity.
+ - samsung,fimd-inv-vsync: invert vsync pulse polarity.
+ - samsung,fimd-inv-vclk: invert video clock polarity.
+ - samsung,fimd-inv-vden: invert video enable signal polarity.
+ - samsung,fimd-frame-rate: Number of video frames per second.
+
+Example:
+
+ The following is an example for the fimd framebuffer controller is split
+ into two portions. The SoC specific portion can be specified in the SoC
+ specific dts file. The board specific portion can be specified in the
+ board specific dts file.
+
+ - SoC Specific portion
+
+ fimd@11C00000 {
+ compatible = "samsung,exynos4210-fimd";
+ interrupt-parent = <&combiner>;
+ reg = <0x11C00000 0x8000>;
+ interrupts = <11 1>, <11 0>, <11 2>;
+ };
+
+ - Board Specific portion
+
+ fimd@11C00000 {
+ samsung,fimd-display = <&lcd_fimd0>;
+ samsung,fimd-vidout-rgb;
+ samsung,fimd-inv-hsync;
+ samsung,fimd-inv-vsync;
+ samsung,fimd-inv-vclk;
+ samsung,fimd-frame-rate = <60>;
+
+ gpios = <&gpf0 0 2 0 0>,
+ <&gpf0 1 2 0 0>,
+ <&gpf0 2 2 0 0>,
+ <&gpf0 3 2 0 0>,
+ <&gpf0 4 2 0 0>,
+ <&gpf0 5 2 0 0>,
+ <&gpf0 6 2 0 0>,
+ <&gpf0 7 2 0 0>,
+ <&gpf1 0 2 0 0>,
+ <&gpf1 1 2 0 0>,
+ <&gpf1 2 2 0 0>,
+ <&gpf1 3 2 0 0>,
+ <&gpf1 4 2 0 0>,
+ <&gpf1 5 2 0 0>,
+ <&gpf1 6 2 0 0>,
+ <&gpf1 7 2 0 0>,
+ <&gpf2 0 2 0 0>,
+ <&gpf2 1 2 0 0>,
+ <&gpf2 2 2 0 0>,
+ <&gpf2 3 2 0 0>,
+ <&gpf2 4 2 0 0>,
+ <&gpf2 5 2 0 0>,
+ <&gpf2 6 2 0 0>,
+ <&gpf2 7 2 0 0>,
+ <&gpf3 0 2 0 0>,
+ <&gpf3 1 2 0 0>,
+ <&gpf3 2 2 0 0>,
+ <&gpf3 3 2 0 0>;
+
+ window0 {
+ samsung,fimd-win-id = <0>;
+ samsung,fimd-win-bpp = <32 24>;
+ samsung,fimd-win-res = <512 300>;
+ samsung,fimd-win-vres = <1024 600>;
+ };
+
+ window1 {
+ samsung,fimd-win-id = <1>;
+ samsung,fimd-win-bpp = <32 24>;
+ samsung,fimd-win-res = <1024 200>;
+ samsung,fimd-win-vres = <1024 600>;
+ };
+ };
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
index 18c84b8..b8be668 100644
--- a/drivers/video/s3c-fb.c
+++ b/drivers/video/s3c-fb.c
@@ -24,6 +24,8 @@
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <mach/map.h>
#include <plat/regs-fb-v4.h>
@@ -220,6 +222,7 @@ struct s3c_fb {
int irq_no;
unsigned long irq_flags;
struct s3c_fb_vsync vsync_info;
+ int *gpios;
};
/**
@@ -1352,27 +1355,215 @@ static void s3c_fb_clear_win(struct s3c_fb *sfb, int win)
writel(reg & ~SHADOWCON_WINx_PROTECT(win), regs + SHADOWCON);
}
+#ifdef CONFIG_OF
+static int s3c_fb_dt_parse_gpios(struct device *dev, struct s3c_fb *sfb,
+ bool request)
+{
+ int nr_gpios, idx, gpio, ret;
+
+ nr_gpios = sfb->pdata->win[0]->max_bpp + 4;
+ sfb->gpios = devm_kzalloc(dev, sizeof(int) * nr_gpios, GFP_KERNEL);
+ if (!sfb->gpios) {
+ dev_err(dev, "unable to allocate private data for gpio\n");
+ return -ENOMEM;
+ }
+
+ for (idx = 0; idx < nr_gpios; idx++) {
+ gpio = of_get_gpio(dev->of_node, idx);
+ if (!gpio_is_valid(gpio)) {
+ dev_err(dev, "invalid gpio[%d]: %d\n", idx, gpio);
+ return -EINVAL;
+ }
+
+ if (!request)
+ continue;
+
+ ret = gpio_request(gpio, "fimd");
+ if (ret) {
+ dev_err(dev, "gpio [%d] request failed\n", gpio);
+ goto gpio_free;
+ }
+ sfb->gpios[idx] = gpio;
+ }
+ return 0;
+
+gpio_free:
+ while (--idx >= 0)
+ gpio_free(sfb->gpios[idx]);
+ return ret;
+}
+
+static void s3c_fb_dt_free_gpios(struct s3c_fb *sfb)
+{
+ unsigned int idx, nr_gpio;
+
+ nr_gpio = sfb->pdata->win[0]->max_bpp + 4;
+ for (idx = 0; idx < nr_gpio; idx++)
+ gpio_free(sfb->gpios[idx]);
+}
+
+static struct s3c_fb_platdata *s3c_fb_dt_parse_pdata(struct device *dev)
+{
+ struct device_node *np = dev->of_node, *win_np;
+ struct device_node *disp_np;
+ struct s3c_fb_platdata *pd;
+ struct s3c_fb_pd_win *win;
+ u32 wnum = 0, data[4];
+
+ pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+ if (!pd) {
+ dev_err(dev, "memory allocation for pdata failed\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ pd->vtiming = devm_kzalloc(dev, sizeof(*pd->vtiming), GFP_KERNEL);
+ if (!pd->vtiming) {
+ dev_err(dev, "memory allocation for vtiming failed\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ if (of_get_property(np, "samsung,fimd-vidout-rgb", NULL))
+ pd->vidcon0 |= VIDCON0_VIDOUT_RGB;
+ if (of_get_property(np, "samsung,fimd-vidout-tv", NULL))
+ pd->vidcon0 |= VIDCON0_VIDOUT_TV;
+ if (of_get_property(np, "samsung,fimd-inv-hsync", NULL))
+ pd->vidcon1 |= VIDCON1_INV_HSYNC;
+ if (of_get_property(np, "samsung,fimd-inv-vsync", NULL))
+ pd->vidcon1 |= VIDCON1_INV_VSYNC;
+ if (of_get_property(np, "samsung,fimd-inv-vclk", NULL))
+ pd->vidcon1 |= VIDCON1_INV_VCLK;
+ if (of_get_property(np, "samsung,fimd-inv-vden", NULL))
+ pd->vidcon1 |= VIDCON1_INV_VDEN;
+
+ disp_np = of_parse_phandle(np, "samsung,fimd-display", 0);
+ if (!disp_np) {
+ dev_err(dev, "unable to find display panel info\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (of_property_read_u32_array(disp_np, "lcd-htiming", data, 4)) {
+ dev_err(dev, "invalid horizontal timing\n");
+ return ERR_PTR(-EINVAL);
+ }
+ pd->vtiming->left_margin = data[0];
+ pd->vtiming->right_margin = data[1];
+ pd->vtiming->hsync_len = data[2];
+ pd->vtiming->xres = data[3];
+
+ if (of_property_read_u32_array(disp_np, "lcd-vtiming", data, 4)) {
+ dev_err(dev, "invalid vertical timing\n");
+ return ERR_PTR(-EINVAL);
+ }
+ pd->vtiming->upper_margin = data[0];
+ pd->vtiming->lower_margin = data[1];
+ pd->vtiming->vsync_len = data[2];
+ pd->vtiming->yres = data[3];
+
+ of_property_read_u32_array(np, "samsung,fimd-frame-rate",
+ &pd->vtiming->refresh, 1);
+
+ for_each_child_of_node(np, win_np) {
+ if (of_property_read_u32_array(win_np, "samsung,fimd-win-id",
+ &wnum, 1)) {
+ dev_err(dev, "window id not specified\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ win = devm_kzalloc(dev, sizeof(*win), GFP_KERNEL);
+ if (!win) {
+ dev_err(dev, "no memory for window[%d] data\n", wnum);
+ return ERR_PTR(-ENOMEM);
+ }
+ pd->win[wnum] = win;
+
+ if (of_property_read_u32_array(win_np, "samsung,fimd-win-bpp",
+ data, 2)) {
+ dev_err(dev, "invalid window bpp\n");
+ return ERR_PTR(-EINVAL);
+ }
+ win->default_bpp = data[0];
+ win->max_bpp = data[1];
+
+ if (of_property_read_u32_array(win_np, "samsung,fimd-win-res",
+ data, 2)) {
+ dev_info(dev, "window [%d] resolution not specified. "
+ "Using lcd resolution X[%d] and Y[%d]", wnum,
+ pd->vtiming->xres, pd->vtiming->yres);
+ win->xres = pd->vtiming->xres;
+ win->yres = pd->vtiming->yres;
+ } else {
+ win->xres = data[0];
+ win->yres = data[1];
+ }
+
+ if (!of_property_read_u32_array(win_np,
+ "samsung,fimd-win-virtres", data, 2)) {
+ win->virtual_x = data[0];
+ win->virtual_y = data[1];
+ }
+ }
+
+ return pd;
+}
+#else
+static int s3c_fb_dt_parse_gpios(struct device *dev, struct s3c_fb *sfb,
+ bool request)
+{
+ return 0;
+}
+
+static void s3c_fb_dt_free_gpios(struct s3c_fb *sfb)
+{
+ return 0;
+}
+
+static int s3c_fb_dt_parse_pdata(struct device *dev,
+ struct s3c_fb_platdata **pdata)
+{
+ return 0;
+}
+#endif /* CONFIG_OF */
+
+static const struct of_device_id s3c_fb_dt_match[];
+
+static inline struct s3c_fb_driverdata *s3c_fb_get_driver_data(
+ struct platform_device *pdev)
+{
+#ifdef CONFIG_OF
+ if (pdev->dev.of_node) {
+ const struct of_device_id *match;
+ match = of_match_node(s3c_fb_dt_match, pdev->dev.of_node);
+ return (struct s3c_fb_driverdata *)match->data;
+ }
+#endif
+ return (struct s3c_fb_driverdata *)
+ platform_get_device_id(pdev)->driver_data;
+}
+
static int __devinit s3c_fb_probe(struct platform_device *pdev)
{
- const struct platform_device_id *platid;
struct s3c_fb_driverdata *fbdrv;
struct device *dev = &pdev->dev;
- struct s3c_fb_platdata *pd;
+ struct s3c_fb_platdata *pd = pdev->dev.platform_data;
struct s3c_fb *sfb;
struct resource *res;
int win;
int ret = 0;
u32 reg;
- platid = platform_get_device_id(pdev);
- fbdrv = (struct s3c_fb_driverdata *)platid->driver_data;
+ fbdrv = s3c_fb_get_driver_data(pdev);
if (fbdrv->variant.nr_windows > S3C_FB_MAX_WIN) {
dev_err(dev, "too many windows, cannot attach\n");
return -EINVAL;
}
- pd = pdev->dev.platform_data;
+ if (pdev->dev.of_node) {
+ pd = s3c_fb_dt_parse_pdata(&pdev->dev);
+ if (IS_ERR(pd))
+ return PTR_ERR(pd);
+ }
+
if (!pd) {
dev_err(dev, "no platform data specified\n");
return -EINVAL;
@@ -1449,7 +1640,12 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
/* setup gpio and output polarity controls */
- pd->setup_gpio();
+ if (dev->of_node) {
+ if (s3c_fb_dt_parse_gpios(dev, sfb, true))
+ goto err_lcd_clk;
+ } else {
+ pd->setup_gpio();
+ }
writel(pd->vidcon1, sfb->regs + VIDCON1);
@@ -1499,6 +1695,7 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
return 0;
err_pm_runtime:
+ s3c_fb_dt_free_gpios(sfb);
pm_runtime_put_sync(sfb->dev);
err_lcd_clk:
@@ -1545,6 +1742,7 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev)
pm_runtime_put_sync(sfb->dev);
pm_runtime_disable(sfb->dev);
+ s3c_fb_dt_free_gpios(sfb);
return 0;
}
@@ -1588,7 +1786,10 @@ static int s3c_fb_resume(struct device *dev)
clk_enable(sfb->lcd_clk);
/* setup gpio and output polarity controls */
- pd->setup_gpio();
+ if (dev->of_node)
+ s3c_fb_dt_parse_gpios(dev, sfb, false);
+ else
+ pd->setup_gpio();
writel(pd->vidcon1, sfb->regs + VIDCON1);
/* set video clock running at under-run */
@@ -1658,7 +1859,10 @@ static int s3c_fb_runtime_resume(struct device *dev)
clk_enable(sfb->lcd_clk);
/* setup gpio and output polarity controls */
- pd->setup_gpio();
+ if (dev->of_node)
+ s3c_fb_dt_parse_gpios(dev, sfb, false);
+ else
+ pd->setup_gpio();
writel(pd->vidcon1, sfb->regs + VIDCON1);
return 0;
@@ -2028,6 +2232,15 @@ static struct platform_device_id s3c_fb_driver_ids[] = {
};
MODULE_DEVICE_TABLE(platform, s3c_fb_driver_ids);
+#ifdef CONFIG_OF
+static const struct of_device_id s3c_fb_dt_match[] = {
+ { .compatible = "samsung,exynos4210-fimd",
+ .data = (void *)&s3c_fb_data_exynos4 },
+ {},
+};
+MODULE_DEVICE_TABLE(of, s3c_fb_dt_match);
+#endif
+
static const struct dev_pm_ops s3cfb_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(s3c_fb_suspend, s3c_fb_resume)
SET_RUNTIME_PM_OPS(s3c_fb_runtime_suspend, s3c_fb_runtime_resume,
@@ -2042,6 +2255,7 @@ static struct platform_driver s3c_fb_driver = {
.name = "s3c-fb",
.owner = THIS_MODULE,
.pm = &s3cfb_pm_ops,
+ .of_match_table = of_match_ptr(s3c_fb_dt_match),
},
};
--
1.6.6.rc2
^ permalink raw reply related
* Re: [PATCH] video/console: Clip the right margin clear to the visible region
From: Chris Wilson @ 2012-03-30 7:56 UTC (permalink / raw)
To: Florian Tobias Schandinat; +Cc: linux-fbdev, linux-kernel
In-Reply-To: <4F750970.6040801@gmx.de>
On Fri, 30 Mar 2012 01:16:32 +0000, Florian Tobias Schandinat <FlorianSchandinat@gmx.de> wrote:
> Hi Chris,
>
> On 03/26/2012 08:17 PM, Chris Wilson wrote:
> > For some unknown reason, yres_virtual was 2x larger the the size specified
> > by i915 and so when blit_clear_margins() tried to clear the full virtual
> > right-hand margin it tried to write far beyond the end of the buffer.
> >
> > This limits the clear to only the visible portion of the right-hand
> > margin, similar to how the bottom margin is treated.
> >
> > Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id8138
>
> as you also found the root of the problem and posted a patch to fix i915
> (or rather all KMS-based framebuffers) by validating the virtual
> resolution in check var, I don't see any reason to apply this one. I'm
> not sure about it, but changing the behaviour of this function might
> cause some undesired changes in user experience and as there is no
> problem with this code as is, I'd prefer to not change it.
Ok, thanks for the review. Preventing userspace from programming an
unhandled value of yres_virtual is definitely the way forward.
-Chris
--
Chris Wilson, Intel Open Source Technology Centre
^ permalink raw reply
* Re: [PATCH v2] video: s3c-fb: Add device tree support
From: Rabin Vincent @ 2012-03-30 15:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1333086797-1625-1-git-send-email-thomas.abraham@linaro.org>
On Fri, Mar 30, 2012 at 11:23, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> + - samsung,fimd-display: The fimd controller is interfaced with the a
> + display device such as a lcd panel. This property should specify the
> + phandle of the display device node. For a display device node that
> + represents a RGB type display interface, it is expected to specify the
> + video interface timing using the following properties.
> +
> + - lcd-htiming: Specifies the horizontal timing for the overlay. The
> + horizontal timing includes four parameters in the following order.
> +
> + - horizontal back porch (in number of lcd clocks)
> + - horizontal front porch (in number of lcd clocks)
> + - hsync pulse width (in number of lcd clocks)
> + - Display panels X resolution.
> +
> + - lcd-vtiming: Specifies the vertical timing for the overlay. The
> + vertical timing includes four parameters in the following order.
> +
> + - vertical back porch (in number of lcd lines)
> + - vertical front porch (in number of lcd lines)
> + - vsync pulse width (in number of lcd clocks)
> + - Y resolution.
In this old thread, it was suggested to use a raw EDID block to supply
timings, and since then a couple of drivers in mainline (sm501fb and
fsl-diu) are doing it that way:
http://lists.ozlabs.org/pipermail/linuxppc-dev/2010-February/080683.html
Shouldn't this driver be doing the same thing? If not, shouldn't
whatever interface this is adding be provided in a common helper (like
that old patch was trying to add) so it's standardized between drivers?
^ permalink raw reply
* Re: [PATCH] video:uvesafb: Fix oops that uvesafb try to execute NX-protected page
From: Florian Tobias Schandinat @ 2012-03-31 21:31 UTC (permalink / raw)
To: Alan Cox; +Cc: Wang YanQing, linux-fbdev, linux-kernel, spock
In-Reply-To: <20120327143243.015ecff6@pyramind.ukuu.org.uk>
On 03/27/2012 01:32 PM, Alan Cox wrote:
> On Tue, 27 Mar 2012 18:01:36 +0800
> Wang YanQing <udknight@gmail.com> wrote:
>
>>
>> Ok! I try to check pcibios_enabled first, but get some opposition by Alan Cox,
>> but I want to make thing work and fix the oops, so I choice the simple way to
>> check the (__supported_pte_mask & _PAGE_NX) instead of to check this variable plus
>> pci kernel boot parameter, pci mmconfig works or not, and more, and more. It is not
>> the best method, but it works and maybe all will feel happy.
Wang, could you please write a better commit message, at least you could
include the oops that your patch fixes.
> Apart from adding a helper in the includes for the arch code of
>
> static inline is_nx_enabled(void)
> {
> return !!(__supported_pte_mask & _PAGE_NX);
> }
As this check is already done in a few other places I think there should
be a separate patch that adds this helper and ports all existing code to
use it.
So, does anyone have any objection against me taking this patch as is?
Thanks,
Florian Tobias Schandinat
^ permalink raw reply
* Re: [PATCH 1/4] fb_defio: add first_io callback
From: Florian Tobias Schandinat @ 2012-03-31 23:38 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <201203281933.57109.heiko@sntech.de>
Hi Heiko,
On 03/28/2012 05:33 PM, Heiko Stübner wrote:
> With this optional callback the driver is notified when the first page
> is entered into the pagelist and a new deferred_io call is scheduled.
>
> A possible use-case for this is runtime-pm. In the first_io call
> pm_runtime_get()
> could be called, which starts an asynchronous runtime_resume of the
> device. In the deferred_io callback a call to
> pm_runtime_barrier()
> makes the sure, the device is resumed by then and a
> pm_runtime_put()
> may put the device back to sleep.
>
> Also, some SoCs may use the runtime-pm system to determine if they
> are able to enter deeper idle states. Therefore it is necessary to
> keep the use-count from the first written page until the conclusion
> of the screen update, to prevent the system from going to sleep before
> completing the pending update.
>
> Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Special characters are allowed in sign-offs. And your other patches are
encoded as quoted-printable anyway (although I'd prefer an encoding my
git takes directly like UTF-8).
> ---
> drivers/video/fb_defio.c | 4 ++++
> include/linux/fb.h | 1 +
> 2 files changed, 5 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c
> index c27e153..070f26f 100644
> --- a/drivers/video/fb_defio.c
> +++ b/drivers/video/fb_defio.c
> @@ -107,6 +107,10 @@ static int fb_deferred_io_mkwrite(struct vm_area_struct *vma,
> /* protect against the workqueue changing the page list */
> mutex_lock(&fbdefio->lock);
>
> + /* first write in this cycle, notify the driver */
> + if (fbdefio->first_io && list_empty(&fbdefio->pagelist))
> + fbdefio->first_io(info);
> +
> /*
> * We want the page to remain locked from ->page_mkwrite until
> * the PTE is marked dirty to avoid page_mkclean() being called
> diff --git a/include/linux/fb.h b/include/linux/fb.h
> index d31cb68..c10e71e 100644
> --- a/include/linux/fb.h
> +++ b/include/linux/fb.h
> @@ -607,6 +607,7 @@ struct fb_deferred_io {
There are some drivers (smscufx & udlfb) that kmalloc this struct. I
think you have to fix (kzalloc) them to avoid breaking them?
> struct mutex lock; /* mutex that protects the page list */
> struct list_head pagelist; /* list of touched pages */
> /* callback */
> + void (*first_io)(struct fb_info *info);
> void (*deferred_io)(struct fb_info *info, struct list_head *pagelist);
> };
> #endif
Thanks,
Florian Tobias Schandinat
^ permalink raw reply
* [PATCH] video:uvesafb: Fix oops that uvesafb try to execute NX-protected page
From: Wang YanQing @ 2012-04-01 0:47 UTC (permalink / raw)
To: FlorianSchandinat; +Cc: alan, linux-fbdev, linux-kernel, spock
In-Reply-To: <20120302004850.GA4139@udknight>
This patch fix the oops below that catched in my machine
[ 81.560602] uvesafb: NVIDIA Corporation, GT216 Board - 0696a290, Chip Rev , OEM: NVIDIA, VBE v3.0
[ 81.609384] uvesafb: protected mode interface info at c000:d350
[ 81.609388] uvesafb: pmi: set display start = c00cd3b3, set palette = c00cd40e
[ 81.609390] uvesafb: pmi: ports = 3b4 3b5 3ba 3c0 3c1 3c4 3c5 3c6 3c7 3c8 3c9 3cc 3ce 3cf 3d0 3d1 3d2 3d3 3d4 3d5 3da
[ 81.614558] uvesafb: VBIOS/hardware doesn't support DDC transfers
[ 81.614562] uvesafb: no monitor limits have been set, default refresh rate will be used
[ 81.614994] uvesafb: scrolling: ypan using protected mode interface, yres_virtualI15
[ 81.744147] kernel tried to execute NX-protected page - exploit attempt? (uid: 0)
[ 81.744153] BUG: unable to handle kernel paging request at c00cd3b3
[ 81.744159] IP: [<c00cd3b3>] 0xc00cd3b2
[ 81.744167] *pdpt = 00000000016d6001 *pde = 0000000001c7b067 *pte = 80000000000cd163
[ 81.744171] Oops: 0011 [#1] SMP
[ 81.744174] Modules linked in: uvesafb(+) cfbcopyarea cfbimgblt cfbfillrect
[ 81.744178]
[ 81.744181] Pid: 3497, comm: modprobe Not tainted 3.3.0-rc4NX+ #71 Acer Aspire 4741 /Aspire 4741
[ 81.744185] EIP: 0060:[<c00cd3b3>] EFLAGS: 00010246 CPU: 0
[ 81.744187] EIP is at 0xc00cd3b3
[ 81.744189] EAX: 00004f07 EBX: 00000000 ECX: 00000000 EDX: 00000000
[ 81.744191] ESI: f763f000 EDI: f763f6e8 EBP: f57f3a0c ESP: f57f3a00
[ 81.744192] DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
[ 81.744195] Process modprobe (pid: 3497, tiõ7f2000 task÷48c600 task.tiõ7f2000)
[ 81.744196] Stack:
[ 81.744197] f82512c5 f759341c 00000000 f57f3a30 c124a9bc 00000001 00000001 000001e0
[ 81.744202] f8251280 f763f000 f7593400 00000000 f57f3a40 c12598dd f5c0c000 00000000
[ 81.744206] f57f3b10 c1255efe c125a21a 00000006 f763f09c 00000000 c1c6cb60 f7593400
[ 81.744210] Call Trace:
[ 81.744215] [<f82512c5>] ? uvesafb_pan_display+0x45/0x60 [uvesafb]
[ 81.744222] [<c124a9bc>] fb_pan_display+0x10c/0x160
[ 81.744226] [<f8251280>] ? uvesafb_vbe_find_mode+0x180/0x180 [uvesafb]
[ 81.744230] [<c12598dd>] bit_update_start+0x1d/0x50
[ 81.744232] [<c1255efe>] fbcon_switch+0x39e/0x550
[ 81.744235] [<c125a21a>] ? bit_cursor+0x4ea/0x560
[ 81.744240] [<c129b6cb>] redraw_screen+0x12b/0x220
[ 81.744245] [<c128843b>] ? tty_do_resize+0x3b/0xc0
[ 81.744247] [<c129ef42>] vc_do_resize+0x3d2/0x3e0
[ 81.744250] [<c129efb4>] vc_resize+0x14/0x20
[ 81.744253] [<c12586bd>] fbcon_init+0x29d/0x500
[ 81.744255] [<c12984c4>] ? set_inverse_trans_unicode+0xe4/0x110
[ 81.744258] [<c129b378>] visual_init+0xb8/0x150
[ 81.744261] [<c129c16c>] bind_con_driver+0x16c/0x360
[ 81.744264] [<c129b47e>] ? register_con_driver+0x6e/0x190
[ 81.744267] [<c129c3a1>] take_over_console+0x41/0x50
[ 81.744269] [<c1257b7a>] fbcon_takeover+0x6a/0xd0
[ 81.744272] [<c12594b8>] fbcon_event_notify+0x758/0x790
[ 81.744277] [<c10929e2>] notifier_call_chain+0x42/0xb0
[ 81.744280] [<c1092d30>] __blocking_notifier_call_chain+0x60/0x90
[ 81.744283] [<c1092d7a>] blocking_notifier_call_chain+0x1a/0x20
[ 81.744285] [<c124a5a1>] fb_notifier_call_chain+0x11/0x20
[ 81.744288] [<c124b759>] register_framebuffer+0x1d9/0x2b0
[ 81.744293] [<c1061c73>] ? ioremap_wc+0x33/0x40
[ 81.744298] [<f82537c6>] uvesafb_probe+0xaba/0xc40 [uvesafb]
[ 81.744302] [<c12bb81f>] platform_drv_probe+0xf/0x20
[ 81.744306] [<c12ba558>] driver_probe_device+0x68/0x170
[ 81.744309] [<c12ba731>] __device_attach+0x41/0x50
[ 81.744313] [<c12b9088>] bus_for_each_drv+0x48/0x70
[ 81.744316] [<c12ba7f3>] device_attach+0x83/0xa0
[ 81.744319] [<c12ba6f0>] ? __driver_attach+0x90/0x90
[ 81.744321] [<c12b991f>] bus_probe_device+0x6f/0x90
[ 81.744324] [<c12b8a45>] device_add+0x5e5/0x680
[ 81.744329] [<c122a1a3>] ? kvasprintf+0x43/0x60
[ 81.744332] [<c121e6e4>] ? kobject_set_name_vargs+0x64/0x70
[ 81.744335] [<c121e6e4>] ? kobject_set_name_vargs+0x64/0x70
[ 81.744339] [<c12bbe9f>] platform_device_add+0xff/0x1b0
[ 81.744343] [<f8252906>] uvesafb_init+0x50/0x9b [uvesafb]
[ 81.744346] [<c100111f>] do_one_initcall+0x2f/0x170
[ 81.744350] [<f82528b6>] ? uvesafb_is_valid_mode+0x66/0x66 [uvesafb]
[ 81.744355] [<c10c6994>] sys_init_module+0xf4/0x1410
[ 81.744359] [<c1157fc0>] ? vfsmount_lock_local_unlock_cpu+0x30/0x30
[ 81.744363] [<c144cb10>] sysenter_do_call+0x12/0x36
[ 81.744365] Code: f5 00 00 00 32 f6 66 8b da 66 d1 e3 66 ba d4 03 8a e3 b0 1c 66 ef b0 1e 66 ef 8a e7 b0 1d 66 ef b0 1f 66 ef e8 fa 00 00 00 61 c3 <60> e8 c8 00 00 00 66 8b f3 66 8b da 66 ba d4 03 b0 0c 8a e5 66
[ 81.744388] EIP: [<c00cd3b3>] 0xc00cd3b3 SS:ESP 0068:f57f3a00
[ 81.744391] CR2: 00000000c00cd3b3
[ 81.744393] ---[ end trace 18b2c87c925b54d6 ]---
Signed-off-by: Wang YanQing <udknight@gmail.com>
---
drivers/video/uvesafb.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
index e7f69ef..f9a670d 100644
--- a/drivers/video/uvesafb.c
+++ b/drivers/video/uvesafb.c
@@ -23,6 +23,7 @@
#include <video/uvesafb.h>
#ifdef CONFIG_X86
#include <video/vga.h>
+#include <linux/pci.h>
#endif
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
@@ -815,8 +816,15 @@ static int __devinit uvesafb_vbe_init(struct fb_info *info)
par->pmi_setpal = pmi_setpal;
par->ypan = ypan;
- if (par->pmi_setpal || par->ypan)
- uvesafb_vbe_getpmi(task, par);
+ if (par->pmi_setpal || par->ypan) {
+ if (pcibios_enabled) {
+ uvesafb_vbe_getpmi(task, par);
+ } else {
+ par->pmi_setpal = par->ypan = 0;
+ printk(KERN_WARNING "uvesafb: PCI BIOS area is NX."
+ "Can't use protected mode interface\n");
+ }
+ }
#else
/* The protected mode interface is not available on non-x86. */
par->pmi_setpal = par->ypan = 0;
--
1.7.9.2.315.g25a78
Signed-off-by: Wang YanQing <udknight@gmail.com>
---
drivers/video/uvesafb.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
index 260cca7..26e83d7 100644
--- a/drivers/video/uvesafb.c
+++ b/drivers/video/uvesafb.c
@@ -815,8 +815,15 @@ static int __devinit uvesafb_vbe_init(struct fb_info *info)
par->pmi_setpal = pmi_setpal;
par->ypan = ypan;
- if (par->pmi_setpal || par->ypan)
- uvesafb_vbe_getpmi(task, par);
+ if (par->pmi_setpal || par->ypan) {
+ if (__supported_pte_mask & _PAGE_NX) {
+ par->pmi_setpal = par->ypan = 0;
+ printk(KERN_WARNING "uvesafb: NX protection is actively."
+ "We have better not to use the PMI.\n");
+ } else {
+ uvesafb_vbe_getpmi(task, par);
+ }
+ }
#else
/* The protected mode interface is not available on non-x86. */
par->pmi_setpal = par->ypan = 0;
--
1.7.9.2.315.g25a78
^ permalink raw reply related
* [PATCH] video:uvesafb: Fix oops that uvesafb try to execute NX-protected page
From: Wang YanQing @ 2012-04-01 0:54 UTC (permalink / raw)
To: FlorianSchandinat; +Cc: linux-fbdev, linux-kernel, spock, alan
In-Reply-To: <20120302004850.GA4139@udknight>
This patch fix the oops below that catched in my machine
[ 81.560602] uvesafb: NVIDIA Corporation, GT216 Board - 0696a290, Chip Rev , OEM: NVIDIA, VBE v3.0
[ 81.609384] uvesafb: protected mode interface info at c000:d350
[ 81.609388] uvesafb: pmi: set display start = c00cd3b3, set palette = c00cd40e
[ 81.609390] uvesafb: pmi: ports = 3b4 3b5 3ba 3c0 3c1 3c4 3c5 3c6 3c7 3c8 3c9 3cc 3ce 3cf 3d0 3d1 3d2 3d3 3d4 3d5 3da
[ 81.614558] uvesafb: VBIOS/hardware doesn't support DDC transfers
[ 81.614562] uvesafb: no monitor limits have been set, default refresh rate will be used
[ 81.614994] uvesafb: scrolling: ypan using protected mode interface, yres_virtualI15
[ 81.744147] kernel tried to execute NX-protected page - exploit attempt? (uid: 0)
[ 81.744153] BUG: unable to handle kernel paging request at c00cd3b3
[ 81.744159] IP: [<c00cd3b3>] 0xc00cd3b2
[ 81.744167] *pdpt = 00000000016d6001 *pde = 0000000001c7b067 *pte = 80000000000cd163
[ 81.744171] Oops: 0011 [#1] SMP
[ 81.744174] Modules linked in: uvesafb(+) cfbcopyarea cfbimgblt cfbfillrect
[ 81.744178]
[ 81.744181] Pid: 3497, comm: modprobe Not tainted 3.3.0-rc4NX+ #71 Acer Aspire 4741 /Aspire 4741
[ 81.744185] EIP: 0060:[<c00cd3b3>] EFLAGS: 00010246 CPU: 0
[ 81.744187] EIP is at 0xc00cd3b3
[ 81.744189] EAX: 00004f07 EBX: 00000000 ECX: 00000000 EDX: 00000000
[ 81.744191] ESI: f763f000 EDI: f763f6e8 EBP: f57f3a0c ESP: f57f3a00
[ 81.744192] DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
[ 81.744195] Process modprobe (pid: 3497, tiõ7f2000 task÷48c600 task.tiõ7f2000)
[ 81.744196] Stack:
[ 81.744197] f82512c5 f759341c 00000000 f57f3a30 c124a9bc 00000001 00000001 000001e0
[ 81.744202] f8251280 f763f000 f7593400 00000000 f57f3a40 c12598dd f5c0c000 00000000
[ 81.744206] f57f3b10 c1255efe c125a21a 00000006 f763f09c 00000000 c1c6cb60 f7593400
[ 81.744210] Call Trace:
[ 81.744215] [<f82512c5>] ? uvesafb_pan_display+0x45/0x60 [uvesafb]
[ 81.744222] [<c124a9bc>] fb_pan_display+0x10c/0x160
[ 81.744226] [<f8251280>] ? uvesafb_vbe_find_mode+0x180/0x180 [uvesafb]
[ 81.744230] [<c12598dd>] bit_update_start+0x1d/0x50
[ 81.744232] [<c1255efe>] fbcon_switch+0x39e/0x550
[ 81.744235] [<c125a21a>] ? bit_cursor+0x4ea/0x560
[ 81.744240] [<c129b6cb>] redraw_screen+0x12b/0x220
[ 81.744245] [<c128843b>] ? tty_do_resize+0x3b/0xc0
[ 81.744247] [<c129ef42>] vc_do_resize+0x3d2/0x3e0
[ 81.744250] [<c129efb4>] vc_resize+0x14/0x20
[ 81.744253] [<c12586bd>] fbcon_init+0x29d/0x500
[ 81.744255] [<c12984c4>] ? set_inverse_trans_unicode+0xe4/0x110
[ 81.744258] [<c129b378>] visual_init+0xb8/0x150
[ 81.744261] [<c129c16c>] bind_con_driver+0x16c/0x360
[ 81.744264] [<c129b47e>] ? register_con_driver+0x6e/0x190
[ 81.744267] [<c129c3a1>] take_over_console+0x41/0x50
[ 81.744269] [<c1257b7a>] fbcon_takeover+0x6a/0xd0
[ 81.744272] [<c12594b8>] fbcon_event_notify+0x758/0x790
[ 81.744277] [<c10929e2>] notifier_call_chain+0x42/0xb0
[ 81.744280] [<c1092d30>] __blocking_notifier_call_chain+0x60/0x90
[ 81.744283] [<c1092d7a>] blocking_notifier_call_chain+0x1a/0x20
[ 81.744285] [<c124a5a1>] fb_notifier_call_chain+0x11/0x20
[ 81.744288] [<c124b759>] register_framebuffer+0x1d9/0x2b0
[ 81.744293] [<c1061c73>] ? ioremap_wc+0x33/0x40
[ 81.744298] [<f82537c6>] uvesafb_probe+0xaba/0xc40 [uvesafb]
[ 81.744302] [<c12bb81f>] platform_drv_probe+0xf/0x20
[ 81.744306] [<c12ba558>] driver_probe_device+0x68/0x170
[ 81.744309] [<c12ba731>] __device_attach+0x41/0x50
[ 81.744313] [<c12b9088>] bus_for_each_drv+0x48/0x70
[ 81.744316] [<c12ba7f3>] device_attach+0x83/0xa0
[ 81.744319] [<c12ba6f0>] ? __driver_attach+0x90/0x90
[ 81.744321] [<c12b991f>] bus_probe_device+0x6f/0x90
[ 81.744324] [<c12b8a45>] device_add+0x5e5/0x680
[ 81.744329] [<c122a1a3>] ? kvasprintf+0x43/0x60
[ 81.744332] [<c121e6e4>] ? kobject_set_name_vargs+0x64/0x70
[ 81.744335] [<c121e6e4>] ? kobject_set_name_vargs+0x64/0x70
[ 81.744339] [<c12bbe9f>] platform_device_add+0xff/0x1b0
[ 81.744343] [<f8252906>] uvesafb_init+0x50/0x9b [uvesafb]
[ 81.744346] [<c100111f>] do_one_initcall+0x2f/0x170
[ 81.744350] [<f82528b6>] ? uvesafb_is_valid_mode+0x66/0x66 [uvesafb]
[ 81.744355] [<c10c6994>] sys_init_module+0xf4/0x1410
[ 81.744359] [<c1157fc0>] ? vfsmount_lock_local_unlock_cpu+0x30/0x30
[ 81.744363] [<c144cb10>] sysenter_do_call+0x12/0x36
[ 81.744365] Code: f5 00 00 00 32 f6 66 8b da 66 d1 e3 66 ba d4 03 8a e3 b0 1c 66 ef b0 1e 66 ef 8a e7 b0 1d 66 ef b0 1f 66 ef e8 fa 00 00 00 61 c3 <60> e8 c8 00 00 00 66 8b f3 66 8b da 66 ba d4 03 b0 0c 8a e5 66
[ 81.744388] EIP: [<c00cd3b3>] 0xc00cd3b3 SS:ESP 0068:f57f3a00
[ 81.744391] CR2: 00000000c00cd3b3
[ 81.744393] ---[ end trace 18b2c87c925b54d6 ]---
Signed-off-by: Wang YanQing <udknight@gmail.com>
---
drivers/video/uvesafb.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
index 260cca7..26e83d7 100644
--- a/drivers/video/uvesafb.c
+++ b/drivers/video/uvesafb.c
@@ -815,8 +815,15 @@ static int __devinit uvesafb_vbe_init(struct fb_info *info)
par->pmi_setpal = pmi_setpal;
par->ypan = ypan;
- if (par->pmi_setpal || par->ypan)
- uvesafb_vbe_getpmi(task, par);
+ if (par->pmi_setpal || par->ypan) {
+ if (__supported_pte_mask & _PAGE_NX) {
+ par->pmi_setpal = par->ypan = 0;
+ printk(KERN_WARNING "uvesafb: NX protection is actively."
+ "We have better not to use the PMI.\n");
+ } else {
+ uvesafb_vbe_getpmi(task, par);
+ }
+ }
#else
/* The protected mode interface is not available on non-x86. */
par->pmi_setpal = par->ypan = 0;
--
1.7.9.2.315.g25a78
^ permalink raw reply related
* Re: [PATCH] video:uvesafb: Fix oops that uvesafb try to execute NX-protected page
From: Wang YanQing @ 2012-04-01 0:55 UTC (permalink / raw)
To: FlorianSchandinat, alan, linux-fbdev, linux-kernel, spock
In-Reply-To: <20120401004728.GA4329@udknight>
On Sun, Apr 01, 2012 at 08:47:28AM +0800, Wang YanQing wrote:
>
> This patch fix the oops below that catched in my machine
>
> [ 81.560602] uvesafb: NVIDIA Corporation, GT216 Board - 0696a290, Chip Rev , OEM: NVIDIA, VBE v3.0
> [ 81.609384] uvesafb: protected mode interface info at c000:d350
> [ 81.609388] uvesafb: pmi: set display start = c00cd3b3, set palette = c00cd40e
> [ 81.609390] uvesafb: pmi: ports = 3b4 3b5 3ba 3c0 3c1 3c4 3c5 3c6 3c7 3c8 3c9 3cc 3ce 3cf 3d0 3d1 3d2 3d3 3d4 3d5 3da
> [ 81.614558] uvesafb: VBIOS/hardware doesn't support DDC transfers
> [ 81.614562] uvesafb: no monitor limits have been set, default refresh rate will be used
> [ 81.614994] uvesafb: scrolling: ypan using protected mode interface, yres_virtualI15
> [ 81.744147] kernel tried to execute NX-protected page - exploit attempt? (uid: 0)
> [ 81.744153] BUG: unable to handle kernel paging request at c00cd3b3
> [ 81.744159] IP: [<c00cd3b3>] 0xc00cd3b2
> [ 81.744167] *pdpt = 00000000016d6001 *pde = 0000000001c7b067 *pte = 80000000000cd163
> [ 81.744171] Oops: 0011 [#1] SMP
> [ 81.744174] Modules linked in: uvesafb(+) cfbcopyarea cfbimgblt cfbfillrect
> [ 81.744178]
> [ 81.744181] Pid: 3497, comm: modprobe Not tainted 3.3.0-rc4NX+ #71 Acer Aspire 4741 /Aspire 4741
> [ 81.744185] EIP: 0060:[<c00cd3b3>] EFLAGS: 00010246 CPU: 0
> [ 81.744187] EIP is at 0xc00cd3b3
> [ 81.744189] EAX: 00004f07 EBX: 00000000 ECX: 00000000 EDX: 00000000
> [ 81.744191] ESI: f763f000 EDI: f763f6e8 EBP: f57f3a0c ESP: f57f3a00
> [ 81.744192] DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
> [ 81.744195] Process modprobe (pid: 3497, tiõ7f2000 task÷48c600 task.tiõ7f2000)
> [ 81.744196] Stack:
> [ 81.744197] f82512c5 f759341c 00000000 f57f3a30 c124a9bc 00000001 00000001 000001e0
> [ 81.744202] f8251280 f763f000 f7593400 00000000 f57f3a40 c12598dd f5c0c000 00000000
> [ 81.744206] f57f3b10 c1255efe c125a21a 00000006 f763f09c 00000000 c1c6cb60 f7593400
> [ 81.744210] Call Trace:
> [ 81.744215] [<f82512c5>] ? uvesafb_pan_display+0x45/0x60 [uvesafb]
> [ 81.744222] [<c124a9bc>] fb_pan_display+0x10c/0x160
> [ 81.744226] [<f8251280>] ? uvesafb_vbe_find_mode+0x180/0x180 [uvesafb]
> [ 81.744230] [<c12598dd>] bit_update_start+0x1d/0x50
> [ 81.744232] [<c1255efe>] fbcon_switch+0x39e/0x550
> [ 81.744235] [<c125a21a>] ? bit_cursor+0x4ea/0x560
> [ 81.744240] [<c129b6cb>] redraw_screen+0x12b/0x220
> [ 81.744245] [<c128843b>] ? tty_do_resize+0x3b/0xc0
> [ 81.744247] [<c129ef42>] vc_do_resize+0x3d2/0x3e0
> [ 81.744250] [<c129efb4>] vc_resize+0x14/0x20
> [ 81.744253] [<c12586bd>] fbcon_init+0x29d/0x500
> [ 81.744255] [<c12984c4>] ? set_inverse_trans_unicode+0xe4/0x110
> [ 81.744258] [<c129b378>] visual_init+0xb8/0x150
> [ 81.744261] [<c129c16c>] bind_con_driver+0x16c/0x360
> [ 81.744264] [<c129b47e>] ? register_con_driver+0x6e/0x190
> [ 81.744267] [<c129c3a1>] take_over_console+0x41/0x50
> [ 81.744269] [<c1257b7a>] fbcon_takeover+0x6a/0xd0
> [ 81.744272] [<c12594b8>] fbcon_event_notify+0x758/0x790
> [ 81.744277] [<c10929e2>] notifier_call_chain+0x42/0xb0
> [ 81.744280] [<c1092d30>] __blocking_notifier_call_chain+0x60/0x90
> [ 81.744283] [<c1092d7a>] blocking_notifier_call_chain+0x1a/0x20
> [ 81.744285] [<c124a5a1>] fb_notifier_call_chain+0x11/0x20
> [ 81.744288] [<c124b759>] register_framebuffer+0x1d9/0x2b0
> [ 81.744293] [<c1061c73>] ? ioremap_wc+0x33/0x40
> [ 81.744298] [<f82537c6>] uvesafb_probe+0xaba/0xc40 [uvesafb]
> [ 81.744302] [<c12bb81f>] platform_drv_probe+0xf/0x20
> [ 81.744306] [<c12ba558>] driver_probe_device+0x68/0x170
> [ 81.744309] [<c12ba731>] __device_attach+0x41/0x50
> [ 81.744313] [<c12b9088>] bus_for_each_drv+0x48/0x70
> [ 81.744316] [<c12ba7f3>] device_attach+0x83/0xa0
> [ 81.744319] [<c12ba6f0>] ? __driver_attach+0x90/0x90
> [ 81.744321] [<c12b991f>] bus_probe_device+0x6f/0x90
> [ 81.744324] [<c12b8a45>] device_add+0x5e5/0x680
> [ 81.744329] [<c122a1a3>] ? kvasprintf+0x43/0x60
> [ 81.744332] [<c121e6e4>] ? kobject_set_name_vargs+0x64/0x70
> [ 81.744335] [<c121e6e4>] ? kobject_set_name_vargs+0x64/0x70
> [ 81.744339] [<c12bbe9f>] platform_device_add+0xff/0x1b0
> [ 81.744343] [<f8252906>] uvesafb_init+0x50/0x9b [uvesafb]
> [ 81.744346] [<c100111f>] do_one_initcall+0x2f/0x170
> [ 81.744350] [<f82528b6>] ? uvesafb_is_valid_mode+0x66/0x66 [uvesafb]
> [ 81.744355] [<c10c6994>] sys_init_module+0xf4/0x1410
> [ 81.744359] [<c1157fc0>] ? vfsmount_lock_local_unlock_cpu+0x30/0x30
> [ 81.744363] [<c144cb10>] sysenter_do_call+0x12/0x36
> [ 81.744365] Code: f5 00 00 00 32 f6 66 8b da 66 d1 e3 66 ba d4 03 8a e3 b0 1c 66 ef b0 1e 66 ef 8a e7 b0 1d 66 ef b0 1f 66 ef e8 fa 00 00 00 61 c3 <60> e8 c8 00 00 00 66 8b f3 66 8b da 66 ba d4 03 b0 0c 8a e5 66
> [ 81.744388] EIP: [<c00cd3b3>] 0xc00cd3b3 SS:ESP 0068:f57f3a00
> [ 81.744391] CR2: 00000000c00cd3b3
> [ 81.744393] ---[ end trace 18b2c87c925b54d6 ]---
>
> Signed-off-by: Wang YanQing <udknight@gmail.com>
> ---
> drivers/video/uvesafb.c | 12 ++++++++++--
> 1 file changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
> index e7f69ef..f9a670d 100644
> --- a/drivers/video/uvesafb.c
> +++ b/drivers/video/uvesafb.c
> @@ -23,6 +23,7 @@
> #include <video/uvesafb.h>
> #ifdef CONFIG_X86
> #include <video/vga.h>
> +#include <linux/pci.h>
> #endif
> #ifdef CONFIG_MTRR
> #include <asm/mtrr.h>
> @@ -815,8 +816,15 @@ static int __devinit uvesafb_vbe_init(struct fb_info *info)
> par->pmi_setpal = pmi_setpal;
> par->ypan = ypan;
>
> - if (par->pmi_setpal || par->ypan)
> - uvesafb_vbe_getpmi(task, par);
> + if (par->pmi_setpal || par->ypan) {
> + if (pcibios_enabled) {
> + uvesafb_vbe_getpmi(task, par);
> + } else {
> + par->pmi_setpal = par->ypan = 0;
> + printk(KERN_WARNING "uvesafb: PCI BIOS area is NX."
> + "Can't use protected mode interface\n");
> + }
> + }
> #else
> /* The protected mode interface is not available on non-x86. */
> par->pmi_setpal = par->ypan = 0;
> --
> 1.7.9.2.315.g25a78
>
> Signed-off-by: Wang YanQing <udknight@gmail.com>
> ---
> drivers/video/uvesafb.c | 11 +++++++++--
> 1 file changed, 9 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
> index 260cca7..26e83d7 100644
> --- a/drivers/video/uvesafb.c
> +++ b/drivers/video/uvesafb.c
> @@ -815,8 +815,15 @@ static int __devinit uvesafb_vbe_init(struct fb_info *info)
> par->pmi_setpal = pmi_setpal;
> par->ypan = ypan;
>
> - if (par->pmi_setpal || par->ypan)
> - uvesafb_vbe_getpmi(task, par);
> + if (par->pmi_setpal || par->ypan) {
> + if (__supported_pte_mask & _PAGE_NX) {
> + par->pmi_setpal = par->ypan = 0;
> + printk(KERN_WARNING "uvesafb: NX protection is actively."
> + "We have better not to use the PMI.\n");
> + } else {
> + uvesafb_vbe_getpmi(task, par);
> + }
> + }
> #else
> /* The protected mode interface is not available on non-x86. */
> par->pmi_setpal = par->ypan = 0;
> --
> 1.7.9.2.315.g25a78
I am so sorry, it just a mistake to resend this patch by me, just ignore it.
Thanks
^ permalink raw reply
* Re: [PATCH] video:uvesafb: Fix oops that uvesafb try to execute NX-protected page
From: Wang YanQing @ 2012-04-01 1:05 UTC (permalink / raw)
To: Alan Cox, FlorianSchandinat, linux-fbdev, linux-kernel, spock
In-Reply-To: <20120328005238.GA3844@udknight>
On Wed, Mar 28, 2012 at 08:52:38AM +0800, Wang YanQing wrote:
> On Tue, Mar 27, 2012 at 02:32:43PM +0100, Alan Cox wrote:
> > On Tue, 27 Mar 2012 18:01:36 +0800
> > Wang YanQing <udknight@gmail.com> wrote:
> >
> > >
> > > Ok! I try to check pcibios_enabled first, but get some opposition by Alan Cox,
> > > but I want to make thing work and fix the oops, so I choice the simple way to
> > > check the (__supported_pte_mask & _PAGE_NX) instead of to check this variable plus
> > > pci kernel boot parameter, pci mmconfig works or not, and more, and more. It is not
> > > the best method, but it works and maybe all will feel happy.
> >
> > Okay let me ask the obvious question - why is it not the best method ?
> >
> > Apart from adding a helper in the includes for the arch code of
> >
> > static inline is_nx_enabled(void)
> > {
> > return !!(__supported_pte_mask & _PAGE_NX);
> > }
> >
> > is there anything else it lacks ?
> >
> > Yes ideally we'd set the relevant ROM areas executable, but for a simple
> > fix is there anything else that's a problem with it ?
> Ok! Maybe you had missed my previous reply
> http://permalink.gmane.org/gmane.linux.kernel/1272433
> It is not the best method, because the check is not enough.
> I means when NX is actively, the pci bios is NX or not also depend on
> the code path in pci_arch_init which will be influenced by the acpi on or off, pci kernel boot
> parameter, even kernel config like pci access method PCI_GOANY, PCI_GOMMCONFIG, or PCI_GODIRECT,
> but if I check the pcibios_enabled, all the above can be ignored.
>
> if uvesafb use the PMI when PCI BIOS is X, it can get the better work efficience then use the redraw
> method as a fallback when do the panning.
Alan
I am just curious, I want to know what I describe above is right a little,
or wrong about all the aspect.
thanks.
^ permalink raw reply
* Re: [PATCH v2] video: s3c-fb: Add device tree support
From: Shawn Guo @ 2012-04-01 6:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAH+eYFCrdtYC+v3tgqsaCS9-Y61JCwA1MLkkPtH14p=JWBbzBw@mail.gmail.com>
On Fri, Mar 30, 2012 at 09:25:14PM +0530, Rabin Vincent wrote:
> On Fri, Mar 30, 2012 at 11:23, Thomas Abraham <thomas.abraham@linaro.org> wrote:
> > + - samsung,fimd-display: The fimd controller is interfaced with the a
> > + display device such as a lcd panel. This property should specify the
> > + phandle of the display device node. For a display device node that
> > + represents a RGB type display interface, it is expected to specify the
> > + video interface timing using the following properties.
> > +
> > + - lcd-htiming: Specifies the horizontal timing for the overlay. The
> > + horizontal timing includes four parameters in the following order.
> > +
> > + - horizontal back porch (in number of lcd clocks)
> > + - horizontal front porch (in number of lcd clocks)
> > + - hsync pulse width (in number of lcd clocks)
> > + - Display panels X resolution.
> > +
> > + - lcd-vtiming: Specifies the vertical timing for the overlay. The
> > + vertical timing includes four parameters in the following order.
> > +
> > + - vertical back porch (in number of lcd lines)
> > + - vertical front porch (in number of lcd lines)
> > + - vsync pulse width (in number of lcd clocks)
> > + - Y resolution.
>
> In this old thread, it was suggested to use a raw EDID block to supply
> timings, and since then a couple of drivers in mainline (sm501fb and
> fsl-diu) are doing it that way:
>
> http://lists.ozlabs.org/pipermail/linuxppc-dev/2010-February/080683.html
>
> Shouldn't this driver be doing the same thing? If not, shouldn't
> whatever interface this is adding be provided in a common helper (like
> that old patch was trying to add) so it's standardized between drivers?
+1
We need a generic binding for the data defined in "struct fb_videomode"
and a generic helper function to retrieve the data from device tree,
so that individual display driver does not have to invent their owns.
--
Regards,
Shawn
^ permalink raw reply
* [PATCH v2] fb_defio: add first_io callback
From: Heiko Stübner @ 2012-04-01 19:51 UTC (permalink / raw)
To: linux-fbdev
With this optional callback the driver is notified when the first page
is entered into the pagelist and a new deferred_io call is scheduled.
A possible use-case for this is runtime-pm. In the first_io call
pm_runtime_get()
could be called, which starts an asynchronous runtime_resume of the
device. In the deferred_io callback a call to
pm_runtime_barrier()
makes the sure, the device is resumed by then and a
pm_runtime_put()
may put the device back to sleep.
Also, some SoCs may use the runtime-pm system to determine if they
are able to enter deeper idle states. Therefore it is necessary to
keep the use-count from the first written page until the conclusion
of the screen update, to prevent the system from going to sleep before
completing the pending update.
Two users of defio were using kmalloc to allocate the structure.
These allocations are changed to kzalloc, to prevent uninitialised
.first_io members in those drivers.
Signed-off-by: Heiko Stübner <heiko@sntech.de>
---
changes since v1: convert fb_deferred_io kmalloc calls to kzalloc
drivers/video/fb_defio.c | 4 ++++
drivers/video/smscufx.c | 2 +-
drivers/video/udlfb.c | 2 +-
include/linux/fb.h | 1 +
4 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c
index c27e153..070f26f 100644
--- a/drivers/video/fb_defio.c
+++ b/drivers/video/fb_defio.c
@@ -107,6 +107,10 @@ static int fb_deferred_io_mkwrite(struct vm_area_struct
*vma,
/* protect against the workqueue changing the page list */
mutex_lock(&fbdefio->lock);
+ /* first write in this cycle, notify the driver */
+ if (fbdefio->first_io && list_empty(&fbdefio->pagelist))
+ fbdefio->first_io(info);
+
/*
* We want the page to remain locked from ->page_mkwrite until
* the PTE is marked dirty to avoid page_mkclean() being called
diff --git a/drivers/video/smscufx.c b/drivers/video/smscufx.c
index ccbfef5..9985785 100644
--- a/drivers/video/smscufx.c
+++ b/drivers/video/smscufx.c
@@ -1083,7 +1083,7 @@ static int ufx_ops_open(struct fb_info *info, int user)
struct fb_deferred_io *fbdefio;
- fbdefio = kmalloc(sizeof(struct fb_deferred_io), GFP_KERNEL);
+ fbdefio = kzalloc(sizeof(struct fb_deferred_io), GFP_KERNEL);
if (fbdefio) {
fbdefio->delay = UFX_DEFIO_WRITE_DELAY;
diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c
index 157df78..8909d47 100644
--- a/drivers/video/udlfb.c
+++ b/drivers/video/udlfb.c
@@ -893,7 +893,7 @@ static int dlfb_ops_open(struct fb_info *info, int user)
struct fb_deferred_io *fbdefio;
- fbdefio = kmalloc(sizeof(struct fb_deferred_io), GFP_KERNEL);
+ fbdefio = kzalloc(sizeof(struct fb_deferred_io), GFP_KERNEL);
if (fbdefio) {
fbdefio->delay = DL_DEFIO_WRITE_DELAY;
diff --git a/include/linux/fb.h b/include/linux/fb.h
index d31cb68..c10e71e 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -607,6 +607,7 @@ struct fb_deferred_io {
struct mutex lock; /* mutex that protects the page list */
struct list_head pagelist; /* list of touched pages */
/* callback */
+ void (*first_io)(struct fb_info *info);
void (*deferred_io)(struct fb_info *info, struct list_head *pagelist);
};
#endif
--
1.7.2.3
^ permalink raw reply related
* [PATCH V3 0/3] OMAPDSS: DISPC: Enable predecimation for DMA and VRFB
From: Chandrabhanu Mahapatra @ 2012-04-02 14:11 UTC (permalink / raw)
To: tomi.valkeinen; +Cc: linux-omap, linux-fbdev, Chandrabhanu Mahapatra
In-Reply-To: <[PATCH V2 0/3] OMAPDSS: DISPC: Enable predecimation for DMA and VRFB>
Hi everyone,
the following patch set directs to enable predecimation for DMA and VRFB
which consists of two pacthes.
The first patch is based on code written by Lajos Molnar <lajos@ti.com> in
Android Kernel, which updates the code with predecimation logic thereby
increasing the downscaling ability of the DISPC module.
The second patch is based on code written by Ville Syrj채l채
<ville.syrjala@nokia.com> which aims to avoid synclost errors occurring
in OMAP3 due to some undocumented horizontal position and timing related
limitations which I faced during testing of the previous patch.
The third patch corrects the usage of dispc fclk in scaling checks by
replacing it with dispc_core_clk as per suggestions of Ville Syrj채l채.
Modifications in V3 series:
* In 1st patch a check for decim_x_min has been added to avoid assigning of
decim_x less than possible leading to assignment of scaling more than 4 times
* In 2nd patch
-> check_horiz_timing() has been changed to check_horiz_timing_omap3() and
function description in code has been added
-> clean up code of dispc_mgr_lclk_rate() has been removed
* In 3rd patch dispc_core_clk_rate() is introduced.
I have tested these patches successfully on OMAP2, OMAP3 AND OMAP4 on the
mainline kernel v3.4rc1. Horizontal and vertical predecimation worked fine
but skewed images were seen on OMAP2 and OMAP3 on HDMI tv during horizontal
predecimation which will be addressed in the future patches.
All your comments and suggestions are welcome.
Regards,
Chandrabhanu
Chandrabhanu Mahapatra (3):
OMAPDSS: DISPC: Enable predecimation
OMAPDSS: DISPC: Handle synclost errors in OMAP3
OMAPDSS: DISPC: Correct DISPC functional clock usage
drivers/video/omap2/dss/dispc.c | 354 +++++++++++++++++++++++++++++---------
drivers/video/omap2/dss/dss.h | 1 +
2 files changed, 271 insertions(+), 84 deletions(-)
--
To unsubscribe from this list: send the line "unsubscribe linux-fbdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH V3 0/3] OMAPDSS: DISPC: Enable predecimation for DMA and VRFB
From: Chandrabhanu Mahapatra @ 2012-04-02 15:25 UTC (permalink / raw)
To: tomi.valkeinen; +Cc: linux-omap, linux-fbdev, Chandrabhanu Mahapatra
In-Reply-To: <1333375180-10470-1-git-send-email-cmahapatra@ti.com>
Hi everyone,
the following patch set directs to enable predecimation for DMA and VRFB
which consists of two pacthes.
The first patch is based on code written by Lajos Molnar <lajos@ti.com> in
Android Kernel, which updates the code with predecimation logic thereby
increasing the downscaling ability of the DISPC module.
The second patch is based on code written by Ville Syrj채l채
<ville.syrjala@nokia.com> which aims to avoid synclost errors occurring
in OMAP3 due to some undocumented horizontal position and timing related
limitations which I faced during testing of the previous patch.
The third patch corrects the usage of dispc fclk in scaling checks by
replacing it with dispc_core_clk as per suggestions of Ville Syrj채l채.
Modifications in V3 series:
* In 1st patch a check for decim_x_min has been added to avoid assigning of
decim_x less than possible leading to assignment of scaling more than 4 times
* In 2nd patch
-> check_horiz_timing() has been changed to check_horiz_timing_omap3() and
function description in code has been added
-> clean up code of dispc_mgr_lclk_rate() has been removed
* In 3rd patch dispc_core_clk_rate() is introduced.
I have tested these patches successfully on OMAP2, OMAP3 AND OMAP4 on the
mainline kernel v3.4rc1. Horizontal and vertical predecimation worked fine
but skewed images were seen on OMAP2 and OMAP3 on HDMI tv during horizontal
predecimation which will be addressed in the future patches.
All your comments and suggestions are welcome.
Regards,
Chandrabhanu
Chandrabhanu Mahapatra (3):
OMAPDSS: DISPC: Enable predecimation
OMAPDSS: DISPC: Handle synclost errors in OMAP3
OMAPDSS: DISPC: Correct DISPC functional clock usage
drivers/video/omap2/dss/dispc.c | 354 +++++++++++++++++++++++++++++---------
drivers/video/omap2/dss/dss.h | 1 +
2 files changed, 271 insertions(+), 84 deletions(-)
--
To unsubscribe from this list: send the line "unsubscribe linux-fbdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH V3 1/3] OMAPDSS: DISPC: Enable predecimation
From: Chandrabhanu Mahapatra @ 2012-04-02 15:25 UTC (permalink / raw)
To: tomi.valkeinen; +Cc: linux-omap, linux-fbdev, Chandrabhanu Mahapatra
In-Reply-To: <1333379598-11544-1-git-send-email-cmahapatra@ti.com>
In OMAP3 and OMAP4, the DISPC Scaler can downscale an image up to 4 times, and
up to 2 times in OMAP2. However, with predecimation, the image can be reduced
to 16 times by fetching only the necessary pixels in memory. Then this
predecimated image can be downscaled further by the DISPC scaler.
The pipeline is configured to use a burst of size 8 * 128 bits which consists
of 8 mini bursts of 16 bytes each. So, horizontal predecimation more than 16
can lead to complete discarding of such mini bursts. L3 interconnect may
handover the bus to some other initiator and inturn delay the fetching of
pixels leading to underflows. So, maximum predecimation limit is fixed at 16.
Based on the downscaling required, a prior calculation of predecimation values
for width and height of an image is done. Since, Predecimation reduces quality
of an image higher priorty is given to DISPC Scaler for downscaling.
This code was successfully tested on OMAP2, OMAP3 and OMAP4. Horizontal and
vertical predecimation worked fine except for some synclost errors due to
undocumented errata in OMAP3 which are fixed later and skewed images were seen
on OMAP2 and OMAP3 during horizontal predecimation which will be addressed in
the future patches.
This code is based on code written by Lajos Molnar <lajos@ti.com> who had added
predecimation support for NV12/YUV/rotated/SDMA buffers.
Signed-off-by: Chandrabhanu Mahapatra <cmahapatra@ti.com>
---
drivers/video/omap2/dss/dispc.c | 266 +++++++++++++++++++++++++++------------
1 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index ee30937..4ab5433 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -1431,7 +1431,7 @@ static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
enum omap_color_mode color_mode, bool fieldmode,
unsigned int field_offset,
unsigned *offset0, unsigned *offset1,
- s32 *row_inc, s32 *pix_inc)
+ s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim)
{
u8 ps;
@@ -1477,10 +1477,10 @@ static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
else
*offset0 = 0;
- *row_inc = pixinc(1 + (screen_width - width) +
- (fieldmode ? screen_width : 0),
- ps);
- *pix_inc = pixinc(1, ps);
+ *row_inc = pixinc(1 +
+ (y_predecim * screen_width - x_predecim * width) +
+ (fieldmode ? screen_width : 0), ps);
+ *pix_inc = pixinc(x_predecim, ps);
break;
case OMAP_DSS_ROT_0 + 4:
@@ -1498,10 +1498,10 @@ static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
*offset0 = field_offset * screen_width * ps;
else
*offset0 = 0;
- *row_inc = pixinc(1 - (screen_width + width) -
- (fieldmode ? screen_width : 0),
- ps);
- *pix_inc = pixinc(1, ps);
+ *row_inc = pixinc(1 -
+ (y_predecim * screen_width + x_predecim * width) -
+ (fieldmode ? screen_width : 0), ps);
+ *pix_inc = pixinc(x_predecim, ps);
break;
default:
@@ -1515,7 +1515,7 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
enum omap_color_mode color_mode, bool fieldmode,
unsigned int field_offset,
unsigned *offset0, unsigned *offset1,
- s32 *row_inc, s32 *pix_inc)
+ s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim)
{
u8 ps;
u16 fbw, fbh;
@@ -1557,10 +1557,14 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
*offset0 = *offset1 + field_offset * screen_width * ps;
else
*offset0 = *offset1;
- *row_inc = pixinc(1 + (screen_width - fbw) +
- (fieldmode ? screen_width : 0),
- ps);
- *pix_inc = pixinc(1, ps);
+ *row_inc = pixinc(1 +
+ (y_predecim * screen_width - fbw * x_predecim) +
+ (fieldmode ? screen_width : 0), ps);
+ if (color_mode = OMAP_DSS_COLOR_YUV2 ||
+ color_mode = OMAP_DSS_COLOR_UYVY)
+ *pix_inc = pixinc(x_predecim, 2 * ps);
+ else
+ *pix_inc = pixinc(x_predecim, ps);
break;
case OMAP_DSS_ROT_90:
*offset1 = screen_width * (fbh - 1) * ps;
@@ -1568,9 +1572,9 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
*offset0 = *offset1 + field_offset * ps;
else
*offset0 = *offset1;
- *row_inc = pixinc(screen_width * (fbh - 1) + 1 +
- (fieldmode ? 1 : 0), ps);
- *pix_inc = pixinc(-screen_width, ps);
+ *row_inc = pixinc(screen_width * (fbh * x_predecim - 1) +
+ y_predecim + (fieldmode ? 1 : 0), ps);
+ *pix_inc = pixinc(-x_predecim * screen_width, ps);
break;
case OMAP_DSS_ROT_180:
*offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
@@ -1579,10 +1583,13 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
else
*offset0 = *offset1;
*row_inc = pixinc(-1 -
- (screen_width - fbw) -
- (fieldmode ? screen_width : 0),
- ps);
- *pix_inc = pixinc(-1, ps);
+ (y_predecim * screen_width - fbw * x_predecim) -
+ (fieldmode ? screen_width : 0), ps);
+ if (color_mode = OMAP_DSS_COLOR_YUV2 ||
+ color_mode = OMAP_DSS_COLOR_UYVY)
+ *pix_inc = pixinc(-x_predecim, 2 * ps);
+ else
+ *pix_inc = pixinc(-x_predecim, ps);
break;
case OMAP_DSS_ROT_270:
*offset1 = (fbw - 1) * ps;
@@ -1590,9 +1597,9 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
*offset0 = *offset1 - field_offset * ps;
else
*offset0 = *offset1;
- *row_inc = pixinc(-screen_width * (fbh - 1) - 1 -
- (fieldmode ? 1 : 0), ps);
- *pix_inc = pixinc(screen_width, ps);
+ *row_inc = pixinc(-screen_width * (fbh * x_predecim - 1) -
+ y_predecim - (fieldmode ? 1 : 0), ps);
+ *pix_inc = pixinc(x_predecim * screen_width, ps);
break;
/* mirroring */
@@ -1602,10 +1609,14 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
*offset0 = *offset1 + field_offset * screen_width * ps;
else
*offset0 = *offset1;
- *row_inc = pixinc(screen_width * 2 - 1 +
+ *row_inc = pixinc(y_predecim * screen_width * 2 - 1 +
(fieldmode ? screen_width : 0),
ps);
- *pix_inc = pixinc(-1, ps);
+ if (color_mode = OMAP_DSS_COLOR_YUV2 ||
+ color_mode = OMAP_DSS_COLOR_UYVY)
+ *pix_inc = pixinc(-x_predecim, 2 * ps);
+ else
+ *pix_inc = pixinc(-x_predecim, ps);
break;
case OMAP_DSS_ROT_90 + 4:
@@ -1614,10 +1625,10 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
*offset0 = *offset1 + field_offset * ps;
else
*offset0 = *offset1;
- *row_inc = pixinc(-screen_width * (fbh - 1) + 1 +
- (fieldmode ? 1 : 0),
+ *row_inc = pixinc(-screen_width * (fbh * x_predecim - 1) +
+ y_predecim + (fieldmode ? 1 : 0),
ps);
- *pix_inc = pixinc(screen_width, ps);
+ *pix_inc = pixinc(x_predecim * screen_width, ps);
break;
case OMAP_DSS_ROT_180 + 4:
@@ -1626,10 +1637,14 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
*offset0 = *offset1 - field_offset * screen_width * ps;
else
*offset0 = *offset1;
- *row_inc = pixinc(1 - screen_width * 2 -
+ *row_inc = pixinc(1 - y_predecim * screen_width * 2 -
(fieldmode ? screen_width : 0),
ps);
- *pix_inc = pixinc(1, ps);
+ if (color_mode = OMAP_DSS_COLOR_YUV2 ||
+ color_mode = OMAP_DSS_COLOR_UYVY)
+ *pix_inc = pixinc(x_predecim, 2 * ps);
+ else
+ *pix_inc = pixinc(x_predecim, ps);
break;
case OMAP_DSS_ROT_270 + 4:
@@ -1638,10 +1653,10 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
*offset0 = *offset1 - field_offset * ps;
else
*offset0 = *offset1;
- *row_inc = pixinc(screen_width * (fbh - 1) - 1 -
- (fieldmode ? 1 : 0),
+ *row_inc = pixinc(screen_width * (fbh * x_predecim - 1) -
+ y_predecim - (fieldmode ? 1 : 0),
ps);
- *pix_inc = pixinc(-screen_width, ps);
+ *pix_inc = pixinc(-x_predecim * screen_width, ps);
break;
default:
@@ -1732,13 +1747,17 @@ static unsigned long calc_fclk(enum omap_channel channel, u16 width,
static int dispc_ovl_calc_scaling(enum omap_plane plane,
enum omap_channel channel, u16 width, u16 height,
u16 out_width, u16 out_height,
- enum omap_color_mode color_mode, bool *five_taps)
+ enum omap_color_mode color_mode, bool *five_taps,
+ int *x_predecim, int *y_predecim)
{
struct omap_overlay *ovl = omap_dss_get_overlay(plane);
const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
const int maxsinglelinewidth dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
+ const int max_decim_limit = 16;
unsigned long fclk = 0;
+ int decim_x, decim_y, error, min_factor;
+ u16 in_width, in_height, in_width_max = 0;
if (width = out_width && height = out_height)
return 0;
@@ -1746,45 +1765,121 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) = 0)
return -EINVAL;
- if (out_width < width / maxdownscale ||
- out_width > width * 8)
+ *x_predecim = max_decim_limit;
+ *y_predecim = max_decim_limit;
+
+ if (color_mode = OMAP_DSS_COLOR_CLUT1 ||
+ color_mode = OMAP_DSS_COLOR_CLUT2 ||
+ color_mode = OMAP_DSS_COLOR_CLUT4 ||
+ color_mode = OMAP_DSS_COLOR_CLUT8) {
+ *x_predecim = 1;
+ *y_predecim = 1;
+ *five_taps = false;
+ return 0;
+ }
+
+ decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale);
+ decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale);
+
+ min_factor = min(decim_x, decim_y);
+
+ if (decim_x > *x_predecim || out_width > width * 8)
return -EINVAL;
- if (out_height < height / maxdownscale ||
- out_height > height * 8)
+ if (decim_y > *y_predecim || out_height > height * 8)
return -EINVAL;
if (cpu_is_omap24xx()) {
- if (width > maxsinglelinewidth)
- DSSERR("Cannot scale max input width exceeded");
*five_taps = false;
- fclk = calc_fclk(channel, width, height, out_width,
- out_height);
+
+ do {
+ in_height = DIV_ROUND_UP(height, decim_y);
+ in_width = DIV_ROUND_UP(width, decim_x);
+ fclk = calc_fclk(channel, in_width, in_height,
+ out_width, out_height);
+ error = (in_width > maxsinglelinewidth || !fclk ||
+ fclk > dispc_fclk_rate());
+ if (error) {
+ if (decim_x = decim_y) {
+ decim_x = min_factor;
+ decim_y++;
+ } else {
+ swap(decim_x, decim_y);
+ if (decim_x < decim_y)
+ decim_x++;
+ }
+ }
+ } while (decim_x <= *x_predecim && decim_y <= *y_predecim &&
+ error);
+
+ if (in_width > maxsinglelinewidth) {
+ DSSERR("Cannot scale max input width exceeded");
+ return -EINVAL;
+ }
} else if (cpu_is_omap34xx()) {
- if (width > (maxsinglelinewidth * 2)) {
+
+ do {
+ in_height = DIV_ROUND_UP(height, decim_y);
+ in_width = DIV_ROUND_UP(width, decim_x);
+ fclk = calc_fclk_five_taps(channel, in_width, in_height,
+ out_width, out_height, color_mode);
+
+ if (in_width > maxsinglelinewidth)
+ if (in_height > out_height &&
+ in_height < out_height * 2)
+ *five_taps = false;
+ if (!*five_taps)
+ fclk = calc_fclk(channel, in_width, in_height,
+ out_width, out_height);
+ error = (in_width > maxsinglelinewidth * 2 ||
+ (in_width > maxsinglelinewidth && *five_taps) ||
+ !fclk || fclk > dispc_fclk_rate());
+ if (error) {
+ if (decim_x = decim_y) {
+ decim_x = min_factor;
+ decim_y++;
+ } else {
+ swap(decim_x, decim_y);
+ if (decim_x < decim_y)
+ decim_x++;
+ }
+ }
+ } while (decim_x <= *x_predecim && decim_y <= *y_predecim
+ && error);
+
+ if (in_width > (maxsinglelinewidth * 2)) {
DSSERR("Cannot setup scaling");
DSSERR("width exceeds maximum width possible");
return -EINVAL;
}
- fclk = calc_fclk_five_taps(channel, width, height, out_width,
- out_height, color_mode);
- if (width > maxsinglelinewidth) {
- if (height > out_height && height < out_height * 2)
- *five_taps = false;
- else {
- DSSERR("cannot setup scaling with five taps");
- return -EINVAL;
- }
+
+ if (in_width > maxsinglelinewidth && *five_taps) {
+ DSSERR("cannot setup scaling with five taps");
+ return -EINVAL;
}
- if (!*five_taps)
- fclk = calc_fclk(channel, width, height, out_width,
- out_height);
} else {
- if (width > maxsinglelinewidth) {
+ int decim_x_min = decim_x;
+ in_height = DIV_ROUND_UP(height, decim_y);
+ in_width_max = dispc_fclk_rate() /
+ DIV_ROUND_UP(dispc_mgr_pclk_rate(channel),
+ out_width);
+ decim_x = DIV_ROUND_UP(width, in_width_max);
+
+ decim_x = decim_x > decim_x_min ? decim_x : decim_x_min;
+ if (decim_x > *x_predecim)
+ return -EINVAL;
+
+ do {
+ in_width = DIV_ROUND_UP(width, decim_x);
+ } while (decim_x <= *x_predecim &&
+ in_width > maxsinglelinewidth && decim_x++);
+
+ if (in_width > maxsinglelinewidth) {
DSSERR("Cannot scale width exceeds max line width");
return -EINVAL;
}
- fclk = calc_fclk(channel, width, height, out_width,
+
+ fclk = calc_fclk(channel, in_width, in_height, out_width,
out_height);
}
@@ -1799,6 +1894,8 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
return -EINVAL;
}
+ *x_predecim = decim_x;
+ *y_predecim = decim_y;
return 0;
}
@@ -1814,8 +1911,11 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
s32 pix_inc;
u16 frame_height = oi->height;
unsigned int field_offset = 0;
- u16 outw, outh;
+ u16 in_height = oi->height;
+ u16 in_width = oi->width;
+ u16 out_width, out_height;
enum omap_channel channel;
+ int x_predecim = 1, y_predecim = 1;
channel = dispc_ovl_get_channel_out(plane);
@@ -1829,32 +1929,35 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
if (oi->paddr = 0)
return -EINVAL;
- outw = oi->out_width = 0 ? oi->width : oi->out_width;
- outh = oi->out_height = 0 ? oi->height : oi->out_height;
+ out_width = oi->out_width = 0 ? oi->width : oi->out_width;
+ out_height = oi->out_height = 0 ? oi->height : oi->out_height;
- if (ilace && oi->height = outh)
+ if (ilace && oi->height = out_height)
fieldmode = 1;
if (ilace) {
if (fieldmode)
- oi->height /= 2;
+ in_height /= 2;
oi->pos_y /= 2;
- outh /= 2;
+ out_height /= 2;
DSSDBG("adjusting for ilace: height %d, pos_y %d, "
"out_height %d\n",
- oi->height, oi->pos_y, outh);
+ in_height, oi->pos_y, out_height);
}
if (!dss_feat_color_mode_supported(plane, oi->color_mode))
return -EINVAL;
- r = dispc_ovl_calc_scaling(plane, channel, oi->width, oi->height,
- outw, outh, oi->color_mode,
- &five_taps);
+ r = dispc_ovl_calc_scaling(plane, channel, in_width, in_height,
+ out_width, out_height, oi->color_mode, &five_taps,
+ &x_predecim, &y_predecim);
if (r)
return r;
+ in_width = DIV_ROUND_UP(in_width, x_predecim);
+ in_height = DIV_ROUND_UP(in_height, y_predecim);
+
if (oi->color_mode = OMAP_DSS_COLOR_YUV2 ||
oi->color_mode = OMAP_DSS_COLOR_UYVY ||
oi->color_mode = OMAP_DSS_COLOR_NV12)
@@ -1868,10 +1971,10 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
* so the integer part must be added to the base address of the
* bottom field.
*/
- if (!oi->height || oi->height = outh)
+ if (!in_height || in_height = out_height)
field_offset = 0;
else
- field_offset = oi->height / outh / 2;
+ field_offset = in_height / out_height / 2;
}
/* Fields are independent but interleaved in memory. */
@@ -1880,14 +1983,16 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
if (oi->rotation_type = OMAP_DSS_ROT_DMA)
calc_dma_rotation_offset(oi->rotation, oi->mirror,
- oi->screen_width, oi->width, frame_height,
+ oi->screen_width, in_width, frame_height,
oi->color_mode, fieldmode, field_offset,
- &offset0, &offset1, &row_inc, &pix_inc);
+ &offset0, &offset1, &row_inc, &pix_inc,
+ x_predecim, y_predecim);
else
calc_vrfb_rotation_offset(oi->rotation, oi->mirror,
- oi->screen_width, oi->width, frame_height,
+ oi->screen_width, in_width, frame_height,
oi->color_mode, fieldmode, field_offset,
- &offset0, &offset1, &row_inc, &pix_inc);
+ &offset0, &offset1, &row_inc, &pix_inc,
+ x_predecim, y_predecim);
DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
offset0, offset1, row_inc, pix_inc);
@@ -1906,19 +2011,18 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
dispc_ovl_set_row_inc(plane, row_inc);
dispc_ovl_set_pix_inc(plane, pix_inc);
- DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, oi->width,
- oi->height, outw, outh);
+ DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, in_width,
+ in_height, out_width, out_height);
dispc_ovl_set_pos(plane, oi->pos_x, oi->pos_y);
- dispc_ovl_set_pic_size(plane, oi->width, oi->height);
+ dispc_ovl_set_pic_size(plane, in_width, in_height);
if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) {
- dispc_ovl_set_scaling(plane, oi->width, oi->height,
- outw, outh,
- ilace, five_taps, fieldmode,
+ dispc_ovl_set_scaling(plane, in_width, in_height, out_width,
+ out_height, ilace, five_taps, fieldmode,
oi->color_mode, oi->rotation);
- dispc_ovl_set_vid_size(plane, outw, outh);
+ dispc_ovl_set_vid_size(plane, out_width, out_height);
dispc_ovl_set_vid_color_conv(plane, cconv);
}
--
1.7.1
^ permalink raw reply related
* [PATCH V3 2/3] OMAPDSS: DISPC: Handle synclost errors in OMAP3
From: Chandrabhanu Mahapatra @ 2012-04-02 15:25 UTC (permalink / raw)
To: tomi.valkeinen; +Cc: linux-omap, linux-fbdev, Chandrabhanu Mahapatra
In-Reply-To: <1333379598-11544-2-git-send-email-cmahapatra@ti.com>
In OMAP3 DISPC video overlays suffer from some undocumented horizontal position
and timing related limitations leading to SYNCLOST errors. Whenever the image
window is moved towards the right of the screen SYNCLOST errors become
frequent. Checks have been implemented to see that DISPC driver rejects
configuration exceeding above limitations.
This code was successfully tested on OMAP3. This code is written based on code
written by Ville Syrj채l채 <ville.syrjala@nokia.com> in Linux OMAP kernel. Ville
Syrj채l채 <ville.syrjala@nokia.com> had added checks for video overlay horizontal
timing and DISPC horizontal blanking length limitations.
Signed-off-by: Chandrabhanu Mahapatra <cmahapatra@ti.com>
---
drivers/video/omap2/dss/dispc.c | 72 +++++++++++++++++++++++++++++++++++++--
1 files changed, 69 insertions(+), 3 deletions(-)
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index 4ab5433..17ffa71 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -1664,6 +1664,63 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
}
}
+/*
+ * This function is used to avoid synclosts in OMAP3, because of some
+ * undocumented horizontal position and timing related limitations.
+ */
+static int check_horiz_timing_omap3(enum omap_channel channel, u16 pos_x,
+ u16 width, u16 height, u16 out_width, u16 out_height)
+{
+ int DS = DIV_ROUND_UP(height, out_height);
+ struct omap_dss_device *dssdev = dispc_mgr_get_device(channel);
+ struct omap_video_timings t = dssdev->panel.timings;
+ unsigned long nonactive, lclk, pclk;
+ static const u8 limits[3] = { 8, 10, 20 };
+ u64 val, blank;
+ int i;
+
+ nonactive = t.x_res + t.hfp + t.hsw + t.hbp - out_width;
+ pclk = dispc_mgr_pclk_rate(channel);
+ if (dispc_mgr_is_lcd(channel))
+ lclk = dispc_mgr_lclk_rate(channel);
+ else
+ lclk = dispc_fclk_rate();
+
+ i = 0;
+ if (out_height < height)
+ i++;
+ if (out_width < width)
+ i++;
+ blank = div_u64((u64)(t.hbp + t.hsw + t.hfp) * lclk, pclk);
+ DSSDBG("blanking period + ppl = %llu (limit = %u)\n", blank, limits[i]);
+ if (blank <= limits[i])
+ return -EINVAL;
+
+ /*
+ * Pixel data should be prepared before visible display point starts.
+ * So, atleast DS-2 lines must have already been fetched by DISPC
+ * during nonactive - pos_x period.
+ */
+ val = div_u64((u64)(nonactive - pos_x) * lclk, pclk);
+ DSSDBG("(nonactive - pos_x) * pcd = %llu max(0, DS - 2) * width = %d\n",
+ val, max(0, DS - 2) * width);
+ if (val < max(0, DS - 2) * width)
+ return -EINVAL;
+
+ /*
+ * All lines need to be refilled during the nonactive period of which
+ * only one line can be loaded during the active period. So, atleast
+ * DS - 1 lines should be loaded during nonactive period.
+ */
+ val = div_u64((u64)nonactive * lclk, pclk);
+ DSSDBG("nonactive * pcd = %llu, max(0, DS - 1) * width = %d\n",
+ val, max(0, DS - 1) * width);
+ if (val < max(0, DS - 1) * width)
+ return -EINVAL;
+
+ return 0;
+}
+
static unsigned long calc_fclk_five_taps(enum omap_channel channel, u16 width,
u16 height, u16 out_width, u16 out_height,
enum omap_color_mode color_mode)
@@ -1748,7 +1805,7 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
enum omap_channel channel, u16 width, u16 height,
u16 out_width, u16 out_height,
enum omap_color_mode color_mode, bool *five_taps,
- int *x_predecim, int *y_predecim)
+ int *x_predecim, int *y_predecim, u16 pos_x)
{
struct omap_overlay *ovl = omap_dss_get_overlay(plane);
const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
@@ -1824,6 +1881,9 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
fclk = calc_fclk_five_taps(channel, in_width, in_height,
out_width, out_height, color_mode);
+ error = check_horiz_timing_omap3(channel, pos_x,
+ in_width, in_height, out_width, out_height);
+
if (in_width > maxsinglelinewidth)
if (in_height > out_height &&
in_height < out_height * 2)
@@ -1831,7 +1891,7 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
if (!*five_taps)
fclk = calc_fclk(channel, in_width, in_height,
out_width, out_height);
- error = (in_width > maxsinglelinewidth * 2 ||
+ error = (error || in_width > maxsinglelinewidth * 2 ||
(in_width > maxsinglelinewidth && *five_taps) ||
!fclk || fclk > dispc_fclk_rate());
if (error) {
@@ -1847,6 +1907,12 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
} while (decim_x <= *x_predecim && decim_y <= *y_predecim
&& error);
+ if (check_horiz_timing_omap3(channel, pos_x, width, height,
+ out_width, out_height)){
+ DSSERR("horizontal timing too tight\n");
+ return -EINVAL;
+ }
+
if (in_width > (maxsinglelinewidth * 2)) {
DSSERR("Cannot setup scaling");
DSSERR("width exceeds maximum width possible");
@@ -1951,7 +2017,7 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
r = dispc_ovl_calc_scaling(plane, channel, in_width, in_height,
out_width, out_height, oi->color_mode, &five_taps,
- &x_predecim, &y_predecim);
+ &x_predecim, &y_predecim, oi->pos_x);
if (r)
return r;
--
1.7.1
--
To unsubscribe from this list: send the line "unsubscribe linux-fbdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox