Screenshot instructions:
Windows
Mac
Red Hat Linux
Ubuntu
Click URL instructions:
Right-click on ad, choose "Copy Link", then paste here →
(This may not be possible with some types of ads)
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
|
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
|
1
(10) |
2
(11) |
3
(4) |
4
(28) |
5
(11) |
6
(4) |
7
(3) |
8
(5) |
9
(3) |
10
(10) |
11
(3) |
12
(2) |
13
|
14
(19) |
15
|
16
(6) |
17
(11) |
18
(5) |
19
(1) |
20
(4) |
21
|
22
(5) |
23
(6) |
24
(3) |
25
(12) |
26
(6) |
27
|
28
(1) |
29
(11) |
30
(5) |
|
|
|
|
From: Krzysztof Helt <krzysztof.h1@po...> - 2009-06-17 21:32:20
|
On Wed, 17 Jun 2009 06:00:53 -0400 (EDT) Mikulas Patocka <mpatocka@...> wrote: > Use the same color-calculating algorithm as in atyfb_imageblit in this driver > or in generic cfb_fillrect. > > This patch fixes bad colors when using an accelerator in 15-bit and 16-bit > modes. > > Signed-off-by: Mikulas Patocka <mpatocka@... > Acked-by: Krzysztof Helt <krzysztof.h1@...> ---------------------------------------------------------------------- Masz juz dosc wysokich rachunkow? Wygraj nowa mozliwosc komunikacji! Sprawdz >>> http://link.interia.pl/f21d2 |
From: Krzysztof Helt <krzysztof.h1@po...> - 2009-06-17 21:31:09
|
On Wed, 17 Jun 2009 10:01:10 -0400 "Rajashekhara, Sudhakar" <sudhakar.raj@...> wrote: > Reseding the same patch with additional Signed-off information. > > Adds LCD controller (LCDC) driver for TI's DA8xx/OMAP-L1xx architecture. > LCDC specifications can be found at http://www.ti.com/litv/pdf/sprufm0a. > > LCDC on DA8xx consists of two independent controllers, the Raster Controller > and the LCD Interface Display Driver (LIDD) controller. LIDD further supports > character and graphic displays. > > This patch adds support for the graphic display (Sharp LQ035Q3DG01) found on > the DA830 based EVM. The EVM details can be found at: > http://support.spectrumdigital.com/boards/dskda830/revc/. > > Signed-off-by: Sudhakar Rajashekhara <sudhakar.raj@...> > Signed-off-by: Pavel Kiryukhin <pkiryukhin@...> > Signed-off-by: Steve Chen <schen@...> > --- > drivers/video/Kconfig | 11 + > drivers/video/Makefile | 1 + > drivers/video/da8xx-fb.c | 964 ++++++++++++++++++++++++++++++++++++++++++++++ > include/linux/da8xx-fb.h | 106 +++++ > 4 files changed, 1082 insertions(+), 0 deletions(-) > create mode 100644 drivers/video/da8xx-fb.c > create mode 100644 include/linux/da8xx-fb.h > > diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig > index 693fb4e..fc0c191 100644 > --- a/drivers/video/Kconfig > +++ b/drivers/video/Kconfig > @@ -1984,6 +1984,17 @@ config FB_DAVINCI > hardware found on the TI DaVinci EVM. If > unsure, say N. > > +config FB_DA8XX > + tristate "DA8xx/OMAP-L1xx Framebuffer support" > + depends on FB && ARCH_DAVINCI_DA830 > + select FB_CFB_FILLRECT > + select FB_CFB_COPYAREA > + select FB_CFB_IMAGEBLIT > + ---help--- > + This is the frame buffer device driver for the TI LCD controller > + found on DA8xx/OMAP-L1xx SoCs. > + If unsure, say N. > + > config FB_VIRTUAL > tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" > depends on FB > diff --git a/drivers/video/Makefile b/drivers/video/Makefile > index 902d199..e7a3e7d 100644 > --- a/drivers/video/Makefile > +++ b/drivers/video/Makefile > @@ -136,6 +136,7 @@ obj-$(CONFIG_FB_BF54X_LQ043) += bf54x-lq043fb.o > obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin-t350mcqb-fb.o > obj-$(CONFIG_FB_MX3) += mx3fb.o > obj-$(CONFIG_FB_DAVINCI) += davincifb.o > +obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o > > # the test framebuffer is last > obj-$(CONFIG_FB_VIRTUAL) += vfb.o > diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c > new file mode 100644 > index 0000000..5e3b861 > --- /dev/null > +++ b/drivers/video/da8xx-fb.c > @@ -0,0 +1,964 @@ > +/* > + * Copyright (C) 2008-2009 MontaVista Software Inc. > + * Copyright (C) 2008-2009 Texas Instruments Inc > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option)any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > + */ > +#include <linux/module.h> > +#include <linux/kernel.h> > +#include <linux/fb.h> > +#include <linux/dma-mapping.h> > +#include <linux/device.h> > +#include <linux/platform_device.h> > +#include <mach/cputype.h> > +#include <mach/io.h> > +#include <mach/hardware.h> > +#include <linux/uaccess.h> > +#include <linux/device.h> > +#include <linux/interrupt.h> > +#include <linux/clk.h> > +#include <linux/da8xx-fb.h> > + > +#define DRIVER_NAME "da8xx_lcdc" > + > +/* LCD Status Register */ > +#define LCD_END_OF_FRAME0 BIT(8) > +#define LCD_FIFO_UNDERFLOW BIT(5) > +#define LCD_SYNC_LOST BIT(2) > + > +/* LCD DMA Control Register */ > +#define LCD_DMA_BURST_SIZE(x) ((x) << 4) > +#define LCD_DMA_BURST_1 0x0 > +#define LCD_DMA_BURST_2 0x1 > +#define LCD_DMA_BURST_4 0x2 > +#define LCD_DMA_BURST_8 0x3 > +#define LCD_DMA_BURST_16 0x4 > +#define LCD_END_OF_FRAME_INT_ENA BIT(2) > +#define LCD_DUAL_FRAME_BUFFER_ENABLE BIT(0) > + > +/* LCD Control Register */ > +#define LCD_CLK_DIVISOR(x) ((x) << 8) > +#define LCD_RASTER_MODE 0x01 > + > +/* LCD Raster Control Register */ > +#define LCD_PALETTE_LOAD_MODE(x) ((x) << 20) > +#define PALETTE_AND_DATA 0x00 > +#define PALETTE_ONLY 0x01 > + > +#define LCD_MONO_8BIT_MODE BIT(9) > +#define LCD_RASTER_ORDER BIT(8) > +#define LCD_TFT_MODE BIT(7) > +#define LCD_UNDERFLOW_INT_ENA BIT(6) > +#define LCD_MONOCHROME_MODE BIT(1) > +#define LCD_RASTER_ENABLE BIT(0) > +#define LCD_TFT_ALT_ENABLE BIT(23) > +#define LCD_STN_565_ENABLE BIT(24) > + > +/* LCD Raster Timing 2 Register */ > +#define LCD_AC_BIAS_TRANSITIONS_PER_INT(x) ((x) << 16) > +#define LCD_AC_BIAS_FREQUENCY(x) ((x) << 8) > +#define LCD_SYNC_CTRL BIT(25) > +#define LCD_SYNC_EDGE BIT(24) > +#define LCD_INVERT_PIXEL_CLOCK BIT(22) > +#define LCD_INVERT_LINE_CLOCK BIT(21) > +#define LCD_INVERT_FRAME_CLOCK BIT(20) > + > +/* LCD Block */ > +#define LCD_CTRL_REG 0x4 > +#define LCD_STAT_REG 0x8 > +#define LCD_RASTER_CTRL_REG 0x28 > +#define LCD_RASTER_TIMING_0_REG 0x2C > +#define LCD_RASTER_TIMING_1_REG 0x30 > +#define LCD_RASTER_TIMING_2_REG 0x34 > +#define LCD_DMA_CTRL_REG 0x40 > +#define LCD_DMA_FRM_BUF_BASE_ADDR_0_REG 0x44 > +#define LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG 0x48 > + > +#define lcdc_read(addr) __raw_readl(da8xx_fb_reg_base + (addr)) > +#define lcdc_write(val, addr) __raw_writel(val, da8xx_fb_reg_base + (addr)) > + Inline functions are preferred over macros. > +#define WSI_TIMEOUT 50 > +#define PALETTE_SIZE 256 > +#define LEFT_MARGIN 64 > +#define RIGHT_MARGIN 64 > +#define UPPER_MARGIN 32 > +#define LOWER_MARGIN 32 > + > +static resource_size_t da8xx_fb_reg_base; > +static wait_queue_head_t da8xx_wq; These two variables should not exist. You should store them in your da8xx_fb_par structure and use them from there (the reg_base seems already there). > + > +struct da8xx_fb_par { > + resource_size_t p_regs_base; > + resource_size_t p_frame_buffer_mem_base; > + resource_size_t p_screen_base; > + resource_size_t p_palette_base; > + unsigned char *v_frame_buffer_mem_base; > + unsigned char *v_screen_base; > + unsigned char *v_palette_base; > + unsigned long screen_size; These address and length fields duplicate standard fields from the fb_info and fb_info->fix structures (except regs_base). Please use standard fields. > + unsigned int palette_size; > + unsigned int bpp; These fields are also duplicated by the fb_info->var->bits_per_pixel and the fb_info->cmap.len. > + struct clk *lcdc_clk; > + unsigned int irq; > + u16 pseudo_palette[16]; > +}; > + > +/* Variable Screen Information */ > +static struct fb_var_screeninfo da8xx_fb_var __devinitdata = { > + .xoffset = 0, > + .yoffset = 0, > + .transp = {0, 0, 0}, > + .nonstd = 0, > + .activate = 0, > + .height = -1, > + .width = -1, > + .pixclock = 46666, /* 46us - AUO display */ > + .accel_flags = 0, > + .left_margin = LEFT_MARGIN, > + .right_margin = RIGHT_MARGIN, > + .upper_margin = UPPER_MARGIN, > + .lower_margin = LOWER_MARGIN, > + .sync = 0, > + .vmode = FB_VMODE_NONINTERLACED > +}; > + > +static struct fb_fix_screeninfo da8xx_fb_fix __devinitdata = { > + .id = "DA8xx FB Drv", > + .type = FB_TYPE_PACKED_PIXELS, > + .type_aux = 0, > + .visual = FB_VISUAL_PSEUDOCOLOR, > + .xpanstep = 1, > + .ypanstep = 1, > + .ywrapstep = 1, > + .accel = FB_ACCEL_NONE > +}; > + > +struct da8xx_panel { > + const char name[25]; /* Full name <vendor>_<model> */ > + unsigned short width; > + unsigned short height; > + int hfp; /* Horizontal front porch */ > + int hbp; /* Horizontal back porch */ > + int hsw; /* Horizontal Sync Pulse Width */ > + int vfp; /* Vertical front porch */ > + int vbp; /* Vertical back porch */ > + int vsw; /* Vertical Sync Pulse Width */ > + int pxl_clk; /* Pixel clock */ > +}; > + > +static struct da8xx_panel known_lcd_panels[] = { > + /* Sharp LCD035Q3DG01 */ > + [0] = { > + .name = "Sharp_LCD035Q3DG01", > + .width = 320, > + .height = 240, > + .hfp = 8, > + .hbp = 6, > + .hsw = 0, > + .vfp = 2, > + .vbp = 2, > + .vsw = 0, > + .pxl_clk = 0x10, > + }, > + /* Sharp LK043T1DG01 */ > + [1] = { > + .name = "Sharp_LK043T1DG01", > + .width = 480, > + .height = 272, > + .hfp = 2, > + .hbp = 2, > + .hsw = 41, > + .vfp = 2, > + .vbp = 2, > + .vsw = 10, > + .pxl_clk = 0x12, > + }, > +}; > + > +static u32 databuf_sz; > +static u32 palette_sz; Again, these should be part of your da8xx_fb_par structure. > +static struct fb_ops da8xx_fb_ops; Just move definition of the da8xx_fb_ops before probe function and this forward declaration is not needed. You can give a pointer to the fb_info structure as the second parameter here. It will be available inside the irq handler as the argument. > + > +/* Disable the Raster Engine of the LCD Controller */ > +static int lcd_disable_raster(struct device *dev) > +{ You give the device structure's pointer as the argument to many functions. You should use fb_info pointer here and use &fb_info->device if needed. Eventually, you can pass only da8xx_fb_par pointer as it is enough to get all needed data to most functions (no dev_xxx() messages then). > + int ret = 0; > + u32 reg; > + > + reg = lcdc_read(LCD_RASTER_CTRL_REG); > + if (reg & LCD_RASTER_ENABLE) { > + lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); > + ret = wait_event_interruptible_timeout(da8xx_wq, > + !lcdc_read(LCD_STAT_REG) & > + LCD_END_OF_FRAME0, WSI_TIMEOUT); > + } > + > + if (ret < 0) > + return ret; > + if (ret == 0) > + return -ETIMEDOUT; > + > + return 0; > +} > + > +static void lcd_blit(int load_mode, u32 p_buf) > +{ > + u32 tmp = p_buf + databuf_sz - 4; > + u32 reg; > + > + /* Update the databuf in the hw. */ > + lcdc_write(p_buf, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); > + lcdc_write(tmp, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); > + > + /* Start the DMA. */ > + reg = lcdc_read(LCD_RASTER_CTRL_REG); > + reg &= ~(3 << 20); > + if (load_mode == LOAD_DATA) > + reg |= LCD_PALETTE_LOAD_MODE(PALETTE_AND_DATA); > + else if (load_mode == LOAD_PALETTE) > + reg |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY); > + > + lcdc_write(reg, LCD_RASTER_CTRL_REG); > +} > + > +/* Configure the Burst Size of DMA */ > +static int lcd_cfg_dma(struct device *dev, int burst_size) > +{ > + u32 reg; > + > + reg = lcdc_read(LCD_DMA_CTRL_REG) & 0x00000001; > + switch (burst_size) { > + case 1: > + reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_1); > + break; > + case 2: > + reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_2); > + break; > + case 4: > + reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_4); > + break; > + case 8: > + reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_8); > + break; > + case 16: > + reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_16); > + break; > + default: > + return -EINVAL; > + } > + lcdc_write(reg | LCD_END_OF_FRAME_INT_ENA, LCD_DMA_CTRL_REG); > + > + return 0; > +} > + > +static void lcd_cfg_ac_bias(struct device *dev, int period, > + int transitions_per_int) > +{ > + u32 reg; > + > + /* Set the AC Bias Period and Number of Transisitons per Interrupt */ > + reg = lcdc_read(LCD_RASTER_TIMING_2_REG) & 0xFFF00000; > + reg |= LCD_AC_BIAS_FREQUENCY(period) | > + LCD_AC_BIAS_TRANSITIONS_PER_INT(transitions_per_int); > + lcdc_write(reg, LCD_RASTER_TIMING_2_REG); > +} > + > +static void lcd_cfg_horizontal_sync(struct device *dev, int back_porch, > + int pulse_width, int front_porch) > +{ > + u32 reg; > + > + reg = lcdc_read(LCD_RASTER_TIMING_0_REG) & 0xf; > + reg |= ((back_porch & 0xff) << 24) > + | ((front_porch & 0xff) << 16) > + | ((pulse_width & 0x3f) << 10); > + lcdc_write(reg, LCD_RASTER_TIMING_0_REG); > +} > + > +static void lcd_cfg_vertical_sync(struct device *dev, int back_porch, > + int pulse_width, int front_porch) > +{ > + u32 reg; > + > + reg = lcdc_read(LCD_RASTER_TIMING_1_REG) & 0x3ff; > + reg |= ((back_porch & 0xff) << 24) > + | ((front_porch & 0xff) << 16) > + | ((pulse_width & 0x3f) << 10); > + lcdc_write(reg, LCD_RASTER_TIMING_1_REG); > +} > + > +static int lcd_cfg_display(struct device *dev, > + const struct lcd_ctrl_config *cfg) > +{ > + u32 reg; > + > + reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(LCD_TFT_MODE | > + LCD_MONO_8BIT_MODE | > + LCD_MONOCHROME_MODE); > + > + switch (cfg->p_disp_panel->panel_shade) { > + case MONOCHROME: > + reg |= LCD_MONOCHROME_MODE; > + if (cfg->mono_8bit_mode) > + reg |= LCD_MONO_8BIT_MODE; > + break; > + case COLOR_ACTIVE: > + reg |= LCD_TFT_MODE; > + if (cfg->tft_alt_mode) > + reg |= LCD_TFT_ALT_ENABLE; > + break; > + > + case COLOR_PASSIVE: > + if (cfg->stn_565_mode) > + reg |= LCD_STN_565_ENABLE; > + break; > + > + default: > + dev_err(dev, "Undefined LCD type\n"); > + return -EINVAL; > + } > + > + /* enable additional interrupts here */ > + reg |= LCD_UNDERFLOW_INT_ENA; > + > + lcdc_write(reg, LCD_RASTER_CTRL_REG); > + > + reg = lcdc_read(LCD_RASTER_TIMING_2_REG); > + > + if (cfg->sync_ctrl) > + reg |= LCD_SYNC_CTRL; > + else > + reg &= ~LCD_SYNC_CTRL; > + > + if (cfg->sync_edge) > + reg |= LCD_SYNC_EDGE; > + else > + reg &= ~LCD_SYNC_EDGE; > + > + if (cfg->invert_pxl_clock) > + reg |= LCD_INVERT_PIXEL_CLOCK; > + else > + reg &= ~LCD_INVERT_PIXEL_CLOCK; > + > + if (cfg->invert_line_clock) > + reg |= LCD_INVERT_LINE_CLOCK; > + else > + reg &= ~LCD_INVERT_LINE_CLOCK; > + > + if (cfg->invert_frm_clock) > + reg |= LCD_INVERT_FRAME_CLOCK; > + else > + reg &= ~LCD_INVERT_FRAME_CLOCK; > + > + lcdc_write(reg, LCD_RASTER_TIMING_2_REG); > + > + return 0; > +} > + > +static int lcd_cfg_frame_buffer(struct device *dev, u32 width, u32 height, > + u32 bpp, u32 raster_order) > +{ > + u32 bpl, reg; > + > + /* Disable Dual Frame Buffer. */ > + reg = lcdc_read(LCD_DMA_CTRL_REG); > + lcdc_write(reg & ~LCD_DUAL_FRAME_BUFFER_ENABLE, > + LCD_DMA_CTRL_REG); > + /* Set the Panel Width */ > + /* Pixels per line = (PPL + 1)*16 */ > + /*0x3F in bits 4..9 gives max horisontal resolution = 1024 pixels*/ > + width &= 0x3f0; > + reg = lcdc_read(LCD_RASTER_TIMING_0_REG); > + reg = (((width >> 4) - 1) << 4) | (reg & 0xfffffc00); You can easily break lines like this into two to reduce bracket's depth: reg &= 0xfffffc00; reg |= ((width >> 4) - 1) << 4; > + lcdc_write(reg, LCD_RASTER_TIMING_0_REG); > + > + /* Set the Panel Height */ > + reg = lcdc_read(LCD_RASTER_TIMING_1_REG); > + reg = ((height - 1) & 0x3ff) | (reg & 0xfffffc00); > + lcdc_write(reg, LCD_RASTER_TIMING_1_REG); > + > + /* Set the Raster Order of the Frame Buffer */ > + reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(1 << 8); > + if (raster_order) > + reg |= LCD_RASTER_ORDER; > + lcdc_write(reg, LCD_RASTER_CTRL_REG); > + > + switch (bpp) { > + case 1: > + case 2: > + case 4: > + case 16: > + palette_sz = 16 * 2; > + break; > + > + case 8: > + palette_sz = 256 * 2; The global palette_sz seems like a way to return this value to a calling function. Just pas the fb_info or da8xx_fb_par pointer here and set their values directly. > + break; > + > + default: > + dev_dbg(dev, "GLCD: Unsupported BPP!\n"); > + return -EINVAL; > + } > + > + bpl = width * bpp / 8; > + databuf_sz = height * bpl + palette_sz; > + > + return 0; > +} > + > +/* Palette Initialization */ > +static int init_palette(struct device *dev, struct fb_info *info) There is no need to pass the device pointer if you can do &info->device here. > +{ > + struct da8xx_fb_par *par = info->par; > + unsigned short *palette = (unsigned short *)par->p_palette_base; > + unsigned short i, size; > + > + /* Palette Size */ > + size = (par->palette_size / sizeof(*palette)); > + > + /* Clear the Palette */ > + memset(palette, 0, par->palette_size); > + > + /* Initialization of Palette for Default values */ > + for (i = 0; i < size; i++) > + *(unsigned short *)(palette + i) = i; > + > + /* Setup the BPP */ > + switch (par->bpp) { > + case 1: > + palette[0] |= BIT(11); > + break; > + case 2: > + palette[0] |= BIT(12); > + break; > + case 4: > + palette[0] |= (2 << 12); > + break; > + case 8: > + palette[0] |= (3 << 12); > + break; > + case 16: > + palette[0] |= (4 << 12); > + break; > + default: > + dev_dbg(dev, "GLCD: Unsupported Video BPP %d!\n", par->bpp); > + return -EINVAL; > + } > + > + for (i = 0; i < size; i++) > + par->pseudo_palette[i] = i; > + > + return 0; > +} > + > +static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, > + unsigned blue, unsigned transp, > + struct fb_info *info) > +{ > + struct da8xx_fb_par *par = info->par; > + unsigned short *palette = (unsigned short *)par->v_palette_base; > + u_short pal; > + > + if (regno > 255) > + return 1; > + > + if (info->fix.visual == FB_VISUAL_DIRECTCOLOR || > + info->fix.visual == FB_VISUAL_TRUECOLOR) > + return 1; > + Setting pallete won't work for truecolor mode (16-bit). Look at other framebuffers (e.g. tdfxfb) how to set palette for truecolor modes. > + if (par->bpp == 8) { > + red >>= 8; > + green >>= 8; > + blue >>= 8; > + } > + > + pal = (red & 0x0f00); > + pal |= (green & 0x00f0); > + pal |= (blue & 0x000f); > + > + palette[regno] = pal; > + > + return 0; > +} > + > +static int lcd_reset(struct device *dev) > +{ > + int ret = 0; > + > + /* Disable the Raster if previously Enabled */ > + if (lcdc_read(LCD_RASTER_CTRL_REG) & LCD_RASTER_ENABLE) > + ret = lcd_disable_raster(dev); > + > + /* 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 device *dev, const struct lcd_ctrl_config *cfg, > + struct da8xx_panel *info) > +{ > + u32 bpp, ret = 0; > + > + ret = lcd_reset(dev); > + if (ret != 0) > + return ret; > + > + /* Configure the LCD clock divisor. */ > + lcdc_write(LCD_CLK_DIVISOR(info->pxl_clk) | > + (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG); > + > + /* Configure the DMA burst size. */ > + ret = lcd_cfg_dma(dev, cfg->dma_burst_sz); > + if (ret < 0) > + return ret; > + > + /* Configure the AC bias properties. */ > + lcd_cfg_ac_bias(dev, cfg->ac_bias, cfg->ac_bias_intrpt); > + > + /* Configure the vertical and horizontal sync properties. */ > + lcd_cfg_vertical_sync(dev, info->vbp, info->vsw, info->vfp); > + lcd_cfg_horizontal_sync(dev, info->hbp, info->hsw, info->hfp); > + > + /* Configure for disply */ > + ret = lcd_cfg_display(dev, cfg); > + if (ret < 0) > + return ret; > + > + if (QVGA != cfg->p_disp_panel->panel_type) { > + dev_err(dev, "GLCD: Only QVGA panel is currently supported !"); > + return -EINVAL; > + } > + if (cfg->bpp <= cfg->p_disp_panel->max_bpp && > + cfg->bpp >= cfg->p_disp_panel->min_bpp) > + bpp = cfg->bpp; > + else > + bpp = cfg->p_disp_panel->max_bpp; > + if (bpp == 12) > + bpp = 16; > + ret = lcd_cfg_frame_buffer(dev, (unsigned int)info->width, > + (unsigned int)info->height, bpp, > + cfg->raster_order); > + if (ret < 0) > + return ret; > + > + /* Configure FDD */ > + lcdc_write((lcdc_read(LCD_RASTER_CTRL_REG) & 0xfff00fff) | > + (cfg->fdd << 12), LCD_RASTER_CTRL_REG); > + > + return 0; > +} > + > +static irqreturn_t lcdc_irq_handler(int irq, void *arg) > +{ > + u32 stat = lcdc_read(LCD_STAT_REG); > + u32 reg; > + > + if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { > + reg = lcdc_read(LCD_RASTER_CTRL_REG); > + lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); > + lcdc_write(stat, LCD_STAT_REG); > + lcdc_write(reg | LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); > + } else > + lcdc_write(stat, LCD_STAT_REG); > + > + wake_up_interruptible(&da8xx_wq); > + return IRQ_HANDLED; > +} > + > +static int fb_check_var(struct fb_var_screeninfo *var, > + struct fb_info *info) > +{ > + int err = 0; > + switch (var->bits_per_pixel) { > + case 1: > + case 8: > + var->red.offset = 0; > + var->red.length = 8; > + var->green.offset = 0; > + var->green.length = 8; > + var->blue.offset = 0; > + var->blue.length = 8; > + var->transp.offset = 0; > + var->transp.length = 0; > + break; > + case 4: > + var->red.offset = 0; > + var->red.length = 4; > + var->green.offset = 0; > + var->green.length = 4; > + var->blue.offset = 0; > + var->blue.length = 4; > + var->transp.offset = 0; > + var->transp.length = 0; > + break; > + case 16: /* RGB 565 */ > + var->red.offset = 0; > + var->red.length = 5; > + var->green.offset = 5; > + var->green.length = 6; > + var->blue.offset = 11; > + var->blue.length = 5; > + var->transp.offset = 0; > + var->transp.length = 0; > + break; > + default: > + err = -EINVAL; > + } > + > + var->red.msb_right = 0; > + var->green.msb_right = 0; > + var->blue.msb_right = 0; > + var->transp.msb_right = 0; > + return err; > +} > + > +static int fb_set_par(struct fb_info *info) > +{ > + struct fb_fix_screeninfo *fix = &info->fix; > + struct fb_var_screeninfo *var = &info->var; > + > + switch (var->bits_per_pixel) { > + case 1: > + fix->visual = FB_VISUAL_MONO01; > + break; > + > + case 2: > + case 4: > + case 8: > + fix->visual = FB_VISUAL_PSEUDOCOLOR; > + break; > + > + case 16: > + fix->visual = FB_VISUAL_TRUECOLOR; > + break; > + } > + > + fix->line_length = (var->xres_virtual * var->bits_per_pixel) / 8; > + return 0; > +} > + This function obviously does not change framebuffer mode as LCD controller's registers are not changed. This call can only mess up your display because fix->line_length is changed. If you do not intend to add mode changing to your driver remove completely the fb_check_var() and fb_set_par() functions. > +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(&dev->dev); > + lcdc_write(0, LCD_RASTER_CTRL_REG); > + > + /* disable DMA */ > + lcdc_write(0, LCD_DMA_CTRL_REG); > + > + unregister_framebuffer(info); > + fb_dealloc_cmap(&info->cmap); > + dma_free_coherent(NULL, databuf_sz + PAGE_SIZE, > + par->v_frame_buffer_mem_base, > + par->p_frame_buffer_mem_base); > + free_irq(par->irq, NULL); > + clk_disable(par->lcdc_clk); > + clk_put(par->lcdc_clk); > + framebuffer_release(info); > + > + } > + return ret; > +} > +static int __init fb_probe(struct platform_device *device) > +{ > + struct da8xx_lcdc_platform_data *fb_pdata = > + device->dev.platform_data; > + struct lcd_ctrl_config *lcd_cfg; > + struct da8xx_panel *lcdc_info; > + struct fb_info *da8xx_fb_info; > + struct resource *lcdc_regs; > + struct clk *fb_clk = NULL; > + struct da8xx_fb_par *par; > + resource_size_t len; > + int ret, i; > + > + if (fb_pdata == NULL) { > + dev_err(&device->dev, "Can not get platform data\n"); > + return -ENOENT; > + } > + > + lcdc_regs = platform_get_resource(device, IORESOURCE_MEM, 0); > + if (!lcdc_regs) { > + dev_err(&device->dev, > + "Can not get memory resource for LCD controller\n"); > + return -ENOENT; > + } > + > + len = lcdc_regs->end - lcdc_regs->start + 1; > + > + lcdc_regs = request_mem_region(lcdc_regs->start, len, lcdc_regs->name); > + if (!lcdc_regs) > + return -EBUSY; > + > + da8xx_fb_reg_base = (resource_size_t) ioremap(lcdc_regs->start, len); > + > + fb_clk = clk_get(&device->dev, NULL); > + if (IS_ERR(fb_clk)) { > + dev_err(&device->dev, "Can not get device clock\n"); > + return -ENODEV; > + } > + ret = clk_enable(fb_clk); > + if (ret) > + goto err_clk_put; > + > + for (i = 0, lcdc_info = known_lcd_panels; > + i < ARRAY_SIZE(known_lcd_panels); > + i++, lcdc_info++) { > + if (strcmp(fb_pdata->type, lcdc_info->name) == 0) > + break; > + } > + > + if (i == ARRAY_SIZE(known_lcd_panels)) { > + dev_err(&device->dev, "GLCD: No valid panel found\n"); > + return -ENODEV; > + } else > + dev_info(&device->dev, "GLCD: Found %s panel\n", > + fb_pdata->type); > + > + lcd_cfg = (struct lcd_ctrl_config *)fb_pdata->controller_data; > + > + if (lcd_init(&device->dev, lcd_cfg, lcdc_info) < 0) { > + dev_err(&device->dev, "lcd_init failed\n"); > + ret = -EFAULT; > + goto err_clk_disable; > + } > + da8xx_fb_info = framebuffer_alloc(sizeof(struct fb_info), > + &device->dev); The first argument to the framebuffer_alloc is amount of additional space allocated after the fb_info structure. You are supposed to put the size of the structure pointed by the fb->info_par parameter here. You have allocated space for two fb_info structure. Your code suggest you wanted space for one fb_info and one da8xx_fb_par structure. > + if (!da8xx_fb_info) { > + dev_dbg(&device->dev, "Memory allocation failed for fb_info\n"); > + ret = -ENOMEM; > + goto err_clk_disable; > + } > + > + par = da8xx_fb_info->par; This is already done inside the framebuffer_alloc(). > + /* allocate frame buffer */ > + par->v_frame_buffer_mem_base = dma_alloc_coherent(NULL, > + databuf_sz + PAGE_SIZE, > + &par->p_frame_buffer_mem_base, > + GFP_KERNEL | GFP_DMA); > + > + if (!par->v_frame_buffer_mem_base) { > + dev_err(&device->dev, > + "GLCD: kmalloc for frame buffer failed\n"); > + ret = -EINVAL; > + goto err_release_fb; > + } > + > + /* move palette base pointer by (PAGE_SIZE - palette_sz) bytes */ > + par->v_palette_base = par->v_frame_buffer_mem_base + > + (PAGE_SIZE - palette_sz); > + par->p_palette_base = par->p_frame_buffer_mem_base + > + (PAGE_SIZE - palette_sz); > + > + /* First palette_sz byte of the frame buffer is the palette */ > + par->palette_size = palette_sz; > + > + /* the rest of the frame buffer is pixel data */ > + par->v_screen_base = par->v_palette_base + palette_sz; > + par->p_screen_base = par->p_palette_base + palette_sz; > + par->screen_size = databuf_sz - palette_sz; > + > + par->lcdc_clk = fb_clk; > + > + da8xx_fb_fix.smem_start = (unsigned long)par->p_screen_base; > + da8xx_fb_fix.smem_len = par->screen_size; It shows that your da8xx_fb_par fields duplicates the standard ones. > + > + init_waitqueue_head(&da8xx_wq); > + > + par->irq = platform_get_irq(device, 0); > + if (par->irq < 0) { > + ret = -ENOENT; > + goto err_release_fb_mem; > + } > + > + ret = request_irq(par->irq, lcdc_irq_handler, 0, > + DRIVER_NAME, NULL); You can give a pointer to the fb_info structure as the last parameter here. It will be available inside the irq handler as the argument. > + if (ret) > + goto err_free_irq; > + > + /* Initialize par */ > + par->bpp = lcd_cfg->bpp; > + > + da8xx_fb_var.xres = lcdc_info->width; > + da8xx_fb_var.xres_virtual = lcdc_info->width; > + > + da8xx_fb_var.yres = lcdc_info->height; > + da8xx_fb_var.yres_virtual = lcdc_info->height; > + > + da8xx_fb_var.grayscale = > + lcd_cfg->p_disp_panel->panel_shade == MONOCHROME ? 1 : 0; > + da8xx_fb_var.bits_per_pixel = lcd_cfg->bpp; > + > + da8xx_fb_var.hsync_len = lcdc_info->hsw; > + da8xx_fb_var.vsync_len = lcdc_info->vsw; > + > + /* Initialize fbinfo */ > + da8xx_fb_info->flags = FBINFO_FLAG_DEFAULT; > + da8xx_fb_info->screen_base = par->v_screen_base; > + da8xx_fb_info->device = &device->dev; This line does the same as there is already done inside the framebuffer_alloc(). > + da8xx_fb_info->fix = da8xx_fb_fix; > + da8xx_fb_info->var = da8xx_fb_var; > + da8xx_fb_info->fbops = &da8xx_fb_ops; > + da8xx_fb_info->pseudo_palette = par->pseudo_palette; > + > + /* Initialize the Palette */ > + ret = init_palette(&device->dev, da8xx_fb_info); I suppose you want to initialize the fb_info->cmap here (the 8 bit palette) which is not allocated yet (next lines). > + if (ret < 0) > + goto err_free_irq; > + > + ret = fb_alloc_cmap(&da8xx_fb_info->cmap, PALETTE_SIZE, 0); > + if (ret) > + goto err_free_irq; > + > + /* Flush the buffer to the screen. */ > + lcd_blit(LOAD_DATA, (u32) par->p_palette_base); > + > + /* initialize var_screeninfo */ > + da8xx_fb_var.activate = FB_ACTIVATE_FORCE; > + fb_set_var(da8xx_fb_info, &da8xx_fb_var); > + > + dev_set_drvdata(&device->dev, da8xx_fb_info); > + /* Register the Frame Buffer */ > + if (register_framebuffer(da8xx_fb_info) < 0) { > + dev_err(&device->dev, > + "GLCD: Frame Buffer Registration Failed!\n"); > + ret = -EINVAL; > + goto err_dealloc_cmap; > + } > + > + /* enable raster engine */ > + lcdc_write(lcdc_read(LCD_RASTER_CTRL_REG) | > + LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); > + > + return 0; > + > +err_dealloc_cmap: > + fb_dealloc_cmap(&da8xx_fb_info->cmap); > + > +err_free_irq: > + free_irq(par->irq, NULL); > + > +err_release_fb_mem: > + dma_free_coherent(NULL, databuf_sz + PAGE_SIZE, > + par->v_frame_buffer_mem_base, > + par->p_frame_buffer_mem_base); > + > +err_release_fb: > + framebuffer_release(da8xx_fb_info); > + > +err_clk_disable: > + clk_disable(fb_clk); > + > +err_clk_put: > + clk_put(fb_clk); > + > + return ret; > +} > + > +static int fb_ioctl(struct fb_info *info, unsigned int cmd, > + unsigned long arg) > +{ > + struct lcd_sync_arg sync_arg; > + > + switch (cmd) { > + case FBIOGET_CONTRAST: > + case FBIOPUT_CONTRAST: > + case FBIGET_BRIGHTNESS: > + case FBIPUT_BRIGHTNESS: > + case FBIGET_COLOR: > + case FBIPUT_COLOR: > + return -EINVAL; > + case FBIPUT_HSYNC: > + if (copy_from_user(&sync_arg, (char *)arg, > + sizeof(struct lcd_sync_arg))) > + return -EINVAL; > + lcd_cfg_horizontal_sync(info->dev, sync_arg.back_porch, > + sync_arg.pulse_width, > + sync_arg.front_porch); > + break; > + case FBIPUT_VSYNC: > + if (copy_from_user(&sync_arg, (char *)arg, > + sizeof(struct lcd_sync_arg))) > + return -EINVAL; > + lcd_cfg_vertical_sync(info->dev, sync_arg.back_porch, > + sync_arg.pulse_width, > + sync_arg.front_porch); > + break; > + default: > + return -EINVAL; > + } > + return 0; > +} > + > +static struct fb_ops da8xx_fb_ops = { > + .owner = THIS_MODULE, > + .fb_check_var = fb_check_var, > + .fb_set_par = fb_set_par, > + .fb_setcolreg = fb_setcolreg, > + .fb_ioctl = fb_ioctl, > + .fb_fillrect = cfb_fillrect, > + .fb_copyarea = cfb_copyarea, > + .fb_imageblit = cfb_imageblit, > +}; > + > +#ifdef CONFIG_PM > +static int fb_suspend(struct platform_device *dev, pm_message_t state) > +{ > + return -EBUSY; > +} > +static int fb_resume(struct platform_device *dev) > +{ > + return -EBUSY; > +} > +#else > +#define fb_suspend NULL > +#define fb_resume NULL > +#endif > + > +static struct platform_driver da8xx_fb_driver = { > + .probe = fb_probe, > + .remove = fb_remove, > + .suspend = fb_suspend, > + .resume = fb_resume, > + .driver = { > + .name = DRIVER_NAME, > + .owner = THIS_MODULE, > + }, > +}; > + > +static int __init da8xx_fb_init(void) > +{ > + return platform_driver_register(&da8xx_fb_driver); > +} > + > +static void __exit da8xx_fb_cleanup(void) > +{ > + platform_driver_unregister(&da8xx_fb_driver); > +} > + > +module_init(da8xx_fb_init); > +module_exit(da8xx_fb_cleanup); > + > +MODULE_DESCRIPTION("Framebuffer driver for TI da8xx/omap-l1xx"); > +MODULE_AUTHOR("MontaVista Software"); > +MODULE_LICENSE("GPL"); > diff --git a/include/linux/da8xx-fb.h b/include/linux/da8xx-fb.h It is probably better to put this header into the include/video or platform specific include directory. The include/linux is for global stuff. > new file mode 100644 > index 0000000..5f77675 > --- /dev/null > +++ b/include/linux/da8xx-fb.h > @@ -0,0 +1,106 @@ > +/* > + * Header file for TI DA8XX LCD controller platform data. > + * > + * Copyright (C) 2008-2009 MontaVista Software Inc. > + * Copyright (C) 2008-2009 Texas Instruments Inc > + * > + * This file is licensed under the terms of the GNU General Public License > + * version 2. This program is licensed "as is" without any warranty of any > + * kind, whether express or implied. > + */ > + > +#ifndef DA8XX_FB_H > +#define DA8XX_FB_H > + > +enum panel_type { > + QVGA = 0 > +}; > + > +enum panel_shade { > + MONOCHROME = 0, > + COLOR_ACTIVE, > + COLOR_PASSIVE, > +}; > + > +enum raster_load_mode { > + LOAD_DATA = 1, > + LOAD_PALETTE, > +}; > + > +struct display_panel { > + enum panel_type panel_type; /* QVGA */ > + int max_bpp; > + int min_bpp; > + enum panel_shade panel_shade; > +}; > + > +struct da8xx_lcdc_platform_data { > + const char manu_name[10]; > + void *controller_data; > + const char type[25]; > +}; > + > +struct lcd_ctrl_config { > + const struct display_panel *p_disp_panel; > + > + /* AC Bias Pin Frequency */ > + int ac_bias; > + > + /* AC Bias Pin Transitions per Interrupt */ > + int ac_bias_intrpt; > + > + /* DMA burst size */ > + int dma_burst_sz; > + > + /* Bits per pixel */ > + int bpp; > + > + /* FIFO DMA Request Delay */ > + int fdd; > + > + /* TFT Alternative Signal Mapping (Only for active) */ > + unsigned char tft_alt_mode; > + > + /* 12 Bit Per Pixel (5-6-5) Mode (Only for passive) */ > + unsigned char stn_565_mode; > + > + /* Mono 8-bit Mode: 1=D0-D7 or 0=D0-D3 */ > + unsigned char mono_8bit_mode; > + > + /* Invert pixel clock */ > + unsigned char invert_pxl_clock; > + > + /* Invert line clock */ > + unsigned char invert_line_clock; > + > + /* Invert frame clock */ > + unsigned char invert_frm_clock; > + > + /* Horizontal and Vertical Sync Edge: 0=rising 1=falling */ > + unsigned char sync_edge; > + > + /* Horizontal and Vertical Sync: Control: 0=ignore */ > + unsigned char sync_ctrl; > + > + /* Raster Data Order Select: 1=Most-to-least 0=Least-to-most */ > + unsigned char raster_order; > +}; > + > +struct lcd_sync_arg { > + int back_porch; > + int front_porch; > + int pulse_width; > +}; > + > +/* ioctls */ > +#define FBIOGET_CONTRAST _IOR('F', 1, int) > +#define FBIOPUT_CONTRAST _IOW('F', 2, int) > +#define FBIGET_BRIGHTNESS _IOR('F', 3, int) > +#define FBIPUT_BRIGHTNESS _IOW('F', 3, int) > +#define FBIGET_COLOR _IOR('F', 5, int) > +#define FBIPUT_COLOR _IOW('F', 6, int) > +#define FBIPUT_HSYNC _IOW('F', 9, int) > +#define FBIPUT_VSYNC _IOW('F', 10, int) > + > +#endif /* ifndef DA8XX_FB_H */ > + > -- > 1.5.6 > I am looking forward to updated version of this patch. Kind regards, Krzysztof Helt ---------------------------------------------------------------------- Nowa akcja Pepsi - nagrody za kody spod nakretek. Zarejestruj sie! http://link.interia.pl/f21cc |
From: Mikulas Patocka <mpatocka@re...> - 2009-06-17 21:05:36
|
On Wed, 17 Jun 2009, Ville Syrjälä wrote: > On Wed, Jun 17, 2009 at 06:02:30AM -0400, Mikulas Patocka wrote: > > On my card, the accelerator corrupts display if its line length is not > > multiple of 64 bytes. > > > > Misaligned lines in the drawn recrangle are shifted left, as if the accelerator > > thought that every line begins on 64-byte boundary. For example, in 800x600x8 > > (scanlines are aligned on 32 bytes) every odd scanline is drawn shifted by > > 32 bytes to the left. > > > > The card is ATI Technologies Inc 3D Rage Pro 215GP (rev 5c) onboard on > > Sparc64 Ultra 5. > > I think normally the offset should be just aligned to 8 bytes and pitch > to 8 bytes and 8 pixels. > > I was under the impression that 64 byte aligned offset and pitch are only > required if block writes are used. But perhaps it is always required > with SGRAM/WRAM, or perhaps you have auto block writes enabled. Can you > check the memory type and the the value of the HW_DEBUG register? Memory is SGRAM M32L1632512A-8Q. See this: http://www.digchip.com/datasheets/parts/datasheet/581/M32L1632512A.php The status line is: atyfb: 3D RAGE PRO (Mach64 GP, PQFP, PCI) [0x4750 rev 0x7c] atyfb: 4M SGRAM (1:1), 14.31818 MHz XTAL, 230 MHz PLL, 100 Mhz MCLK, 100 MHz XCLK The debug register is zero (printed with printk("ATI INIT ENGINE, DEBUG %08X", aty_ld_le32(HW_DEBUG, par)); at the end of aty_init_engine). > > This patch disables accelerator if scanline is not multiple of 64 bytes. > > A better option would be to round the pitch up in check_var(). Also it > would be more proper to use fix.line_length as the pitch value instead > of var.xres_virtual. That way check_var() could leave var.xres_virtual > alone and just round fix.line_length to whatever is required. > > Actually now that I think about it I would prefer to round to 64 bytes > always when SGRAM/WRAM is found. The reason is that the mach64 DirectFB > driver always enables auto block writes on SGRAM boards and if atyfb > uses less alignment things will not work correctly. Perhaps atyfb should > enable auto block writes too. So patch it to align line length (I don't know fb well to pick the right place) and send me the patch and I'll test it. BTW. why doesn't it use accelerator for screen scrolling? It seems to redraw all non-empty characters, which is fast if most of the screen is empty but gets slower if the screen is full of text. Mikulas > -- > Ville Syrjälä > syrjala@... > http://www.sci.fi/~syrjala/ > |
From: Krzysztof Helt <krzysztof.h1@po...> - 2009-06-17 18:20:11
|
From: Krzysztof Helt <krzysztof.h1@...> Add a mutex to avoid a circular locking problem between the mm layer semaphore and fbdev ioctl mutex through the fb_mmap() call. Also, add mutex to all places where smem_start and smem_len fields change so the mutex inside the fb_mmap() is actually used. Changing of these fields before calling the framebuffer_register() are not mutexed. Signed-off-by: Krzysztof Helt <krzysztof.h1@...> --- Consider this is 2.6.31 material. It removes one lockdep (fb_mmap() and register_framebuffer()) but there is still another one (fb_release() and register_framebuffer()). It also cleans up handling of the smem_start and smem_len fields used by mutexed section of the fb_mmap(). diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c index 018850c..497ff8a 100644 --- a/drivers/video/atafb.c +++ b/drivers/video/atafb.c @@ -2414,7 +2414,10 @@ static int atafb_get_fix(struct fb_fix_screeninfo *fix, struct fb_info *info) if (err) return err; memset(fix, 0, sizeof(struct fb_fix_screeninfo)); - return fbhw->encode_fix(fix, &par); + mutex_lock(&info->mm_lock); + err = fbhw->encode_fix(fix, &par); + mutex_unlock(&info->mm_lock); + return err; } static int atafb_get_var(struct fb_var_screeninfo *var, struct fb_info *info) @@ -2743,7 +2746,9 @@ static int atafb_set_par(struct fb_info *info) /* Decode wanted screen parameters */ fbhw->decode_var(&info->var, par); + mutex_lock(&info->mm_lock); fbhw->encode_fix(&info->fix, par); + mutex_unlock(&info->mm_lock); /* Set new videomode */ ata_set_par(par); diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 2fb63f6..a443c5a 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -270,7 +270,9 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo) smem_len = (var->xres_virtual * var->yres_virtual * ((var->bits_per_pixel + 7) / 8)); + mutex_lock(&info->mm_lock); info->fix.smem_len = max(smem_len, sinfo->smem_len); + mutex_unlock(&info->mm_lock); info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len, (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL); diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index d412a1d..5141ba2 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1310,8 +1310,6 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd, static int fb_mmap(struct file *file, struct vm_area_struct * vma) -__acquires(&info->lock) -__releases(&info->lock) { int fbidx = iminor(file->f_path.dentry->d_inode); struct fb_info *info = registered_fb[fbidx]; @@ -1325,16 +1323,14 @@ __releases(&info->lock) off = vma->vm_pgoff << PAGE_SHIFT; if (!fb) return -ENODEV; + mutex_lock(&info->mm_lock); if (fb->fb_mmap) { int res; - mutex_lock(&info->lock); res = fb->fb_mmap(info, vma); - mutex_unlock(&info->lock); + mutex_unlock(&info->mm_lock); return res; } - mutex_lock(&info->lock); - /* frame buffer memory */ start = info->fix.smem_start; len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len); @@ -1342,13 +1338,13 @@ __releases(&info->lock) /* memory mapped io */ off -= len; if (info->var.accel_flags) { - mutex_unlock(&info->lock); + mutex_unlock(&info->mm_lock); return -EINVAL; } start = info->fix.mmio_start; len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len); } - mutex_unlock(&info->lock); + mutex_unlock(&info->mm_lock); start &= PAGE_MASK; if ((vma->vm_end - vma->vm_start + off) > len) return -EINVAL; @@ -1491,6 +1487,7 @@ register_framebuffer(struct fb_info *fb_info) break; fb_info->node = i; mutex_init(&fb_info->lock); + mutex_init(&fb_info->mm_lock); fb_info->dev = device_create(fb_class, fb_info->device, MKDEV(FB_MAJOR, i), NULL, "fb%d", i); diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index f153c58..0bf2190 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c @@ -750,24 +750,26 @@ static void update_lcdc(struct fb_info *info) static int map_video_memory(struct fb_info *info) { phys_addr_t phys; + u32 smem_len = info->fix.line_length * info->var.yres_virtual; pr_debug("info->var.xres_virtual = %d\n", info->var.xres_virtual); pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual); pr_debug("info->fix.line_length = %d\n", info->fix.line_length); + pr_debug("MAP_VIDEO_MEMORY: smem_len = %u\n", smem_len); - info->fix.smem_len = info->fix.line_length * info->var.yres_virtual; - pr_debug("MAP_VIDEO_MEMORY: smem_len = %d\n", info->fix.smem_len); - info->screen_base = fsl_diu_alloc(info->fix.smem_len, &phys); + info->screen_base = fsl_diu_alloc(smem_len, &phys); if (info->screen_base == NULL) { printk(KERN_ERR "Unable to allocate fb memory\n"); return -ENOMEM; } + mutex_lock(&info->mm_lock); info->fix.smem_start = (unsigned long) phys; + info->fix.smem_len = smem_len; + mutex_unlock(&info->mm_lock); info->screen_size = info->fix.smem_len; pr_debug("Allocated fb @ paddr=0x%08lx, size=%d.\n", - info->fix.smem_start, - info->fix.smem_len); + info->fix.smem_start, info->fix.smem_len); pr_debug("screen base %p\n", info->screen_base); return 0; @@ -776,9 +778,11 @@ static int map_video_memory(struct fb_info *info) static void unmap_video_memory(struct fb_info *info) { fsl_diu_free(info->screen_base, info->fix.smem_len); + mutex_lock(&info->mm_lock); info->screen_base = NULL; info->fix.smem_start = 0; info->fix.smem_len = 0; + mutex_unlock(&info->mm_lock); } /* diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index 2e94019..7196067 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c @@ -1090,8 +1090,10 @@ static int encode_fix(struct fb_fix_screeninfo *fix, struct fb_info *info) memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, "I810"); + mutex_lock(&info->mm_lock); fix->smem_start = par->fb.physical; fix->smem_len = par->fb.size; + mutex_unlock(&info->mm_lock); fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; fix->xpanstep = 8; diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index 8e7a275..59c3a2e 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -724,8 +724,10 @@ static void matroxfb_update_fix(WPMINFO2) struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix; DBG(__func__) + mutex_lock(&ACCESS_FBINFO(fbcon).mm_lock); fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes); fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes); + mutex_unlock(&ACCESS_FBINFO(fbcon).mm_lock); } static int matroxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) @@ -2081,6 +2083,7 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm spin_lock_init(&ACCESS_FBINFO(lock.accel)); init_rwsem(&ACCESS_FBINFO(crtc2.lock)); init_rwsem(&ACCESS_FBINFO(altout.lock)); + mutex_init(&ACCESS_FBINFO(fbcon).mm_lock); ACCESS_FBINFO(irq_flags) = 0; init_waitqueue_head(&ACCESS_FBINFO(crtc1.vsync.wait)); init_waitqueue_head(&ACCESS_FBINFO(crtc2.vsync.wait)); diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c index 7ac4c5f..909e10a 100644 --- a/drivers/video/matrox/matroxfb_crtc2.c +++ b/drivers/video/matrox/matroxfb_crtc2.c @@ -289,13 +289,16 @@ static int matroxfb_dh_release(struct fb_info* info, int user) { #undef m2info } -static void matroxfb_dh_init_fix(struct matroxfb_dh_fb_info *m2info) { +static void matroxfb_dh_init_fix(struct matroxfb_dh_fb_info *m2info) +{ struct fb_fix_screeninfo *fix = &m2info->fbcon.fix; strcpy(fix->id, "MATROX DH"); + mutex_lock(&m2info->fbcon.mm_lock); fix->smem_start = m2info->video.base; fix->smem_len = m2info->video.len_usable; + mutex_unlock(&m2info->fbcon.mm_lock); fix->ypanstep = 1; fix->ywrapstep = 0; fix->xpanstep = 8; /* TBD */ diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c index b7af525..567fb94 100644 --- a/drivers/video/mx3fb.c +++ b/drivers/video/mx3fb.c @@ -669,7 +669,7 @@ static uint32_t bpp_to_pixfmt(int bpp) } static int mx3fb_blank(int blank, struct fb_info *fbi); -static int mx3fb_map_video_memory(struct fb_info *fbi); +static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len); static int mx3fb_unmap_video_memory(struct fb_info *fbi); /** @@ -742,8 +742,7 @@ static int mx3fb_set_par(struct fb_info *fbi) if (fbi->fix.smem_start) mx3fb_unmap_video_memory(fbi); - fbi->fix.smem_len = mem_len; - if (mx3fb_map_video_memory(fbi) < 0) { + if (mx3fb_map_video_memory(fbi, mem_len) < 0) { mutex_unlock(&mx3_fbi->mutex); return -ENOMEM; } @@ -1198,6 +1197,7 @@ static int mx3fb_resume(struct platform_device *pdev) /** * mx3fb_map_video_memory() - allocates the DRAM memory for the frame buffer. * @fbi: framebuffer information pointer + * @mem_len: length of mapped memory * @return: Error code indicating success or failure * * This buffer is remapped into a non-cached, non-buffered, memory region to @@ -1205,23 +1205,26 @@ static int mx3fb_resume(struct platform_device *pdev) * area is remapped, all virtual memory access to the video memory should occur * at the new region. */ -static int mx3fb_map_video_memory(struct fb_info *fbi) +static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len) { int retval = 0; dma_addr_t addr; fbi->screen_base = dma_alloc_writecombine(fbi->device, - fbi->fix.smem_len, + mem_len, &addr, GFP_DMA); if (!fbi->screen_base) { dev_err(fbi->device, "Cannot allocate %u bytes framebuffer memory\n", - fbi->fix.smem_len); + mem_len); retval = -EBUSY; goto err0; } + mutex_lock(&fbi->mm_lock); fbi->fix.smem_start = addr; + fbi->fix.smem_len = mem_len; + mutex_unlock(&fbi->mm_lock); dev_dbg(fbi->device, "allocated fb @ p=0x%08x, v=0x%p, size=%d.\n", (uint32_t) fbi->fix.smem_start, fbi->screen_base, fbi->fix.smem_len); @@ -1251,8 +1254,10 @@ static int mx3fb_unmap_video_memory(struct fb_info *fbi) fbi->screen_base, fbi->fix.smem_start); fbi->screen_base = 0; + mutex_lock(&fbi->mm_lock); fbi->fix.smem_start = 0; fbi->fix.smem_len = 0; + mutex_unlock(&fbi->mm_lock); return 0; } diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c index 060d72f..4ea99bf 100644 --- a/drivers/video/omap/omapfb_main.c +++ b/drivers/video/omap/omapfb_main.c @@ -393,8 +393,10 @@ static void set_fb_fix(struct fb_info *fbi) rg = &plane->fbdev->mem_desc.region[plane->idx]; fbi->screen_base = rg->vaddr; + mutex_lock(&fbi->mm_lock); fix->smem_start = rg->paddr; fix->smem_len = rg->size; + mutex_unlock(&fbi->mm_lock); fix->type = FB_TYPE_PACKED_PIXELS; bpp = var->bits_per_pixel; @@ -886,8 +888,10 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) * plane memory is dealloce'd, the other * screen parameters in var / fix are invalid. */ + mutex_lock(&fbi->mm_lock); fbi->fix.smem_start = 0; fbi->fix.smem_len = 0; + mutex_unlock(&fbi->mm_lock); } } } diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c index 03b3670..bacfabd 100644 --- a/drivers/video/platinumfb.c +++ b/drivers/video/platinumfb.c @@ -141,7 +141,9 @@ static int platinumfb_set_par (struct fb_info *info) offset = 0x10; info->screen_base = pinfo->frame_buffer + init->fb_offset + offset; + mutex_lock(&info->mm_lock); info->fix.smem_start = (pinfo->frame_buffer_phys) + init->fb_offset + offset; + mutex_unlock(&info->mm_lock); info->fix.visual = (pinfo->cmode == CMODE_8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; info->fix.line_length = vmode_attrs[pinfo->vmode-1].hres * (1<<pinfo->cmode) diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 0889d50..6506117 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -815,8 +815,10 @@ static int overlayfb_map_video_memory(struct pxafb_layer *ofb) ofb->video_mem_phys = virt_to_phys(ofb->video_mem); ofb->video_mem_size = size; + mutex_lock(&ofb->fb.mm_lock); ofb->fb.fix.smem_start = ofb->video_mem_phys; ofb->fb.fix.smem_len = ofb->fb.fix.line_length * var->yres_virtual; + mutex_unlock(&ofb->fb.mm_lock); ofb->fb.screen_base = ofb->video_mem; return 0; } diff --git a/drivers/video/sh7760fb.c b/drivers/video/sh7760fb.c index 653bdfe..9f6d6e6 100644 --- a/drivers/video/sh7760fb.c +++ b/drivers/video/sh7760fb.c @@ -120,18 +120,6 @@ static int sh7760_setcolreg (u_int regno, return 0; } -static void encode_fix(struct fb_fix_screeninfo *fix, struct fb_info *info, - unsigned long stride) -{ - memset(fix, 0, sizeof(struct fb_fix_screeninfo)); - strcpy(fix->id, "sh7760-lcdc"); - - fix->smem_start = (unsigned long)info->screen_base; - fix->smem_len = info->screen_size; - - fix->line_length = stride; -} - static int sh7760fb_get_color_info(struct device *dev, u16 lddfr, int *bpp, int *gray) { @@ -334,7 +322,8 @@ static int sh7760fb_set_par(struct fb_info *info) iowrite32(ldsarl, par->base + LDSARL); /* mem for lower half of DSTN */ - encode_fix(&info->fix, info, stride); + info->fix.line_length = stride; + sh7760fb_check_var(&info->var, info); sh7760fb_blank(FB_BLANK_UNBLANK, info); /* panel on! */ @@ -435,6 +424,8 @@ static int sh7760fb_alloc_mem(struct fb_info *info) info->screen_base = fbmem; info->screen_size = vram; + info->fix.smem_start = (unsigned long)info->screen_base; + info->fix.smem_len = info->screen_size; return 0; } @@ -520,6 +511,8 @@ static int __devinit sh7760fb_probe(struct platform_device *pdev) info->var.transp.length = 0; info->var.transp.msb_right = 0; + strcpy(info->fix.id, "sh7760-lcdc"); + /* set the DON2 bit now, before cmap allocation, as it will randomize * palette memory. */ diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index 7e17ee9..b30176a 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c @@ -1847,8 +1847,10 @@ sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) strcpy(fix->id, ivideo->myid); + mutex_lock(&info->mm_lock); fix->smem_start = ivideo->video_base + ivideo->video_offset; fix->smem_len = ivideo->sisfb_mem; + mutex_unlock(&info->mm_lock); fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index eb5d73a..98f24f0 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c @@ -145,7 +145,7 @@ static inline void sm501fb_sync_regs(struct sm501fb_info *info) #define SM501_MEMF_ACCEL (8) static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem, - unsigned int why, size_t size) + unsigned int why, size_t size, u32 smem_len) { struct sm501fb_par *par; struct fb_info *fbi; @@ -172,7 +172,7 @@ static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem, if (ptr > 0) ptr &= ~(PAGE_SIZE - 1); - if (fbi && ptr < fbi->fix.smem_len) + if (fbi && ptr < smem_len) return -ENOMEM; break; @@ -197,7 +197,7 @@ static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem, case SM501_MEMF_ACCEL: fbi = inf->fb[HEAD_CRT]; - ptr = fbi ? fbi->fix.smem_len : 0; + ptr = fbi ? smem_len : 0; fbi = inf->fb[HEAD_PANEL]; if (fbi) { @@ -413,6 +413,7 @@ static int sm501fb_set_par_common(struct fb_info *info, unsigned int mem_type; unsigned int clock_type; unsigned int head_addr; + unsigned int smem_len; dev_dbg(fbi->dev, "%s: %dx%d, bpp = %d, virtual %dx%d\n", __func__, var->xres, var->yres, var->bits_per_pixel, @@ -453,18 +454,20 @@ static int sm501fb_set_par_common(struct fb_info *info, /* allocate fb memory within 501 */ info->fix.line_length = (var->xres_virtual * var->bits_per_pixel)/8; - info->fix.smem_len = info->fix.line_length * var->yres_virtual; + smem_len = info->fix.line_length * var->yres_virtual; dev_dbg(fbi->dev, "%s: line length = %u\n", __func__, info->fix.line_length); - if (sm501_alloc_mem(fbi, &par->screen, mem_type, - info->fix.smem_len)) { + if (sm501_alloc_mem(fbi, &par->screen, mem_type, smem_len, smem_len)) { dev_err(fbi->dev, "no memory available\n"); return -ENOMEM; } + mutex_lock(&info->mm_lock); info->fix.smem_start = fbi->fbmem_res->start + par->screen.sm_addr; + info->fix.smem_len = smem_len; + mutex_unlock(&info->mm_lock); info->screen_base = fbi->fbmem + par->screen.sm_addr; info->screen_size = info->fix.smem_len; @@ -637,7 +640,8 @@ static int sm501fb_set_par_crt(struct fb_info *info) if ((control & SM501_DC_CRT_CONTROL_SEL) == 0) { /* the head is displaying panel data... */ - sm501_alloc_mem(fbi, &par->screen, SM501_MEMF_CRT, 0); + sm501_alloc_mem(fbi, &par->screen, SM501_MEMF_CRT, 0, + info->fix.smem_len); goto out_update; } @@ -1289,7 +1293,8 @@ static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base) par->cursor_regs = info->regs + reg_base; - ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024); + ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024, + fbi->fix.smem_len); if (ret < 0) return ret; diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c index d0674f1..8a141c2 100644 --- a/drivers/video/w100fb.c +++ b/drivers/video/w100fb.c @@ -523,6 +523,7 @@ static int w100fb_set_par(struct fb_info *info) info->fix.ywrapstep = 0; info->fix.line_length = par->xres * BITS_PER_PIXEL / 8; + mutex_lock(&info->mm_lock); if ((par->xres*par->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1)) { par->extmem_active = 1; info->fix.smem_len = par->mach->mem->size+1; @@ -530,6 +531,7 @@ static int w100fb_set_par(struct fb_info *info) par->extmem_active = 0; info->fix.smem_len = MEM_INT_SIZE+1; } + mutex_unlock(&info->mm_lock); w100fb_activate_var(par); } diff --git a/include/linux/fb.h b/include/linux/fb.h index 330c4b1..89a4d91 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -814,6 +814,7 @@ struct fb_info { int node; int flags; struct mutex lock; /* Lock for open/release/ioctl funcs */ + struct mutex mm_lock; /* Lock for fb_mmap and smem_* fields */ struct fb_var_screeninfo var; /* Current var */ struct fb_fix_screeninfo fix; /* Current fix */ struct fb_monspecs monspecs; /* Current Monitor specs */ ---------------------------------------------------------------------- Interia.pl w Twojej kieszeni! Kliknij >>>http://link.interia.pl/f21b8 |
From: Ville Syrjälä <syrjala@sc...> - 2009-06-17 17:24:28
|
On Wed, Jun 17, 2009 at 06:00:53AM -0400, Mikulas Patocka wrote: > Use the same color-calculating algorithm as in atyfb_imageblit in this driver > or in generic cfb_fillrect. > > This patch fixes bad colors when using an accelerator in 15-bit and 16-bit > modes. > > Signed-off-by: Mikulas Patocka <mpatocka@... Acked-by: Ville Syrjala <syrjala@...> -- Ville Syrjälä syrjala@... http://www.sci.fi/~syrjala/ |
From: Ville Syrjälä <syrjala@sc...> - 2009-06-17 17:22:05
|
On Wed, Jun 17, 2009 at 06:02:30AM -0400, Mikulas Patocka wrote: > On my card, the accelerator corrupts display if its line length is not > multiple of 64 bytes. > > Misaligned lines in the drawn recrangle are shifted left, as if the accelerator > thought that every line begins on 64-byte boundary. For example, in 800x600x8 > (scanlines are aligned on 32 bytes) every odd scanline is drawn shifted by > 32 bytes to the left. > > The card is ATI Technologies Inc 3D Rage Pro 215GP (rev 5c) onboard on > Sparc64 Ultra 5. I think normally the offset should be just aligned to 8 bytes and pitch to 8 bytes and 8 pixels. I was under the impression that 64 byte aligned offset and pitch are only required if block writes are used. But perhaps it is always required with SGRAM/WRAM, or perhaps you have auto block writes enabled. Can you check the memory type and the the value of the HW_DEBUG register? > This patch disables accelerator if scanline is not multiple of 64 bytes. A better option would be to round the pitch up in check_var(). Also it would be more proper to use fix.line_length as the pitch value instead of var.xres_virtual. That way check_var() could leave var.xres_virtual alone and just round fix.line_length to whatever is required. Actually now that I think about it I would prefer to round to 64 bytes always when SGRAM/WRAM is found. The reason is that the mach64 DirectFB driver always enables auto block writes on SGRAM boards and if atyfb uses less alignment things will not work correctly. Perhaps atyfb should enable auto block writes too. -- Ville Syrjälä syrjala@... http://www.sci.fi/~syrjala/ |
From: Rajashekhara, Sudhakar <sudhakar.raj@ti...> - 2009-06-17 14:43:16
|
Reseding the same patch with additional Signed-off information. Adds LCD controller (LCDC) driver for TI's DA8xx/OMAP-L1xx architecture. LCDC specifications can be found at http://www.ti.com/litv/pdf/sprufm0a. LCDC on DA8xx consists of two independent controllers, the Raster Controller and the LCD Interface Display Driver (LIDD) controller. LIDD further supports character and graphic displays. This patch adds support for the graphic display (Sharp LQ035Q3DG01) found on the DA830 based EVM. The EVM details can be found at: http://support.spectrumdigital.com/boards/dskda830/revc/. Signed-off-by: Sudhakar Rajashekhara <sudhakar.raj@...> Signed-off-by: Pavel Kiryukhin <pkiryukhin@...> Signed-off-by: Steve Chen <schen@...> --- drivers/video/Kconfig | 11 + drivers/video/Makefile | 1 + drivers/video/da8xx-fb.c | 964 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/da8xx-fb.h | 106 +++++ 4 files changed, 1082 insertions(+), 0 deletions(-) create mode 100644 drivers/video/da8xx-fb.c create mode 100644 include/linux/da8xx-fb.h diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 693fb4e..fc0c191 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1984,6 +1984,17 @@ config FB_DAVINCI hardware found on the TI DaVinci EVM. If unsure, say N. +config FB_DA8XX + tristate "DA8xx/OMAP-L1xx Framebuffer support" + depends on FB && ARCH_DAVINCI_DA830 + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + This is the frame buffer device driver for the TI LCD controller + found on DA8xx/OMAP-L1xx SoCs. + If unsure, say N. + config FB_VIRTUAL tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" depends on FB diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 902d199..e7a3e7d 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -136,6 +136,7 @@ obj-$(CONFIG_FB_BF54X_LQ043) += bf54x-lq043fb.o obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin-t350mcqb-fb.o obj-$(CONFIG_FB_MX3) += mx3fb.o obj-$(CONFIG_FB_DAVINCI) += davincifb.o +obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o # the test framebuffer is last obj-$(CONFIG_FB_VIRTUAL) += vfb.o diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c new file mode 100644 index 0000000..5e3b861 --- /dev/null +++ b/drivers/video/da8xx-fb.c @@ -0,0 +1,964 @@ +/* + * Copyright (C) 2008-2009 MontaVista Software Inc. + * Copyright (C) 2008-2009 Texas Instruments Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option)any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/fb.h> +#include <linux/dma-mapping.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <mach/cputype.h> +#include <mach/io.h> +#include <mach/hardware.h> +#include <linux/uaccess.h> +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/clk.h> +#include <linux/da8xx-fb.h> + +#define DRIVER_NAME "da8xx_lcdc" + +/* LCD Status Register */ +#define LCD_END_OF_FRAME0 BIT(8) +#define LCD_FIFO_UNDERFLOW BIT(5) +#define LCD_SYNC_LOST BIT(2) + +/* LCD DMA Control Register */ +#define LCD_DMA_BURST_SIZE(x) ((x) << 4) +#define LCD_DMA_BURST_1 0x0 +#define LCD_DMA_BURST_2 0x1 +#define LCD_DMA_BURST_4 0x2 +#define LCD_DMA_BURST_8 0x3 +#define LCD_DMA_BURST_16 0x4 +#define LCD_END_OF_FRAME_INT_ENA BIT(2) +#define LCD_DUAL_FRAME_BUFFER_ENABLE BIT(0) + +/* LCD Control Register */ +#define LCD_CLK_DIVISOR(x) ((x) << 8) +#define LCD_RASTER_MODE 0x01 + +/* LCD Raster Control Register */ +#define LCD_PALETTE_LOAD_MODE(x) ((x) << 20) +#define PALETTE_AND_DATA 0x00 +#define PALETTE_ONLY 0x01 + +#define LCD_MONO_8BIT_MODE BIT(9) +#define LCD_RASTER_ORDER BIT(8) +#define LCD_TFT_MODE BIT(7) +#define LCD_UNDERFLOW_INT_ENA BIT(6) +#define LCD_MONOCHROME_MODE BIT(1) +#define LCD_RASTER_ENABLE BIT(0) +#define LCD_TFT_ALT_ENABLE BIT(23) +#define LCD_STN_565_ENABLE BIT(24) + +/* LCD Raster Timing 2 Register */ +#define LCD_AC_BIAS_TRANSITIONS_PER_INT(x) ((x) << 16) +#define LCD_AC_BIAS_FREQUENCY(x) ((x) << 8) +#define LCD_SYNC_CTRL BIT(25) +#define LCD_SYNC_EDGE BIT(24) +#define LCD_INVERT_PIXEL_CLOCK BIT(22) +#define LCD_INVERT_LINE_CLOCK BIT(21) +#define LCD_INVERT_FRAME_CLOCK BIT(20) + +/* LCD Block */ +#define LCD_CTRL_REG 0x4 +#define LCD_STAT_REG 0x8 +#define LCD_RASTER_CTRL_REG 0x28 +#define LCD_RASTER_TIMING_0_REG 0x2C +#define LCD_RASTER_TIMING_1_REG 0x30 +#define LCD_RASTER_TIMING_2_REG 0x34 +#define LCD_DMA_CTRL_REG 0x40 +#define LCD_DMA_FRM_BUF_BASE_ADDR_0_REG 0x44 +#define LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG 0x48 + +#define lcdc_read(addr) __raw_readl(da8xx_fb_reg_base + (addr)) +#define lcdc_write(val, addr) __raw_writel(val, da8xx_fb_reg_base + (addr)) + +#define WSI_TIMEOUT 50 +#define PALETTE_SIZE 256 +#define LEFT_MARGIN 64 +#define RIGHT_MARGIN 64 +#define UPPER_MARGIN 32 +#define LOWER_MARGIN 32 + +static resource_size_t da8xx_fb_reg_base; +static wait_queue_head_t da8xx_wq; + +struct da8xx_fb_par { + resource_size_t p_regs_base; + resource_size_t p_frame_buffer_mem_base; + resource_size_t p_screen_base; + resource_size_t p_palette_base; + unsigned char *v_frame_buffer_mem_base; + unsigned char *v_screen_base; + unsigned char *v_palette_base; + unsigned long screen_size; + unsigned int palette_size; + unsigned int bpp; + struct clk *lcdc_clk; + unsigned int irq; + u16 pseudo_palette[16]; +}; + +/* Variable Screen Information */ +static struct fb_var_screeninfo da8xx_fb_var __devinitdata = { + .xoffset = 0, + .yoffset = 0, + .transp = {0, 0, 0}, + .nonstd = 0, + .activate = 0, + .height = -1, + .width = -1, + .pixclock = 46666, /* 46us - AUO display */ + .accel_flags = 0, + .left_margin = LEFT_MARGIN, + .right_margin = RIGHT_MARGIN, + .upper_margin = UPPER_MARGIN, + .lower_margin = LOWER_MARGIN, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED +}; + +static struct fb_fix_screeninfo da8xx_fb_fix __devinitdata = { + .id = "DA8xx FB Drv", + .type = FB_TYPE_PACKED_PIXELS, + .type_aux = 0, + .visual = FB_VISUAL_PSEUDOCOLOR, + .xpanstep = 1, + .ypanstep = 1, + .ywrapstep = 1, + .accel = FB_ACCEL_NONE +}; + +struct da8xx_panel { + const char name[25]; /* Full name <vendor>_<model> */ + unsigned short width; + unsigned short height; + int hfp; /* Horizontal front porch */ + int hbp; /* Horizontal back porch */ + int hsw; /* Horizontal Sync Pulse Width */ + int vfp; /* Vertical front porch */ + int vbp; /* Vertical back porch */ + int vsw; /* Vertical Sync Pulse Width */ + int pxl_clk; /* Pixel clock */ +}; + +static struct da8xx_panel known_lcd_panels[] = { + /* Sharp LCD035Q3DG01 */ + [0] = { + .name = "Sharp_LCD035Q3DG01", + .width = 320, + .height = 240, + .hfp = 8, + .hbp = 6, + .hsw = 0, + .vfp = 2, + .vbp = 2, + .vsw = 0, + .pxl_clk = 0x10, + }, + /* Sharp LK043T1DG01 */ + [1] = { + .name = "Sharp_LK043T1DG01", + .width = 480, + .height = 272, + .hfp = 2, + .hbp = 2, + .hsw = 41, + .vfp = 2, + .vbp = 2, + .vsw = 10, + .pxl_clk = 0x12, + }, +}; + +static u32 databuf_sz; +static u32 palette_sz; +static struct fb_ops da8xx_fb_ops; + +/* Disable the Raster Engine of the LCD Controller */ +static int lcd_disable_raster(struct device *dev) +{ + int ret = 0; + u32 reg; + + reg = lcdc_read(LCD_RASTER_CTRL_REG); + if (reg & LCD_RASTER_ENABLE) { + lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); + ret = wait_event_interruptible_timeout(da8xx_wq, + !lcdc_read(LCD_STAT_REG) & + LCD_END_OF_FRAME0, WSI_TIMEOUT); + } + + if (ret < 0) + return ret; + if (ret == 0) + return -ETIMEDOUT; + + return 0; +} + +static void lcd_blit(int load_mode, u32 p_buf) +{ + u32 tmp = p_buf + databuf_sz - 4; + u32 reg; + + /* Update the databuf in the hw. */ + lcdc_write(p_buf, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); + lcdc_write(tmp, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); + + /* Start the DMA. */ + reg = lcdc_read(LCD_RASTER_CTRL_REG); + reg &= ~(3 << 20); + if (load_mode == LOAD_DATA) + reg |= LCD_PALETTE_LOAD_MODE(PALETTE_AND_DATA); + else if (load_mode == LOAD_PALETTE) + reg |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY); + + lcdc_write(reg, LCD_RASTER_CTRL_REG); +} + +/* Configure the Burst Size of DMA */ +static int lcd_cfg_dma(struct device *dev, int burst_size) +{ + u32 reg; + + reg = lcdc_read(LCD_DMA_CTRL_REG) & 0x00000001; + switch (burst_size) { + case 1: + reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_1); + break; + case 2: + reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_2); + break; + case 4: + reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_4); + break; + case 8: + reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_8); + break; + case 16: + reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_16); + break; + default: + return -EINVAL; + } + lcdc_write(reg | LCD_END_OF_FRAME_INT_ENA, LCD_DMA_CTRL_REG); + + return 0; +} + +static void lcd_cfg_ac_bias(struct device *dev, int period, + int transitions_per_int) +{ + u32 reg; + + /* Set the AC Bias Period and Number of Transisitons per Interrupt */ + reg = lcdc_read(LCD_RASTER_TIMING_2_REG) & 0xFFF00000; + reg |= LCD_AC_BIAS_FREQUENCY(period) | + LCD_AC_BIAS_TRANSITIONS_PER_INT(transitions_per_int); + lcdc_write(reg, LCD_RASTER_TIMING_2_REG); +} + +static void lcd_cfg_horizontal_sync(struct device *dev, int back_porch, + int pulse_width, int front_porch) +{ + u32 reg; + + reg = lcdc_read(LCD_RASTER_TIMING_0_REG) & 0xf; + reg |= ((back_porch & 0xff) << 24) + | ((front_porch & 0xff) << 16) + | ((pulse_width & 0x3f) << 10); + lcdc_write(reg, LCD_RASTER_TIMING_0_REG); +} + +static void lcd_cfg_vertical_sync(struct device *dev, int back_porch, + int pulse_width, int front_porch) +{ + u32 reg; + + reg = lcdc_read(LCD_RASTER_TIMING_1_REG) & 0x3ff; + reg |= ((back_porch & 0xff) << 24) + | ((front_porch & 0xff) << 16) + | ((pulse_width & 0x3f) << 10); + lcdc_write(reg, LCD_RASTER_TIMING_1_REG); +} + +static int lcd_cfg_display(struct device *dev, + const struct lcd_ctrl_config *cfg) +{ + u32 reg; + + reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(LCD_TFT_MODE | + LCD_MONO_8BIT_MODE | + LCD_MONOCHROME_MODE); + + switch (cfg->p_disp_panel->panel_shade) { + case MONOCHROME: + reg |= LCD_MONOCHROME_MODE; + if (cfg->mono_8bit_mode) + reg |= LCD_MONO_8BIT_MODE; + break; + case COLOR_ACTIVE: + reg |= LCD_TFT_MODE; + if (cfg->tft_alt_mode) + reg |= LCD_TFT_ALT_ENABLE; + break; + + case COLOR_PASSIVE: + if (cfg->stn_565_mode) + reg |= LCD_STN_565_ENABLE; + break; + + default: + dev_err(dev, "Undefined LCD type\n"); + return -EINVAL; + } + + /* enable additional interrupts here */ + reg |= LCD_UNDERFLOW_INT_ENA; + + lcdc_write(reg, LCD_RASTER_CTRL_REG); + + reg = lcdc_read(LCD_RASTER_TIMING_2_REG); + + if (cfg->sync_ctrl) + reg |= LCD_SYNC_CTRL; + else + reg &= ~LCD_SYNC_CTRL; + + if (cfg->sync_edge) + reg |= LCD_SYNC_EDGE; + else + reg &= ~LCD_SYNC_EDGE; + + if (cfg->invert_pxl_clock) + reg |= LCD_INVERT_PIXEL_CLOCK; + else + reg &= ~LCD_INVERT_PIXEL_CLOCK; + + if (cfg->invert_line_clock) + reg |= LCD_INVERT_LINE_CLOCK; + else + reg &= ~LCD_INVERT_LINE_CLOCK; + + if (cfg->invert_frm_clock) + reg |= LCD_INVERT_FRAME_CLOCK; + else + reg &= ~LCD_INVERT_FRAME_CLOCK; + + lcdc_write(reg, LCD_RASTER_TIMING_2_REG); + + return 0; +} + +static int lcd_cfg_frame_buffer(struct device *dev, u32 width, u32 height, + u32 bpp, u32 raster_order) +{ + u32 bpl, reg; + + /* Disable Dual Frame Buffer. */ + reg = lcdc_read(LCD_DMA_CTRL_REG); + lcdc_write(reg & ~LCD_DUAL_FRAME_BUFFER_ENABLE, + LCD_DMA_CTRL_REG); + /* Set the Panel Width */ + /* Pixels per line = (PPL + 1)*16 */ + /*0x3F in bits 4..9 gives max horisontal resolution = 1024 pixels*/ + width &= 0x3f0; + reg = lcdc_read(LCD_RASTER_TIMING_0_REG); + reg = (((width >> 4) - 1) << 4) | (reg & 0xfffffc00); + lcdc_write(reg, LCD_RASTER_TIMING_0_REG); + + /* Set the Panel Height */ + reg = lcdc_read(LCD_RASTER_TIMING_1_REG); + reg = ((height - 1) & 0x3ff) | (reg & 0xfffffc00); + lcdc_write(reg, LCD_RASTER_TIMING_1_REG); + + /* Set the Raster Order of the Frame Buffer */ + reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(1 << 8); + if (raster_order) + reg |= LCD_RASTER_ORDER; + lcdc_write(reg, LCD_RASTER_CTRL_REG); + + switch (bpp) { + case 1: + case 2: + case 4: + case 16: + palette_sz = 16 * 2; + break; + + case 8: + palette_sz = 256 * 2; + break; + + default: + dev_dbg(dev, "GLCD: Unsupported BPP!\n"); + return -EINVAL; + } + + bpl = width * bpp / 8; + databuf_sz = height * bpl + palette_sz; + + return 0; +} + +/* Palette Initialization */ +static int init_palette(struct device *dev, struct fb_info *info) +{ + struct da8xx_fb_par *par = info->par; + unsigned short *palette = (unsigned short *)par->p_palette_base; + unsigned short i, size; + + /* Palette Size */ + size = (par->palette_size / sizeof(*palette)); + + /* Clear the Palette */ + memset(palette, 0, par->palette_size); + + /* Initialization of Palette for Default values */ + for (i = 0; i < size; i++) + *(unsigned short *)(palette + i) = i; + + /* Setup the BPP */ + switch (par->bpp) { + case 1: + palette[0] |= BIT(11); + break; + case 2: + palette[0] |= BIT(12); + break; + case 4: + palette[0] |= (2 << 12); + break; + case 8: + palette[0] |= (3 << 12); + break; + case 16: + palette[0] |= (4 << 12); + break; + default: + dev_dbg(dev, "GLCD: Unsupported Video BPP %d!\n", par->bpp); + return -EINVAL; + } + + for (i = 0; i < size; i++) + par->pseudo_palette[i] = i; + + return 0; +} + +static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + struct da8xx_fb_par *par = info->par; + unsigned short *palette = (unsigned short *)par->v_palette_base; + u_short pal; + + if (regno > 255) + return 1; + + if (info->fix.visual == FB_VISUAL_DIRECTCOLOR || + info->fix.visual == FB_VISUAL_TRUECOLOR) + return 1; + + if (par->bpp == 8) { + red >>= 8; + green >>= 8; + blue >>= 8; + } + + pal = (red & 0x0f00); + pal |= (green & 0x00f0); + pal |= (blue & 0x000f); + + palette[regno] = pal; + + return 0; +} + +static int lcd_reset(struct device *dev) +{ + int ret = 0; + + /* Disable the Raster if previously Enabled */ + if (lcdc_read(LCD_RASTER_CTRL_REG) & LCD_RASTER_ENABLE) + ret = lcd_disable_raster(dev); + + /* 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 device *dev, const struct lcd_ctrl_config *cfg, + struct da8xx_panel *info) +{ + u32 bpp, ret = 0; + + ret = lcd_reset(dev); + if (ret != 0) + return ret; + + /* Configure the LCD clock divisor. */ + lcdc_write(LCD_CLK_DIVISOR(info->pxl_clk) | + (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG); + + /* Configure the DMA burst size. */ + ret = lcd_cfg_dma(dev, cfg->dma_burst_sz); + if (ret < 0) + return ret; + + /* Configure the AC bias properties. */ + lcd_cfg_ac_bias(dev, cfg->ac_bias, cfg->ac_bias_intrpt); + + /* Configure the vertical and horizontal sync properties. */ + lcd_cfg_vertical_sync(dev, info->vbp, info->vsw, info->vfp); + lcd_cfg_horizontal_sync(dev, info->hbp, info->hsw, info->hfp); + + /* Configure for disply */ + ret = lcd_cfg_display(dev, cfg); + if (ret < 0) + return ret; + + if (QVGA != cfg->p_disp_panel->panel_type) { + dev_err(dev, "GLCD: Only QVGA panel is currently supported !"); + return -EINVAL; + } + if (cfg->bpp <= cfg->p_disp_panel->max_bpp && + cfg->bpp >= cfg->p_disp_panel->min_bpp) + bpp = cfg->bpp; + else + bpp = cfg->p_disp_panel->max_bpp; + if (bpp == 12) + bpp = 16; + ret = lcd_cfg_frame_buffer(dev, (unsigned int)info->width, + (unsigned int)info->height, bpp, + cfg->raster_order); + if (ret < 0) + return ret; + + /* Configure FDD */ + lcdc_write((lcdc_read(LCD_RASTER_CTRL_REG) & 0xfff00fff) | + (cfg->fdd << 12), LCD_RASTER_CTRL_REG); + + return 0; +} + +static irqreturn_t lcdc_irq_handler(int irq, void *arg) +{ + u32 stat = lcdc_read(LCD_STAT_REG); + u32 reg; + + if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { + reg = lcdc_read(LCD_RASTER_CTRL_REG); + lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); + lcdc_write(stat, LCD_STAT_REG); + lcdc_write(reg | LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); + } else + lcdc_write(stat, LCD_STAT_REG); + + wake_up_interruptible(&da8xx_wq); + return IRQ_HANDLED; +} + +static int fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + int err = 0; + switch (var->bits_per_pixel) { + case 1: + case 8: + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 4: + var->red.offset = 0; + var->red.length = 4; + var->green.offset = 0; + var->green.length = 4; + var->blue.offset = 0; + var->blue.length = 4; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 16: /* RGB 565 */ + var->red.offset = 0; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 11; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + break; + default: + err = -EINVAL; + } + + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + var->transp.msb_right = 0; + return err; +} + +static int fb_set_par(struct fb_info *info) +{ + struct fb_fix_screeninfo *fix = &info->fix; + struct fb_var_screeninfo *var = &info->var; + + switch (var->bits_per_pixel) { + case 1: + fix->visual = FB_VISUAL_MONO01; + break; + + case 2: + case 4: + case 8: + fix->visual = FB_VISUAL_PSEUDOCOLOR; + break; + + case 16: + fix->visual = FB_VISUAL_TRUECOLOR; + break; + } + + fix->line_length = (var->xres_virtual * var->bits_per_pixel) / 8; + return 0; +} + +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(&dev->dev); + lcdc_write(0, LCD_RASTER_CTRL_REG); + + /* disable DMA */ + lcdc_write(0, LCD_DMA_CTRL_REG); + + unregister_framebuffer(info); + fb_dealloc_cmap(&info->cmap); + dma_free_coherent(NULL, databuf_sz + PAGE_SIZE, + par->v_frame_buffer_mem_base, + par->p_frame_buffer_mem_base); + free_irq(par->irq, NULL); + clk_disable(par->lcdc_clk); + clk_put(par->lcdc_clk); + framebuffer_release(info); + + } + return ret; +} +static int __init fb_probe(struct platform_device *device) +{ + struct da8xx_lcdc_platform_data *fb_pdata = + device->dev.platform_data; + struct lcd_ctrl_config *lcd_cfg; + struct da8xx_panel *lcdc_info; + struct fb_info *da8xx_fb_info; + struct resource *lcdc_regs; + struct clk *fb_clk = NULL; + struct da8xx_fb_par *par; + resource_size_t len; + int ret, i; + + if (fb_pdata == NULL) { + dev_err(&device->dev, "Can not get platform data\n"); + return -ENOENT; + } + + lcdc_regs = platform_get_resource(device, IORESOURCE_MEM, 0); + if (!lcdc_regs) { + dev_err(&device->dev, + "Can not get memory resource for LCD controller\n"); + return -ENOENT; + } + + len = lcdc_regs->end - lcdc_regs->start + 1; + + lcdc_regs = request_mem_region(lcdc_regs->start, len, lcdc_regs->name); + if (!lcdc_regs) + return -EBUSY; + + da8xx_fb_reg_base = (resource_size_t) ioremap(lcdc_regs->start, len); + + fb_clk = clk_get(&device->dev, NULL); + if (IS_ERR(fb_clk)) { + dev_err(&device->dev, "Can not get device clock\n"); + return -ENODEV; + } + ret = clk_enable(fb_clk); + if (ret) + goto err_clk_put; + + for (i = 0, lcdc_info = known_lcd_panels; + i < ARRAY_SIZE(known_lcd_panels); + i++, lcdc_info++) { + if (strcmp(fb_pdata->type, lcdc_info->name) == 0) + break; + } + + if (i == ARRAY_SIZE(known_lcd_panels)) { + dev_err(&device->dev, "GLCD: No valid panel found\n"); + return -ENODEV; + } else + dev_info(&device->dev, "GLCD: Found %s panel\n", + fb_pdata->type); + + lcd_cfg = (struct lcd_ctrl_config *)fb_pdata->controller_data; + + if (lcd_init(&device->dev, lcd_cfg, lcdc_info) < 0) { + dev_err(&device->dev, "lcd_init failed\n"); + ret = -EFAULT; + goto err_clk_disable; + } + da8xx_fb_info = framebuffer_alloc(sizeof(struct fb_info), + &device->dev); + if (!da8xx_fb_info) { + dev_dbg(&device->dev, "Memory allocation failed for fb_info\n"); + ret = -ENOMEM; + goto err_clk_disable; + } + + par = da8xx_fb_info->par; + /* allocate frame buffer */ + par->v_frame_buffer_mem_base = dma_alloc_coherent(NULL, + databuf_sz + PAGE_SIZE, + &par->p_frame_buffer_mem_base, + GFP_KERNEL | GFP_DMA); + + if (!par->v_frame_buffer_mem_base) { + dev_err(&device->dev, + "GLCD: kmalloc for frame buffer failed\n"); + ret = -EINVAL; + goto err_release_fb; + } + + /* move palette base pointer by (PAGE_SIZE - palette_sz) bytes */ + par->v_palette_base = par->v_frame_buffer_mem_base + + (PAGE_SIZE - palette_sz); + par->p_palette_base = par->p_frame_buffer_mem_base + + (PAGE_SIZE - palette_sz); + + /* First palette_sz byte of the frame buffer is the palette */ + par->palette_size = palette_sz; + + /* the rest of the frame buffer is pixel data */ + par->v_screen_base = par->v_palette_base + palette_sz; + par->p_screen_base = par->p_palette_base + palette_sz; + par->screen_size = databuf_sz - palette_sz; + + par->lcdc_clk = fb_clk; + + da8xx_fb_fix.smem_start = (unsigned long)par->p_screen_base; + da8xx_fb_fix.smem_len = par->screen_size; + + init_waitqueue_head(&da8xx_wq); + + par->irq = platform_get_irq(device, 0); + if (par->irq < 0) { + ret = -ENOENT; + goto err_release_fb_mem; + } + + ret = request_irq(par->irq, lcdc_irq_handler, 0, + DRIVER_NAME, NULL); + if (ret) + goto err_free_irq; + + /* Initialize par */ + par->bpp = lcd_cfg->bpp; + + da8xx_fb_var.xres = lcdc_info->width; + da8xx_fb_var.xres_virtual = lcdc_info->width; + + da8xx_fb_var.yres = lcdc_info->height; + da8xx_fb_var.yres_virtual = lcdc_info->height; + + da8xx_fb_var.grayscale = + lcd_cfg->p_disp_panel->panel_shade == MONOCHROME ? 1 : 0; + da8xx_fb_var.bits_per_pixel = lcd_cfg->bpp; + + da8xx_fb_var.hsync_len = lcdc_info->hsw; + da8xx_fb_var.vsync_len = lcdc_info->vsw; + + /* Initialize fbinfo */ + da8xx_fb_info->flags = FBINFO_FLAG_DEFAULT; + da8xx_fb_info->screen_base = par->v_screen_base; + da8xx_fb_info->device = &device->dev; + da8xx_fb_info->fix = da8xx_fb_fix; + da8xx_fb_info->var = da8xx_fb_var; + da8xx_fb_info->fbops = &da8xx_fb_ops; + da8xx_fb_info->pseudo_palette = par->pseudo_palette; + + /* Initialize the Palette */ + ret = init_palette(&device->dev, da8xx_fb_info); + if (ret < 0) + goto err_free_irq; + + ret = fb_alloc_cmap(&da8xx_fb_info->cmap, PALETTE_SIZE, 0); + if (ret) + goto err_free_irq; + + /* Flush the buffer to the screen. */ + lcd_blit(LOAD_DATA, (u32) par->p_palette_base); + + /* initialize var_screeninfo */ + da8xx_fb_var.activate = FB_ACTIVATE_FORCE; + fb_set_var(da8xx_fb_info, &da8xx_fb_var); + + dev_set_drvdata(&device->dev, da8xx_fb_info); + /* Register the Frame Buffer */ + if (register_framebuffer(da8xx_fb_info) < 0) { + dev_err(&device->dev, + "GLCD: Frame Buffer Registration Failed!\n"); + ret = -EINVAL; + goto err_dealloc_cmap; + } + + /* enable raster engine */ + lcdc_write(lcdc_read(LCD_RASTER_CTRL_REG) | + LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); + + return 0; + +err_dealloc_cmap: + fb_dealloc_cmap(&da8xx_fb_info->cmap); + +err_free_irq: + free_irq(par->irq, NULL); + +err_release_fb_mem: + dma_free_coherent(NULL, databuf_sz + PAGE_SIZE, + par->v_frame_buffer_mem_base, + par->p_frame_buffer_mem_base); + +err_release_fb: + framebuffer_release(da8xx_fb_info); + +err_clk_disable: + clk_disable(fb_clk); + +err_clk_put: + clk_put(fb_clk); + + return ret; +} + +static int fb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) +{ + struct lcd_sync_arg sync_arg; + + switch (cmd) { + case FBIOGET_CONTRAST: + case FBIOPUT_CONTRAST: + case FBIGET_BRIGHTNESS: + case FBIPUT_BRIGHTNESS: + case FBIGET_COLOR: + case FBIPUT_COLOR: + return -EINVAL; + case FBIPUT_HSYNC: + if (copy_from_user(&sync_arg, (char *)arg, + sizeof(struct lcd_sync_arg))) + return -EINVAL; + lcd_cfg_horizontal_sync(info->dev, sync_arg.back_porch, + sync_arg.pulse_width, + sync_arg.front_porch); + break; + case FBIPUT_VSYNC: + if (copy_from_user(&sync_arg, (char *)arg, + sizeof(struct lcd_sync_arg))) + return -EINVAL; + lcd_cfg_vertical_sync(info->dev, sync_arg.back_porch, + sync_arg.pulse_width, + sync_arg.front_porch); + break; + default: + return -EINVAL; + } + return 0; +} + +static struct fb_ops da8xx_fb_ops = { + .owner = THIS_MODULE, + .fb_check_var = fb_check_var, + .fb_set_par = fb_set_par, + .fb_setcolreg = fb_setcolreg, + .fb_ioctl = fb_ioctl, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +}; + +#ifdef CONFIG_PM +static int fb_suspend(struct platform_device *dev, pm_message_t state) +{ + return -EBUSY; +} +static int fb_resume(struct platform_device *dev) +{ + return -EBUSY; +} +#else +#define fb_suspend NULL +#define fb_resume NULL +#endif + +static struct platform_driver da8xx_fb_driver = { + .probe = fb_probe, + .remove = fb_remove, + .suspend = fb_suspend, + .resume = fb_resume, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init da8xx_fb_init(void) +{ + return platform_driver_register(&da8xx_fb_driver); +} + +static void __exit da8xx_fb_cleanup(void) +{ + platform_driver_unregister(&da8xx_fb_driver); +} + +module_init(da8xx_fb_init); +module_exit(da8xx_fb_cleanup); + +MODULE_DESCRIPTION("Framebuffer driver for TI da8xx/omap-l1xx"); +MODULE_AUTHOR("MontaVista Software"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/da8xx-fb.h b/include/linux/da8xx-fb.h new file mode 100644 index 0000000..5f77675 --- /dev/null +++ b/include/linux/da8xx-fb.h @@ -0,0 +1,106 @@ +/* + * Header file for TI DA8XX LCD controller platform data. + * + * Copyright (C) 2008-2009 MontaVista Software Inc. + * Copyright (C) 2008-2009 Texas Instruments Inc + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef DA8XX_FB_H +#define DA8XX_FB_H + +enum panel_type { + QVGA = 0 +}; + +enum panel_shade { + MONOCHROME = 0, + COLOR_ACTIVE, + COLOR_PASSIVE, +}; + +enum raster_load_mode { + LOAD_DATA = 1, + LOAD_PALETTE, +}; + +struct display_panel { + enum panel_type panel_type; /* QVGA */ + int max_bpp; + int min_bpp; + enum panel_shade panel_shade; +}; + +struct da8xx_lcdc_platform_data { + const char manu_name[10]; + void *controller_data; + const char type[25]; +}; + +struct lcd_ctrl_config { + const struct display_panel *p_disp_panel; + + /* AC Bias Pin Frequency */ + int ac_bias; + + /* AC Bias Pin Transitions per Interrupt */ + int ac_bias_intrpt; + + /* DMA burst size */ + int dma_burst_sz; + + /* Bits per pixel */ + int bpp; + + /* FIFO DMA Request Delay */ + int fdd; + + /* TFT Alternative Signal Mapping (Only for active) */ + unsigned char tft_alt_mode; + + /* 12 Bit Per Pixel (5-6-5) Mode (Only for passive) */ + unsigned char stn_565_mode; + + /* Mono 8-bit Mode: 1=D0-D7 or 0=D0-D3 */ + unsigned char mono_8bit_mode; + + /* Invert pixel clock */ + unsigned char invert_pxl_clock; + + /* Invert line clock */ + unsigned char invert_line_clock; + + /* Invert frame clock */ + unsigned char invert_frm_clock; + + /* Horizontal and Vertical Sync Edge: 0=rising 1=falling */ + unsigned char sync_edge; + + /* Horizontal and Vertical Sync: Control: 0=ignore */ + unsigned char sync_ctrl; + + /* Raster Data Order Select: 1=Most-to-least 0=Least-to-most */ + unsigned char raster_order; +}; + +struct lcd_sync_arg { + int back_porch; + int front_porch; + int pulse_width; +}; + +/* ioctls */ +#define FBIOGET_CONTRAST _IOR('F', 1, int) +#define FBIOPUT_CONTRAST _IOW('F', 2, int) +#define FBIGET_BRIGHTNESS _IOR('F', 3, int) +#define FBIPUT_BRIGHTNESS _IOW('F', 3, int) +#define FBIGET_COLOR _IOR('F', 5, int) +#define FBIPUT_COLOR _IOW('F', 6, int) +#define FBIPUT_HSYNC _IOW('F', 9, int) +#define FBIPUT_VSYNC _IOW('F', 10, int) + +#endif /* ifndef DA8XX_FB_H */ + -- 1.5.6 |
From: Rajashekhara, Sudhakar <sudhakar.raj@ti...> - 2009-06-17 14:25:01
|
Adds LCD controller (LCDC) driver for TI's DA8xx/OMAP-L1xx architecture. LCDC specifications can be found at http://www.ti.com/litv/pdf/sprufm0a. LCDC on DA8xx consists of two independent controllers, the Raster Controller and the LCD Interface Display Driver (LIDD) controller. LIDD further supports character and graphic displays. This patch adds support for the graphic display (Sharp LQ035Q3DG01) found on the DA830 based EVM. The EVM details can be found at: http://support.spectrumdigital.com/boards/dskda830/revc/. Signed-off-by: Sudhakar Rajashekhara <sudhakar.raj@...> --- drivers/video/Kconfig | 11 + drivers/video/Makefile | 1 + drivers/video/da8xx-fb.c | 964 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/da8xx-fb.h | 106 +++++ 4 files changed, 1082 insertions(+), 0 deletions(-) create mode 100644 drivers/video/da8xx-fb.c create mode 100644 include/linux/da8xx-fb.h diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 693fb4e..fc0c191 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1984,6 +1984,17 @@ config FB_DAVINCI hardware found on the TI DaVinci EVM. If unsure, say N. +config FB_DA8XX + tristate "DA8xx/OMAP-L1xx Framebuffer support" + depends on FB && ARCH_DAVINCI_DA830 + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + This is the frame buffer device driver for the TI LCD controller + found on DA8xx/OMAP-L1xx SoCs. + If unsure, say N. + config FB_VIRTUAL tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" depends on FB diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 902d199..e7a3e7d 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -136,6 +136,7 @@ obj-$(CONFIG_FB_BF54X_LQ043) += bf54x-lq043fb.o obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin-t350mcqb-fb.o obj-$(CONFIG_FB_MX3) += mx3fb.o obj-$(CONFIG_FB_DAVINCI) += davincifb.o +obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o # the test framebuffer is last obj-$(CONFIG_FB_VIRTUAL) += vfb.o diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c new file mode 100644 index 0000000..5e3b861 --- /dev/null +++ b/drivers/video/da8xx-fb.c @@ -0,0 +1,964 @@ +/* + * Copyright (C) 2008-2009 MontaVista Software Inc. + * Copyright (C) 2008-2009 Texas Instruments Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option)any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/fb.h> +#include <linux/dma-mapping.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <mach/cputype.h> +#include <mach/io.h> +#include <mach/hardware.h> +#include <linux/uaccess.h> +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/clk.h> +#include <linux/da8xx-fb.h> + +#define DRIVER_NAME "da8xx_lcdc" + +/* LCD Status Register */ +#define LCD_END_OF_FRAME0 BIT(8) +#define LCD_FIFO_UNDERFLOW BIT(5) +#define LCD_SYNC_LOST BIT(2) + +/* LCD DMA Control Register */ +#define LCD_DMA_BURST_SIZE(x) ((x) << 4) +#define LCD_DMA_BURST_1 0x0 +#define LCD_DMA_BURST_2 0x1 +#define LCD_DMA_BURST_4 0x2 +#define LCD_DMA_BURST_8 0x3 +#define LCD_DMA_BURST_16 0x4 +#define LCD_END_OF_FRAME_INT_ENA BIT(2) +#define LCD_DUAL_FRAME_BUFFER_ENABLE BIT(0) + +/* LCD Control Register */ +#define LCD_CLK_DIVISOR(x) ((x) << 8) +#define LCD_RASTER_MODE 0x01 + +/* LCD Raster Control Register */ +#define LCD_PALETTE_LOAD_MODE(x) ((x) << 20) +#define PALETTE_AND_DATA 0x00 +#define PALETTE_ONLY 0x01 + +#define LCD_MONO_8BIT_MODE BIT(9) +#define LCD_RASTER_ORDER BIT(8) +#define LCD_TFT_MODE BIT(7) +#define LCD_UNDERFLOW_INT_ENA BIT(6) +#define LCD_MONOCHROME_MODE BIT(1) +#define LCD_RASTER_ENABLE BIT(0) +#define LCD_TFT_ALT_ENABLE BIT(23) +#define LCD_STN_565_ENABLE BIT(24) + +/* LCD Raster Timing 2 Register */ +#define LCD_AC_BIAS_TRANSITIONS_PER_INT(x) ((x) << 16) +#define LCD_AC_BIAS_FREQUENCY(x) ((x) << 8) +#define LCD_SYNC_CTRL BIT(25) +#define LCD_SYNC_EDGE BIT(24) +#define LCD_INVERT_PIXEL_CLOCK BIT(22) +#define LCD_INVERT_LINE_CLOCK BIT(21) +#define LCD_INVERT_FRAME_CLOCK BIT(20) + +/* LCD Block */ +#define LCD_CTRL_REG 0x4 +#define LCD_STAT_REG 0x8 +#define LCD_RASTER_CTRL_REG 0x28 +#define LCD_RASTER_TIMING_0_REG 0x2C +#define LCD_RASTER_TIMING_1_REG 0x30 +#define LCD_RASTER_TIMING_2_REG 0x34 +#define LCD_DMA_CTRL_REG 0x40 +#define LCD_DMA_FRM_BUF_BASE_ADDR_0_REG 0x44 +#define LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG 0x48 + +#define lcdc_read(addr) __raw_readl(da8xx_fb_reg_base + (addr)) +#define lcdc_write(val, addr) __raw_writel(val, da8xx_fb_reg_base + (addr)) + +#define WSI_TIMEOUT 50 +#define PALETTE_SIZE 256 +#define LEFT_MARGIN 64 +#define RIGHT_MARGIN 64 +#define UPPER_MARGIN 32 +#define LOWER_MARGIN 32 + +static resource_size_t da8xx_fb_reg_base; +static wait_queue_head_t da8xx_wq; + +struct da8xx_fb_par { + resource_size_t p_regs_base; + resource_size_t p_frame_buffer_mem_base; + resource_size_t p_screen_base; + resource_size_t p_palette_base; + unsigned char *v_frame_buffer_mem_base; + unsigned char *v_screen_base; + unsigned char *v_palette_base; + unsigned long screen_size; + unsigned int palette_size; + unsigned int bpp; + struct clk *lcdc_clk; + unsigned int irq; + u16 pseudo_palette[16]; +}; + +/* Variable Screen Information */ +static struct fb_var_screeninfo da8xx_fb_var __devinitdata = { + .xoffset = 0, + .yoffset = 0, + .transp = {0, 0, 0}, + .nonstd = 0, + .activate = 0, + .height = -1, + .width = -1, + .pixclock = 46666, /* 46us - AUO display */ + .accel_flags = 0, + .left_margin = LEFT_MARGIN, + .right_margin = RIGHT_MARGIN, + .upper_margin = UPPER_MARGIN, + .lower_margin = LOWER_MARGIN, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED +}; + +static struct fb_fix_screeninfo da8xx_fb_fix __devinitdata = { + .id = "DA8xx FB Drv", + .type = FB_TYPE_PACKED_PIXELS, + .type_aux = 0, + .visual = FB_VISUAL_PSEUDOCOLOR, + .xpanstep = 1, + .ypanstep = 1, + .ywrapstep = 1, + .accel = FB_ACCEL_NONE +}; + +struct da8xx_panel { + const char name[25]; /* Full name <vendor>_<model> */ + unsigned short width; + unsigned short height; + int hfp; /* Horizontal front porch */ + int hbp; /* Horizontal back porch */ + int hsw; /* Horizontal Sync Pulse Width */ + int vfp; /* Vertical front porch */ + int vbp; /* Vertical back porch */ + int vsw; /* Vertical Sync Pulse Width */ + int pxl_clk; /* Pixel clock */ +}; + +static struct da8xx_panel known_lcd_panels[] = { + /* Sharp LCD035Q3DG01 */ + [0] = { + .name = "Sharp_LCD035Q3DG01", + .width = 320, + .height = 240, + .hfp = 8, + .hbp = 6, + .hsw = 0, + .vfp = 2, + .vbp = 2, + .vsw = 0, + .pxl_clk = 0x10, + }, + /* Sharp LK043T1DG01 */ + [1] = { + .name = "Sharp_LK043T1DG01", + .width = 480, + .height = 272, + .hfp = 2, + .hbp = 2, + .hsw = 41, + .vfp = 2, + .vbp = 2, + .vsw = 10, + .pxl_clk = 0x12, + }, +}; + +static u32 databuf_sz; +static u32 palette_sz; +static struct fb_ops da8xx_fb_ops; + +/* Disable the Raster Engine of the LCD Controller */ +static int lcd_disable_raster(struct device *dev) +{ + int ret = 0; + u32 reg; + + reg = lcdc_read(LCD_RASTER_CTRL_REG); + if (reg & LCD_RASTER_ENABLE) { + lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); + ret = wait_event_interruptible_timeout(da8xx_wq, + !lcdc_read(LCD_STAT_REG) & + LCD_END_OF_FRAME0, WSI_TIMEOUT); + } + + if (ret < 0) + return ret; + if (ret == 0) + return -ETIMEDOUT; + + return 0; +} + +static void lcd_blit(int load_mode, u32 p_buf) +{ + u32 tmp = p_buf + databuf_sz - 4; + u32 reg; + + /* Update the databuf in the hw. */ + lcdc_write(p_buf, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); + lcdc_write(tmp, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); + + /* Start the DMA. */ + reg = lcdc_read(LCD_RASTER_CTRL_REG); + reg &= ~(3 << 20); + if (load_mode == LOAD_DATA) + reg |= LCD_PALETTE_LOAD_MODE(PALETTE_AND_DATA); + else if (load_mode == LOAD_PALETTE) + reg |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY); + + lcdc_write(reg, LCD_RASTER_CTRL_REG); +} + +/* Configure the Burst Size of DMA */ +static int lcd_cfg_dma(struct device *dev, int burst_size) +{ + u32 reg; + + reg = lcdc_read(LCD_DMA_CTRL_REG) & 0x00000001; + switch (burst_size) { + case 1: + reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_1); + break; + case 2: + reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_2); + break; + case 4: + reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_4); + break; + case 8: + reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_8); + break; + case 16: + reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_16); + break; + default: + return -EINVAL; + } + lcdc_write(reg | LCD_END_OF_FRAME_INT_ENA, LCD_DMA_CTRL_REG); + + return 0; +} + +static void lcd_cfg_ac_bias(struct device *dev, int period, + int transitions_per_int) +{ + u32 reg; + + /* Set the AC Bias Period and Number of Transisitons per Interrupt */ + reg = lcdc_read(LCD_RASTER_TIMING_2_REG) & 0xFFF00000; + reg |= LCD_AC_BIAS_FREQUENCY(period) | + LCD_AC_BIAS_TRANSITIONS_PER_INT(transitions_per_int); + lcdc_write(reg, LCD_RASTER_TIMING_2_REG); +} + +static void lcd_cfg_horizontal_sync(struct device *dev, int back_porch, + int pulse_width, int front_porch) +{ + u32 reg; + + reg = lcdc_read(LCD_RASTER_TIMING_0_REG) & 0xf; + reg |= ((back_porch & 0xff) << 24) + | ((front_porch & 0xff) << 16) + | ((pulse_width & 0x3f) << 10); + lcdc_write(reg, LCD_RASTER_TIMING_0_REG); +} + +static void lcd_cfg_vertical_sync(struct device *dev, int back_porch, + int pulse_width, int front_porch) +{ + u32 reg; + + reg = lcdc_read(LCD_RASTER_TIMING_1_REG) & 0x3ff; + reg |= ((back_porch & 0xff) << 24) + | ((front_porch & 0xff) << 16) + | ((pulse_width & 0x3f) << 10); + lcdc_write(reg, LCD_RASTER_TIMING_1_REG); +} + +static int lcd_cfg_display(struct device *dev, + const struct lcd_ctrl_config *cfg) +{ + u32 reg; + + reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(LCD_TFT_MODE | + LCD_MONO_8BIT_MODE | + LCD_MONOCHROME_MODE); + + switch (cfg->p_disp_panel->panel_shade) { + case MONOCHROME: + reg |= LCD_MONOCHROME_MODE; + if (cfg->mono_8bit_mode) + reg |= LCD_MONO_8BIT_MODE; + break; + case COLOR_ACTIVE: + reg |= LCD_TFT_MODE; + if (cfg->tft_alt_mode) + reg |= LCD_TFT_ALT_ENABLE; + break; + + case COLOR_PASSIVE: + if (cfg->stn_565_mode) + reg |= LCD_STN_565_ENABLE; + break; + + default: + dev_err(dev, "Undefined LCD type\n"); + return -EINVAL; + } + + /* enable additional interrupts here */ + reg |= LCD_UNDERFLOW_INT_ENA; + + lcdc_write(reg, LCD_RASTER_CTRL_REG); + + reg = lcdc_read(LCD_RASTER_TIMING_2_REG); + + if (cfg->sync_ctrl) + reg |= LCD_SYNC_CTRL; + else + reg &= ~LCD_SYNC_CTRL; + + if (cfg->sync_edge) + reg |= LCD_SYNC_EDGE; + else + reg &= ~LCD_SYNC_EDGE; + + if (cfg->invert_pxl_clock) + reg |= LCD_INVERT_PIXEL_CLOCK; + else + reg &= ~LCD_INVERT_PIXEL_CLOCK; + + if (cfg->invert_line_clock) + reg |= LCD_INVERT_LINE_CLOCK; + else + reg &= ~LCD_INVERT_LINE_CLOCK; + + if (cfg->invert_frm_clock) + reg |= LCD_INVERT_FRAME_CLOCK; + else + reg &= ~LCD_INVERT_FRAME_CLOCK; + + lcdc_write(reg, LCD_RASTER_TIMING_2_REG); + + return 0; +} + +static int lcd_cfg_frame_buffer(struct device *dev, u32 width, u32 height, + u32 bpp, u32 raster_order) +{ + u32 bpl, reg; + + /* Disable Dual Frame Buffer. */ + reg = lcdc_read(LCD_DMA_CTRL_REG); + lcdc_write(reg & ~LCD_DUAL_FRAME_BUFFER_ENABLE, + LCD_DMA_CTRL_REG); + /* Set the Panel Width */ + /* Pixels per line = (PPL + 1)*16 */ + /*0x3F in bits 4..9 gives max horisontal resolution = 1024 pixels*/ + width &= 0x3f0; + reg = lcdc_read(LCD_RASTER_TIMING_0_REG); + reg = (((width >> 4) - 1) << 4) | (reg & 0xfffffc00); + lcdc_write(reg, LCD_RASTER_TIMING_0_REG); + + /* Set the Panel Height */ + reg = lcdc_read(LCD_RASTER_TIMING_1_REG); + reg = ((height - 1) & 0x3ff) | (reg & 0xfffffc00); + lcdc_write(reg, LCD_RASTER_TIMING_1_REG); + + /* Set the Raster Order of the Frame Buffer */ + reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(1 << 8); + if (raster_order) + reg |= LCD_RASTER_ORDER; + lcdc_write(reg, LCD_RASTER_CTRL_REG); + + switch (bpp) { + case 1: + case 2: + case 4: + case 16: + palette_sz = 16 * 2; + break; + + case 8: + palette_sz = 256 * 2; + break; + + default: + dev_dbg(dev, "GLCD: Unsupported BPP!\n"); + return -EINVAL; + } + + bpl = width * bpp / 8; + databuf_sz = height * bpl + palette_sz; + + return 0; +} + +/* Palette Initialization */ +static int init_palette(struct device *dev, struct fb_info *info) +{ + struct da8xx_fb_par *par = info->par; + unsigned short *palette = (unsigned short *)par->p_palette_base; + unsigned short i, size; + + /* Palette Size */ + size = (par->palette_size / sizeof(*palette)); + + /* Clear the Palette */ + memset(palette, 0, par->palette_size); + + /* Initialization of Palette for Default values */ + for (i = 0; i < size; i++) + *(unsigned short *)(palette + i) = i; + + /* Setup the BPP */ + switch (par->bpp) { + case 1: + palette[0] |= BIT(11); + break; + case 2: + palette[0] |= BIT(12); + break; + case 4: + palette[0] |= (2 << 12); + break; + case 8: + palette[0] |= (3 << 12); + break; + case 16: + palette[0] |= (4 << 12); + break; + default: + dev_dbg(dev, "GLCD: Unsupported Video BPP %d!\n", par->bpp); + return -EINVAL; + } + + for (i = 0; i < size; i++) + par->pseudo_palette[i] = i; + + return 0; +} + +static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + struct da8xx_fb_par *par = info->par; + unsigned short *palette = (unsigned short *)par->v_palette_base; + u_short pal; + + if (regno > 255) + return 1; + + if (info->fix.visual == FB_VISUAL_DIRECTCOLOR || + info->fix.visual == FB_VISUAL_TRUECOLOR) + return 1; + + if (par->bpp == 8) { + red >>= 8; + green >>= 8; + blue >>= 8; + } + + pal = (red & 0x0f00); + pal |= (green & 0x00f0); + pal |= (blue & 0x000f); + + palette[regno] = pal; + + return 0; +} + +static int lcd_reset(struct device *dev) +{ + int ret = 0; + + /* Disable the Raster if previously Enabled */ + if (lcdc_read(LCD_RASTER_CTRL_REG) & LCD_RASTER_ENABLE) + ret = lcd_disable_raster(dev); + + /* 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 device *dev, const struct lcd_ctrl_config *cfg, + struct da8xx_panel *info) +{ + u32 bpp, ret = 0; + + ret = lcd_reset(dev); + if (ret != 0) + return ret; + + /* Configure the LCD clock divisor. */ + lcdc_write(LCD_CLK_DIVISOR(info->pxl_clk) | + (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG); + + /* Configure the DMA burst size. */ + ret = lcd_cfg_dma(dev, cfg->dma_burst_sz); + if (ret < 0) + return ret; + + /* Configure the AC bias properties. */ + lcd_cfg_ac_bias(dev, cfg->ac_bias, cfg->ac_bias_intrpt); + + /* Configure the vertical and horizontal sync properties. */ + lcd_cfg_vertical_sync(dev, info->vbp, info->vsw, info->vfp); + lcd_cfg_horizontal_sync(dev, info->hbp, info->hsw, info->hfp); + + /* Configure for disply */ + ret = lcd_cfg_display(dev, cfg); + if (ret < 0) + return ret; + + if (QVGA != cfg->p_disp_panel->panel_type) { + dev_err(dev, "GLCD: Only QVGA panel is currently supported !"); + return -EINVAL; + } + if (cfg->bpp <= cfg->p_disp_panel->max_bpp && + cfg->bpp >= cfg->p_disp_panel->min_bpp) + bpp = cfg->bpp; + else + bpp = cfg->p_disp_panel->max_bpp; + if (bpp == 12) + bpp = 16; + ret = lcd_cfg_frame_buffer(dev, (unsigned int)info->width, + (unsigned int)info->height, bpp, + cfg->raster_order); + if (ret < 0) + return ret; + + /* Configure FDD */ + lcdc_write((lcdc_read(LCD_RASTER_CTRL_REG) & 0xfff00fff) | + (cfg->fdd << 12), LCD_RASTER_CTRL_REG); + + return 0; +} + +static irqreturn_t lcdc_irq_handler(int irq, void *arg) +{ + u32 stat = lcdc_read(LCD_STAT_REG); + u32 reg; + + if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { + reg = lcdc_read(LCD_RASTER_CTRL_REG); + lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); + lcdc_write(stat, LCD_STAT_REG); + lcdc_write(reg | LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); + } else + lcdc_write(stat, LCD_STAT_REG); + + wake_up_interruptible(&da8xx_wq); + return IRQ_HANDLED; +} + +static int fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + int err = 0; + switch (var->bits_per_pixel) { + case 1: + case 8: + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 4: + var->red.offset = 0; + var->red.length = 4; + var->green.offset = 0; + var->green.length = 4; + var->blue.offset = 0; + var->blue.length = 4; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 16: /* RGB 565 */ + var->red.offset = 0; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 11; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + break; + default: + err = -EINVAL; + } + + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + var->transp.msb_right = 0; + return err; +} + +static int fb_set_par(struct fb_info *info) +{ + struct fb_fix_screeninfo *fix = &info->fix; + struct fb_var_screeninfo *var = &info->var; + + switch (var->bits_per_pixel) { + case 1: + fix->visual = FB_VISUAL_MONO01; + break; + + case 2: + case 4: + case 8: + fix->visual = FB_VISUAL_PSEUDOCOLOR; + break; + + case 16: + fix->visual = FB_VISUAL_TRUECOLOR; + break; + } + + fix->line_length = (var->xres_virtual * var->bits_per_pixel) / 8; + return 0; +} + +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(&dev->dev); + lcdc_write(0, LCD_RASTER_CTRL_REG); + + /* disable DMA */ + lcdc_write(0, LCD_DMA_CTRL_REG); + + unregister_framebuffer(info); + fb_dealloc_cmap(&info->cmap); + dma_free_coherent(NULL, databuf_sz + PAGE_SIZE, + par->v_frame_buffer_mem_base, + par->p_frame_buffer_mem_base); + free_irq(par->irq, NULL); + clk_disable(par->lcdc_clk); + clk_put(par->lcdc_clk); + framebuffer_release(info); + + } + return ret; +} +static int __init fb_probe(struct platform_device *device) +{ + struct da8xx_lcdc_platform_data *fb_pdata = + device->dev.platform_data; + struct lcd_ctrl_config *lcd_cfg; + struct da8xx_panel *lcdc_info; + struct fb_info *da8xx_fb_info; + struct resource *lcdc_regs; + struct clk *fb_clk = NULL; + struct da8xx_fb_par *par; + resource_size_t len; + int ret, i; + + if (fb_pdata == NULL) { + dev_err(&device->dev, "Can not get platform data\n"); + return -ENOENT; + } + + lcdc_regs = platform_get_resource(device, IORESOURCE_MEM, 0); + if (!lcdc_regs) { + dev_err(&device->dev, + "Can not get memory resource for LCD controller\n"); + return -ENOENT; + } + + len = lcdc_regs->end - lcdc_regs->start + 1; + + lcdc_regs = request_mem_region(lcdc_regs->start, len, lcdc_regs->name); + if (!lcdc_regs) + return -EBUSY; + + da8xx_fb_reg_base = (resource_size_t) ioremap(lcdc_regs->start, len); + + fb_clk = clk_get(&device->dev, NULL); + if (IS_ERR(fb_clk)) { + dev_err(&device->dev, "Can not get device clock\n"); + return -ENODEV; + } + ret = clk_enable(fb_clk); + if (ret) + goto err_clk_put; + + for (i = 0, lcdc_info = known_lcd_panels; + i < ARRAY_SIZE(known_lcd_panels); + i++, lcdc_info++) { + if (strcmp(fb_pdata->type, lcdc_info->name) == 0) + break; + } + + if (i == ARRAY_SIZE(known_lcd_panels)) { + dev_err(&device->dev, "GLCD: No valid panel found\n"); + return -ENODEV; + } else + dev_info(&device->dev, "GLCD: Found %s panel\n", + fb_pdata->type); + + lcd_cfg = (struct lcd_ctrl_config *)fb_pdata->controller_data; + + if (lcd_init(&device->dev, lcd_cfg, lcdc_info) < 0) { + dev_err(&device->dev, "lcd_init failed\n"); + ret = -EFAULT; + goto err_clk_disable; + } + da8xx_fb_info = framebuffer_alloc(sizeof(struct fb_info), + &device->dev); + if (!da8xx_fb_info) { + dev_dbg(&device->dev, "Memory allocation failed for fb_info\n"); + ret = -ENOMEM; + goto err_clk_disable; + } + + par = da8xx_fb_info->par; + /* allocate frame buffer */ + par->v_frame_buffer_mem_base = dma_alloc_coherent(NULL, + databuf_sz + PAGE_SIZE, + &par->p_frame_buffer_mem_base, + GFP_KERNEL | GFP_DMA); + + if (!par->v_frame_buffer_mem_base) { + dev_err(&device->dev, + "GLCD: kmalloc for frame buffer failed\n"); + ret = -EINVAL; + goto err_release_fb; + } + + /* move palette base pointer by (PAGE_SIZE - palette_sz) bytes */ + par->v_palette_base = par->v_frame_buffer_mem_base + + (PAGE_SIZE - palette_sz); + par->p_palette_base = par->p_frame_buffer_mem_base + + (PAGE_SIZE - palette_sz); + + /* First palette_sz byte of the frame buffer is the palette */ + par->palette_size = palette_sz; + + /* the rest of the frame buffer is pixel data */ + par->v_screen_base = par->v_palette_base + palette_sz; + par->p_screen_base = par->p_palette_base + palette_sz; + par->screen_size = databuf_sz - palette_sz; + + par->lcdc_clk = fb_clk; + + da8xx_fb_fix.smem_start = (unsigned long)par->p_screen_base; + da8xx_fb_fix.smem_len = par->screen_size; + + init_waitqueue_head(&da8xx_wq); + + par->irq = platform_get_irq(device, 0); + if (par->irq < 0) { + ret = -ENOENT; + goto err_release_fb_mem; + } + + ret = request_irq(par->irq, lcdc_irq_handler, 0, + DRIVER_NAME, NULL); + if (ret) + goto err_free_irq; + + /* Initialize par */ + par->bpp = lcd_cfg->bpp; + + da8xx_fb_var.xres = lcdc_info->width; + da8xx_fb_var.xres_virtual = lcdc_info->width; + + da8xx_fb_var.yres = lcdc_info->height; + da8xx_fb_var.yres_virtual = lcdc_info->height; + + da8xx_fb_var.grayscale = + lcd_cfg->p_disp_panel->panel_shade == MONOCHROME ? 1 : 0; + da8xx_fb_var.bits_per_pixel = lcd_cfg->bpp; + + da8xx_fb_var.hsync_len = lcdc_info->hsw; + da8xx_fb_var.vsync_len = lcdc_info->vsw; + + /* Initialize fbinfo */ + da8xx_fb_info->flags = FBINFO_FLAG_DEFAULT; + da8xx_fb_info->screen_base = par->v_screen_base; + da8xx_fb_info->device = &device->dev; + da8xx_fb_info->fix = da8xx_fb_fix; + da8xx_fb_info->var = da8xx_fb_var; + da8xx_fb_info->fbops = &da8xx_fb_ops; + da8xx_fb_info->pseudo_palette = par->pseudo_palette; + + /* Initialize the Palette */ + ret = init_palette(&device->dev, da8xx_fb_info); + if (ret < 0) + goto err_free_irq; + + ret = fb_alloc_cmap(&da8xx_fb_info->cmap, PALETTE_SIZE, 0); + if (ret) + goto err_free_irq; + + /* Flush the buffer to the screen. */ + lcd_blit(LOAD_DATA, (u32) par->p_palette_base); + + /* initialize var_screeninfo */ + da8xx_fb_var.activate = FB_ACTIVATE_FORCE; + fb_set_var(da8xx_fb_info, &da8xx_fb_var); + + dev_set_drvdata(&device->dev, da8xx_fb_info); + /* Register the Frame Buffer */ + if (register_framebuffer(da8xx_fb_info) < 0) { + dev_err(&device->dev, + "GLCD: Frame Buffer Registration Failed!\n"); + ret = -EINVAL; + goto err_dealloc_cmap; + } + + /* enable raster engine */ + lcdc_write(lcdc_read(LCD_RASTER_CTRL_REG) | + LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); + + return 0; + +err_dealloc_cmap: + fb_dealloc_cmap(&da8xx_fb_info->cmap); + +err_free_irq: + free_irq(par->irq, NULL); + +err_release_fb_mem: + dma_free_coherent(NULL, databuf_sz + PAGE_SIZE, + par->v_frame_buffer_mem_base, + par->p_frame_buffer_mem_base); + +err_release_fb: + framebuffer_release(da8xx_fb_info); + +err_clk_disable: + clk_disable(fb_clk); + +err_clk_put: + clk_put(fb_clk); + + return ret; +} + +static int fb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) +{ + struct lcd_sync_arg sync_arg; + + switch (cmd) { + case FBIOGET_CONTRAST: + case FBIOPUT_CONTRAST: + case FBIGET_BRIGHTNESS: + case FBIPUT_BRIGHTNESS: + case FBIGET_COLOR: + case FBIPUT_COLOR: + return -EINVAL; + case FBIPUT_HSYNC: + if (copy_from_user(&sync_arg, (char *)arg, + sizeof(struct lcd_sync_arg))) + return -EINVAL; + lcd_cfg_horizontal_sync(info->dev, sync_arg.back_porch, + sync_arg.pulse_width, + sync_arg.front_porch); + break; + case FBIPUT_VSYNC: + if (copy_from_user(&sync_arg, (char *)arg, + sizeof(struct lcd_sync_arg))) + return -EINVAL; + lcd_cfg_vertical_sync(info->dev, sync_arg.back_porch, + sync_arg.pulse_width, + sync_arg.front_porch); + break; + default: + return -EINVAL; + } + return 0; +} + +static struct fb_ops da8xx_fb_ops = { + .owner = THIS_MODULE, + .fb_check_var = fb_check_var, + .fb_set_par = fb_set_par, + .fb_setcolreg = fb_setcolreg, + .fb_ioctl = fb_ioctl, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +}; + +#ifdef CONFIG_PM +static int fb_suspend(struct platform_device *dev, pm_message_t state) +{ + return -EBUSY; +} +static int fb_resume(struct platform_device *dev) +{ + return -EBUSY; +} +#else +#define fb_suspend NULL +#define fb_resume NULL +#endif + +static struct platform_driver da8xx_fb_driver = { + .probe = fb_probe, + .remove = fb_remove, + .suspend = fb_suspend, + .resume = fb_resume, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init da8xx_fb_init(void) +{ + return platform_driver_register(&da8xx_fb_driver); +} + +static void __exit da8xx_fb_cleanup(void) +{ + platform_driver_unregister(&da8xx_fb_driver); +} + +module_init(da8xx_fb_init); +module_exit(da8xx_fb_cleanup); + +MODULE_DESCRIPTION("Framebuffer driver for TI da8xx/omap-l1xx"); +MODULE_AUTHOR("MontaVista Software"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/da8xx-fb.h b/include/linux/da8xx-fb.h new file mode 100644 index 0000000..5f77675 --- /dev/null +++ b/include/linux/da8xx-fb.h @@ -0,0 +1,106 @@ +/* + * Header file for TI DA8XX LCD controller platform data. + * + * Copyright (C) 2008-2009 MontaVista Software Inc. + * Copyright (C) 2008-2009 Texas Instruments Inc + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef DA8XX_FB_H +#define DA8XX_FB_H + +enum panel_type { + QVGA = 0 +}; + +enum panel_shade { + MONOCHROME = 0, + COLOR_ACTIVE, + COLOR_PASSIVE, +}; + +enum raster_load_mode { + LOAD_DATA = 1, + LOAD_PALETTE, +}; + +struct display_panel { + enum panel_type panel_type; /* QVGA */ + int max_bpp; + int min_bpp; + enum panel_shade panel_shade; +}; + +struct da8xx_lcdc_platform_data { + const char manu_name[10]; + void *controller_data; + const char type[25]; +}; + +struct lcd_ctrl_config { + const struct display_panel *p_disp_panel; + + /* AC Bias Pin Frequency */ + int ac_bias; + + /* AC Bias Pin Transitions per Interrupt */ + int ac_bias_intrpt; + + /* DMA burst size */ + int dma_burst_sz; + + /* Bits per pixel */ + int bpp; + + /* FIFO DMA Request Delay */ + int fdd; + + /* TFT Alternative Signal Mapping (Only for active) */ + unsigned char tft_alt_mode; + + /* 12 Bit Per Pixel (5-6-5) Mode (Only for passive) */ + unsigned char stn_565_mode; + + /* Mono 8-bit Mode: 1=D0-D7 or 0=D0-D3 */ + unsigned char mono_8bit_mode; + + /* Invert pixel clock */ + unsigned char invert_pxl_clock; + + /* Invert line clock */ + unsigned char invert_line_clock; + + /* Invert frame clock */ + unsigned char invert_frm_clock; + + /* Horizontal and Vertical Sync Edge: 0=rising 1=falling */ + unsigned char sync_edge; + + /* Horizontal and Vertical Sync: Control: 0=ignore */ + unsigned char sync_ctrl; + + /* Raster Data Order Select: 1=Most-to-least 0=Least-to-most */ + unsigned char raster_order; +}; + +struct lcd_sync_arg { + int back_porch; + int front_porch; + int pulse_width; +}; + +/* ioctls */ +#define FBIOGET_CONTRAST _IOR('F', 1, int) +#define FBIOPUT_CONTRAST _IOW('F', 2, int) +#define FBIGET_BRIGHTNESS _IOR('F', 3, int) +#define FBIPUT_BRIGHTNESS _IOW('F', 3, int) +#define FBIGET_COLOR _IOR('F', 5, int) +#define FBIPUT_COLOR _IOW('F', 6, int) +#define FBIPUT_HSYNC _IOW('F', 9, int) +#define FBIPUT_VSYNC _IOW('F', 10, int) + +#endif /* ifndef DA8XX_FB_H */ + -- 1.5.6 |
From: Imre Deak <imre.deak@no...> - 2009-06-17 10:25:52
|
On Tue, Jun 16, 2009 at 06:58:25PM +0200, ext Krzysztof Helt wrote: > On Thu, 11 Jun 2009 15:02:06 +0300 > Imre Deak <imre.deak@...> wrote: > > > Hi, > > > > the following pull request is for the patchset updated based on your comments: > > > > The following changes since commit 07a2039b8eb0af4ff464efd3dfd95de5c02648c6: > > Linus Torvalds (1): > > Linux 2.6.30 > > > > are available in the git repository at: > > > > git://koowaldah.org/people/imre/linux-2.6-fb master > > > > Daniel Stone (1): > > omapfb: dispc: Allow multiple external IRQ handlers > > > > Hunyue Yau (1): > > omapfb: Add support for the 2430SDP LCD > > > > Imre Deak (5): > > omapfb: Add support for MIPI-DCS compatible LCDs > > N770: Enable LCD MIPI-DCS in Kconfig > > omapfb: dispc: Various typo fixes > > omapfb: Add FB manual update option to Kconfig > > omapfb: HWA742: fix pointer to be const > > > > Jonathan McDowell (1): > > omapfb: Add support for the Amstrad Delta LCD > > > > Jouni Hogander (2): > > omapfb: dispc: Disable iface clocks along with func clocks > > omapfb: dispc: Enable wake up capability > > > > Jouni Högander (1): > > omapfb: suspend/resume only if FB device is already initialized > > > > Kevin Hilman (1): > > omapfb: Add support for the 3430SDP LCD > > > > Koen Kooi (1): > > omapfb: Add support for the OMAP3 Beagle DVI output > > > > Kyungmin Park (1): > > omapfb: Add support for the Apollon LCD > > > > Rodrigo Vivi (1): > > omapfb: Add support for rotation on the Blizzard LCD ctrl > > > > Stanley.Miao (1): > > omapfb: Add support for the ZOOM MDK LCD > > > > Steve Sakoman (2): > > omapfb: Add support for the OMAP3 EVM LCD > > omapfb: Add support for the Gumstix Overo LCD > > > > arun c (2): > > omapfb: Add support for the OMAP2EVM LCD > > omapfb: Fix coding style / remove dead line > > > > arch/arm/configs/n770_defconfig | 2 +- > > arch/arm/configs/omap3_beagle_defconfig | 47 ++- > > arch/arm/configs/omap_3430sdp_defconfig | 39 ++- > > arch/arm/configs/omap_ldp_defconfig | 54 +++- > > arch/arm/plat-omap/include/mach/lcd_mipid.h | 5 + > > arch/arm/plat-omap/include/mach/omapfb.h | 4 +- > > drivers/video/omap/Kconfig | 82 +++- > > drivers/video/omap/Makefile | 12 + > > drivers/video/omap/blizzard.c | 91 ++++- > > drivers/video/omap/dispc.c | 130 ++++--- > > drivers/video/omap/dispc.h | 7 +- > > drivers/video/omap/hwa742.c | 2 +- > > drivers/video/omap/lcd_2430sdp.c | 200 +++++++++ > > drivers/video/omap/lcd_ams_delta.c | 137 ++++++ > > drivers/video/omap/lcd_apollon.c | 138 ++++++ > > drivers/video/omap/lcd_ldp.c | 200 +++++++++ > > drivers/video/omap/lcd_mipid.c | 625 +++++++++++++++++++++++++++ > > drivers/video/omap/lcd_omap2evm.c | 189 ++++++++ > > drivers/video/omap/lcd_omap3beagle.c | 133 ++++++ > > drivers/video/omap/lcd_omap3evm.c | 191 ++++++++ > > drivers/video/omap/lcd_overo.c | 179 ++++++++ > > drivers/video/omap/omapfb_main.c | 64 ++- > > drivers/video/omap/rfbi.c | 7 +- > > 23 files changed, 2424 insertions(+), 114 deletions(-) > > create mode 100644 drivers/video/omap/lcd_2430sdp.c > > create mode 100644 drivers/video/omap/lcd_ams_delta.c > > create mode 100644 drivers/video/omap/lcd_apollon.c > > create mode 100644 drivers/video/omap/lcd_ldp.c > > create mode 100644 drivers/video/omap/lcd_mipid.c > > create mode 100644 drivers/video/omap/lcd_omap2evm.c > > create mode 100644 drivers/video/omap/lcd_omap3beagle.c > > create mode 100644 drivers/video/omap/lcd_omap3evm.c > > create mode 100644 drivers/video/omap/lcd_overo.c > > > > I assume you introduced small changes after my review. > > For the whole patchset: > > Acked-by: Krzysztof Helt <krzysztof.h1@...> Yes, I've updated the patchset based on our discussion. I've also added your acked-by line. --Imre |
From: Mikulas Patocka <mpatocka@re...> - 2009-06-17 10:16:25
|
On my card, the accelerator corrupts display if its line length is not multiple of 64 bytes. Misaligned lines in the drawn recrangle are shifted left, as if the accelerator thought that every line begins on 64-byte boundary. For example, in 800x600x8 (scanlines are aligned on 32 bytes) every odd scanline is drawn shifted by 32 bytes to the left. The card is ATI Technologies Inc 3D Rage Pro 215GP (rev 5c) onboard on Sparc64 Ultra 5. This patch disables accelerator if scanline is not multiple of 64 bytes. I don't have any other cards to test. If someone tests that his card doesn't have this bug, he can whitelist it. (note: if you find a better place where to disable the accelerator on non-conforming modes, do it there) Signed-off-by: Mikulas Patocka <mpatocka@... --- drivers/video/aty/mach64_accel.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) Index: linux-2.6.30-fast/drivers/video/aty/mach64_accel.c =================================================================== --- linux-2.6.30-fast.orig/drivers/video/aty/mach64_accel.c 2009-06-17 08:49:01.000000000 +0200 +++ linux-2.6.30-fast/drivers/video/aty/mach64_accel.c 2009-06-17 10:46:03.000000000 +0200 @@ -35,6 +35,14 @@ static u32 rotation24bpp(u32 dx, u32 dir return ((rotation << 8) | DST_24_ROTATION_ENABLE); } +static inline int no_accel(struct fb_info *info) +{ + /* + * The lines must be aligned on 64-byte boundary. + */ + return (info->var.xres_virtual * ((info->var.bits_per_pixel + 7) >> 3)) & 63; +} + void aty_reset_engine(const struct atyfb_par *par) { /* reset engine */ @@ -199,7 +207,7 @@ void atyfb_copyarea(struct fb_info *info return; if (!area->width || !area->height) return; - if (!par->accel_flags) { + if (!par->accel_flags || no_accel(info)) { cfb_copyarea(info, area); return; } @@ -245,7 +253,7 @@ void atyfb_fillrect(struct fb_info *info return; if (!rect->width || !rect->height) return; - if (!par->accel_flags) { + if (!par->accel_flags || no_accel(info)) { cfb_fillrect(info, rect); return; } @@ -285,7 +293,7 @@ void atyfb_imageblit(struct fb_info *inf return; if (!image->width || !image->height) return; - if (!par->accel_flags || + if (!par->accel_flags || no_accel(info) || (image->depth != 1 && info->var.bits_per_pixel != image->depth)) { cfb_imageblit(info, image); return; |
From: Mikulas Patocka <mpatocka@re...> - 2009-06-17 10:00:56
|
Use the same color-calculating algorithm as in atyfb_imageblit in this driver or in generic cfb_fillrect. This patch fixes bad colors when using an accelerator in 15-bit and 16-bit modes. Signed-off-by: Mikulas Patocka <mpatocka@... --- drivers/video/aty/mach64_accel.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) Index: linux-2.6.30-fast/drivers/video/aty/mach64_accel.c =================================================================== --- linux-2.6.30-fast.orig/drivers/video/aty/mach64_accel.c 2009-06-15 21:42:10.000000000 +0200 +++ linux-2.6.30-fast/drivers/video/aty/mach64_accel.c 2009-06-17 08:49:01.000000000 +0200 @@ -239,7 +239,7 @@ void atyfb_copyarea(struct fb_info *info void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct atyfb_par *par = (struct atyfb_par *) info->par; - u32 color = rect->color, dx = rect->dx, width = rect->width, rotation = 0; + u32 color, dx = rect->dx, width = rect->width, rotation = 0; if (par->asleep) return; @@ -250,8 +250,11 @@ void atyfb_fillrect(struct fb_info *info return; } - color |= (rect->color << 8); - color |= (rect->color << 16); + if (info->fix.visual == FB_VISUAL_TRUECOLOR || + info->fix.visual == FB_VISUAL_DIRECTCOLOR) + color = ((u32 *)(info->pseudo_palette))[rect->color]; + else + color = rect->color; if (info->var.bits_per_pixel == 24) { /* In 24 bpp, the engine is in 8 bpp - this requires that all */ |