You can subscribe to this list here.
2001 |
Jan
|
Feb
|
Mar
(1) |
Apr
(104) |
May
(81) |
Jun
(248) |
Jul
(133) |
Aug
(33) |
Sep
(53) |
Oct
(82) |
Nov
(166) |
Dec
(71) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2002 |
Jan
(121) |
Feb
(42) |
Mar
(39) |
Apr
(84) |
May
(87) |
Jun
(58) |
Jul
(97) |
Aug
(130) |
Sep
(32) |
Oct
(139) |
Nov
(108) |
Dec
(216) |
2003 |
Jan
(299) |
Feb
(136) |
Mar
(392) |
Apr
(141) |
May
(137) |
Jun
(107) |
Jul
(94) |
Aug
(262) |
Sep
(300) |
Oct
(216) |
Nov
(72) |
Dec
(94) |
2004 |
Jan
(174) |
Feb
(192) |
Mar
(215) |
Apr
(314) |
May
(319) |
Jun
(293) |
Jul
(205) |
Aug
(161) |
Sep
(192) |
Oct
(226) |
Nov
(308) |
Dec
(89) |
2005 |
Jan
(127) |
Feb
(269) |
Mar
(588) |
Apr
(106) |
May
(77) |
Jun
(77) |
Jul
(161) |
Aug
(239) |
Sep
(86) |
Oct
(112) |
Nov
(153) |
Dec
(145) |
2006 |
Jan
(87) |
Feb
(57) |
Mar
(129) |
Apr
(109) |
May
(102) |
Jun
(232) |
Jul
(97) |
Aug
(69) |
Sep
(67) |
Oct
(69) |
Nov
(214) |
Dec
(82) |
2007 |
Jan
(133) |
Feb
(307) |
Mar
(121) |
Apr
(171) |
May
(229) |
Jun
(156) |
Jul
(185) |
Aug
(160) |
Sep
(122) |
Oct
(130) |
Nov
(78) |
Dec
(27) |
2008 |
Jan
(105) |
Feb
(137) |
Mar
(146) |
Apr
(148) |
May
(239) |
Jun
(208) |
Jul
(157) |
Aug
(244) |
Sep
(119) |
Oct
(125) |
Nov
(189) |
Dec
(225) |
2009 |
Jan
(157) |
Feb
(139) |
Mar
(106) |
Apr
(130) |
May
(246) |
Jun
(189) |
Jul
(128) |
Aug
(127) |
Sep
(88) |
Oct
(86) |
Nov
(216) |
Dec
(9) |
2010 |
Jan
(5) |
Feb
|
Mar
(11) |
Apr
(31) |
May
(3) |
Jun
|
Jul
(7) |
Aug
|
Sep
(1) |
Oct
|
Nov
(1) |
Dec
|
2012 |
Jan
|
Feb
|
Mar
(3) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2013 |
Jan
(1) |
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Benjamin H. <be...@ke...> - 2009-09-22 00:37:56
|
On Mon, 2009-09-21 at 18:27 +0530, Jaswinder Singh Rajput wrote: > Indentation is not an issue if I am not breaking any lines. I am > moving > the function where it should be and avoid unnecessary goto(break) and > duplicate checking 'if (i == ARRAY_SIZE(post_dividers))'. Where it "should be" is a matter of taste :-) > > If you really want to silence that warning, just initialize the > value > > > > I am trying to save some CPU cycles and you are suggesting to add some > more ;-) Saving CPU cycles in the mode setting code ? :-) Anyway, Paul maintains this driver afaik so it's his call :-) Cheers, Ben. |
From: Jaswinder S. R. <jas...@ke...> - 2009-09-21 12:59:01
|
Hello Ben, On Mon, 2009-09-21 at 08:19 +1000, Benjamin Herrenschmidt wrote: > On Sun, 2009-09-20 at 13:44 +0530, Jaswinder Singh Rajput wrote: > > In function aty128_var_to_pll moving block to where it should be. > > > > This also fixed following compilation warning: > > CC [M] drivers/video/aty/aty128fb.o > > drivers/video/aty/aty128fb.c: In function ‘aty128_decode_var’: > > drivers/video/aty/aty128fb.c:1520: warning: ‘pll.post_divider’ may be used uninitialized in this function > > I dislike moving pretty much the whole function 2 indentation levels to > the right just because gcc is being silly. > Indentation is not an issue if I am not breaking any lines. I am moving the function where it should be and avoid unnecessary goto(break) and duplicate checking 'if (i == ARRAY_SIZE(post_dividers))'. > If you really want to silence that warning, just initialize the value > I am trying to save some CPU cycles and you are suggesting to add some more ;-) -- JSR > > > Signed-off-by: Jaswinder Singh Rajput <jas...@gm...> > > --- > > drivers/video/aty/aty128fb.c | 33 ++++++++++++++++----------------- > > 1 files changed, 16 insertions(+), 17 deletions(-) > > > > diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c > > index e4e4d43..fd6746e 100644 > > --- a/drivers/video/aty/aty128fb.c > > +++ b/drivers/video/aty/aty128fb.c > > @@ -1328,8 +1328,7 @@ static int aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll, > > unsigned char post_dividers[] = {1,2,4,8,3,6,12}; > > u32 output_freq; > > u32 vclk; /* in .01 MHz */ > > - int i = 0; > > - u32 n, d; > > + int i; > > > > vclk = 100000000 / period_in_ps; /* convert units to 10 kHz */ > > > > @@ -1343,27 +1342,27 @@ static int aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll, > > for (i = 0; i < ARRAY_SIZE(post_dividers); i++) { > > output_freq = post_dividers[i] * vclk; > > if (output_freq >= c.ppll_min && output_freq <= c.ppll_max) { > > + u32 n, d; > > + > > pll->post_divider = post_dividers[i]; > > - break; > > - } > > - } > > > > - if (i == ARRAY_SIZE(post_dividers)) > > - return -EINVAL; > > + /* calculate feedback divider */ > > + n = c.ref_divider * output_freq; > > + d = c.ref_clk; > > > > - /* calculate feedback divider */ > > - n = c.ref_divider * output_freq; > > - d = c.ref_clk; > > + pll->feedback_divider = round_div(n, d); > > + pll->vclk = vclk; > > > > - pll->feedback_divider = round_div(n, d); > > - pll->vclk = vclk; > > + DBG("post %d feedback %d vlck %d output %d " > > + "ref_divider %d vclk_per: %d\n", pll->post_divider, > > + pll->feedback_divider, vclk, output_freq, > > + c.ref_divider, period_in_ps); > > > > - DBG("post %d feedback %d vlck %d output %d ref_divider %d " > > - "vclk_per: %d\n", pll->post_divider, > > - pll->feedback_divider, vclk, output_freq, > > - c.ref_divider, period_in_ps); > > + return 0; > > + } > > + } > > > > - return 0; > > + return -EINVAL; > > } > > > > |
From: Benjamin H. <be...@ke...> - 2009-09-20 22:24:55
|
On Sun, 2009-09-20 at 13:44 +0530, Jaswinder Singh Rajput wrote: > In function aty128_var_to_pll moving block to where it should be. > > This also fixed following compilation warning: > CC [M] drivers/video/aty/aty128fb.o > drivers/video/aty/aty128fb.c: In function ‘aty128_decode_var’: > drivers/video/aty/aty128fb.c:1520: warning: ‘pll.post_divider’ may be used uninitialized in this function I dislike moving pretty much the whole function 2 indentation levels to the right just because gcc is being silly. If you really want to silence that warning, just initialize the value Ben. > Signed-off-by: Jaswinder Singh Rajput <jas...@gm...> > --- > drivers/video/aty/aty128fb.c | 33 ++++++++++++++++----------------- > 1 files changed, 16 insertions(+), 17 deletions(-) > > diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c > index e4e4d43..fd6746e 100644 > --- a/drivers/video/aty/aty128fb.c > +++ b/drivers/video/aty/aty128fb.c > @@ -1328,8 +1328,7 @@ static int aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll, > unsigned char post_dividers[] = {1,2,4,8,3,6,12}; > u32 output_freq; > u32 vclk; /* in .01 MHz */ > - int i = 0; > - u32 n, d; > + int i; > > vclk = 100000000 / period_in_ps; /* convert units to 10 kHz */ > > @@ -1343,27 +1342,27 @@ static int aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll, > for (i = 0; i < ARRAY_SIZE(post_dividers); i++) { > output_freq = post_dividers[i] * vclk; > if (output_freq >= c.ppll_min && output_freq <= c.ppll_max) { > + u32 n, d; > + > pll->post_divider = post_dividers[i]; > - break; > - } > - } > > - if (i == ARRAY_SIZE(post_dividers)) > - return -EINVAL; > + /* calculate feedback divider */ > + n = c.ref_divider * output_freq; > + d = c.ref_clk; > > - /* calculate feedback divider */ > - n = c.ref_divider * output_freq; > - d = c.ref_clk; > + pll->feedback_divider = round_div(n, d); > + pll->vclk = vclk; > > - pll->feedback_divider = round_div(n, d); > - pll->vclk = vclk; > + DBG("post %d feedback %d vlck %d output %d " > + "ref_divider %d vclk_per: %d\n", pll->post_divider, > + pll->feedback_divider, vclk, output_freq, > + c.ref_divider, period_in_ps); > > - DBG("post %d feedback %d vlck %d output %d ref_divider %d " > - "vclk_per: %d\n", pll->post_divider, > - pll->feedback_divider, vclk, output_freq, > - c.ref_divider, period_in_ps); > + return 0; > + } > + } > > - return 0; > + return -EINVAL; > } > > |
From: Peter K. <ja...@su...> - 2009-09-20 15:29:41
|
Fixes `s3c_fb_remove' referenced in section `.data' of drivers/built-in.o: defined in discarded section `.devexit.text' of drivers/built-in.o With CONFIG_HOTPLUG=n, functions marked with __devexit gets removed, so make sure we use __devexit_p when referencing pointers to them. Signed-off-by: Peter Korsgaard <ja...@su...> Acked-by: Ben Dooks <ben...@fl...> --- drivers/video/s3c-fb.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) Seems like this never made it to mainline, even though Ben acked it back in June. Andrew, please push to Linus. diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index 5a72083..adf9632 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c @@ -1036,7 +1036,7 @@ static int s3c_fb_resume(struct platform_device *pdev) static struct platform_driver s3c_fb_driver = { .probe = s3c_fb_probe, - .remove = s3c_fb_remove, + .remove = __devexit_p(s3c_fb_remove), .suspend = s3c_fb_suspend, .resume = s3c_fb_resume, .driver = { -- 1.6.3.3 |
From: Jaswinder S. R. <jas...@ke...> - 2009-09-20 08:15:16
|
In function aty128_var_to_pll moving block to where it should be. This also fixed following compilation warning: CC [M] drivers/video/aty/aty128fb.o drivers/video/aty/aty128fb.c: In function ‘aty128_decode_var’: drivers/video/aty/aty128fb.c:1520: warning: ‘pll.post_divider’ may be used uninitialized in this function Signed-off-by: Jaswinder Singh Rajput <jas...@gm...> --- drivers/video/aty/aty128fb.c | 33 ++++++++++++++++----------------- 1 files changed, 16 insertions(+), 17 deletions(-) diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index e4e4d43..fd6746e 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -1328,8 +1328,7 @@ static int aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll, unsigned char post_dividers[] = {1,2,4,8,3,6,12}; u32 output_freq; u32 vclk; /* in .01 MHz */ - int i = 0; - u32 n, d; + int i; vclk = 100000000 / period_in_ps; /* convert units to 10 kHz */ @@ -1343,27 +1342,27 @@ static int aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll, for (i = 0; i < ARRAY_SIZE(post_dividers); i++) { output_freq = post_dividers[i] * vclk; if (output_freq >= c.ppll_min && output_freq <= c.ppll_max) { + u32 n, d; + pll->post_divider = post_dividers[i]; - break; - } - } - if (i == ARRAY_SIZE(post_dividers)) - return -EINVAL; + /* calculate feedback divider */ + n = c.ref_divider * output_freq; + d = c.ref_clk; - /* calculate feedback divider */ - n = c.ref_divider * output_freq; - d = c.ref_clk; + pll->feedback_divider = round_div(n, d); + pll->vclk = vclk; - pll->feedback_divider = round_div(n, d); - pll->vclk = vclk; + DBG("post %d feedback %d vlck %d output %d " + "ref_divider %d vclk_per: %d\n", pll->post_divider, + pll->feedback_divider, vclk, output_freq, + c.ref_divider, period_in_ps); - DBG("post %d feedback %d vlck %d output %d ref_divider %d " - "vclk_per: %d\n", pll->post_divider, - pll->feedback_divider, vclk, output_freq, - c.ref_divider, period_in_ps); + return 0; + } + } - return 0; + return -EINVAL; } -- 1.6.4.4 |
From: Mike F. <va...@ge...> - 2009-09-17 21:37:19
|
From: Michael Hennerich <mic...@an...> Framebuffer driver for the Landscape LCD EZ-Extender (ADZS-BFLLCD-EZEXT) http://docs.blackfin.uclinux.org/doku.php?id=hw:cards:landscape_lcd_ez-extender Signed-off-by: Michael Hennerich <mic...@an...> Signed-off-by: Bryan Wu <coo...@ke...> Signed-off-by: Mike Frysinger <va...@ge...> --- v2 - rename spidev driver to fix section mismatch warnings arch/blackfin/include/asm/bfin-lq035q1.h | 28 + drivers/video/Kconfig | 13 + drivers/video/Makefile | 1 + drivers/video/bfin-lq035q1-fb.c | 855 ++++++++++++++++++++++++++++++ 4 files changed, 897 insertions(+), 0 deletions(-) create mode 100644 arch/blackfin/include/asm/bfin-lq035q1.h create mode 100644 drivers/video/bfin-lq035q1-fb.c diff --git a/arch/blackfin/include/asm/bfin-lq035q1.h b/arch/blackfin/include/asm/bfin-lq035q1.h new file mode 100644 index 0000000..a87a6b6 --- /dev/null +++ b/arch/blackfin/include/asm/bfin-lq035q1.h @@ -0,0 +1,28 @@ +/* + * Blackfin LCD Framebuffer driver SHARP LQ035Q1DH02 + * + * Copyright 2008-2009 Analog Devices Inc. + * Licensed under the GPL-2 or later. + */ + +#ifndef BFIN_LQ035Q1_H +#define BFIN_LQ035Q1_H + +#define LQ035_RL (0 << 8) /* Right -> Left Scan */ +#define LQ035_LR (1 << 8) /* Left -> Right Scan */ +#define LQ035_TB (1 << 9) /* Top -> Botton Scan */ +#define LQ035_BT (0 << 9) /* Botton -> Top Scan */ +#define LQ035_BGR (1 << 11) /* Use BGR format */ +#define LQ035_RGB (0 << 11) /* Use RGB format */ +#define LQ035_NORM (1 << 13) /* Reversal */ +#define LQ035_REV (0 << 13) /* Reversal */ + +struct bfin_lq035q1fb_disp_info { + + unsigned mode; + /* GPIOs */ + int use_bl; + unsigned gpio_bl; +}; + +#endif /* BFIN_LQ035Q1_H */ diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index cef3e1d..bb10916 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -611,6 +611,19 @@ config FB_BFIN_T350MCQB This display is a QVGA 320x240 24-bit RGB display interfaced by an 8-bit wide PPI It uses PPI[0..7] PPI_FS1, PPI_FS2 and PPI_CLK. +config FB_BFIN_LQ035Q1 + tristate "SHARP LQ035Q1DH02 TFT LCD" + depends on FB && BLACKFIN + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select BFIN_GPTIMERS + select SPI + help + This is the framebuffer device driver for a SHARP LQ035Q1DH02 TFT display found on + the Blackfin Landscape LCD EZ-Extender Card. + This display is a QVGA 320x240 18-bit RGB display interfaced by an 16-bit wide PPI + It uses PPI[0..15] PPI_FS1, PPI_FS2 and PPI_CLK. config FB_STI tristate "HP STI frame buffer device support" diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 01a819f..cc7682b 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -134,6 +134,7 @@ obj-$(CONFIG_FB_EFI) += efifb.o obj-$(CONFIG_FB_VGA16) += vga16fb.o obj-$(CONFIG_FB_OF) += offb.o obj-$(CONFIG_FB_BF54X_LQ043) += bf54x-lq043fb.o +obj-$(CONFIG_FB_BFIN_LQ035Q1) += bfin-lq035q1-fb.o obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin-t350mcqb-fb.o obj-$(CONFIG_FB_MX3) += mx3fb.o diff --git a/drivers/video/bfin-lq035q1-fb.c b/drivers/video/bfin-lq035q1-fb.c new file mode 100644 index 0000000..e766bba --- /dev/null +++ b/drivers/video/bfin-lq035q1-fb.c @@ -0,0 +1,855 @@ +/* + * Blackfin LCD Framebuffer driver SHARP LQ035Q1DH02 + * + * Copyright 2008-2009 Analog Devices Inc. + * Licensed under the GPL-2 or later. + */ + +#define pr_fmt(fmt) DRIVER_NAME ": " fmt + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/backlight.h> +#include <linux/lcd.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/dma-mapping.h> + +#include <asm/blackfin.h> +#include <asm/irq.h> +#include <asm/dma.h> +#include <asm/portmux.h> +#include <asm/gptimers.h> + +#include <asm/bfin-lq035q1.h> + +#if defined(BF533_FAMILY) || defined(BF538_FAMILY) +#define TIMER_HSYNC_id TIMER1_id +#define TIMER_HSYNCbit TIMER1bit +#define TIMER_HSYNC_STATUS_TRUN TIMER_STATUS_TRUN1 +#define TIMER_HSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL1 +#define TIMER_HSYNC_STATUS_TOVF TIMER_STATUS_TOVF1 + +#define TIMER_VSYNC_id TIMER2_id +#define TIMER_VSYNCbit TIMER2bit +#define TIMER_VSYNC_STATUS_TRUN TIMER_STATUS_TRUN2 +#define TIMER_VSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL2 +#define TIMER_VSYNC_STATUS_TOVF TIMER_STATUS_TOVF2 +#else +#define TIMER_HSYNC_id TIMER0_id +#define TIMER_HSYNCbit TIMER0bit +#define TIMER_HSYNC_STATUS_TRUN TIMER_STATUS_TRUN0 +#define TIMER_HSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL0 +#define TIMER_HSYNC_STATUS_TOVF TIMER_STATUS_TOVF0 + +#define TIMER_VSYNC_id TIMER1_id +#define TIMER_VSYNCbit TIMER1bit +#define TIMER_VSYNC_STATUS_TRUN TIMER_STATUS_TRUN1 +#define TIMER_VSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL1 +#define TIMER_VSYNC_STATUS_TOVF TIMER_STATUS_TOVF1 +#endif + +#define LCD_X_RES 320 /* Horizontal Resolution */ +#define LCD_Y_RES 240 /* Vertical Resolution */ +#define DMA_BUS_SIZE 16 + +#define USE_RGB565_16_BIT_PPI + +#ifdef USE_RGB565_16_BIT_PPI +#define LCD_BPP 16 /* Bit Per Pixel */ +#define CLOCKS_PER_PIX 1 +#define CPLD_PIPELINE_DELAY_COR 0 /* NO CPLB */ +#endif + +/* Interface 16/18-bit TFT over an 8-bit wide PPI using a small Programmable Logic Device (CPLD) + * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165 + */ + +#ifdef USE_RGB565_8_BIT_PPI +#define LCD_BPP 16 /* Bit Per Pixel */ +#define CLOCKS_PER_PIX 2 +#define CPLD_PIPELINE_DELAY_COR 3 /* RGB565 */ +#endif + +#ifdef USE_RGB888_8_BIT_PPI +#define LCD_BPP 24 /* Bit Per Pixel */ +#define CLOCKS_PER_PIX 3 +#define CPLD_PIPELINE_DELAY_COR 5 /* RGB888 */ +#endif + + /* + * HS and VS timing parameters (all in number of PPI clk ticks) + */ + +#define U_LINE 4 /* Blanking Lines */ + +#define H_ACTPIX (LCD_X_RES * CLOCKS_PER_PIX) /* active horizontal pixel */ +#define H_PERIOD (336 * CLOCKS_PER_PIX) /* HS period */ +#define H_PULSE (2 * CLOCKS_PER_PIX) /* HS pulse width */ +#define H_START (7 * CLOCKS_PER_PIX + CPLD_PIPELINE_DELAY_COR) /* first valid pixel */ + +#define V_LINES (LCD_Y_RES + U_LINE) /* total vertical lines */ +#define V_PULSE (2 * CLOCKS_PER_PIX) /* VS pulse width (1-5 H_PERIODs) */ +#define V_PERIOD (H_PERIOD * V_LINES) /* VS period */ + +#define ACTIVE_VIDEO_MEM_OFFSET ((U_LINE / 2) * LCD_X_RES * (LCD_BPP / 8)) + +#define BFIN_LCD_NBR_PALETTE_ENTRIES 256 + +#define PPI_TX_MODE 0x2 +#define PPI_XFER_TYPE_11 0xC +#define PPI_PORT_CFG_01 0x10 +#define PPI_POLS_1 0x8000 + +#if (CLOCKS_PER_PIX > 1) +#define PPI_PMODE (DLEN_8 | PACK_EN) +#else +#define PPI_PMODE (DLEN_16) +#endif + +#define LQ035_INDEX 0x74 +#define LQ035_DATA 0x76 + +#define LQ035_DRIVER_OUTPUT_CTL 0x1 +#define LQ035_SHUT_CTL 0x11 + +#define LQ035_DRIVER_OUTPUT_MASK (LQ035_LR | LQ035_TB | LQ035_BGR | LQ035_REV) +#define LQ035_DRIVER_OUTPUT_DEFAULT (0x2AEF & ~LQ035_DRIVER_OUTPUT_MASK) + +#define LQ035_SHUT (1 << 0) /* Shutdown */ +#define LQ035_ON (0 << 0) /* Shutdown */ + +#define DRIVER_NAME "bfin-lq035q1" +static char driver_name[] = DRIVER_NAME; + +struct bfin_lq035q1fb_info { + struct fb_info *fb; + struct device *dev; + struct bfin_lq035q1fb_disp_info *disp_info; + unsigned char *fb_buffer; /* RGB Buffer */ + dma_addr_t dma_handle; + int lq035_mmap; + int lq035_open_cnt; + int irq; + spinlock_t lock; /* lock */ + u32 pseudo_pal[16]; +}; + +static int nocursor; +module_param(nocursor, int, 0644); +MODULE_PARM_DESC(nocursor, "cursor enable/disable"); + + +static struct { + struct spi_device *spidev; + unsigned short mode; + unsigned short init; +} spi_control; + +static int lq035q1_control(unsigned char reg, unsigned short value) +{ + int ret; + u8 regs[3] = {LQ035_INDEX, 0, 0}; + u8 dat[3] = {LQ035_DATA, 0, 0}; + + if (spi_control.spidev) { + regs[2] = reg; + dat[1] = value >> 8; + dat[2] = value & 0xFF; + + ret = spi_write(spi_control.spidev, regs, ARRAY_SIZE(regs)); + ret |= spi_write(spi_control.spidev, dat, ARRAY_SIZE(dat)); + } else + return -ENODEV; + + return ret; +} + +static int __devinit lq035q1_spidev_probe(struct spi_device *spi) +{ + int ret; + spi_control.spidev = spi; + + ret = lq035q1_control(LQ035_SHUT_CTL, LQ035_ON); + ret |= lq035q1_control(LQ035_DRIVER_OUTPUT_CTL, spi_control.mode); + + if (ret) + return ret; + + spi_control.init = 1; + + return 0; +} + +static int __devexit lq035q1_spidev_remove(struct spi_device *spi) +{ + return lq035q1_control(LQ035_SHUT_CTL, LQ035_SHUT); +} + +#ifdef CONFIG_PM +static int lq035q1_spidev_suspend(struct spi_device *spi, pm_message_t state) +{ + return lq035q1_control(LQ035_SHUT_CTL, LQ035_SHUT); +} + +static int lq035q1_spidev_resume(struct spi_device *spi) +{ + int ret = lq035q1_control(LQ035_DRIVER_OUTPUT_CTL, spi_control.mode); + + if (ret) + return ret; + + return lq035q1_control(LQ035_SHUT_CTL, LQ035_ON); +} +#else +#define lq035q1_spidev_suspend NULL +#define lq035q1_spidev_resume NULL +#endif + +/* Power down all displays on reboot, poweroff or halt */ +static void lq035q1_spidev_shutdown(struct spi_device *spi) +{ + lq035q1_control(LQ035_SHUT_CTL, LQ035_SHUT); +} + +static struct spi_driver spidev_spi_driver = { + .driver = { + .name = DRIVER_NAME"-spi", + .owner = THIS_MODULE, + }, + .probe = lq035q1_spidev_probe, + .remove = __devexit_p(lq035q1_spidev_remove), + .shutdown = lq035q1_spidev_shutdown, + .suspend = lq035q1_spidev_suspend, + .resume = lq035q1_spidev_resume, +}; + +static int lq035q1_backlight(struct bfin_lq035q1fb_info *info, unsigned arg) +{ + if (info->disp_info->use_bl) + gpio_set_value(info->disp_info->gpio_bl, arg); + + return 0; +} + +static void bfin_lq035q1_config_ppi(struct bfin_lq035q1fb_info *fbi) +{ + bfin_write_PPI_DELAY(H_START); + bfin_write_PPI_COUNT(H_ACTPIX - 1); + bfin_write_PPI_FRAME(V_LINES); + + bfin_write_PPI_CONTROL(PPI_TX_MODE | /* output mode , PORT_DIR */ + PPI_XFER_TYPE_11 | /* sync mode XFR_TYPE */ + PPI_PORT_CFG_01 | /* two frame sync PORT_CFG */ + PPI_PMODE | /* 8/16 bit data length / PACK_EN? */ + PPI_POLS_1); /* faling edge syncs POLS */ +} + +static inline void bfin_lq035q1_disable_ppi(void) +{ + bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() & ~PORT_EN); +} + +static inline void bfin_lq035q1_enable_ppi(void) +{ + bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() | PORT_EN); +} + +static void bfin_lq035q1_start_timers(void) +{ + enable_gptimers(TIMER_VSYNCbit | TIMER_HSYNCbit); +} + +static void bfin_lq035q1_stop_timers(void) +{ + disable_gptimers(TIMER_HSYNCbit | TIMER_VSYNCbit); + + set_gptimer_status(0, TIMER_HSYNC_STATUS_TRUN | TIMER_VSYNC_STATUS_TRUN | + TIMER_HSYNC_STATUS_TIMIL | TIMER_VSYNC_STATUS_TIMIL | + TIMER_HSYNC_STATUS_TOVF | TIMER_VSYNC_STATUS_TOVF); + +} + +static void bfin_lq035q1_init_timers(void) +{ + + bfin_lq035q1_stop_timers(); + + set_gptimer_period(TIMER_HSYNC_id, H_PERIOD); + set_gptimer_pwidth(TIMER_HSYNC_id, H_PULSE); + set_gptimer_config(TIMER_HSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT | + TIMER_TIN_SEL | TIMER_CLK_SEL| + TIMER_EMU_RUN); + + set_gptimer_period(TIMER_VSYNC_id, V_PERIOD); + set_gptimer_pwidth(TIMER_VSYNC_id, V_PULSE); + set_gptimer_config(TIMER_VSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT | + TIMER_TIN_SEL | TIMER_CLK_SEL | + TIMER_EMU_RUN); + +} + +static void bfin_lq035q1_config_dma(struct bfin_lq035q1fb_info *fbi) +{ + + set_dma_config(CH_PPI, + set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO, + INTR_DISABLE, DIMENSION_2D, + DATA_SIZE_16, + DMA_NOSYNC_KEEP_DMA_BUF)); + set_dma_x_count(CH_PPI, (LCD_X_RES * LCD_BPP) / DMA_BUS_SIZE); + set_dma_x_modify(CH_PPI, DMA_BUS_SIZE / 8); + set_dma_y_count(CH_PPI, V_LINES); + + set_dma_y_modify(CH_PPI, DMA_BUS_SIZE / 8); + set_dma_start_addr(CH_PPI, (unsigned long)fbi->fb_buffer); + +} + +#if (CLOCKS_PER_PIX == 1) +static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, + P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, + P_PPI0_D3, P_PPI0_D4, P_PPI0_D5, + P_PPI0_D6, P_PPI0_D7, P_PPI0_D8, + P_PPI0_D9, P_PPI0_D10, P_PPI0_D11, + P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, + P_PPI0_D15, 0}; +#else +static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, + P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, + P_PPI0_D3, P_PPI0_D4, P_PPI0_D5, + P_PPI0_D6, P_PPI0_D7, 0}; +#endif + +static int bfin_lq035q1_request_ports(int action) +{ + if (action) { + /* ANOMALY_05000400 - PPI Does Not Start Properly In Specific Mode: + * Drive PPI_FS3 Low + */ + if (ANOMALY_05000400) { + int ret = gpio_request(P_IDENT(P_PPI0_FS3), "PPI_FS3"); + if (ret) + return ret; + gpio_direction_output(P_IDENT(P_PPI0_FS3), 0); + } + + if (peripheral_request_list(ppi0_req_16, DRIVER_NAME)) { + pr_err("requesting peripherals failed\n"); + return -EFAULT; + } + } else { + peripheral_free_list(ppi0_req_16); + if (ANOMALY_05000400) + gpio_free(P_IDENT(P_PPI0_FS3)); + } + + return 0; +} + +static int bfin_lq035q1_fb_open(struct fb_info *info, int user) +{ + struct bfin_lq035q1fb_info *fbi = info->par; + + spin_lock(&fbi->lock); + fbi->lq035_open_cnt++; + + if (fbi->lq035_open_cnt <= 1) { + + bfin_lq035q1_disable_ppi(); + SSYNC(); + + bfin_lq035q1_config_dma(fbi); + bfin_lq035q1_config_ppi(fbi); + bfin_lq035q1_init_timers(); + + /* start dma */ + enable_dma(CH_PPI); + bfin_lq035q1_enable_ppi(); + bfin_lq035q1_start_timers(); + lq035q1_backlight(fbi, 1); + } + + spin_unlock(&fbi->lock); + + return 0; +} + +static int bfin_lq035q1_fb_release(struct fb_info *info, int user) +{ + struct bfin_lq035q1fb_info *fbi = info->par; + + spin_lock(&fbi->lock); + + fbi->lq035_open_cnt--; + fbi->lq035_mmap = 0; + + if (fbi->lq035_open_cnt <= 0) { + lq035q1_backlight(fbi, 0); + bfin_lq035q1_disable_ppi(); + SSYNC(); + disable_dma(CH_PPI); + bfin_lq035q1_stop_timers(); + } + + spin_unlock(&fbi->lock); + + return 0; +} + +static int bfin_lq035q1_fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + + switch (var->bits_per_pixel) { +#if (LCD_BPP == 24) + case 24:/* TRUECOLOUR, 16m */ +#else + case 16:/* DIRECTCOLOUR, 64k */ +#endif + var->red.offset = info->var.red.offset; + var->green.offset = info->var.green.offset; + var->blue.offset = info->var.blue.offset; + var->red.length = info->var.red.length; + var->green.length = info->var.green.length; + var->blue.length = info->var.blue.length; + var->transp.offset = 0; + var->transp.length = 0; + var->transp.msb_right = 0; + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + break; + default: + pr_debug("%s: depth not supported: %u BPP\n", __func__, + var->bits_per_pixel); + return -EINVAL; + } + + 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_debug("%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_debug("%s: Memory Limit requested yres_virtual = %u\n", + __func__, var->yres_virtual); + return -ENOMEM; + } + + + return 0; +} + +static int bfin_lq035q1_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + struct bfin_lq035q1fb_info *fbi = info->par; + + if (fbi->lq035_mmap) + return -1; + + spin_lock(&fbi->lock); + fbi->lq035_mmap = 1; + spin_unlock(&fbi->lock); + + vma->vm_start = (unsigned long)(fbi->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET); + + vma->vm_end = vma->vm_start + info->fix.smem_len; + /* For those who don't understand how mmap works, go read + * Documentation/nommu-mmap.txt. + * For those that do, you will know that the VM_MAYSHARE flag + * must be set in the vma->vm_flags structure on noMMU + * Other flags can be set, and are documented in + * include/linux/mm.h + */ + vma->vm_flags |= VM_MAYSHARE | VM_SHARED; + + return 0; +} + +int bfin_lq035q1_fb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + if (nocursor) + return 0; + else + return -EINVAL; /* just to force soft_cursor() call */ +} + +static int bfin_lq035q1_fb_setcolreg(u_int regno, u_int red, u_int green, + u_int blue, u_int transp, + struct fb_info *info) +{ + if (regno >= BFIN_LCD_NBR_PALETTE_ENTRIES) + return -EINVAL; + + if (info->var.grayscale) { + /* grayscale = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; + } + + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { + + u32 value; + /* Place color in the pseudopalette */ + if (regno > 16) + return -EINVAL; + + red >>= (16 - info->var.red.length); + green >>= (16 - info->var.green.length); + blue >>= (16 - info->var.blue.length); + + value = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + value &= 0xFFFFFF; + + ((u32 *) (info->pseudo_palette))[regno] = value; + + } + + return 0; +} + +static struct fb_ops bfin_lq035q1_fb_ops = { + .owner = THIS_MODULE, + .fb_open = bfin_lq035q1_fb_open, + .fb_release = bfin_lq035q1_fb_release, + .fb_check_var = bfin_lq035q1_fb_check_var, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_mmap = bfin_lq035q1_fb_mmap, + .fb_cursor = bfin_lq035q1_fb_cursor, + .fb_setcolreg = bfin_lq035q1_fb_setcolreg, +}; + +static irqreturn_t bfin_lq035q1_irq_error(int irq, void *dev_id) +{ + /*struct bfin_lq035q1fb_info *info = (struct bfin_lq035q1fb_info *)dev_id;*/ + + u16 status = bfin_read_PPI_STATUS(); + bfin_write_PPI_STATUS(-1); + + if (status) { + bfin_lq035q1_disable_ppi(); + disable_dma(CH_PPI); + + /* start dma */ + enable_dma(CH_PPI); + bfin_lq035q1_enable_ppi(); + bfin_write_PPI_STATUS(-1); + } + + return IRQ_HANDLED; +} + +static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) +{ + struct bfin_lq035q1fb_info *info; + struct fb_info *fbinfo; + int ret; + + ret = request_dma(CH_PPI, "CH_PPI"); + if (ret < 0) { + pr_err("couldn't request CH_PPI DMA\n"); + goto out1; + } + + fbinfo = + framebuffer_alloc(sizeof(struct bfin_lq035q1fb_info), &pdev->dev); + if (!fbinfo) { + ret = -ENOMEM; + goto out2; + } + + info = fbinfo->par; + info->fb = fbinfo; + info->dev = &pdev->dev; + + info->disp_info = pdev->dev.platform_data; + + spi_control.mode = (info->disp_info->mode & + LQ035_DRIVER_OUTPUT_MASK) | LQ035_DRIVER_OUTPUT_DEFAULT; + + platform_set_drvdata(pdev, fbinfo); + + strcpy(fbinfo->fix.id, driver_name); + + fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; + fbinfo->fix.type_aux = 0; + fbinfo->fix.xpanstep = 0; + fbinfo->fix.ypanstep = 0; + fbinfo->fix.ywrapstep = 0; + fbinfo->fix.accel = FB_ACCEL_NONE; + fbinfo->fix.visual = FB_VISUAL_TRUECOLOR; + + fbinfo->var.nonstd = 0; + fbinfo->var.activate = FB_ACTIVATE_NOW; + fbinfo->var.height = -1; + fbinfo->var.width = -1; + fbinfo->var.accel_flags = 0; + fbinfo->var.vmode = FB_VMODE_NONINTERLACED; + + fbinfo->var.xres = LCD_X_RES; + fbinfo->var.xres_virtual = LCD_X_RES; + fbinfo->var.yres = LCD_Y_RES; + fbinfo->var.yres_virtual = LCD_Y_RES; + fbinfo->var.bits_per_pixel = LCD_BPP; + + if (info->disp_info->mode & LQ035_BGR) { +#if (LCD_BPP == 24) + fbinfo->var.red.offset = 0; + fbinfo->var.green.offset = 8; + fbinfo->var.blue.offset = 16; +#else + fbinfo->var.red.offset = 0; + fbinfo->var.green.offset = 5; + fbinfo->var.blue.offset = 11; +#endif + } else { +#if (LCD_BPP == 24) + fbinfo->var.red.offset = 16; + fbinfo->var.green.offset = 8; + fbinfo->var.blue.offset = 0; +#else + fbinfo->var.red.offset = 11; + fbinfo->var.green.offset = 5; + fbinfo->var.blue.offset = 0; +#endif + } + + fbinfo->var.transp.offset = 0; + +#if (LCD_BPP == 24) + fbinfo->var.red.length = 8; + fbinfo->var.green.length = 8; + fbinfo->var.blue.length = 8; +#else + fbinfo->var.red.length = 5; + fbinfo->var.green.length = 6; + fbinfo->var.blue.length = 5; +#endif + + fbinfo->var.transp.length = 0; + + fbinfo->fix.smem_len = LCD_X_RES * LCD_Y_RES * LCD_BPP / 8 + + ACTIVE_VIDEO_MEM_OFFSET; + + fbinfo->fix.line_length = fbinfo->var.xres_virtual * + fbinfo->var.bits_per_pixel / 8; + + + fbinfo->fbops = &bfin_lq035q1_fb_ops; + fbinfo->flags = FBINFO_FLAG_DEFAULT; + + info->fb_buffer = + dma_alloc_coherent(NULL, fbinfo->fix.smem_len, &info->dma_handle, + GFP_KERNEL); + + if (NULL == info->fb_buffer) { + pr_err("couldn't allocate dma buffer\n"); + ret = -ENOMEM; + goto out3; + } + + fbinfo->screen_base = (void *)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; + fbinfo->fix.smem_start = (int)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; + + fbinfo->fbops = &bfin_lq035q1_fb_ops; + + fbinfo->pseudo_palette = &info->pseudo_pal; + + ret = fb_alloc_cmap(&fbinfo->cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0); + if (ret < 0) { + pr_err("failed to allocate colormap (%d entries)\n", + BFIN_LCD_NBR_PALETTE_ENTRIES); + goto out4; + } + + ret = bfin_lq035q1_request_ports(1); + if (ret) { + pr_err("couldn't request gpio port\n"); + goto out6; + } + + info->irq = platform_get_irq(pdev, 0); + if (info->irq < 0) { + ret = -EINVAL; + goto out7; + } + + ret = request_irq(info->irq, bfin_lq035q1_irq_error, IRQF_DISABLED, + "PPI ERROR", info); + if (ret < 0) { + pr_err("unable to request PPI ERROR IRQ\n"); + goto out7; + } + + ret = spi_register_driver(&spidev_spi_driver); + if (ret < 0) { + pr_err("couldn't register SPI Interface\n"); + goto out8; + } + + if (info->disp_info->use_bl) { + ret = gpio_request(info->disp_info->gpio_bl, "LQ035 Backlight"); + + if (ret) { + pr_err("failed to request GPIO %d\n", + info->disp_info->gpio_bl); + goto out9; + } + gpio_direction_output(info->disp_info->gpio_bl, 0); + } + + ret = register_framebuffer(fbinfo); + if (ret < 0) { + pr_err("unable to register framebuffer\n"); + goto out10; + } + + pr_info("%dx%d %d-bit RGB FrameBuffer initialized\n", + LCD_X_RES, LCD_Y_RES, LCD_BPP); + + return 0; + +out10: + if (info->disp_info->use_bl) + gpio_free(info->disp_info->gpio_bl); +out9: + spi_unregister_driver(&spidev_spi_driver); +out8: + free_irq(info->irq, info); +out7: + bfin_lq035q1_request_ports(0); +out6: + fb_dealloc_cmap(&fbinfo->cmap); +out4: + dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, + info->dma_handle); +out3: + framebuffer_release(fbinfo); +out2: + free_dma(CH_PPI); +out1: + platform_set_drvdata(pdev, NULL); + + return ret; +} + +static int __devexit bfin_lq035q1_remove(struct platform_device *pdev) +{ + struct fb_info *fbinfo = platform_get_drvdata(pdev); + struct bfin_lq035q1fb_info *info = fbinfo->par; + + if (info->disp_info->use_bl) + gpio_free(info->disp_info->gpio_bl); + + spi_unregister_driver(&spidev_spi_driver); + + unregister_framebuffer(fbinfo); + + free_dma(CH_PPI); + free_irq(info->irq, info); + + if (info->fb_buffer != NULL) + dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, + info->dma_handle); + + fb_dealloc_cmap(&fbinfo->cmap); + + bfin_lq035q1_request_ports(0); + + platform_set_drvdata(pdev, NULL); + framebuffer_release(fbinfo); + + pr_info("unregistered LCD driver\n"); + + return 0; +} + +#ifdef CONFIG_PM +static int bfin_lq035q1_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct fb_info *fbinfo = platform_get_drvdata(pdev); + struct bfin_lq035q1fb_info *info = fbinfo->par; + + if (info->lq035_open_cnt) { + lq035q1_backlight(info, 0); + bfin_lq035q1_disable_ppi(); + SSYNC(); + disable_dma(CH_PPI); + bfin_lq035q1_stop_timers(); + bfin_write_PPI_STATUS(-1); + } + + return 0; +} + +static int bfin_lq035q1_resume(struct platform_device *pdev) +{ + struct fb_info *fbinfo = platform_get_drvdata(pdev); + struct bfin_lq035q1fb_info *info = fbinfo->par; + + if (info->lq035_open_cnt) { + bfin_lq035q1_disable_ppi(); + SSYNC(); + + bfin_lq035q1_config_dma(info); + bfin_lq035q1_config_ppi(info); + bfin_lq035q1_init_timers(); + + /* start dma */ + enable_dma(CH_PPI); + bfin_lq035q1_enable_ppi(); + bfin_lq035q1_start_timers(); + lq035q1_backlight(info, 1); + } + + return 0; +} +#else +#define bfin_lq035q1_suspend NULL +#define bfin_lq035q1_resume NULL +#endif + +static struct platform_driver bfin_lq035q1_driver = { + .probe = bfin_lq035q1_probe, + .remove = __devexit_p(bfin_lq035q1_remove), + .suspend = bfin_lq035q1_suspend, + .resume = bfin_lq035q1_resume, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init bfin_lq035q1_driver_init(void) +{ + return platform_driver_register(&bfin_lq035q1_driver); +} +module_init(bfin_lq035q1_driver_init); + +static void __exit bfin_lq035q1_driver_cleanup(void) +{ + platform_driver_unregister(&bfin_lq035q1_driver); +} +module_exit(bfin_lq035q1_driver_cleanup); + +MODULE_DESCRIPTION("Blackfin TFT LCD Driver"); +MODULE_LICENSE("GPL"); -- 1.6.5.rc1 |
From: Sudhakar R. <sud...@ti...> - 2009-09-16 10:07:55
|
Currently end-of-frame interrupt is being used while disabling LCD controller to wait or the frame being diaplyed to complete. But when the LCD is disabled by clearing the LCD Raster Control enable bit in the LCD Raster Control Register, the LCD allows the current frame to complete before it is disabled. Hence disable end-of-frame interrupt and remove waitqueue related code which was used to handle this interrupt. Because of above modifications, modify the lcd_disable_raster() and lcd_reset() functions to return void instead of int. Signed-off-by: Sudhakar Rajashekhara <sud...@ti...> --- This patch applies to mmotm tree available at http://git.zen-sources.org/?p=mmotm.git;a=summary. drivers/video/da8xx-fb.c | 36 ++++++++---------------------------- 1 files changed, 8 insertions(+), 28 deletions(-) diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index 04de744..42e1005 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c @@ -107,7 +107,6 @@ static inline void lcdc_write(unsigned int val, unsigned int addr) } struct da8xx_fb_par { - wait_queue_head_t da8xx_wq; resource_size_t p_palette_base; unsigned char *v_palette_base; struct clk *lcdc_clk; @@ -193,21 +192,13 @@ static struct da8xx_panel known_lcd_panels[] = { }; /* Disable the Raster Engine of the LCD Controller */ -static int lcd_disable_raster(struct da8xx_fb_par *par) +static void lcd_disable_raster(struct da8xx_fb_par *par) { - int ret = 0; u32 reg; reg = lcdc_read(LCD_RASTER_CTRL_REG); - if (reg & LCD_RASTER_ENABLE) { + if (reg & LCD_RASTER_ENABLE) lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); - ret = wait_event_interruptible_timeout(par->da8xx_wq, - !lcdc_read(LCD_STAT_REG) & - LCD_END_OF_FRAME0, WSI_TIMEOUT); - if (ret == 0) - ret = -ETIMEDOUT; - } - return ret; } static void lcd_blit(int load_mode, struct da8xx_fb_par *par) @@ -255,7 +246,7 @@ static int lcd_cfg_dma(int burst_size) default: return -EINVAL; } - lcdc_write(reg | LCD_END_OF_FRAME_INT_ENA, LCD_DMA_CTRL_REG); + lcdc_write(reg, LCD_DMA_CTRL_REG); return 0; } @@ -450,19 +441,15 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, return 0; } -static int lcd_reset(struct da8xx_fb_par *par) +static void lcd_reset(struct da8xx_fb_par *par) { - int ret = 0; - /* Disable the Raster if previously Enabled */ if (lcdc_read(LCD_RASTER_CTRL_REG) & LCD_RASTER_ENABLE) - ret = lcd_disable_raster(par); + lcd_disable_raster(par); /* DMA has to be disabled */ lcdc_write(0, LCD_DMA_CTRL_REG); lcdc_write(0, LCD_RASTER_CTRL_REG); - - return ret; } static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, @@ -471,9 +458,7 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, u32 bpp; int ret = 0; - ret = lcd_reset(par); - if (ret != 0) - return ret; + lcd_reset(par); /* Configure the LCD clock divisor. */ lcdc_write(LCD_CLK_DIVISOR(panel->pxl_clk) | @@ -529,7 +514,6 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, static irqreturn_t lcdc_irq_handler(int irq, void *arg) { u32 stat = lcdc_read(LCD_STAT_REG); - struct da8xx_fb_par *par = arg; u32 reg; if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { @@ -540,7 +524,6 @@ static irqreturn_t lcdc_irq_handler(int irq, void *arg) } else lcdc_write(stat, LCD_STAT_REG); - wake_up_interruptible(&par->da8xx_wq); return IRQ_HANDLED; } @@ -595,13 +578,12 @@ static int fb_check_var(struct fb_var_screeninfo *var, static int __devexit fb_remove(struct platform_device *dev) { struct fb_info *info = dev_get_drvdata(&dev->dev); - int ret = 0; if (info) { struct da8xx_fb_par *par = info->par; if (lcdc_read(LCD_RASTER_CTRL_REG) & LCD_RASTER_ENABLE) - ret = lcd_disable_raster(par); + lcd_disable_raster(par); lcdc_write(0, LCD_RASTER_CTRL_REG); /* disable DMA */ @@ -620,7 +602,7 @@ static int __devexit fb_remove(struct platform_device *dev) release_mem_region(lcdc_regs->start, resource_size(lcdc_regs)); } - return ret; + return 0; } static int fb_ioctl(struct fb_info *info, unsigned int cmd, @@ -774,8 +756,6 @@ static int __init fb_probe(struct platform_device *device) par->lcdc_clk = fb_clk; - init_waitqueue_head(&par->da8xx_wq); - par->irq = platform_get_irq(device, 0); if (par->irq < 0) { ret = -ENOENT; -- 1.5.6 |
From: Paul M. <le...@li...> - 2009-09-15 12:56:52
|
On Tue, Sep 15, 2009 at 02:00:09PM +0200, Guennadi Liakhovetski wrote: > The following two patches add panning support to the SH LCDC framebuffer > driver. Apart from the driver itself the patches also touch a bunch of sh > board files, so, I think, it would be best to push them via SH tree. > Looks good. Applied, thanks. |
From: Guennadi L. <g.l...@gm...> - 2009-09-15 12:00:37
|
From: Phil Edworthy <phi...@re...> Switch to using both register sets - side A and side B for display panning. Signed-off-by: Phil Edworthy <phi...@re...> Signed-off-by: Guennadi Liakhovetski <g.l...@gm...> --- arch/sh/boards/board-ap325rxa.c | 2 +- arch/sh/boards/mach-ecovec24/setup.c | 2 +- arch/sh/boards/mach-kfr2r09/setup.c | 2 +- arch/sh/boards/mach-migor/setup.c | 2 +- arch/sh/boards/mach-se/7724/setup.c | 2 +- drivers/video/sh_mobile_lcdcfb.c | 47 +++++++++++++++++++++++++++++++-- 6 files changed, 49 insertions(+), 8 deletions(-) diff --git a/arch/sh/boards/board-ap325rxa.c b/arch/sh/boards/board-ap325rxa.c index 9c97301..6675763 100644 --- a/arch/sh/boards/board-ap325rxa.c +++ b/arch/sh/boards/board-ap325rxa.c @@ -211,7 +211,7 @@ static struct resource lcdc_resources[] = { [0] = { .name = "LCDC", .start = 0xfe940000, /* P4-only space */ - .end = 0xfe941fff, + .end = 0xfe942fff, .flags = IORESOURCE_MEM, }, [1] = { diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 428d118..08627bd 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -235,7 +235,7 @@ static struct resource lcdc_resources[] = { [0] = { .name = "LCDC", .start = 0xfe940000, - .end = 0xfe941fff, + .end = 0xfe942fff, .flags = IORESOURCE_MEM, }, [1] = { diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c index 7155be0..c08d33f 100644 --- a/arch/sh/boards/mach-kfr2r09/setup.c +++ b/arch/sh/boards/mach-kfr2r09/setup.c @@ -162,7 +162,7 @@ static struct resource kfr2r09_sh_lcdc_resources[] = { [0] = { .name = "LCDC", .start = 0xfe940000, /* P4-only space */ - .end = 0xfe941fff, + .end = 0xfe942fff, .flags = IORESOURCE_MEM, }, [1] = { diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c index be8f0d9..6ed1fd3 100644 --- a/arch/sh/boards/mach-migor/setup.c +++ b/arch/sh/boards/mach-migor/setup.c @@ -279,7 +279,7 @@ static struct resource migor_lcdc_resources[] = { [0] = { .name = "LCDC", .start = 0xfe940000, /* P4-only space */ - .end = 0xfe941fff, + .end = 0xfe942fff, .flags = IORESOURCE_MEM, }, [1] = { diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c index 1876c83..00973e0 100644 --- a/arch/sh/boards/mach-se/7724/setup.c +++ b/arch/sh/boards/mach-se/7724/setup.c @@ -166,7 +166,7 @@ static struct resource lcdc_resources[] = { [0] = { .name = "LCDC", .start = 0xfe940000, - .end = 0xfe941fff, + .end = 0xfe942fff, .flags = IORESOURCE_MEM, }, [1] = { diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 7f30cb3..3ad5157 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -23,6 +23,8 @@ #include <asm/atomic.h> #define PALETTE_NR 16 +#define SIDE_B_OFFSET 0x1000 +#define MIRROR_OFFSET 0x2000 /* shared registers */ #define _LDDCKR 0x410 @@ -100,6 +102,10 @@ static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = { #define LDINTR_FS 0x00000004 #define LDINTR_VSS 0x00000002 #define LDINTR_VES 0x00000001 +#define LDRCNTR_SRS 0x00020000 +#define LDRCNTR_SRC 0x00010000 +#define LDRCNTR_MRS 0x00000002 +#define LDRCNTR_MRC 0x00000001 struct sh_mobile_lcdc_priv; struct sh_mobile_lcdc_chan { @@ -132,10 +138,39 @@ struct sh_mobile_lcdc_priv { int started; }; +static bool banked(int reg_nr) +{ + switch (reg_nr) { + case LDMT1R: + case LDMT2R: + case LDMT3R: + case LDDFR: + case LDSM1R: + case LDSA1R: + case LDMLSR: + case LDHCNR: + case LDHSYNR: + case LDVLNR: + case LDVSYNR: + return true; + } + return false; +} + static void lcdc_write_chan(struct sh_mobile_lcdc_chan *chan, int reg_nr, unsigned long data) { iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr]); + if (banked(reg_nr)) + iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr] + + SIDE_B_OFFSET); +} + +static void lcdc_write_chan_mirror(struct sh_mobile_lcdc_chan *chan, + int reg_nr, unsigned long data) +{ + iowrite32(data, chan->lcdc->base + chan->reg_offs[reg_nr] + + MIRROR_OFFSET); } static unsigned long lcdc_read_chan(struct sh_mobile_lcdc_chan *chan, @@ -308,10 +343,16 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data) /* VSYNC End */ if (ldintr & LDINTR_VES) { + unsigned long ldrcntr = lcdc_read(priv, _LDRCNTR); /* Set the source address for the next refresh */ - lcdc_write_chan(ch, LDSA1R, ch->dma_handle + - ch->new_pan_offset); - lcdc_write(ch->lcdc, _LDRCNTR, 0); + lcdc_write_chan_mirror(ch, LDSA1R, ch->dma_handle + + ch->new_pan_offset); + if (lcdc_chan_is_sublcd(ch)) + lcdc_write(ch->lcdc, _LDRCNTR, + ldrcntr ^ LDRCNTR_SRS); + else + lcdc_write(ch->lcdc, _LDRCNTR, + ldrcntr ^ LDRCNTR_MRS); ch->pan_offset = ch->new_pan_offset; } } -- 1.6.2.4 |
From: Guennadi L. <g.l...@gm...> - 2009-09-15 12:00:31
|
From: Phil Edworthy <phi...@re...> Signed-off-by: Phil Edworthy <phi...@re...> Signed-off-by: Guennadi Liakhovetski <g.l...@gm...> --- drivers/video/sh_mobile_lcdcfb.c | 76 +++++++++++++++++++++++++++++++++----- 1 files changed, 66 insertions(+), 10 deletions(-) diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 1cb5213..7f30cb3 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -31,6 +31,7 @@ #define _LDSR 0x46c #define _LDCNT1R 0x470 #define _LDCNT2R 0x474 +#define _LDRCNTR 0x478 #define _LDDDSR 0x47c #define _LDDWD0R 0x800 #define _LDDRDR 0x840 @@ -94,7 +95,11 @@ static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = { #define DISPLAY_BEU 0x00000008 #define LCDC_ENABLE 0x00000001 #define LDINTR_FE 0x00000400 +#define LDINTR_VSE 0x00000200 +#define LDINTR_VEE 0x00000100 #define LDINTR_FS 0x00000004 +#define LDINTR_VSS 0x00000002 +#define LDINTR_VES 0x00000001 struct sh_mobile_lcdc_priv; struct sh_mobile_lcdc_chan { @@ -110,6 +115,8 @@ struct sh_mobile_lcdc_chan { struct fb_deferred_io defio; struct scatterlist *sglist; unsigned long frame_end; + unsigned long pan_offset; + unsigned long new_pan_offset; wait_queue_head_t frame_end_wait; }; @@ -266,30 +273,46 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data) struct sh_mobile_lcdc_priv *priv = data; struct sh_mobile_lcdc_chan *ch; unsigned long tmp; + unsigned long ldintr; int is_sub; int k; /* acknowledge interrupt */ - tmp = lcdc_read(priv, _LDINTR); - tmp &= 0xffffff00; /* mask in high 24 bits */ - tmp |= 0x000000ff ^ LDINTR_FS; /* status in low 8 */ + ldintr = tmp = lcdc_read(priv, _LDINTR); + /* + * disable further VSYNC End IRQs, preserve all other enabled IRQs, + * write 0 to bits 0-6 to ack all triggered IRQs. + */ + tmp &= 0xffffff00 & ~LDINTR_VEE; lcdc_write(priv, _LDINTR, tmp); /* figure out if this interrupt is for main or sub lcd */ is_sub = (lcdc_read(priv, _LDSR) & (1 << 10)) ? 1 : 0; - /* wake up channel and disable clocks*/ + /* wake up channel and disable clocks */ for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!ch->enabled) continue; - if (is_sub == lcdc_chan_is_sublcd(ch)) { - ch->frame_end = 1; - wake_up(&ch->frame_end_wait); + /* Frame Start */ + if (ldintr & LDINTR_FS) { + if (is_sub == lcdc_chan_is_sublcd(ch)) { + ch->frame_end = 1; + wake_up(&ch->frame_end_wait); - sh_mobile_lcdc_clk_off(priv); + sh_mobile_lcdc_clk_off(priv); + } + } + + /* VSYNC End */ + if (ldintr & LDINTR_VES) { + /* Set the source address for the next refresh */ + lcdc_write_chan(ch, LDSA1R, ch->dma_handle + + ch->new_pan_offset); + lcdc_write(ch->lcdc, _LDRCNTR, 0); + ch->pan_offset = ch->new_pan_offset; } } @@ -649,6 +672,9 @@ static struct fb_fix_screeninfo sh_mobile_lcdc_fix = { .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_TRUECOLOR, .accel = FB_ACCEL_NONE, + .xpanstep = 0, + .ypanstep = 1, + .ywrapstep = 0, }; static void sh_mobile_lcdc_fillrect(struct fb_info *info, @@ -672,13 +698,38 @@ static void sh_mobile_lcdc_imageblit(struct fb_info *info, sh_mobile_lcdc_deferred_io_touch(info); } +static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct sh_mobile_lcdc_chan *ch = info->par; + + if (info->var.xoffset == var->xoffset && + info->var.yoffset == var->yoffset) + return 0; /* No change, do nothing */ + + ch->new_pan_offset = (var->yoffset * info->fix.line_length) + + (var->xoffset * (info->var.bits_per_pixel / 8)); + + if (ch->new_pan_offset != ch->pan_offset) { + unsigned long ldintr; + ldintr = lcdc_read(ch->lcdc, _LDINTR); + ldintr |= LDINTR_VEE; + lcdc_write(ch->lcdc, _LDINTR, ldintr); + sh_mobile_lcdc_deferred_io_touch(info); + } + + return 0; +} + static struct fb_ops sh_mobile_lcdc_ops = { + .owner = THIS_MODULE, .fb_setcolreg = sh_mobile_lcdc_setcolreg, .fb_read = fb_sys_read, .fb_write = fb_sys_write, .fb_fillrect = sh_mobile_lcdc_fillrect, .fb_copyarea = sh_mobile_lcdc_copyarea, .fb_imageblit = sh_mobile_lcdc_imageblit, + .fb_pan_display = sh_mobile_fb_pan_display, }; static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp) @@ -846,6 +897,8 @@ static int __init sh_mobile_lcdc_probe(struct platform_device *pdev) goto err1; } init_waitqueue_head(&priv->ch[i].frame_end_wait); + priv->ch[j].pan_offset = 0; + priv->ch[j].new_pan_offset = 0; switch (pdata->ch[i].chan) { case LCDC_CHAN_MAINLCD: @@ -888,7 +941,9 @@ static int __init sh_mobile_lcdc_probe(struct platform_device *pdev) info = priv->ch[i].info; info->fbops = &sh_mobile_lcdc_ops; info->var.xres = info->var.xres_virtual = cfg->lcd_cfg.xres; - info->var.yres = info->var.yres_virtual = cfg->lcd_cfg.yres; + info->var.yres = cfg->lcd_cfg.yres; + /* Default Y virtual resolution is 2x panel size */ + info->var.yres_virtual = info->var.yres * 2; info->var.width = cfg->lcd_size_cfg.width; info->var.height = cfg->lcd_size_cfg.height; info->var.activate = FB_ACTIVATE_NOW; @@ -898,7 +953,8 @@ static int __init sh_mobile_lcdc_probe(struct platform_device *pdev) info->fix = sh_mobile_lcdc_fix; info->fix.line_length = cfg->lcd_cfg.xres * (cfg->bpp / 8); - info->fix.smem_len = info->fix.line_length * cfg->lcd_cfg.yres; + info->fix.smem_len = info->fix.line_length * + info->var.yres_virtual; buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len, &priv->ch[i].dma_handle, GFP_KERNEL); -- 1.6.2.4 |
From: Guennadi L. <g.l...@gm...> - 2009-09-15 12:00:25
|
The following two patches add panning support to the SH LCDC framebuffer driver. Apart from the driver itself the patches also touch a bunch of sh board files, so, I think, it would be best to push them via SH tree. Thanks Guennadi --- Guennadi Liakhovetski, Ph.D. Freelance Open-Source Software Developer http://www.open-technology.de/ |
From: Mike F. <va...@ge...> - 2009-09-14 17:49:26
|
From: Michael Hennerich <mic...@an...> The LCD commands DMA/timers as well as PPI which we need to save/restore. Signed-off-by: Michael Hennerich <mic...@an...> Signed-off-by: Mike Frysinger <va...@ge...> --- drivers/video/bfin-t350mcqb-fb.c | 28 +++++++++++++++++++++++----- 1 files changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c index 5cc36cf..46cb07f 100644 --- a/drivers/video/bfin-t350mcqb-fb.c +++ b/drivers/video/bfin-t350mcqb-fb.c @@ -634,17 +634,35 @@ static int __devexit bfin_t350mcqb_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int bfin_t350mcqb_suspend(struct platform_device *pdev, pm_message_t state) { - bfin_t350mcqb_disable_ppi(); - disable_dma(CH_PPI); - bfin_write_PPI_STATUS(0xFFFF); + struct fb_info *fbinfo = platform_get_drvdata(pdev); + struct bfin_t350mcqbfb_info *fbi = fbinfo->par; + + if (fbi->lq043_open_cnt) { + bfin_t350mcqb_disable_ppi(); + disable_dma(CH_PPI); + bfin_t350mcqb_stop_timers(); + bfin_write_PPI_STATUS(-1); + } + return 0; } static int bfin_t350mcqb_resume(struct platform_device *pdev) { - enable_dma(CH_PPI); - bfin_t350mcqb_enable_ppi(); + struct fb_info *fbinfo = platform_get_drvdata(pdev); + struct bfin_t350mcqbfb_info *fbi = fbinfo->par; + + if (fbi->lq043_open_cnt) { + bfin_t350mcqb_config_dma(fbi); + bfin_t350mcqb_config_ppi(fbi); + bfin_t350mcqb_init_timers(); + + /* start dma */ + enable_dma(CH_PPI); + bfin_t350mcqb_enable_ppi(); + bfin_t350mcqb_start_timers(); + } return 0; } -- 1.6.4.2 |
From: Mike F. <va...@ge...> - 2009-09-14 17:49:20
|
From: Michael Hennerich <mic...@an...> The height/width framebuffer members need to be set in millimeters so that software can do proper scaling. Signed-off-by: Michael Hennerich <mic...@an...> Signed-off-by: Mike Frysinger <va...@ge...> --- drivers/video/bfin-t350mcqb-fb.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c index 46cb07f..2549c53 100644 --- a/drivers/video/bfin-t350mcqb-fb.c +++ b/drivers/video/bfin-t350mcqb-fb.c @@ -487,8 +487,8 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev) fbinfo->var.nonstd = 0; fbinfo->var.activate = FB_ACTIVATE_NOW; - fbinfo->var.height = -1; - fbinfo->var.width = -1; + fbinfo->var.height = 53; + fbinfo->var.width = 70; fbinfo->var.accel_flags = 0; fbinfo->var.vmode = FB_VMODE_NONINTERLACED; -- 1.6.4.2 |
From: Mike F. <va...@ge...> - 2009-09-14 17:49:18
|
From: Michael Hennerich <mic...@an...> Framebuffer driver for the Landscape LCD EZ-Extender (ADZS-BFLLCD-EZEXT) http://docs.blackfin.uclinux.org/doku.php?id=hw:cards:landscape_lcd_ez-extender Signed-off-by: Michael Hennerich <mic...@an...> Signed-off-by: Mike Frysinger <va...@ge...> Signed-off-by: Bryan Wu <coo...@ke...> --- arch/blackfin/include/asm/bfin-lq035q1.h | 28 + drivers/video/Kconfig | 13 + drivers/video/Makefile | 1 + drivers/video/bfin-lq035q1-fb.c | 855 ++++++++++++++++++++++++++++++ 4 files changed, 897 insertions(+), 0 deletions(-) create mode 100644 arch/blackfin/include/asm/bfin-lq035q1.h create mode 100644 drivers/video/bfin-lq035q1-fb.c diff --git a/arch/blackfin/include/asm/bfin-lq035q1.h b/arch/blackfin/include/asm/bfin-lq035q1.h new file mode 100644 index 0000000..a87a6b6 --- /dev/null +++ b/arch/blackfin/include/asm/bfin-lq035q1.h @@ -0,0 +1,28 @@ +/* + * Blackfin LCD Framebufer driver SHARP LQ035Q1DH02 + * + * Copyright 2008-2009 Analog Devices Inc. + * Licensed under the GPL-2 or later. + */ + +#ifndef BFIN_LQ035Q1_H +#define BFIN_LQ035Q1_H + +#define LQ035_RL (0 << 8) /* Right -> Left Scan */ +#define LQ035_LR (1 << 8) /* Left -> Right Scan */ +#define LQ035_TB (1 << 9) /* Top -> Botton Scan */ +#define LQ035_BT (0 << 9) /* Botton -> Top Scan */ +#define LQ035_BGR (1 << 11) /* Use BGR format */ +#define LQ035_RGB (0 << 11) /* Use RGB format */ +#define LQ035_NORM (1 << 13) /* Reversal */ +#define LQ035_REV (0 << 13) /* Reversal */ + +struct bfin_lq035q1fb_disp_info { + + unsigned mode; + /* GPIOs */ + int use_bl; + unsigned gpio_bl; +}; + +#endif /* BFIN_LQ035Q1_H */ diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 3b54b39..94501e0 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -609,6 +609,19 @@ config FB_BFIN_T350MCQB This display is a QVGA 320x240 24-bit RGB display interfaced by an 8-bit wide PPI It uses PPI[0..7] PPI_FS1, PPI_FS2 and PPI_CLK. +config FB_BFIN_LQ035Q1 + tristate "SHARP LQ035Q1DH02 TFT LCD" + depends on FB && BLACKFIN + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select BFIN_GPTIMERS + select SPI + help + This is the framebuffer device driver for a SHARP LQ035Q1DH02 TFT display found on + the Blackfin Landscape LCD EZ-Extender Card. + This display is a QVGA 320x240 18-bit RGB display interfaced by an 16-bit wide PPI + It uses PPI[0..15] PPI_FS1, PPI_FS2 and PPI_CLK. config FB_STI tristate "HP STI frame buffer device support" diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 01a819f..cc7682b 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -134,6 +134,7 @@ obj-$(CONFIG_FB_EFI) += efifb.o obj-$(CONFIG_FB_VGA16) += vga16fb.o obj-$(CONFIG_FB_OF) += offb.o obj-$(CONFIG_FB_BF54X_LQ043) += bf54x-lq043fb.o +obj-$(CONFIG_FB_BFIN_LQ035Q1) += bfin-lq035q1-fb.o obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin-t350mcqb-fb.o obj-$(CONFIG_FB_MX3) += mx3fb.o diff --git a/drivers/video/bfin-lq035q1-fb.c b/drivers/video/bfin-lq035q1-fb.c new file mode 100644 index 0000000..23eb369 --- /dev/null +++ b/drivers/video/bfin-lq035q1-fb.c @@ -0,0 +1,855 @@ +/* + * Blackfin LCD Framebufer driver SHARP LQ035Q1DH02 + * + * Copyright 2008-2009 Analog Devices Inc. + * Licensed under the GPL-2 or later. + */ + +#define pr_fmt(fmt) DRIVER_NAME ": " fmt + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/backlight.h> +#include <linux/lcd.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/dma-mapping.h> + +#include <asm/blackfin.h> +#include <asm/irq.h> +#include <asm/dma.h> +#include <asm/portmux.h> +#include <asm/gptimers.h> + +#include <asm/bfin-lq035q1.h> + +#if defined(BF533_FAMILY) || defined(BF538_FAMILY) +#define TIMER_HSYNC_id TIMER1_id +#define TIMER_HSYNCbit TIMER1bit +#define TIMER_HSYNC_STATUS_TRUN TIMER_STATUS_TRUN1 +#define TIMER_HSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL1 +#define TIMER_HSYNC_STATUS_TOVF TIMER_STATUS_TOVF1 + +#define TIMER_VSYNC_id TIMER2_id +#define TIMER_VSYNCbit TIMER2bit +#define TIMER_VSYNC_STATUS_TRUN TIMER_STATUS_TRUN2 +#define TIMER_VSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL2 +#define TIMER_VSYNC_STATUS_TOVF TIMER_STATUS_TOVF2 +#else +#define TIMER_HSYNC_id TIMER0_id +#define TIMER_HSYNCbit TIMER0bit +#define TIMER_HSYNC_STATUS_TRUN TIMER_STATUS_TRUN0 +#define TIMER_HSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL0 +#define TIMER_HSYNC_STATUS_TOVF TIMER_STATUS_TOVF0 + +#define TIMER_VSYNC_id TIMER1_id +#define TIMER_VSYNCbit TIMER1bit +#define TIMER_VSYNC_STATUS_TRUN TIMER_STATUS_TRUN1 +#define TIMER_VSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL1 +#define TIMER_VSYNC_STATUS_TOVF TIMER_STATUS_TOVF1 +#endif + +#define LCD_X_RES 320 /* Horizontal Resolution */ +#define LCD_Y_RES 240 /* Vertical Resolution */ +#define DMA_BUS_SIZE 16 + +#define USE_RGB565_16_BIT_PPI + +#ifdef USE_RGB565_16_BIT_PPI +#define LCD_BPP 16 /* Bit Per Pixel */ +#define CLOCKS_PER_PIX 1 +#define CPLD_PIPELINE_DELAY_COR 0 /* NO CPLB */ +#endif + +/* Interface 16/18-bit TFT over an 8-bit wide PPI using a small Programmable Logic Device (CPLD) + * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165 + */ + +#ifdef USE_RGB565_8_BIT_PPI +#define LCD_BPP 16 /* Bit Per Pixel */ +#define CLOCKS_PER_PIX 2 +#define CPLD_PIPELINE_DELAY_COR 3 /* RGB565 */ +#endif + +#ifdef USE_RGB888_8_BIT_PPI +#define LCD_BPP 24 /* Bit Per Pixel */ +#define CLOCKS_PER_PIX 3 +#define CPLD_PIPELINE_DELAY_COR 5 /* RGB888 */ +#endif + + /* + * HS and VS timing parameters (all in number of PPI clk ticks) + */ + +#define U_LINE 4 /* Blanking Lines */ + +#define H_ACTPIX (LCD_X_RES * CLOCKS_PER_PIX) /* active horizontal pixel */ +#define H_PERIOD (336 * CLOCKS_PER_PIX) /* HS period */ +#define H_PULSE (2 * CLOCKS_PER_PIX) /* HS pulse width */ +#define H_START (7 * CLOCKS_PER_PIX + CPLD_PIPELINE_DELAY_COR) /* first valid pixel */ + +#define V_LINES (LCD_Y_RES + U_LINE) /* total vertical lines */ +#define V_PULSE (2 * CLOCKS_PER_PIX) /* VS pulse width (1-5 H_PERIODs) */ +#define V_PERIOD (H_PERIOD * V_LINES) /* VS period */ + +#define ACTIVE_VIDEO_MEM_OFFSET ((U_LINE / 2) * LCD_X_RES * (LCD_BPP / 8)) + +#define BFIN_LCD_NBR_PALETTE_ENTRIES 256 + +#define PPI_TX_MODE 0x2 +#define PPI_XFER_TYPE_11 0xC +#define PPI_PORT_CFG_01 0x10 +#define PPI_POLS_1 0x8000 + +#if (CLOCKS_PER_PIX > 1) +#define PPI_PMODE (DLEN_8 | PACK_EN) +#else +#define PPI_PMODE (DLEN_16) +#endif + +#define LQ035_INDEX 0x74 +#define LQ035_DATA 0x76 + +#define LQ035_DRIVER_OUTPUT_CTL 0x1 +#define LQ035_SHUT_CTL 0x11 + +#define LQ035_DRIVER_OUTPUT_MASK (LQ035_LR | LQ035_TB | LQ035_BGR | LQ035_REV) +#define LQ035_DRIVER_OUTPUT_DEFAULT (0x2AEF & ~LQ035_DRIVER_OUTPUT_MASK) + +#define LQ035_SHUT (1 << 0) /* Shutdown */ +#define LQ035_ON (0 << 0) /* Shutdown */ + +#define DRIVER_NAME "bfin-lq035q1" +static char driver_name[] = DRIVER_NAME; + +struct bfin_lq035q1fb_info { + struct fb_info *fb; + struct device *dev; + struct bfin_lq035q1fb_disp_info *disp_info; + unsigned char *fb_buffer; /* RGB Buffer */ + dma_addr_t dma_handle; + int lq035_mmap; + int lq035_open_cnt; + int irq; + spinlock_t lock; /* lock */ + u32 pseudo_pal[16]; +}; + +static int nocursor; +module_param(nocursor, int, 0644); +MODULE_PARM_DESC(nocursor, "cursor enable/disable"); + + +static struct { + struct spi_device *spidev; + unsigned short mode; + unsigned short init; +} spi_control; + +static int lq035q1_control(unsigned char reg, unsigned short value) +{ + int ret; + u8 regs[3] = {LQ035_INDEX, 0, 0}; + u8 dat[3] = {LQ035_DATA, 0, 0}; + + if (spi_control.spidev) { + regs[2] = reg; + dat[1] = value >> 8; + dat[2] = value & 0xFF; + + ret = spi_write(spi_control.spidev, regs, ARRAY_SIZE(regs)); + ret |= spi_write(spi_control.spidev, dat, ARRAY_SIZE(dat)); + } else + return -ENODEV; + + return ret; +} + +static int __devinit lq035q1_spidev_probe(struct spi_device *spi) +{ + int ret; + spi_control.spidev = spi; + + ret = lq035q1_control(LQ035_SHUT_CTL, LQ035_ON); + ret |= lq035q1_control(LQ035_DRIVER_OUTPUT_CTL, spi_control.mode); + + if (ret) + return ret; + + spi_control.init = 1; + + return 0; +} + +static int __devexit lq035q1_spidev_remove(struct spi_device *spi) +{ + return lq035q1_control(LQ035_SHUT_CTL, LQ035_SHUT); +} + +#ifdef CONFIG_PM +static int lq035q1_spidev_suspend(struct spi_device *spi, pm_message_t state) +{ + return lq035q1_control(LQ035_SHUT_CTL, LQ035_SHUT); +} + +static int lq035q1_spidev_resume(struct spi_device *spi) +{ + int ret = lq035q1_control(LQ035_DRIVER_OUTPUT_CTL, spi_control.mode); + + if (ret) + return ret; + + return lq035q1_control(LQ035_SHUT_CTL, LQ035_ON); +} +#else +#define lq035q1_spidev_suspend NULL +#define lq035q1_spidev_resume NULL +#endif + +/* Power down all displays on reboot, poweroff or halt */ +static void lq035q1_spidev_shutdown(struct spi_device *spi) +{ + lq035q1_control(LQ035_SHUT_CTL, LQ035_SHUT); +} + +static struct spi_driver spidev_spi = { + .driver = { + .name = DRIVER_NAME"-spi", + .owner = THIS_MODULE, + }, + .probe = lq035q1_spidev_probe, + .remove = __devexit_p(lq035q1_spidev_remove), + .shutdown = lq035q1_spidev_shutdown, + .suspend = lq035q1_spidev_suspend, + .resume = lq035q1_spidev_resume, +}; + +static int lq035q1_backlight(struct bfin_lq035q1fb_info *info, unsigned arg) +{ + if (info->disp_info->use_bl) + gpio_set_value(info->disp_info->gpio_bl, arg); + + return 0; +} + +static void bfin_lq035q1_config_ppi(struct bfin_lq035q1fb_info *fbi) +{ + bfin_write_PPI_DELAY(H_START); + bfin_write_PPI_COUNT(H_ACTPIX - 1); + bfin_write_PPI_FRAME(V_LINES); + + bfin_write_PPI_CONTROL(PPI_TX_MODE | /* output mode , PORT_DIR */ + PPI_XFER_TYPE_11 | /* sync mode XFR_TYPE */ + PPI_PORT_CFG_01 | /* two frame sync PORT_CFG */ + PPI_PMODE | /* 8/16 bit data length / PACK_EN? */ + PPI_POLS_1); /* faling edge syncs POLS */ +} + +static inline void bfin_lq035q1_disable_ppi(void) +{ + bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() & ~PORT_EN); +} + +static inline void bfin_lq035q1_enable_ppi(void) +{ + bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() | PORT_EN); +} + +static void bfin_lq035q1_start_timers(void) +{ + enable_gptimers(TIMER_VSYNCbit | TIMER_HSYNCbit); +} + +static void bfin_lq035q1_stop_timers(void) +{ + disable_gptimers(TIMER_HSYNCbit | TIMER_VSYNCbit); + + set_gptimer_status(0, TIMER_HSYNC_STATUS_TRUN | TIMER_VSYNC_STATUS_TRUN | + TIMER_HSYNC_STATUS_TIMIL | TIMER_VSYNC_STATUS_TIMIL | + TIMER_HSYNC_STATUS_TOVF | TIMER_VSYNC_STATUS_TOVF); + +} + +static void bfin_lq035q1_init_timers(void) +{ + + bfin_lq035q1_stop_timers(); + + set_gptimer_period(TIMER_HSYNC_id, H_PERIOD); + set_gptimer_pwidth(TIMER_HSYNC_id, H_PULSE); + set_gptimer_config(TIMER_HSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT | + TIMER_TIN_SEL | TIMER_CLK_SEL| + TIMER_EMU_RUN); + + set_gptimer_period(TIMER_VSYNC_id, V_PERIOD); + set_gptimer_pwidth(TIMER_VSYNC_id, V_PULSE); + set_gptimer_config(TIMER_VSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT | + TIMER_TIN_SEL | TIMER_CLK_SEL | + TIMER_EMU_RUN); + +} + +static void bfin_lq035q1_config_dma(struct bfin_lq035q1fb_info *fbi) +{ + + set_dma_config(CH_PPI, + set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO, + INTR_DISABLE, DIMENSION_2D, + DATA_SIZE_16, + DMA_NOSYNC_KEEP_DMA_BUF)); + set_dma_x_count(CH_PPI, (LCD_X_RES * LCD_BPP) / DMA_BUS_SIZE); + set_dma_x_modify(CH_PPI, DMA_BUS_SIZE / 8); + set_dma_y_count(CH_PPI, V_LINES); + + set_dma_y_modify(CH_PPI, DMA_BUS_SIZE / 8); + set_dma_start_addr(CH_PPI, (unsigned long)fbi->fb_buffer); + +} + +#if (CLOCKS_PER_PIX == 1) +static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, + P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, + P_PPI0_D3, P_PPI0_D4, P_PPI0_D5, + P_PPI0_D6, P_PPI0_D7, P_PPI0_D8, + P_PPI0_D9, P_PPI0_D10, P_PPI0_D11, + P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, + P_PPI0_D15, 0}; +#else +static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, + P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, + P_PPI0_D3, P_PPI0_D4, P_PPI0_D5, + P_PPI0_D6, P_PPI0_D7, 0}; +#endif + +static int bfin_lq035q1_request_ports(int action) +{ + if (action) { + /* ANOMALY_05000400 - PPI Does Not Start Properly In Specific Mode: + * Drive PPI_FS3 Low + */ + if (ANOMALY_05000400) { + int ret = gpio_request(P_IDENT(P_PPI0_FS3), "PPI_FS3"); + if (ret) + return ret; + gpio_direction_output(P_IDENT(P_PPI0_FS3), 0); + } + + if (peripheral_request_list(ppi0_req_16, DRIVER_NAME)) { + pr_err("requesting peripherals failed\n"); + return -EFAULT; + } + } else { + peripheral_free_list(ppi0_req_16); + if (ANOMALY_05000400) + gpio_free(P_IDENT(P_PPI0_FS3)); + } + + return 0; +} + +static int bfin_lq035q1_fb_open(struct fb_info *info, int user) +{ + struct bfin_lq035q1fb_info *fbi = info->par; + + spin_lock(&fbi->lock); + fbi->lq035_open_cnt++; + + if (fbi->lq035_open_cnt <= 1) { + + bfin_lq035q1_disable_ppi(); + SSYNC(); + + bfin_lq035q1_config_dma(fbi); + bfin_lq035q1_config_ppi(fbi); + bfin_lq035q1_init_timers(); + + /* start dma */ + enable_dma(CH_PPI); + bfin_lq035q1_enable_ppi(); + bfin_lq035q1_start_timers(); + lq035q1_backlight(fbi, 1); + } + + spin_unlock(&fbi->lock); + + return 0; +} + +static int bfin_lq035q1_fb_release(struct fb_info *info, int user) +{ + struct bfin_lq035q1fb_info *fbi = info->par; + + spin_lock(&fbi->lock); + + fbi->lq035_open_cnt--; + fbi->lq035_mmap = 0; + + if (fbi->lq035_open_cnt <= 0) { + lq035q1_backlight(fbi, 0); + bfin_lq035q1_disable_ppi(); + SSYNC(); + disable_dma(CH_PPI); + bfin_lq035q1_stop_timers(); + } + + spin_unlock(&fbi->lock); + + return 0; +} + +static int bfin_lq035q1_fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + + switch (var->bits_per_pixel) { +#if (LCD_BPP == 24) + case 24:/* TRUECOLOUR, 16m */ +#else + case 16:/* DIRECTCOLOUR, 64k */ +#endif + var->red.offset = info->var.red.offset; + var->green.offset = info->var.green.offset; + var->blue.offset = info->var.blue.offset; + var->red.length = info->var.red.length; + var->green.length = info->var.green.length; + var->blue.length = info->var.blue.length; + var->transp.offset = 0; + var->transp.length = 0; + var->transp.msb_right = 0; + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + break; + default: + pr_debug("%s: depth not supported: %u BPP\n", __func__, + var->bits_per_pixel); + return -EINVAL; + } + + 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_debug("%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_debug("%s: Memory Limit requested yres_virtual = %u\n", + __func__, var->yres_virtual); + return -ENOMEM; + } + + + return 0; +} + +static int bfin_lq035q1_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + struct bfin_lq035q1fb_info *fbi = info->par; + + if (fbi->lq035_mmap) + return -1; + + spin_lock(&fbi->lock); + fbi->lq035_mmap = 1; + spin_unlock(&fbi->lock); + + vma->vm_start = (unsigned long)(fbi->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET); + + vma->vm_end = vma->vm_start + info->fix.smem_len; + /* For those who don't understand how mmap works, go read + * Documentation/nommu-mmap.txt. + * For those that do, you will know that the VM_MAYSHARE flag + * must be set in the vma->vm_flags structure on noMMU + * Other flags can be set, and are documented in + * include/linux/mm.h + */ + vma->vm_flags |= VM_MAYSHARE | VM_SHARED; + + return 0; +} + +int bfin_lq035q1_fb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + if (nocursor) + return 0; + else + return -EINVAL; /* just to force soft_cursor() call */ +} + +static int bfin_lq035q1_fb_setcolreg(u_int regno, u_int red, u_int green, + u_int blue, u_int transp, + struct fb_info *info) +{ + if (regno >= BFIN_LCD_NBR_PALETTE_ENTRIES) + return -EINVAL; + + if (info->var.grayscale) { + /* grayscale = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; + } + + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { + + u32 value; + /* Place color in the pseudopalette */ + if (regno > 16) + return -EINVAL; + + red >>= (16 - info->var.red.length); + green >>= (16 - info->var.green.length); + blue >>= (16 - info->var.blue.length); + + value = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + value &= 0xFFFFFF; + + ((u32 *) (info->pseudo_palette))[regno] = value; + + } + + return 0; +} + +static struct fb_ops bfin_lq035q1_fb_ops = { + .owner = THIS_MODULE, + .fb_open = bfin_lq035q1_fb_open, + .fb_release = bfin_lq035q1_fb_release, + .fb_check_var = bfin_lq035q1_fb_check_var, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_mmap = bfin_lq035q1_fb_mmap, + .fb_cursor = bfin_lq035q1_fb_cursor, + .fb_setcolreg = bfin_lq035q1_fb_setcolreg, +}; + +static irqreturn_t bfin_lq035q1_irq_error(int irq, void *dev_id) +{ + /*struct bfin_lq035q1fb_info *info = (struct bfin_lq035q1fb_info *)dev_id;*/ + + u16 status = bfin_read_PPI_STATUS(); + bfin_write_PPI_STATUS(-1); + + if (status) { + bfin_lq035q1_disable_ppi(); + disable_dma(CH_PPI); + + /* start dma */ + enable_dma(CH_PPI); + bfin_lq035q1_enable_ppi(); + bfin_write_PPI_STATUS(-1); + } + + return IRQ_HANDLED; +} + +static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) +{ + struct bfin_lq035q1fb_info *info; + struct fb_info *fbinfo; + int ret; + + ret = request_dma(CH_PPI, "CH_PPI"); + if (ret < 0) { + pr_err("couldn't request CH_PPI DMA\n"); + goto out1; + } + + fbinfo = + framebuffer_alloc(sizeof(struct bfin_lq035q1fb_info), &pdev->dev); + if (!fbinfo) { + ret = -ENOMEM; + goto out2; + } + + info = fbinfo->par; + info->fb = fbinfo; + info->dev = &pdev->dev; + + info->disp_info = pdev->dev.platform_data; + + spi_control.mode = (info->disp_info->mode & + LQ035_DRIVER_OUTPUT_MASK) | LQ035_DRIVER_OUTPUT_DEFAULT; + + platform_set_drvdata(pdev, fbinfo); + + strcpy(fbinfo->fix.id, driver_name); + + fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; + fbinfo->fix.type_aux = 0; + fbinfo->fix.xpanstep = 0; + fbinfo->fix.ypanstep = 0; + fbinfo->fix.ywrapstep = 0; + fbinfo->fix.accel = FB_ACCEL_NONE; + fbinfo->fix.visual = FB_VISUAL_TRUECOLOR; + + fbinfo->var.nonstd = 0; + fbinfo->var.activate = FB_ACTIVATE_NOW; + fbinfo->var.height = -1; + fbinfo->var.width = -1; + fbinfo->var.accel_flags = 0; + fbinfo->var.vmode = FB_VMODE_NONINTERLACED; + + fbinfo->var.xres = LCD_X_RES; + fbinfo->var.xres_virtual = LCD_X_RES; + fbinfo->var.yres = LCD_Y_RES; + fbinfo->var.yres_virtual = LCD_Y_RES; + fbinfo->var.bits_per_pixel = LCD_BPP; + + if (info->disp_info->mode & LQ035_BGR) { +#if (LCD_BPP == 24) + fbinfo->var.red.offset = 0; + fbinfo->var.green.offset = 8; + fbinfo->var.blue.offset = 16; +#else + fbinfo->var.red.offset = 0; + fbinfo->var.green.offset = 5; + fbinfo->var.blue.offset = 11; +#endif + } else { +#if (LCD_BPP == 24) + fbinfo->var.red.offset = 16; + fbinfo->var.green.offset = 8; + fbinfo->var.blue.offset = 0; +#else + fbinfo->var.red.offset = 11; + fbinfo->var.green.offset = 5; + fbinfo->var.blue.offset = 0; +#endif + } + + fbinfo->var.transp.offset = 0; + +#if (LCD_BPP == 24) + fbinfo->var.red.length = 8; + fbinfo->var.green.length = 8; + fbinfo->var.blue.length = 8; +#else + fbinfo->var.red.length = 5; + fbinfo->var.green.length = 6; + fbinfo->var.blue.length = 5; +#endif + + fbinfo->var.transp.length = 0; + + fbinfo->fix.smem_len = LCD_X_RES * LCD_Y_RES * LCD_BPP / 8 + + ACTIVE_VIDEO_MEM_OFFSET; + + fbinfo->fix.line_length = fbinfo->var.xres_virtual * + fbinfo->var.bits_per_pixel / 8; + + + fbinfo->fbops = &bfin_lq035q1_fb_ops; + fbinfo->flags = FBINFO_FLAG_DEFAULT; + + info->fb_buffer = + dma_alloc_coherent(NULL, fbinfo->fix.smem_len, &info->dma_handle, + GFP_KERNEL); + + if (NULL == info->fb_buffer) { + pr_err("couldn't allocate dma buffer\n"); + ret = -ENOMEM; + goto out3; + } + + fbinfo->screen_base = (void *)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; + fbinfo->fix.smem_start = (int)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; + + fbinfo->fbops = &bfin_lq035q1_fb_ops; + + fbinfo->pseudo_palette = &info->pseudo_pal; + + ret = fb_alloc_cmap(&fbinfo->cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0); + if (ret < 0) { + pr_err("failed to allocate colormap (%d entries)\n", + BFIN_LCD_NBR_PALETTE_ENTRIES); + goto out4; + } + + ret = bfin_lq035q1_request_ports(1); + if (ret) { + pr_err("couldn't request gpio port\n"); + goto out6; + } + + info->irq = platform_get_irq(pdev, 0); + if (info->irq < 0) { + ret = -EINVAL; + goto out7; + } + + ret = request_irq(info->irq, bfin_lq035q1_irq_error, IRQF_DISABLED, + "PPI ERROR", info); + if (ret < 0) { + pr_err("unable to request PPI ERROR IRQ\n"); + goto out7; + } + + ret = spi_register_driver(&spidev_spi); + if (ret < 0) { + pr_err("couldn't register SPI Interface\n"); + goto out8; + } + + if (info->disp_info->use_bl) { + ret = gpio_request(info->disp_info->gpio_bl, "LQ035 Backlight"); + + if (ret) { + pr_err("failed to request GPIO %d\n", + info->disp_info->gpio_bl); + goto out9; + } + gpio_direction_output(info->disp_info->gpio_bl, 0); + } + + ret = register_framebuffer(fbinfo); + if (ret < 0) { + pr_err("unable to register framebuffer\n"); + goto out10; + } + + pr_info("%dx%d %d-bit RGB FrameBuffer initialized\n", + LCD_X_RES, LCD_Y_RES, LCD_BPP); + + return 0; + +out10: + if (info->disp_info->use_bl) + gpio_free(info->disp_info->gpio_bl); +out9: + spi_unregister_driver(&spidev_spi); +out8: + free_irq(info->irq, info); +out7: + bfin_lq035q1_request_ports(0); +out6: + fb_dealloc_cmap(&fbinfo->cmap); +out4: + dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, + info->dma_handle); +out3: + framebuffer_release(fbinfo); +out2: + free_dma(CH_PPI); +out1: + platform_set_drvdata(pdev, NULL); + + return ret; +} + +static int __devexit bfin_lq035q1_remove(struct platform_device *pdev) +{ + struct fb_info *fbinfo = platform_get_drvdata(pdev); + struct bfin_lq035q1fb_info *info = fbinfo->par; + + if (info->disp_info->use_bl) + gpio_free(info->disp_info->gpio_bl); + + spi_unregister_driver(&spidev_spi); + + unregister_framebuffer(fbinfo); + + free_dma(CH_PPI); + free_irq(info->irq, info); + + if (info->fb_buffer != NULL) + dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, + info->dma_handle); + + fb_dealloc_cmap(&fbinfo->cmap); + + bfin_lq035q1_request_ports(0); + + platform_set_drvdata(pdev, NULL); + framebuffer_release(fbinfo); + + pr_info("unregistered LCD driver\n"); + + return 0; +} + +#ifdef CONFIG_PM +static int bfin_lq035q1_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct fb_info *fbinfo = platform_get_drvdata(pdev); + struct bfin_lq035q1fb_info *info = fbinfo->par; + + if (info->lq035_open_cnt) { + lq035q1_backlight(info, 0); + bfin_lq035q1_disable_ppi(); + SSYNC(); + disable_dma(CH_PPI); + bfin_lq035q1_stop_timers(); + bfin_write_PPI_STATUS(-1); + } + + return 0; +} + +static int bfin_lq035q1_resume(struct platform_device *pdev) +{ + struct fb_info *fbinfo = platform_get_drvdata(pdev); + struct bfin_lq035q1fb_info *info = fbinfo->par; + + if (info->lq035_open_cnt) { + bfin_lq035q1_disable_ppi(); + SSYNC(); + + bfin_lq035q1_config_dma(info); + bfin_lq035q1_config_ppi(info); + bfin_lq035q1_init_timers(); + + /* start dma */ + enable_dma(CH_PPI); + bfin_lq035q1_enable_ppi(); + bfin_lq035q1_start_timers(); + lq035q1_backlight(info, 1); + } + + return 0; +} +#else +#define bfin_lq035q1_suspend NULL +#define bfin_lq035q1_resume NULL +#endif + +static struct platform_driver bfin_lq035q1_driver = { + .probe = bfin_lq035q1_probe, + .remove = __devexit_p(bfin_lq035q1_remove), + .suspend = bfin_lq035q1_suspend, + .resume = bfin_lq035q1_resume, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init bfin_lq035q1_driver_init(void) +{ + return platform_driver_register(&bfin_lq035q1_driver); +} +module_init(bfin_lq035q1_driver_init); + +static void __exit bfin_lq035q1_driver_cleanup(void) +{ + platform_driver_unregister(&bfin_lq035q1_driver); +} +module_exit(bfin_lq035q1_driver_cleanup); + +MODULE_DESCRIPTION("Blackfin TFT LCD Driver"); +MODULE_LICENSE("GPL"); -- 1.6.4.2 |
From: Felipe C. <fel...@gm...> - 2009-09-14 15:22:44
|
On Mon, Sep 14, 2009 at 5:43 PM, Aguirre Rodriguez, Sergio Alberto <saa...@ti...> wrote: > Hi, > > This patch has been lying around for some weeks now, with just responses about successful testing (detailed in the description). > > Is there anything holding it for merge? Or should I try sending it to other ML? > > BTW, It applies cleanly on mainline aswell. Try running 'get_maintainer' script to find other people that have worked on this code: Trilok Soni <son...@gm...> Andrew Morton <ak...@li...> Tony Lindgren <to...@at...> Russell King <rmk...@ar...> Krzysztof Helt <krz...@wp...> My feedback is: please mention in the message how the bug can be triggered. And watch your uppercases: omapfb: reorder register_framebuffer call -- Felipe Contreras |
From: Aguirre R. S. A. <saa...@ti...> - 2009-09-14 14:43:35
|
Hi, This patch has been lying around for some weeks now, with just responses about successful testing (detailed in the description). Is there anything holding it for merge? Or should I try sending it to other ML? BTW, It applies cleanly on mainline aswell. Regards, Sergio > -----Original Message----- > From: Sergio Aguirre [mailto:ser...@gm...] On Behalf Of > Sergio Aguirre > Sent: Saturday, September 12, 2009 11:34 AM > To: Imre Deak > Cc: lin...@li...; lin...@vg...; > Aguirre Rodriguez, Sergio Alberto > Subject: [PATCH] omapfb: Reorder Register_framebuffer call > > This fixes the issue in which mm_lock mutex was attempted to be > used without initializing previously. > > Thanks to the testers! > - OMAP3430 SDP (Anand Gadiyar) > - OMAP3530 EVM (Vaibhav Hiremath) > - LogicPD's OMAP boards (Peter Brada) > - Beagleboard Rev. C2 (Eric Witcher) > > Signed-off-by: Sergio Aguirre <saa...@ti...> > Tested-by: Vaibhav Hiremath <hva...@ti...> > Tested-by: Anand Gadiyar <ga...@ti...> > Tested-by: Peter Barada <pe...@lo...> > Tested-by: Eric Witcher <ewi...@mi...> > --- > drivers/video/omap/omapfb_main.c | 20 +++++++++++--------- > 1 files changed, 11 insertions(+), 9 deletions(-) > > diff --git a/drivers/video/omap/omapfb_main.c > b/drivers/video/omap/omapfb_main.c > index 125e605..60f9482 100644 > --- a/drivers/video/omap/omapfb_main.c > +++ b/drivers/video/omap/omapfb_main.c > @@ -1503,12 +1503,21 @@ static int fbinfo_init(struct omapfb_device > *fbdev, struct fb_info *info) > var->rotate = def_rotate; > var->bits_per_pixel = fbdev->panel->bpp; > > + r = register_framebuffer(info); > + if (r != 0) { > + dev_err(fbdev->dev, > + "registering framebuffer failed\n"); > + return r; > + } > + > set_fb_var(info, var); > set_fb_fix(info); > > r = fb_alloc_cmap(&info->cmap, 16, 0); > - if (r != 0) > + if (r != 0) { > dev_err(fbdev->dev, "unable to allocate color map memory\n"); > + unregister_framebuffer(info); > + } > > return r; > } > @@ -1773,15 +1782,8 @@ static int omapfb_do_probe(struct platform_device > *pdev, > init_state++; > > vram = 0; > - for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { > - r = register_framebuffer(fbdev->fb_info[i]); > - if (r != 0) { > - dev_err(fbdev->dev, > - "registering framebuffer %d failed\n", i); > - goto cleanup; > - } > + for (i = 0; i < fbdev->mem_desc.region_cnt; i++) > vram += fbdev->mem_desc.region[i].size; > - } > > fbdev->state = OMAPFB_ACTIVE; > > -- > 1.6.3.2 > |
From: Jonathan C. <co...@lw...> - 2009-09-13 23:08:24
|
On Sat, 5 Sep 2009 16:01:40 -0700 Andrew Morton <ak...@li...> wrote: > Send 'em over. I haven't heard anything from the original viafb > submitters for a long time. Hopefully Florian has time to help out > with some review-n-test. OK, I've been doing some hacking and a bunch of flinging patches around in git. The result is three branches, all of which are based on 2.6.31 and can be found in: git://git.lwn.net/linux-2.6.git Whether these trees will be useful to anybody remains to be seen; I'm hoping they can serve as a starting point for the pulling-together of a lot of divergent via code. Branch #1 is viafb-mm; it contains all of the patches found in -mm as of today: Alexey Dobriyan (1): viafb: switch to seq_file Florian Tobias Schandinat (19): viafb: Remove duplicated cx700 register initialization viafb: remove temporary start address handling viafb: shrink and merge viafb_update_viafb_par viafb: split up viafb_set_start_addr viafb: clean up ioremap_nocache error handling viafb: clean up viamodeh viafb: remove duplicated mode information viafb: clean up duoview viafb: clean up virtual memory handling viafb: remove unused video device stuff viafb: remove lvds initialization viafb: another small cleanup of viafb_par viafb: improve viafb_par viafb: rewrite the 2d engine viafb: 2d engine rewrite v2 viafb: Clean the hardware cursor handling up. viafb: improve pitch handling viafb: hardware acceleration initialization cleanup viafb: use read-only mode parsing Harald Welte (2): viafb: make module parameters visible in sysfs viafb: remove unused structure member Branch #2 (olpc-vx855) is all of the viafb/vx855-related stuff from the OLPC tree, separated from all the other OLPC stuff and pulled forward to 2.6.31. What can be found there is: Chris Ball (3): viafb: Add 1200x900 DCON/LCD panel modes for OLPC XO-1.5 viafb: Do not probe for LVDS/TMDS on OLPC XO-1.5 Add missing includes to via/{hw,lcd}.c Daniel Drake (1): viafb: Don't accelerate blit of color images Deepak Saxena (2): vx855-gpio: Fix parameter order in call to outl vx855-gpio: Initialize spinlock prior to use Harald Welte (16): [FB] viafb: Add missing break statement in switch [FB] viafb: Add support for the VX855 chipset [FB] viafb: Fix various resource leaks during module_init() [FB] viafb: make viafb a first-class citizen using pci_driver viafb: pass reference to pci device when calling framebuffer_alloc() viafb: use proper pci config API viafb: get rid of some duplicated fields in private structure viafb: Remove MMIO from private structure viafb: make module parameters visible in sysfs viafb: clean up duplicated code from 2D acceleration viafb: introduce wrapper for 2D engine registers viafb: initialize 2D engine registers from loop viafb: Determine type of 2D engine and store it in chip_info viafb: Add support for 2D accelerated framebuffer on VX800/VX855 viafb: rework the I2C support in the VIA framebuffer driver [MFD] Add VIA VX855 multi-function device Paul Fox (2): fix comment describing numeric API indices eliminate the spinlock when reading a gpio. My sense is that all of this stuff could conceivably be merged for 2.6.32. The only problem is that any attempt to merge with viafb-mm leads to the sort of pain that only high-proof alcohol can fix. I am almost certain not to get this work done in the merge window - my liver can't handle it - and there's no pressing reason to get this stuff into the mainline right now. So I don't think 2.6.32 is in the cards for this stuff. OLPC has earned itself a painful merge by keeping this stuff out-of-tree. But I fear I'll be the one who eventually cleans up that mess. Branch #3 (olpc-jc) is the work I've done so far, based on top of the OLPC changes: Jonathan Corbet (4): viafb: Split via-core from viafb viafb: Separate out i2c initialization from viafb viafb: Move port configuration into via-core viafb: add support for onboard GPIOs This is just there in case anybody wants to take a look; I'm really just getting started. jon |
From: Sergio A. <saa...@ti...> - 2009-09-12 16:34:30
|
This fixes the issue in which mm_lock mutex was attempted to be used without initializing previously. Thanks to the testers! - OMAP3430 SDP (Anand Gadiyar) - OMAP3530 EVM (Vaibhav Hiremath) - LogicPD's OMAP boards (Peter Brada) - Beagleboard Rev. C2 (Eric Witcher) Signed-off-by: Sergio Aguirre <saa...@ti...> Tested-by: Vaibhav Hiremath <hva...@ti...> Tested-by: Anand Gadiyar <ga...@ti...> Tested-by: Peter Barada <pe...@lo...> Tested-by: Eric Witcher <ewi...@mi...> --- drivers/video/omap/omapfb_main.c | 20 +++++++++++--------- 1 files changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c index 125e605..60f9482 100644 --- a/drivers/video/omap/omapfb_main.c +++ b/drivers/video/omap/omapfb_main.c @@ -1503,12 +1503,21 @@ static int fbinfo_init(struct omapfb_device *fbdev, struct fb_info *info) var->rotate = def_rotate; var->bits_per_pixel = fbdev->panel->bpp; + r = register_framebuffer(info); + if (r != 0) { + dev_err(fbdev->dev, + "registering framebuffer failed\n"); + return r; + } + set_fb_var(info, var); set_fb_fix(info); r = fb_alloc_cmap(&info->cmap, 16, 0); - if (r != 0) + if (r != 0) { dev_err(fbdev->dev, "unable to allocate color map memory\n"); + unregister_framebuffer(info); + } return r; } @@ -1773,15 +1782,8 @@ static int omapfb_do_probe(struct platform_device *pdev, init_state++; vram = 0; - for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { - r = register_framebuffer(fbdev->fb_info[i]); - if (r != 0) { - dev_err(fbdev->dev, - "registering framebuffer %d failed\n", i); - goto cleanup; - } + for (i = 0; i < fbdev->mem_desc.region_cnt; i++) vram += fbdev->mem_desc.region[i].size; - } fbdev->state = OMAPFB_ACTIVE; -- 1.6.3.2 |
From: Pawel O. <p.o...@sa...> - 2009-09-11 18:06:38
|
This patch adds debugfs information in s3c-fb directory in debugfs root. Reviewed-by: Marek Szyprowski <m.s...@sa...> Reviewed-by: Kyungmin Park <kyu...@sa...> Signed-off-by: Pawel Osciak <p.o...@sa...> --- drivers/video/Kconfig | 16 +++- drivers/video/s3c-fb.c | 237 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 249 insertions(+), 4 deletions(-) diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 3b54b39..922a1cb 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1917,10 +1917,18 @@ config FB_S3C Currently the support is only for the S3C6400 and S3C6410 SoCs. config FB_S3C_DEBUG_REGWRITE - bool "Debug register writes" - depends on FB_S3C - ---help--- - Show all register writes via printk(KERN_DEBUG) + bool "Debug register writes" + depends on FB_S3C + ---help--- + Show all register writes via printk(KERN_DEBUG) + +config FB_S3C_DEBUG_FS + bool "Enable debug information in DebugFS" + depends on FB_S3C && DEBUG_FS + default n + ---help--- + Enable this if you want debugging information in debugfs. + If unsure, say N. config FB_S3C2410 tristate "S3C2410 LCD framebuffer support" diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index 226d225..6721f20 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c @@ -26,6 +26,12 @@ #include <plat/s3c-fb.h> +#ifdef CONFIG_FB_S3C_DEBUG_FS +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#endif + + #include <mach/map.h> #include <mach/regs-fb.h> #include <plat/fb.h> @@ -62,6 +68,11 @@ struct s3c_fb; +#ifdef CONFIG_FB_S3C_DEBUG_FS +static void __devinit s3c_fb_debugfs_init(struct s3c_fb *sfb); +static void __devinit s3c_fb_debugfs_remove(void); +#endif + /** * struct s3c_fb_win - per window private data for each framebuffer. * @windata: The platform data supplied for the window configuration. @@ -1441,6 +1452,10 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) platform_set_drvdata(pdev, sfb); +#ifdef CONFIG_FB_S3C_DEBUG_FS + s3c_fb_debugfs_init(sfb); +#endif + return 0; err_irq: @@ -1474,6 +1489,10 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev) struct s3c_fb *sfb = platform_get_drvdata(pdev); int win; +#ifdef CONFIG_FB_S3C_DEBUG_FS + s3c_fb_debugfs_remove(); +#endif + for (win = 0; win < S3C_FB_MAX_WIN; win++) if (sfb->windows[win]) s3c_fb_release_win(sfb, sfb->windows[win]); @@ -1567,6 +1586,224 @@ static void __exit s3c_fb_cleanup(void) platform_driver_unregister(&s3c_fb_driver); } +/* DEBUGFS */ + +#ifdef CONFIG_FB_S3C_DEBUG_FS +static struct dentry *debugfs_dir; + +static void *dbg_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + int *win_no; + + if (v == SEQ_START_TOKEN) + return pos; + + win_no = (int *)pos; + *win_no += 1; + if (*win_no >= S3C_FB_MAX_WIN) + return NULL; + + return pos; +} + +static int dbg_blend_seq_show(struct seq_file *s, void *v) +{ + struct s3c_fb *sfb = s->private; + int *win_no = v; + u32 vidosdc, wincon; + + if (v == SEQ_START_TOKEN) { + seq_printf(s, "win| mode AEN0 AEN1\n"); + return 0; + } + + if (!s3c_fb_has_alpha(*win_no)) + return SEQ_SKIP; + + seq_printf(s, "%2d | ", *win_no); + + vidosdc = readl(sfb->regs + VIDOSD_C(*win_no)); + wincon = readl(sfb->regs + WINCONx(*win_no)); + if (wincon & WINCONx_BLD_PIX) { + seq_printf(s, " per pixel "); + if (wincon & WINCONx_ALPHA_SEL) + seq_printf(s, "value "); + else + seq_printf(s, "global "); + } else { + seq_printf(s, " global "); + if (wincon & WINCONx_ALPHA_SEL) + seq_printf(s, "val 1 "); + else + seq_printf(s, "val 0 "); + } + seq_printf(s, "%04x %04x\n", + (vidosdc & VIDOSD14C_ALPHA0_MASK) + >> VIDOSD14C_ALPHA0_B_SHIFT, + vidosdc & VIDOSD14C_ALPHA1_MASK); + + return 0; +} + +static int dbg_ckey_seq_show(struct seq_file *s, void *v) +{ + struct s3c_fb *sfb = s->private; + int *win_no = v; + u32 keycon0, keycon1; + + if (v == SEQ_START_TOKEN) { + seq_printf(s, "win| enabled direction value mask\n"); + return 0; + } + + if (!has_colorkey(*win_no)) + return SEQ_SKIP; + + seq_printf(s, "%2d | ", *win_no); + + keycon0 = readl(sfb->regs + WxKEYCON0(*win_no)); + keycon1 = readl(sfb->regs + WxKEYCON1(*win_no)); + + seq_printf(s, " %d ", keycon0 & WxKEYCON0_KEYEN_F); + if (keycon0 & WxKEYCON0_DIRCON) + seq_printf(s, " FG "); + else + seq_printf(s, " BG "); + + seq_printf(s, " %06x ", keycon1 & WxKEYCON1_COLVAL_MASK); + seq_printf(s, "%06x ", keycon0 & WxKEYCON0_COMPKEY_MASK); + seq_printf(s, "\n"); + + return 0; +} + +static inline void *single_start(struct seq_file *p, loff_t *pos) +{ + if (*pos == 0) + return SEQ_START_TOKEN; + + return NULL + (*pos == 0); +} + +static inline void single_stop(struct seq_file *p, void *v) +{ +} + +static const struct seq_operations dbg_blend_seq_ops = { + .start = single_start, + .next = dbg_seq_next, + .stop = single_stop, + .show = dbg_blend_seq_show, +}; + +static const struct seq_operations dbg_ckey_seq_ops = { + .start = single_start, + .next = dbg_seq_next, + .stop = single_stop, + .show = dbg_ckey_seq_show, +}; + +static int dbg_blend_open(struct inode *inode, struct file *file) +{ + struct seq_file *seq; + int ret; + + ret = seq_open(file, &dbg_blend_seq_ops); + if (ret) + return ret; + + seq = file->private_data; + seq->private = inode->i_private; + + return 0; +} + +static const struct file_operations dbg_blend_fops = { + .owner = THIS_MODULE, + .open = dbg_blend_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int dbg_ckey_open(struct inode *inode, struct file *file) +{ + struct seq_file *seq; + int ret; + + ret = seq_open(file, &dbg_ckey_seq_ops); + if (ret) + return ret; + + seq = file->private_data; + seq->private = inode->i_private; + + return 0; +} + +static const struct file_operations dbg_ckey_fops = { + .owner = THIS_MODULE, + .open = dbg_ckey_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int dbg_winen_show(struct seq_file *s, void *v) +{ + struct s3c_fb *sfb = s->private; + int win_no; + + for (win_no = 0; win_no < S3C_FB_MAX_WIN; ++win_no) { + if (sfb->enabled & (1 << win_no)) + seq_printf(s, "Win%d: enabled\n", win_no); + else + seq_printf(s, "Win%d: disabled\n", win_no); + } + + return 0; +} + +static int dbg_winen_open(struct inode *inode, struct file *file) +{ + return single_open(file, dbg_winen_show, inode->i_private); +} + +static const struct file_operations dbg_winen_fops = { + .owner = THIS_MODULE, + .open = dbg_winen_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void __devinit s3c_fb_debugfs_init(struct s3c_fb *sfb) +{ + debugfs_dir = debugfs_create_dir("s3c-fb", NULL); + if (! debugfs_dir || IS_ERR(debugfs_dir)) { + dev_warn(sfb->dev, "Could not create debugfs directory\n"); + return; + } + + debugfs_create_file("windows_enabled", S_IRUGO, debugfs_dir, sfb, + &dbg_winen_fops); + + debugfs_create_file("blending", S_IRUGO, debugfs_dir, sfb, + &dbg_blend_fops); + + debugfs_create_file("color_key", S_IRUGO, debugfs_dir, sfb, + &dbg_ckey_fops); +} + +static void __devinit s3c_fb_debugfs_remove(void) +{ + if (debugfs_dir) + debugfs_remove_recursive(debugfs_dir); +} +#endif /* CONFIG_DEBUG_FS */ + +/* DEBUGFS END */ + module_init(s3c_fb_init); module_exit(s3c_fb_cleanup); -- 1.6.4.2.253.g0b1fac |
From: Pawel O. <p.o...@sa...> - 2009-09-11 18:06:31
|
This feature allows blending based on color key value. Pixels with key value get blended with alpha1, while the rest gets blended with alpha0. Reviewed-by: Marek Szyprowski <m.s...@sa...> Reviewed-by: Kyungmin Park <kyu...@sa...> Signed-off-by: Pawel Osciak <p.o...@sa...> --- arch/arm/plat-s3c/include/plat/s3c-fb.h | 2 ++ drivers/video/s3c-fb.c | 27 ++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletions(-) diff --git a/arch/arm/plat-s3c/include/plat/s3c-fb.h b/arch/arm/plat-s3c/include/plat/s3c-fb.h index 080524d..def54ec 100644 --- a/arch/arm/plat-s3c/include/plat/s3c-fb.h +++ b/arch/arm/plat-s3c/include/plat/s3c-fb.h @@ -67,6 +67,8 @@ typedef enum s3c_fb_alpha_mode { #define S3CFB_IOCTL_SET_COLOR_KEY_MODE _IO(S3CFB_IOCTL_MAGIC, 2) /* param: 1 - on, 0 - off */ #define S3CFB_IOCTL_COLOR_KEY_ENABLE _IO(S3CFB_IOCTL_MAGIC, 3) +/* param: 1 - on, 0 - off */ +#define S3CFB_IOCTL_COLOR_KEY_BLEND_ENABLE _IO(S3CFB_IOCTL_MAGIC, 8) /* Param: s3c_fb_source */ diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index 6721f20..5ea6a5b 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c @@ -926,7 +926,8 @@ static int s3c_fb_color_key_enable(struct s3c_fb_win *win, int enable) int keycon0_reg; if (! has_colorkey(win->index)) { - dev_err(sfb->dev, "Window does not support color keying\n"); + dev_err(sfb->dev, "Window %d does not support color keying\n", + win->index); return -EINVAL; } @@ -941,6 +942,27 @@ static int s3c_fb_color_key_enable(struct s3c_fb_win *win, int enable) return 0; } +static int s3c_fb_color_key_blending_enable(struct s3c_fb_win *win, int enable) +{ + struct s3c_fb *sfb = win->parent; + int keycon0_reg; + + if (! has_colorkey(win->index)) { + dev_err(sfb->dev, "Window %d does not support color keying\n", + win->index); + return -EINVAL; + } + + keycon0_reg = readl(sfb->regs + WxKEYCON0(win->index)); + if (enable) + keycon0_reg |= WxKEYCON0_KEYBL_EN; + else + keycon0_reg &= ~WxKEYCON0_KEYBL_EN; + + writel(keycon0_reg, sfb->regs + WxKEYCON0(win->index)); + + return 0; +} static int s3c_fb_set_color_key_mode(struct s3c_fb_win *win, enum s3c_fb_color_key_mode mode) { @@ -1115,6 +1137,9 @@ static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd, case S3CFB_IOCTL_COLOR_KEY_ENABLE: return s3c_fb_color_key_enable(win, arg); + case S3CFB_IOCTL_COLOR_KEY_BLEND_ENABLE: + return s3c_fb_color_key_blending_enable(win, arg); + case S3CFB_IOCTL_SET_SOURCE: return s3c_fb_set_source(win, arg); -- 1.6.4.2.253.g0b1fac |
From: Pawel O. <p.o...@sa...> - 2009-09-11 18:06:20
|
Reviewed-by: Marek Szyprowski <m.s...@sa...> Reviewed-by: Kyungmin Park <kyu...@sa...> Signed-off-by: Pawel Osciak <p.o...@sa...> --- drivers/video/s3c-fb.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index 307a7e8..226d225 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c @@ -401,6 +401,7 @@ static int s3c_fb_set_par(struct fb_info *info) writel(osdc_data, regs + VIDOSD_C(win_no)); data = WINCONx_ENWIN; + sfb->enabled |= (1 << win_no); /* note, since we have to round up the bits-per-pixel, we end up * relying on the bitfield information for r/g/b/a to work out @@ -633,6 +634,7 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info) /* disable the DMA and display 0x0 (black) */ writel(WINxMAP_MAP | WINxMAP_MAP_COLOUR(0x0), sfb->regs + WINxMAP(index)); + sfb->enabled &= ~(1 << index); break; case FB_BLANK_UNBLANK: -- 1.6.4.2.253.g0b1fac |
From: Pawel O. <p.o...@sa...> - 2009-09-11 18:06:14
|
For S3C64xx, only windows 1 and 2 have VIDOSD_D registers. The VIDOSD_x register functions differ depending on the window number, as does the ability of setting up size and alpha: win0: size in VIDOSD_C win1-2: alpha in VIDOSD_C and size in VIDOSD_D win3-4: alpha in VIDOSD_C Reviewed-by: Marek Szyprowski <m.s...@sa...> Reviewed-by: Kyungmin Park <kyu...@sa...> Signed-off-by: Pawel Osciak <p.o...@sa...> --- arch/arm/mach-s3c6400/include/mach/regs-fb.h | 14 +++++++- arch/arm/plat-s3c/include/plat/regs-fb.h | 44 +++++++++++++------------ drivers/video/s3c-fb.c | 27 ++++++++++------ 3 files changed, 52 insertions(+), 33 deletions(-) diff --git a/arch/arm/mach-s3c6400/include/mach/regs-fb.h b/arch/arm/mach-s3c6400/include/mach/regs-fb.h index 84facc9..b926057 100644 --- a/arch/arm/mach-s3c6400/include/mach/regs-fb.h +++ b/arch/arm/mach-s3c6400/include/mach/regs-fb.h @@ -46,7 +46,7 @@ #define WINCON(_win) (0x20 + ((_win) * 4)) -/* OSD1 and OSD4 do not have register D */ +/* Only OSD1 and OSD2 have register VIDOSD_D */ #define VIDOSD_A(_win) (0x40 + ((_win) * 16)) #define VIDOSD_B(_win) (0x44 + ((_win) * 16)) @@ -168,7 +168,17 @@ */ /* return true if window _win has OSD register D */ -#define s3c_fb_has_osd_d(_win) ((_win) != 4 && (_win) != 0) +#define s3c_fb_has_osd_d(_win) ((_win) == 1 || (_win) == 2) + +/* Return true if the window allows setting its alpha. + * If so, then the register to put the alpha values in is VIDOSD_C */ +#define s3c_fb_has_alpha(_win) ((_win) > 0) + +/* Return true if the window allows adjusting its size. + * If so, then the register to put it in is VIDOSD_C for win0 and D otherwise */ +#define s3c_fb_allows_size(_win) ((_win) < 3) +#define VIDOSD_SIZE(_win) (((_win) == 0) ? \ + (VIDOSD_C(_win)) : (VIDOSD_D(_win))) static inline unsigned int s3c_fb_win_pal_size(unsigned int win) { diff --git a/arch/arm/plat-s3c/include/plat/regs-fb.h b/arch/arm/plat-s3c/include/plat/regs-fb.h index 26b878b..efe163c 100644 --- a/arch/arm/plat-s3c/include/plat/regs-fb.h +++ b/arch/arm/plat-s3c/include/plat/regs-fb.h @@ -240,27 +240,29 @@ #define VIDOSDxB_BOTRIGHT_Y(_x) ((_x) << 0) /* For VIDOSD[1..4]C */ -#define VIDISD14C_ALPHA0_R(_x) ((_x) << 20) -#define VIDISD14C_ALPHA0_G_MASK (0xf << 16) -#define VIDISD14C_ALPHA0_G_SHIFT (16) -#define VIDISD14C_ALPHA0_G_LIMIT (0xf) -#define VIDISD14C_ALPHA0_G(_x) ((_x) << 16) -#define VIDISD14C_ALPHA0_B_MASK (0xf << 12) -#define VIDISD14C_ALPHA0_B_SHIFT (12) -#define VIDISD14C_ALPHA0_B_LIMIT (0xf) -#define VIDISD14C_ALPHA0_B(_x) ((_x) << 12) -#define VIDISD14C_ALPHA1_R_MASK (0xf << 8) -#define VIDISD14C_ALPHA1_R_SHIFT (8) -#define VIDISD14C_ALPHA1_R_LIMIT (0xf) -#define VIDISD14C_ALPHA1_R(_x) ((_x) << 8) -#define VIDISD14C_ALPHA1_G_MASK (0xf << 4) -#define VIDISD14C_ALPHA1_G_SHIFT (4) -#define VIDISD14C_ALPHA1_G_LIMIT (0xf) -#define VIDISD14C_ALPHA1_G(_x) ((_x) << 4) -#define VIDISD14C_ALPHA1_B_MASK (0xf << 0) -#define VIDISD14C_ALPHA1_B_SHIFT (0) -#define VIDISD14C_ALPHA1_B_LIMIT (0xf) -#define VIDISD14C_ALPHA1_B(_x) ((_x) << 0) +#define VIDOSD14C_ALPHA0_R(_x) ((_x) << 20) +#define VIDOSD14C_ALPHA0_G_MASK (0xf << 16) +#define VIDOSD14C_ALPHA0_G_SHIFT (16) +#define VIDOSD14C_ALPHA0_G_LIMIT (0xf) +#define VIDOSD14C_ALPHA0_G(_x) ((_x) << 16) +#define VIDOSD14C_ALPHA0_B_MASK (0xf << 12) +#define VIDOSD14C_ALPHA0_B_SHIFT (12) +#define VIDOSD14C_ALPHA0_B_LIMIT (0xf) +#define VIDOSD14C_ALPHA0_B(_x) ((_x) << 12) +#define VIDOSD14C_ALPHA1_R_MASK (0xf << 8) +#define VIDOSD14C_ALPHA1_R_SHIFT (8) +#define VIDOSD14C_ALPHA1_R_LIMIT (0xf) +#define VIDOSD14C_ALPHA1_R(_x) ((_x) << 8) +#define VIDOSD14C_ALPHA1_G_MASK (0xf << 4) +#define VIDOSD14C_ALPHA1_G_SHIFT (4) +#define VIDOSD14C_ALPHA1_G_LIMIT (0xf) +#define VIDOSD14C_ALPHA1_G(_x) ((_x) << 4) +#define VIDOSD14C_ALPHA1_B_MASK (0xf << 0) +#define VIDOSD14C_ALPHA1_B_SHIFT (0) +#define VIDOSD14C_ALPHA1_B_LIMIT (0xf) +#define VIDOSD14C_ALPHA1_B(_x) ((_x) << 0) +#define VIDOSD14C_ALPHA0_MASK (0xfff << VIDOSD14C_ALPHA0_B_SHIFT) +#define VIDOSD14C_ALPHA1_MASK (0xfff) /* Video buffer addresses */ #define VIDW_BUF_START(_buff) (0xA0 + ((_buff) * 8)) diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index 54ed018..307a7e8 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c @@ -390,15 +390,15 @@ static int s3c_fb_set_par(struct fb_info *info) data = var->xres * var->yres; - osdc_data = VIDISD14C_ALPHA1_R(0xf) | - VIDISD14C_ALPHA1_G(0xf) | - VIDISD14C_ALPHA1_B(0xf); + if (s3c_fb_allows_size(win_no)) + writel(data, regs + VIDOSD_SIZE(win_no)); - if (s3c_fb_has_osd_d(win_no)) { - writel(data, regs + VIDOSD_D(win_no)); + osdc_data = VIDOSD14C_ALPHA1_R(0xf) | + VIDOSD14C_ALPHA1_G(0xf) | + VIDOSD14C_ALPHA1_B(0xf); + + if (s3c_fb_has_alpha(win_no)) writel(osdc_data, regs + VIDOSD_C(win_no)); - } else - writel(data, regs + VIDOSD_C(win_no)); data = WINCONx_ENWIN; @@ -1046,13 +1046,18 @@ static int s3c_fb_set_win_alpha(struct s3c_fb_win *win, struct s3c_fb *sfb = win->parent; u32 vidosdc_reg = 0; - if (win->index == 0) { + if (!s3c_fb_has_alpha(win->index)) { dev_err(sfb->dev, "Alpha cannot be set for window %d\n.", win->index); + return -EINVAL; } - vidosdc_reg = alpha->r0 << 20 | alpha->g0 << 16 | alpha->b0 << 12 - | alpha->r1 << 8 | alpha->g1 << 4 | alpha->b1; + vidosdc_reg = VIDOSD14C_ALPHA0_R(alpha->r0) + | VIDOSD14C_ALPHA0_G(alpha->g0) + | VIDOSD14C_ALPHA0_B(alpha->b0) + | VIDOSD14C_ALPHA1_R(alpha->r1) + | VIDOSD14C_ALPHA1_G(alpha->g1) + | VIDOSD14C_ALPHA1_B(alpha->b1); writel(vidosdc_reg, sfb->regs + VIDOSD_C(win->index)); return 0; @@ -1331,6 +1336,8 @@ static void s3c_fb_clear_win(struct s3c_fb *sfb, int win) writel(0, regs + VIDOSD_A(win)); writel(0, regs + VIDOSD_B(win)); writel(0, regs + VIDOSD_C(win)); + if (s3c_fb_has_osd_d(win)) + writel(0, regs + VIDOSD_D(win)); } static int __devinit s3c_fb_probe(struct platform_device *pdev) -- 1.6.4.2.253.g0b1fac |
From: Pawel O. <p.o...@sa...> - 2009-09-11 18:06:13
|
Reviewed-by: Marek Szyprowski <m.s...@sa...> Reviewed-by: Kyungmin Park <kyu...@sa...> Signed-off-by: Pawel Osciak <p.o...@sa...> --- arch/arm/mach-s3c6400/include/mach/regs-fb.h | 6 ++ arch/arm/plat-s3c/include/plat/regs-fb.h | 7 +++ arch/arm/plat-s3c/include/plat/s3c-fb.h | 27 +++++++++ drivers/video/s3c-fb.c | 75 ++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-s3c6400/include/mach/regs-fb.h b/arch/arm/mach-s3c6400/include/mach/regs-fb.h index 6339426..84facc9 100644 --- a/arch/arm/mach-s3c6400/include/mach/regs-fb.h +++ b/arch/arm/mach-s3c6400/include/mach/regs-fb.h @@ -24,6 +24,9 @@ * override them at a later date. */ +#ifndef __ASM_ARCH_REGS_FB_H +#define __ASM_ARCH_REGS_FB_H __FILE__ + #include <plat/regs-fb.h> #define S3C_FB_MAX_WIN (5) /* number of hardware windows available. */ @@ -262,3 +265,6 @@ static inline void s3c_fb_init_palette(unsigned int window, * 1110 -none- -none- -none- -none- -none- * 1111 -none- -none- -none- -none- -none- */ + +#endif /* __ASM_ARCH_REGS_FB_H */ + diff --git a/arch/arm/plat-s3c/include/plat/regs-fb.h b/arch/arm/plat-s3c/include/plat/regs-fb.h index 4c024ca..26b878b 100644 --- a/arch/arm/plat-s3c/include/plat/regs-fb.h +++ b/arch/arm/plat-s3c/include/plat/regs-fb.h @@ -28,6 +28,9 @@ * ensure all the localised SoC support is included as necessary. */ +#ifndef __PLAT_S3C_REGS_FB_H +#define __PLAT_S3C_REGS_FB_H __FILE__ + /* VIDCON0 */ #define VIDCON0 (0x00) @@ -179,6 +182,8 @@ #define WINCONx_BURSTLEN_16WORD (0x0 << 9) #define WINCONx_BURSTLEN_8WORD (0x1 << 9) #define WINCONx_BURSTLEN_4WORD (0x2 << 9) +#define WINCONx_BLD_PIX (1 << 6) +#define WINCONx_ALPHA_SEL (1 << 1) #define WINCONx_ENWIN (1 << 0) #define WINCON0_BPPMODE_MASK (0xf << 2) @@ -369,3 +374,5 @@ #define WPALCON_W0PAL_16BPP_A555 (0x5 << 0) #define WPALCON_W0PAL_16BPP_565 (0x6 << 0) +#endif /* __PLAT_S3C_REGS_FB_H */ + diff --git a/arch/arm/plat-s3c/include/plat/s3c-fb.h b/arch/arm/plat-s3c/include/plat/s3c-fb.h index b08f9ad..080524d 100644 --- a/arch/arm/plat-s3c/include/plat/s3c-fb.h +++ b/arch/arm/plat-s3c/include/plat/s3c-fb.h @@ -21,6 +21,16 @@ struct s3c_fb_color { __u32 b : 8; } __attribute__((__packed__)); +struct s3c_fb_alpha { + __u32 reserved : 8; + __u32 r0 : 4; + __u32 g0 : 4; + __u32 b0 : 4; + __u32 r1 : 4; + __u32 g1 : 4; + __u32 b1 : 4; +} __attribute__((__packed__)); + typedef enum s3c_fb_color_key_mode { S3CFB_COLORKEY_MODE_BG = 0, S3CFB_COLORKEY_MODE_FG = 1 @@ -32,6 +42,17 @@ typedef enum s3c_fb_source { S3CFB_SOURCE_LOCAL_YCbCr = 2 } s3c_fb_source_t; +typedef enum s3c_fb_alpha_mode { + /* Use alpha value from each pixel */ + S3CFB_ALPHA_PIXEL_VALUE, + /* Use global alpha (0 or 1) value chosen by alpha bit of the pixel */ + S3CFB_ALPHA_PIXEL_SWITCH, + /* Blend all pixels with global alpha0 value */ + S3CFB_ALPHA_PLANE_0, + /* Blend all pixels with global alpha1 value */ + S3CFB_ALPHA_PLANE_1 +} s3c_fb_alpha_mode_t; + #ifndef FBIO_WAITFORVSYNC #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) #endif @@ -50,5 +71,11 @@ typedef enum s3c_fb_source { /* Param: s3c_fb_source */ #define S3CFB_IOCTL_SET_SOURCE _IO(S3CFB_IOCTL_MAGIC, 5) + +/* Param: s3c_fb_alpha_mode */ +#define S3CFB_IOCTL_SET_ALPHA_MODE _IO(S3CFB_IOCTL_MAGIC, 6) + +#define S3CFB_IOCTL_SET_WINDOW_ALPHA _IOW(S3CFB_IOCTL_MAGIC, 7,\ + struct s3c_fb_alpha) #endif /* __LINUX_S3C_FB_H__ */ diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index 28622c0..54ed018 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c @@ -997,6 +997,67 @@ static int s3c_fb_set_source(struct s3c_fb_win *win, s3c_fb_source_t source) return 0; } +static int s3c_fb_set_alpha_mode(struct s3c_fb_win *win, + s3c_fb_alpha_mode_t mode) +{ + struct s3c_fb *sfb = win->parent; + int wincon_reg; + + if (win->index == 0) { + dev_err(sfb->dev, + "Alpha mode for window %d is not supported.\n", + win->index); + return -EINVAL; + } + + wincon_reg = readl(sfb->regs + WINCONx(win->index)); + wincon_reg &= ~(WINCONx_BLD_PIX | WINCONx_ALPHA_SEL); + + switch (mode) { + case S3CFB_ALPHA_PIXEL_VALUE: + /* Use alpha value of each pixel */ + wincon_reg |= WINCONx_BLD_PIX | WINCONx_ALPHA_SEL; + break; + case S3CFB_ALPHA_PIXEL_SWITCH: + /* Use global alpha chosen by the alpha bit of each pixel */ + wincon_reg |= WINCONx_BLD_PIX; + break; + case S3CFB_ALPHA_PLANE_0: + /* Use global alpha0 for every pixel */ + wincon_reg &= ~WINCONx_BLD_PIX; + break; + case S3CFB_ALPHA_PLANE_1: + /* Use global alpha1 for every pixel */ + wincon_reg &= ~WINCONx_BLD_PIX; + wincon_reg |= WINCONx_ALPHA_SEL; + break; + default: + return -EINVAL; + } + + writel(wincon_reg, sfb->regs + WINCONx(win->index)); + + return 0; +} + +static int s3c_fb_set_win_alpha(struct s3c_fb_win *win, + struct s3c_fb_alpha *alpha) +{ + struct s3c_fb *sfb = win->parent; + u32 vidosdc_reg = 0; + + if (win->index == 0) { + dev_err(sfb->dev, "Alpha cannot be set for window %d\n.", + win->index); + } + + vidosdc_reg = alpha->r0 << 20 | alpha->g0 << 16 | alpha->b0 << 12 + | alpha->r1 << 8 | alpha->g1 << 4 | alpha->b1; + writel(vidosdc_reg, sfb->regs + VIDOSD_C(win->index)); + + return 0; +} + static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { @@ -1039,6 +1100,20 @@ static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd, case S3CFB_IOCTL_SET_SOURCE: return s3c_fb_set_source(win, arg); + + case S3CFB_IOCTL_SET_ALPHA_MODE: + return s3c_fb_set_alpha_mode(win, arg); + + case S3CFB_IOCTL_SET_WINDOW_ALPHA: { + struct s3c_fb_alpha alpha_arg; + ret = copy_from_user(&alpha_arg, (void __user *)arg, + sizeof(struct s3c_fb_alpha)); + if (ret) + return ret; + + return s3c_fb_set_win_alpha(win, &alpha_arg); + } + default: return -ENOTTY; } -- 1.6.4.2.253.g0b1fac |
From: Pawel O. <p.o...@sa...> - 2009-09-11 18:06:09
|
Reviewed-by: Marek Szyprowski <m.s...@sa...> Reviewed-by: Kyungmin Park <kyu...@sa...> Signed-off-by: Pawel Osciak <p.o...@sa...> --- arch/arm/plat-s3c/include/plat/regs-fb.h | 3 + arch/arm/plat-s3c/include/plat/s3c-fb.h | 45 ++++++++ drivers/video/s3c-fb.c | 164 ++++++++++++++++++++++++++++++ 3 files changed, 212 insertions(+), 0 deletions(-) create mode 100644 arch/arm/plat-s3c/include/plat/s3c-fb.h diff --git a/arch/arm/plat-s3c/include/plat/regs-fb.h b/arch/arm/plat-s3c/include/plat/regs-fb.h index 8048cae..8d3071d 100644 --- a/arch/arm/plat-s3c/include/plat/regs-fb.h +++ b/arch/arm/plat-s3c/include/plat/regs-fb.h @@ -323,6 +323,7 @@ /* Window colour-key control registers */ +#define WxKEYCON0(_x) (0x140 + ((_x-1) * 8)) #define WxKEYCON0_KEYBL_EN (1 << 26) #define WxKEYCON0_KEYEN_F (1 << 25) #define WxKEYCON0_DIRCON (1 << 24) @@ -330,6 +331,8 @@ #define WxKEYCON0_COMPKEY_SHIFT (0) #define WxKEYCON0_COMPKEY_LIMIT (0xffffff) #define WxKEYCON0_COMPKEY(_x) ((_x) << 0) + +#define WxKEYCON1(_x) (0x144 + ((_x-1) * 8)) #define WxKEYCON1_COLVAL_MASK (0xffffff << 0) #define WxKEYCON1_COLVAL_SHIFT (0) #define WxKEYCON1_COLVAL_LIMIT (0xffffff) diff --git a/arch/arm/plat-s3c/include/plat/s3c-fb.h b/arch/arm/plat-s3c/include/plat/s3c-fb.h new file mode 100644 index 0000000..0aebc40 --- /dev/null +++ b/arch/arm/plat-s3c/include/plat/s3c-fb.h @@ -0,0 +1,45 @@ +/* + * include/linux/s3c/s3c-fb.h + * + * Copyright 2009 Samsung Electronics Co., Ltd. + * Author: Pawel Osciak <p.o...@sa...> + * + * 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_S3C_FB_H__ +#define __LINUX_S3C_FB_H__ + +#include <linux/types.h> + +struct s3c_fb_color { + __u32 a : 8; + __u32 r : 8; + __u32 g : 8; + __u32 b : 8; +} __attribute__((__packed__)); + +typedef enum s3c_fb_color_key_mode { + S3CFB_COLORKEY_MODE_BG = 0, + S3CFB_COLORKEY_MODE_FG = 1 +} s3c_fb_color_key_mode_t; + +#ifndef FBIO_WAITFORVSYNC +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) +#endif + +#define S3CFB_IOCTL_MAGIC 'k' + +#define S3CFB_IOCTL_SET_COLOR_KEY _IOW(S3CFB_IOCTL_MAGIC, 0,\ + struct s3c_fb_color) +#define S3CFB_IOCTL_SET_COLOR_KEY_MASK _IOW(S3CFB_IOCTL_MAGIC, 1,\ + struct s3c_fb_color) +/* param: s3c_fb_color_key_mode */ +#define S3CFB_IOCTL_SET_COLOR_KEY_MODE _IO(S3CFB_IOCTL_MAGIC, 2) +/* param: 1 - on, 0 - off */ +#define S3CFB_IOCTL_COLOR_KEY_ENABLE _IO(S3CFB_IOCTL_MAGIC, 3) + +#endif /* __LINUX_S3C_FB_H__ */ + diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index 001a1a1..2de3151 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 <plat/s3c-fb.h> + #include <mach/map.h> #include <mach/regs-fb.h> #include <plat/fb.h> @@ -43,6 +45,7 @@ * is being built for. */ +/*#define CONFIG_FB_S3C_DEBUG_REGWRITE*/ #ifdef CONFIG_FB_S3C_DEBUG_REGWRITE #undef writel #define writel(v, r) do { \ @@ -821,11 +824,148 @@ static int s3c_fb_pan_display(struct fb_var_screeninfo *var, return 0; } +static inline int s3c_fb_color_to_rgb565(struct s3c_fb_color *color) +{ + return (((color->r & 0x1f) << 19) | 0x70000) + | (((color->g & 0x3f) << 10) | 0x300) + | (((color->b & 0x1f) << 3) | 0x7); +} + +static inline int s3c_fb_color_to_rgb888(struct s3c_fb_color *color) +{ + return (color->r << 16) | (color->g << 8) | color->b; +} + +static inline int has_colorkey(int win_no) +{ + if (win_no == 0) + return 0; + else + return 1; +} + +static int s3c_fb_set_color_key(struct s3c_fb_win *win, + struct s3c_fb_color *color_key) +{ + struct s3c_fb *sfb = win->parent; + void __iomem *regs = sfb->regs; + int color = 0; + + if (! has_colorkey(win->index)) { + dev_err(sfb->dev, "Window %d does not support color keying\n", + win->index); + return -EINVAL; + } + + dev_info(sfb->dev, "Window %d, BPP: %d\n", win->index, + win->fbinfo->var.bits_per_pixel); + + if (win->fbinfo->var.bits_per_pixel == 16) { + color = s3c_fb_color_to_rgb565(color_key); + } else if (win->fbinfo->var.bits_per_pixel >= 24) { + /*|| win->fbinfo->var.bits_per_pixel == 28) {*/ + color = s3c_fb_color_to_rgb888(color_key); + } else { + dev_err(sfb->dev, "Invalid BPP\n"); + return -EINVAL; + } + + writel(color, regs + WxKEYCON1(win->index)); + + return 0; +} + +static int s3c_fb_set_color_key_mask(struct s3c_fb_win *win, + struct s3c_fb_color *color_key_mask) +{ + struct s3c_fb *sfb = win->parent; + void __iomem *regs = sfb->regs; + int keycon0_reg; + int mask = 0; + + if (! has_colorkey(win->index)) { + dev_err(sfb->dev, "Window %d does not support color keying\n", + win->index); + return -EINVAL; + } + + if (win->fbinfo->var.bits_per_pixel == 16) { + mask = s3c_fb_color_to_rgb565(color_key_mask); + } else if (win->fbinfo->var.bits_per_pixel >= 24) { + /*|| win->fbinfo->var.bits_per_pixel == 28) {*/ + mask = s3c_fb_color_to_rgb888(color_key_mask); + } else { + dev_err(sfb->dev, "Invalid BPP\n"); + return -EINVAL; + } + + keycon0_reg = readl(regs + WxKEYCON0(win->index)); + keycon0_reg &= ~WxKEYCON0_COMPKEY_MASK; + keycon0_reg |= mask; + writel(keycon0_reg, regs + WxKEYCON0(win->index)); + + return 0; +} + +static int s3c_fb_color_key_enable(struct s3c_fb_win *win, int enable) +{ + struct s3c_fb *sfb = win->parent; + int keycon0_reg; + + if (! has_colorkey(win->index)) { + dev_err(sfb->dev, "Window does not support color keying\n"); + return -EINVAL; + } + + keycon0_reg = readl(sfb->regs + WxKEYCON0(win->index)); + if (enable) + keycon0_reg |= WxKEYCON0_KEYEN_F; + else + keycon0_reg &= ~WxKEYCON0_KEYEN_F; + + writel(keycon0_reg, sfb->regs + WxKEYCON0(win->index)); + + return 0; +} + +static int s3c_fb_set_color_key_mode(struct s3c_fb_win *win, + enum s3c_fb_color_key_mode mode) +{ + struct s3c_fb *sfb = win->parent; + int keycon0_reg; + + if (! has_colorkey(win->index)) { + dev_err(sfb->dev, "Window %d does not support color keying\n", + win->index); + return -EINVAL; + } + + keycon0_reg = readl(sfb->regs + WxKEYCON0(win->index)); + + switch(mode) { + case S3CFB_COLORKEY_MODE_BG: + keycon0_reg &= ~WxKEYCON0_DIRCON; + break; + case S3CFB_COLORKEY_MODE_FG: + keycon0_reg |= WxKEYCON0_DIRCON; + break; + default: + dev_err(sfb->dev, "Invalid colorkey mode\n"); + return -EINVAL; + } + + writel(keycon0_reg, sfb->regs + WxKEYCON0(win->index)); + s3c_fb_color_key_enable(win, 1); + + return 0; +} + static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { struct s3c_fb_win *win = info->par; struct s3c_fb *sfb = win->parent; + int ret; switch (cmd) { case FBIO_WAITFORVSYNC: { @@ -835,6 +975,30 @@ static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd, return s3c_fb_wait_for_vsync(sfb, crtc); } + case S3CFB_IOCTL_SET_COLOR_KEY: { + struct s3c_fb_color ck_arg; + ret = copy_from_user(&ck_arg, (void __user *)arg, + sizeof(struct s3c_fb_color)); + if (ret) + return ret; + + return s3c_fb_set_color_key(win, &ck_arg); + } + case S3CFB_IOCTL_SET_COLOR_KEY_MASK: { + struct s3c_fb_color ck_mask_arg; + ret = copy_from_user(&ck_mask_arg, (void __user *)arg, + sizeof(struct s3c_fb_color)); + if (ret) + return ret; + + return s3c_fb_set_color_key_mask(win, &ck_mask_arg); + } + case S3CFB_IOCTL_SET_COLOR_KEY_MODE: + return s3c_fb_set_color_key_mode(win, arg); + + case S3CFB_IOCTL_COLOR_KEY_ENABLE: + return s3c_fb_color_key_enable(win, arg); + default: return -ENOTTY; } -- 1.6.4.2.253.g0b1fac |
From: Pawel O. <p.o...@sa...> - 2009-09-11 18:06:07
|
It is now possible to switch between local bus and DMA as the source for a window. Local source mode can handle RGB and YCbCr formats. Reviewed-by: Marek Szyprowski <m.s...@sa...> Reviewed-by: Kyungmin Park <kyu...@sa...> Signed-off-by: Pawel Osciak <p.o...@sa...> --- arch/arm/plat-s3c/include/plat/regs-fb.h | 1 + arch/arm/plat-s3c/include/plat/s3c-fb.h | 9 ++++++ drivers/video/s3c-fb.c | 40 ++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 0 deletions(-) diff --git a/arch/arm/plat-s3c/include/plat/regs-fb.h b/arch/arm/plat-s3c/include/plat/regs-fb.h index 8d3071d..4c024ca 100644 --- a/arch/arm/plat-s3c/include/plat/regs-fb.h +++ b/arch/arm/plat-s3c/include/plat/regs-fb.h @@ -170,6 +170,7 @@ /* WINCONx */ +#define WINCONx(_x) (0x20 + ((_x) * 4)) #define WINCONx_BITSWP (1 << 18) #define WINCONx_BYTSWP (1 << 17) #define WINCONx_HAWSWP (1 << 16) diff --git a/arch/arm/plat-s3c/include/plat/s3c-fb.h b/arch/arm/plat-s3c/include/plat/s3c-fb.h index 0aebc40..b08f9ad 100644 --- a/arch/arm/plat-s3c/include/plat/s3c-fb.h +++ b/arch/arm/plat-s3c/include/plat/s3c-fb.h @@ -26,6 +26,12 @@ typedef enum s3c_fb_color_key_mode { S3CFB_COLORKEY_MODE_FG = 1 } s3c_fb_color_key_mode_t; +typedef enum s3c_fb_source { + S3CFB_SOURCE_DMA = 0, + S3CFB_SOURCE_LOCAL_RGB = 1, + S3CFB_SOURCE_LOCAL_YCbCr = 2 +} s3c_fb_source_t; + #ifndef FBIO_WAITFORVSYNC #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) #endif @@ -41,5 +47,8 @@ typedef enum s3c_fb_color_key_mode { /* param: 1 - on, 0 - off */ #define S3CFB_IOCTL_COLOR_KEY_ENABLE _IO(S3CFB_IOCTL_MAGIC, 3) + +/* Param: s3c_fb_source */ +#define S3CFB_IOCTL_SET_SOURCE _IO(S3CFB_IOCTL_MAGIC, 5) #endif /* __LINUX_S3C_FB_H__ */ diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index 2de3151..28622c0 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c @@ -960,6 +960,43 @@ static int s3c_fb_set_color_key_mode(struct s3c_fb_win *win, return 0; } +static int s3c_fb_set_source(struct s3c_fb_win *win, s3c_fb_source_t source) +{ + struct s3c_fb *sfb = win->parent; + int wincon_reg, new_val; + + if (win->index > 2) { + dev_err(sfb->dev, "Source change not supported for window %d\n", + win->index); + return -EINVAL; + } + + wincon_reg = readl(sfb->regs + WINCONx(win->index)); + new_val = wincon_reg; + + switch (source) { + case S3CFB_SOURCE_DMA: + new_val &= ~(WINCONx_ENLOCAL | WINCONx_YCbCr); + break; + case S3CFB_SOURCE_LOCAL_RGB: + new_val &= ~WINCONx_YCbCr; + new_val |= WINCONx_ENLOCAL; + break; + case S3CFB_SOURCE_LOCAL_YCbCr: + new_val |= WINCONx_YCbCr | WINCONx_ENLOCAL; + break; + default: + return -EINVAL; + } + + /* The window has to be disabled during source switch */ + writel(wincon_reg & ~WINCONx_ENWIN, sfb->regs + WINCONx(win->index)); + new_val |= WINCONx_ENWIN; + writel(new_val, sfb->regs + WINCONx(win->index)); + + return 0; +} + static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { @@ -999,6 +1036,9 @@ static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd, case S3CFB_IOCTL_COLOR_KEY_ENABLE: return s3c_fb_color_key_enable(win, arg); + + case S3CFB_IOCTL_SET_SOURCE: + return s3c_fb_set_source(win, arg); default: return -ENOTTY; } -- 1.6.4.2.253.g0b1fac |