You can subscribe to this list here.
2001 |
Jan
|
Feb
|
Mar
(1) |
Apr
(104) |
May
(81) |
Jun
(248) |
Jul
(133) |
Aug
(33) |
Sep
(53) |
Oct
(82) |
Nov
(166) |
Dec
(71) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2002 |
Jan
(121) |
Feb
(42) |
Mar
(39) |
Apr
(84) |
May
(87) |
Jun
(58) |
Jul
(97) |
Aug
(130) |
Sep
(32) |
Oct
(139) |
Nov
(108) |
Dec
(216) |
2003 |
Jan
(299) |
Feb
(136) |
Mar
(392) |
Apr
(141) |
May
(137) |
Jun
(107) |
Jul
(94) |
Aug
(262) |
Sep
(300) |
Oct
(216) |
Nov
(72) |
Dec
(94) |
2004 |
Jan
(174) |
Feb
(192) |
Mar
(215) |
Apr
(314) |
May
(319) |
Jun
(293) |
Jul
(205) |
Aug
(161) |
Sep
(192) |
Oct
(226) |
Nov
(308) |
Dec
(89) |
2005 |
Jan
(127) |
Feb
(269) |
Mar
(588) |
Apr
(106) |
May
(77) |
Jun
(77) |
Jul
(161) |
Aug
(239) |
Sep
(86) |
Oct
(112) |
Nov
(153) |
Dec
(145) |
2006 |
Jan
(87) |
Feb
(57) |
Mar
(129) |
Apr
(109) |
May
(102) |
Jun
(232) |
Jul
(97) |
Aug
(69) |
Sep
(67) |
Oct
(69) |
Nov
(214) |
Dec
(82) |
2007 |
Jan
(133) |
Feb
(307) |
Mar
(121) |
Apr
(171) |
May
(229) |
Jun
(156) |
Jul
(185) |
Aug
(160) |
Sep
(122) |
Oct
(130) |
Nov
(78) |
Dec
(27) |
2008 |
Jan
(105) |
Feb
(137) |
Mar
(146) |
Apr
(148) |
May
(239) |
Jun
(208) |
Jul
(157) |
Aug
(244) |
Sep
(119) |
Oct
(125) |
Nov
(189) |
Dec
(225) |
2009 |
Jan
(157) |
Feb
(139) |
Mar
(106) |
Apr
(130) |
May
(246) |
Jun
(189) |
Jul
(128) |
Aug
(127) |
Sep
(88) |
Oct
(86) |
Nov
(216) |
Dec
(9) |
2010 |
Jan
(5) |
Feb
|
Mar
(11) |
Apr
(31) |
May
(3) |
Jun
|
Jul
(7) |
Aug
|
Sep
(1) |
Oct
|
Nov
(1) |
Dec
|
2012 |
Jan
|
Feb
|
Mar
(3) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2013 |
Jan
(1) |
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Giuseppe C. <cj...@cr...> - 2009-05-27 18:59:02
|
This patch adds support for GXT4000P and GXT6500P cards found on some IBM pSeries machines. GXT4000P/6000P and GXT4500P/6500P couples are identical from software's point of view and are based on the same Raster Engine (RC1000), except for a different reference clock for the PLL. GXT6x00P models are equipped with an additional Geometry Engine (GT1000) but this driver doesn't use it. Regards, Giuseppe Signed-off-by: Nico Macrionitis <ac...@cr...> Signed-off-by: Giuseppe Coviello <cj...@cr...> --- /usr/src/linux-2.6.30-rc3/drivers/video/Kconfig 2009-04-22 05:07:00.000000000 +0200 +++ Kconfig 2009-05-05 10:55:17.000000000 +0200 @@ -1985,8 +1985,10 @@ select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT ---help--- - Say Y here to enable support for the IBM GXT4500P display - adaptor, found on some IBM System P (pSeries) machines. + Say Y here to enable support for the IBM GXT4000P/6000P and + GXT4500P/6500P display adaptor based on Raster Engine RC1000, + found on some IBM System P (pSeries) machines. This driver + doesn't use Geometry Engine GT1000. config FB_PS3 tristate "PS3 GPU framebuffer driver" --- /usr/src/linux-2.6.30-rc3/drivers/video/gxt4500.c 2009-04-22 05:07:00.000000000 +0200 +++ gxt4500c 2009-05-05 10:47:41.000000000 +0200 @@ -1,6 +1,7 @@ /* - * Frame buffer device for IBM GXT4500P and GXT6000P display adaptors - * + * Frame buffer device for IBM GXT4500P/6500P and GXT4000P/6000P + * display adaptors + * * Copyright (C) 2006 Paul Mackerras, IBM Corp. <pa...@sa...> */ @@ -14,6 +15,8 @@ #include <linux/string.h> #define PCI_DEVICE_ID_IBM_GXT4500P 0x21c +#define PCI_DEVICE_ID_IBM_GXT6500P 0x21b +#define PCI_DEVICE_ID_IBM_GXT4000P 0x16e #define PCI_DEVICE_ID_IBM_GXT6000P 0x170 /* GXT4500P registers */ @@ -173,6 +176,8 @@ /* List of supported cards */ enum gxt_cards { GXT4500P, + GXT6500P, + GXT4000P, GXT6000P }; @@ -182,6 +187,8 @@ const char *cardname; } cardinfo[] = { [GXT4500P] = { .refclk_ps = 9259, .cardname = "IBM GXT4500P" }, + [GXT6500P] = { .refclk_ps = 9259, .cardname = "IBM GXT6500P" }, + [GXT4000P] = { .refclk_ps = 40000, .cardname = "IBM GXT4000P" }, [GXT6000P] = { .refclk_ps = 40000, .cardname = "IBM GXT6000P" }, }; @@ -736,6 +743,10 @@ static const struct pci_device_id gxt4500_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT4500P), .driver_data = GXT4500P }, + { PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT6500P), + .driver_data = GXT6500P }, + { PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT4000P), + .driver_data = GXT4000P }, { PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT6000P), .driver_data = GXT6000P }, { 0 } @@ -768,7 +779,7 @@ module_exit(gxt4500_exit); MODULE_AUTHOR("Paul Mackerras <pa...@sa...>"); -MODULE_DESCRIPTION("FBDev driver for IBM GXT4500P/6000P"); +MODULE_DESCRIPTION("FBDev driver for IBM GXT4500P/6500P and GXT4000P/6000P"); MODULE_LICENSE("GPL"); module_param(mode_option, charp, 0); MODULE_PARM_DESC(mode_option, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\""); |
From: H H. S. <har...@vi...> - 2009-05-27 16:35:35
|
On Tuesday, May 26, 2009 8:05 PM, Ryan Mallon wrote: >>> This patch adds support for the ep93xx framebuffer. Patch is against >>> arm ep93xx branch. >>> >>> Can anybody with ep93xx hardware please test, specifically with regard >>> to the physical address bit 27 bug. My hardware has the bug, but I'm >>> not sure about other ep93xx chips. >> >> I have not seen the address bit 27 bug on my custom hardware with >> EP9307 Rev E0 silicon. > > Have you had the driver allocate a physical memory address which has bit > 27 set? I'm basically wondering whether to enable the check by default > or not. If the problem only exists on a few ep93xx chips then it may be > better to leave the check off by default. I just thought about it... On my platform it's impossible to allocate a physical memory address which has bit 27 set. My board has 64MB SDRAM on SDCE0 and the bootloader is setting the SROMLL bit when configuring the SDRAM controller. This results in my SDRAM getting physically mapped to: 0xc0000000 - 0xc1ffffff 0xc4000000 - 0xc5ffffff Looking at the various SDRAM address mappings it appears the only way to get a physical address with bit 27 set is to have SROMLL = 0. This is generally not a good idea because the SDRAM gets very segmented with certain memory configurations. Refer to the following document for more information: http://arm.cirrus.com/files/HOWTO/EP93xx%20SDRAM%20Address%20Ranges.pdf >>> + >>> +static struct platform_device ep93xx_fb_device = { >>> + .name = "ep93xxfb", >>> + .id = 0, >> >> Since there can only be one framebuffer device how about using >> .id = -1? This will change the clk dev_id to "ep93xxfb". Also, >> maybe change the name to "ep93xx-fb", that's how the usb host is >> named. > > Will fix both. Ok. You might need to change the name in the driver also. >>> + .dev.platform_data = &ep93xxfb_data, >>> + .dev.coherent_dma_mask = 0xf7ffffff, >> >> I think this is supposed to be >> >> .dev.coherent_dma_mask = DMA_BIT_MASK(32), >> >> Or is the missing bit due to the address bit 27 bug? > > Yeah, its for bit 27. Not sure how to handle this correctly if the check > is a driver option. If you don't have this problem, just change it to > DMA_BIT_MASK(32) for testing. I have been using DMA_BIT_MASK(32) for quite a while with no problems. Isn't there also supposed to be a: .dev.dma_mask = &ep93xx_fb_device.dev.coherent_dma_mask, in the platform_device struct? Look at the ep93xx_ohci_device for reference. Regards, Hartley |
From: Eric M. <eri...@gm...> - 2009-05-27 08:21:19
|
Hi Krzysztof, Sorry for late reply, and thanks for the time reviewing this. See the revised version below with changes: 1. removed the unnecessary error checking of pseudo color in check_var(). The pseudo color mode is actually be well supported. 2. determine_best_pix_fmt() moved into check_var(), and set_pix_fmt() is called to ensure a correct var. 3. set_graphics_start() removed from set_par 4. removed duplicate fields in pxa168fb_info and fb_info 5. correct the error exiting path 6. add __init attribute to pxa168fb_init_mode() ===================>8======================= >From 27a53df0467f379de5ca2d6d117852fbaf93c2fc Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek <bu...@ma...> Date: Wed, 11 Feb 2009 17:25:24 +0800 Subject: [PATCH] fb: add support of LCD display controller on pxa168/910 (base layer) This driver is originally written by Lennert, modified by Green to be feature complete, and ported by Jun Nie and Kevin Liu for pxa168/910 processors. The patch adds support for the on-chip LCD display controller, it currently supports the base (graphics) layer only. Signed-off-by: Lennert Buytenhek <bu...@ma...> Signed-off-by: Green Wan <gw...@ma...> Cc: Peter Liao <pl...@ma...> Signed-off-by: Jun Nie <nj...@ma...> Signed-off-by: Kevin Liu <kl...@ma...> Signed-off-by: Eric Miao <eri...@ma...> --- drivers/video/Kconfig | 10 + drivers/video/Makefile | 1 + drivers/video/pxa168fb.c | 803 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/video/pxa168fb.h | 558 ++++++++++++++++++++++++++++++++ include/video/pxa168fb.h | 127 ++++++++ 5 files changed, 1499 insertions(+), 0 deletions(-) create mode 100644 drivers/video/pxa168fb.c create mode 100644 drivers/video/pxa168fb.h create mode 100644 include/video/pxa168fb.h diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 0048f11..13fd66a 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1759,6 +1759,16 @@ config FB_68328 Say Y here if you want to support the built-in frame buffer of the Motorola 68328 CPU family. +config FB_PXA168 + tristate "PXA168/910 LCD framebuffer support" + depends on FB && (CPU_PXA168 || CPU_PXA910) + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + Frame buffer driver for the built-in LCD controller in the Marvell + MMP processor. + config FB_PXA tristate "PXA LCD framebuffer support" depends on FB && ARCH_PXA diff --git a/drivers/video/Makefile b/drivers/video/Makefile index d8d0be5..01a819f 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -97,6 +97,7 @@ obj-$(CONFIG_FB_GBE) += gbefb.o obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o obj-$(CONFIG_FB_PXA) += pxafb.o +obj-$(CONFIG_FB_PXA168) += pxa168fb.o obj-$(CONFIG_FB_W100) += w100fb.o obj-$(CONFIG_FB_TMIO) += tmiofb.o obj-$(CONFIG_FB_AU1100) += au1100fb.o diff --git a/drivers/video/pxa168fb.c b/drivers/video/pxa168fb.c new file mode 100644 index 0000000..84d8327 --- /dev/null +++ b/drivers/video/pxa168fb.c @@ -0,0 +1,803 @@ +/* + * linux/drivers/video/pxa168fb.c -- Marvell PXA168 LCD Controller + * + * Copyright (C) 2008 Marvell International Ltd. + * All rights reserved. + * + * 2009-02-16 adapted from original version for PXA168/910 + * Jun Nie <nj...@ma...> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/fb.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/uaccess.h> +#include <video/pxa168fb.h> + +#include "pxa168fb.h" + +#define DEFAULT_REFRESH 60 /* Hz */ + +static int determine_best_pix_fmt(struct fb_var_screeninfo *var) +{ + /* + * Pseudocolor mode? + */ + if (var->bits_per_pixel == 8) + return PIX_FMT_PSEUDOCOLOR; + + /* + * Check for 565/1555. + */ + if (var->bits_per_pixel == 16 && var->red.length <= 5 && + var->green.length <= 6 && var->blue.length <= 5) { + if (var->transp.length == 0) { + if (var->red.offset >= var->blue.offset) + return PIX_FMT_RGB565; + else + return PIX_FMT_BGR565; + } + + if (var->transp.length == 1 && var->green.length <= 5) { + if (var->red.offset >= var->blue.offset) + return PIX_FMT_RGB1555; + else + return PIX_FMT_BGR1555; + } + + /* fall through */ + } + + /* + * Check for 888/A888. + */ + if (var->bits_per_pixel <= 32 && var->red.length <= 8 && + var->green.length <= 8 && var->blue.length <= 8) { + if (var->bits_per_pixel == 24 && var->transp.length == 0) { + if (var->red.offset >= var->blue.offset) + return PIX_FMT_RGB888PACK; + else + return PIX_FMT_BGR888PACK; + } + + if (var->bits_per_pixel == 32 && var->transp.length == 8) { + if (var->red.offset >= var->blue.offset) + return PIX_FMT_RGBA888; + else + return PIX_FMT_BGRA888; + } else { + if (var->red.offset >= var->blue.offset) + return PIX_FMT_RGB888UNPACK; + else + return PIX_FMT_BGR888UNPACK; + } + + /* fall through */ + } + + return -EINVAL; +} + +static void set_pix_fmt(struct fb_var_screeninfo *var, int pix_fmt) +{ + switch (pix_fmt) { + case PIX_FMT_RGB565: + var->bits_per_pixel = 16; + var->red.offset = 11; var->red.length = 5; + var->green.offset = 5; var->green.length = 6; + var->blue.offset = 0; var->blue.length = 5; + var->transp.offset = 0; var->transp.length = 0; + break; + case PIX_FMT_BGR565: + var->bits_per_pixel = 16; + 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; + case PIX_FMT_RGB1555: + var->bits_per_pixel = 16; + var->red.offset = 10; var->red.length = 5; + var->green.offset = 5; var->green.length = 5; + var->blue.offset = 0; var->blue.length = 5; + var->transp.offset = 15; var->transp.length = 1; + break; + case PIX_FMT_BGR1555: + var->bits_per_pixel = 16; + var->red.offset = 0; var->red.length = 5; + var->green.offset = 5; var->green.length = 5; + var->blue.offset = 10; var->blue.length = 5; + var->transp.offset = 15; var->transp.length = 1; + break; + case PIX_FMT_RGB888PACK: + var->bits_per_pixel = 24; + var->red.offset = 16; var->red.length = 8; + var->green.offset = 8; var->green.length = 8; + var->blue.offset = 0; var->blue.length = 8; + var->transp.offset = 0; var->transp.length = 0; + break; + case PIX_FMT_BGR888PACK: + var->bits_per_pixel = 24; + var->red.offset = 0; var->red.length = 8; + var->green.offset = 8; var->green.length = 8; + var->blue.offset = 16; var->blue.length = 8; + var->transp.offset = 0; var->transp.length = 0; + break; + case PIX_FMT_RGBA888: + var->bits_per_pixel = 32; + var->red.offset = 16; var->red.length = 8; + var->green.offset = 8; var->green.length = 8; + var->blue.offset = 0; var->blue.length = 8; + var->transp.offset = 24; var->transp.length = 8; + break; + case PIX_FMT_BGRA888: + var->bits_per_pixel = 32; + var->red.offset = 0; var->red.length = 8; + var->green.offset = 8; var->green.length = 8; + var->blue.offset = 16; var->blue.length = 8; + var->transp.offset = 24; var->transp.length = 8; + break; + case PIX_FMT_PSEUDOCOLOR: + var->bits_per_pixel = 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; + } +} + +static void set_mode(struct pxa168fb_info *fbi, struct fb_var_screeninfo *var, + struct fb_videomode *mode, int pix_fmt, int ystretch) +{ + struct fb_info *info = fbi->info; + + set_pix_fmt(var, pix_fmt); + + var->xres = mode->xres; + var->yres = mode->yres; + var->xres_virtual = max(var->xres, var->xres_virtual); + if (ystretch) + var->yres_virtual = info->fix.smem_len / + (var->xres_virtual * (var->bits_per_pixel >> 3)); + else + var->yres_virtual = max(var->yres, var->yres_virtual); + var->grayscale = 0; + var->accel_flags = FB_ACCEL_NONE; + var->pixclock = mode->pixclock; + var->left_margin = mode->left_margin; + var->right_margin = mode->right_margin; + var->upper_margin = mode->upper_margin; + var->lower_margin = mode->lower_margin; + var->hsync_len = mode->hsync_len; + var->vsync_len = mode->vsync_len; + var->sync = mode->sync; + var->vmode = FB_VMODE_NONINTERLACED; + var->rotate = FB_ROTATE_UR; +} + +static int pxa168fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct pxa168fb_info *fbi = info->par; + int pix_fmt; + + /* + * Determine which pixel format we're going to use. + */ + pix_fmt = determine_best_pix_fmt(var); + if (pix_fmt < 0) + return pix_fmt; + set_pix_fmt(var, pix_fmt); + fbi->pix_fmt = pix_fmt; + + /* + * Basic geometry sanity checks. + */ + if (var->xoffset + var->xres > var->xres_virtual) + return -EINVAL; + if (var->yoffset + var->yres > var->yres_virtual) + return -EINVAL; + if (var->xres + var->right_margin + + var->hsync_len + var->left_margin > 2048) + return -EINVAL; + if (var->yres + var->lower_margin + + var->vsync_len + var->upper_margin > 2048) + return -EINVAL; + + /* + * Check size of framebuffer. + */ + if (var->xres_virtual * var->yres_virtual * + (var->bits_per_pixel >> 3) > info->fix.smem_len) + return -EINVAL; + + return 0; +} + +/* + * The hardware clock divider has an integer and a fractional + * stage: + * + * clk2 = clk_in / integer_divider + * clk_out = clk2 * (1 - (fractional_divider >> 12)) + * + * Calculate integer and fractional divider for given clk_in + * and clk_out. + */ +static void set_clock_divider(struct pxa168fb_info *fbi, + const struct fb_videomode *m) +{ + int divider_int; + int needed_pixclk; + u64 div_result; + u32 x = 0; + + /* + * Notice: The field pixclock is used by linux fb + * is in pixel second. E.g. struct fb_videomode & + * struct fb_var_screeninfo + */ + + /* + * Check input values. + */ + if (!m || !m->pixclock || !m->refresh) { + dev_err(fbi->dev, "Input refresh or pixclock is wrong.\n"); + return; + } + + /* + * Using PLL/AXI clock. + */ + x = 0x80000000; + + /* + * Calc divider according to refresh rate. + */ + div_result = 1000000000000ll; + do_div(div_result, m->pixclock); + needed_pixclk = (u32)div_result; + + divider_int = clk_get_rate(fbi->clk) / needed_pixclk; + + /* check whether divisor is too small. */ + if (divider_int < 2) { + dev_warn(fbi->dev, "Warning: clock source is too slow." + "Try smaller resolution\n"); + divider_int = 2; + } + + /* + * Set setting to reg. + */ + x |= divider_int; + writel(x, fbi->reg_base + LCD_CFG_SCLK_DIV); +} + +static void set_dma_control0(struct pxa168fb_info *fbi) +{ + u32 x; + + /* + * Set bit to enable graphics DMA. + */ + x = readl(fbi->reg_base + LCD_SPU_DMA_CTRL0); + x |= fbi->active ? 0x00000100 : 0; + fbi->active = 0; + + /* + * If we are in a pseudo-color mode, we need to enable + * palette lookup. + */ + if (fbi->pix_fmt == PIX_FMT_PSEUDOCOLOR) + x |= 0x10000000; + + /* + * Configure hardware pixel format. + */ + x &= ~(0xF << 16); + x |= (fbi->pix_fmt >> 1) << 16; + + /* + * Check red and blue pixel swap. + * 1. source data swap + * 2. panel output data swap + */ + x &= ~(1 << 12); + x |= ((fbi->pix_fmt & 1) ^ (fbi->panel_rbswap)) << 12; + + writel(x, fbi->reg_base + LCD_SPU_DMA_CTRL0); +} + +static void set_dma_control1(struct pxa168fb_info *fbi, int sync) +{ + u32 x; + + /* + * Configure default bits: vsync triggers DMA, gated clock + * enable, power save enable, configure alpha registers to + * display 100% graphics, and set pixel command. + */ + x = readl(fbi->reg_base + LCD_SPU_DMA_CTRL1); + x |= 0x2032ff81; + + /* + * We trigger DMA on the falling edge of vsync if vsync is + * active low, or on the rising edge if vsync is active high. + */ + if (!(sync & FB_SYNC_VERT_HIGH_ACT)) + x |= 0x08000000; + + writel(x, fbi->reg_base + LCD_SPU_DMA_CTRL1); +} + +static void set_graphics_start(struct fb_info *info, int xoffset, int yoffset) +{ + struct pxa168fb_info *fbi = info->par; + struct fb_var_screeninfo *var = &info->var; + int pixel_offset; + unsigned long addr; + + pixel_offset = (yoffset * var->xres_virtual) + xoffset; + + addr = fbi->fb_start_dma + (pixel_offset * (var->bits_per_pixel >> 3)); + writel(addr, fbi->reg_base + LCD_CFG_GRA_START_ADDR0); +} + +static void set_dumb_panel_control(struct fb_info *info) +{ + struct pxa168fb_info *fbi = info->par; + struct pxa168fb_mach_info *mi = fbi->dev->platform_data; + u32 x; + + /* + * Preserve enable flag. + */ + x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL) & 0x00000001; + + x |= (fbi->is_blanked ? 0x7 : mi->dumb_mode) << 28; + x |= mi->gpio_output_data << 20; + x |= mi->gpio_output_mask << 12; + x |= mi->panel_rgb_reverse_lanes ? 0x00000080 : 0; + x |= mi->invert_composite_blank ? 0x00000040 : 0; + x |= (info->var.sync & FB_SYNC_COMP_HIGH_ACT) ? 0x00000020 : 0; + x |= mi->invert_pix_val_ena ? 0x00000010 : 0; + x |= (info->var.sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 0x00000008; + x |= (info->var.sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 0x00000004; + x |= mi->invert_pixclock ? 0x00000002 : 0; + + writel(x, fbi->reg_base + LCD_SPU_DUMB_CTRL); +} + +static void set_dumb_screen_dimensions(struct fb_info *info) +{ + struct pxa168fb_info *fbi = info->par; + struct fb_var_screeninfo *v = &info->var; + int x; + int y; + + x = v->xres + v->right_margin + v->hsync_len + v->left_margin; + y = v->yres + v->lower_margin + v->vsync_len + v->upper_margin; + + writel((y << 16) | x, fbi->reg_base + LCD_SPUT_V_H_TOTAL); +} + +static int pxa168fb_set_par(struct fb_info *info) +{ + struct pxa168fb_info *fbi = info->par; + struct fb_var_screeninfo *var = &info->var; + struct fb_videomode mode; + u32 x; + struct pxa168fb_mach_info *mi; + + mi = fbi->dev->platform_data; + + /* + * Set additional mode info. + */ + if (fbi->pix_fmt == PIX_FMT_PSEUDOCOLOR) + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + else + info->fix.visual = FB_VISUAL_TRUECOLOR; + info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8; + info->fix.ypanstep = var->yres; + + /* + * Disable panel output while we setup the display. + */ + x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL); + writel(x & ~1, fbi->reg_base + LCD_SPU_DUMB_CTRL); + + /* + * Configure global panel parameters. + */ + writel((var->yres << 16) | var->xres, + fbi->reg_base + LCD_SPU_V_H_ACTIVE); + + /* + * convet var to video mode + */ + fb_var_to_videomode(&mode, &info->var); + + /* Calculate clock divisor. */ + set_clock_divider(fbi, &mode); + + /* Configure dma ctrl regs. */ + set_dma_control0(fbi); + set_dma_control1(fbi, info->var.sync); + + /* + * Configure graphics DMA parameters. + */ + x = readl(fbi->reg_base + LCD_CFG_GRA_PITCH); + x = (x & ~0xFFFF) | ((var->xres_virtual * var->bits_per_pixel) >> 3); + writel(x, fbi->reg_base + LCD_CFG_GRA_PITCH); + writel((var->yres << 16) | var->xres, + fbi->reg_base + LCD_SPU_GRA_HPXL_VLN); + writel((var->yres << 16) | var->xres, + fbi->reg_base + LCD_SPU_GZM_HPXL_VLN); + + /* + * Configure dumb panel ctrl regs & timings. + */ + set_dumb_panel_control(info); + set_dumb_screen_dimensions(info); + + writel((var->left_margin << 16) | var->right_margin, + fbi->reg_base + LCD_SPU_H_PORCH); + writel((var->upper_margin << 16) | var->lower_margin, + fbi->reg_base + LCD_SPU_V_PORCH); + + /* + * Re-enable panel output. + */ + x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL); + writel(x | 1, fbi->reg_base + LCD_SPU_DUMB_CTRL); + + return 0; +} + +static unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf) +{ + return ((chan & 0xffff) >> (16 - bf->length)) << bf->offset; +} + +static u32 to_rgb(u16 red, u16 green, u16 blue) +{ + red >>= 8; + green >>= 8; + blue >>= 8; + + return (red << 16) | (green << 8) | blue; +} + +static int +pxa168fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, + unsigned int blue, unsigned int trans, struct fb_info *info) +{ + struct pxa168fb_info *fbi = info->par; + u32 val; + + if (info->var.grayscale) + red = green = blue = (19595 * red + 38470 * green + + 7471 * blue) >> 16; + + if (info->fix.visual == FB_VISUAL_TRUECOLOR && regno < 16) { + val = chan_to_field(red, &info->var.red); + val |= chan_to_field(green, &info->var.green); + val |= chan_to_field(blue , &info->var.blue); + fbi->pseudo_palette[regno] = val; + } + + if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) { + val = to_rgb(red, green, blue); + writel(val, fbi->reg_base + LCD_SPU_SRAM_WRDAT); + writel(0x8300 | regno, fbi->reg_base + LCD_SPU_SRAM_CTRL); + } + + return 0; +} + +static int pxa168fb_blank(int blank, struct fb_info *info) +{ + struct pxa168fb_info *fbi = info->par; + + fbi->is_blanked = (blank == FB_BLANK_UNBLANK) ? 0 : 1; + set_dumb_panel_control(info); + + return 0; +} + +static int pxa168fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + set_graphics_start(info, var->xoffset, var->yoffset); + + return 0; +} + +static irqreturn_t pxa168fb_handle_irq(int irq, void *dev_id) +{ + struct pxa168fb_info *fbi = dev_id; + u32 isr = readl(fbi->reg_base + SPU_IRQ_ISR); + + if ((isr & GRA_FRAME_IRQ0_ENA_MASK)) { + + writel(isr & (~GRA_FRAME_IRQ0_ENA_MASK), + fbi->reg_base + SPU_IRQ_ISR); + + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static struct fb_ops pxa168fb_ops = { + .owner = THIS_MODULE, + .fb_check_var = pxa168fb_check_var, + .fb_set_par = pxa168fb_set_par, + .fb_setcolreg = pxa168fb_setcolreg, + .fb_blank = pxa168fb_blank, + .fb_pan_display = pxa168fb_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +}; + +static int __init pxa168fb_init_mode(struct fb_info *info, + struct pxa168fb_mach_info *mi) +{ + struct pxa168fb_info *fbi = info->par; + struct fb_var_screeninfo *var = &info->var; + int ret = 0; + u32 total_w, total_h, refresh; + u64 div_result; + const struct fb_videomode *m; + + /* + * Set default value + */ + refresh = DEFAULT_REFRESH; + + /* try to find best video mode. */ + m = fb_find_best_mode(&info->var, &info->modelist); + if (m) + fb_videomode_to_var(&info->var, m); + + /* Init settings. */ + var->xres_virtual = var->xres; + var->yres_virtual = info->fix.smem_len / + (var->xres_virtual * (var->bits_per_pixel >> 3)); + dev_dbg(fbi->dev, "pxa168fb: find best mode: res = %dx%d\n", + var->xres, var->yres); + + /* correct pixclock. */ + total_w = var->xres + var->left_margin + var->right_margin + + var->hsync_len; + total_h = var->yres + var->upper_margin + var->lower_margin + + var->vsync_len; + + div_result = 1000000000000ll; + do_div(div_result, total_w * total_h * refresh); + var->pixclock = (u32)div_result; + + return ret; +} + +static int __init pxa168fb_probe(struct platform_device *pdev) +{ + struct pxa168fb_mach_info *mi; + struct fb_info *info = 0; + struct pxa168fb_info *fbi = 0; + struct resource *res; + struct clk *clk; + int irq, ret; + + mi = pdev->dev.platform_data; + if (mi == NULL) { + dev_err(&pdev->dev, "no platform data defined\n"); + return -EINVAL; + } + + clk = clk_get(&pdev->dev, "LCDCLK"); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "unable to get LCDCLK"); + return PTR_ERR(clk); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "no IO memory defined\n"); + return -ENOENT; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "no IRQ defined\n"); + return -ENOENT; + } + + info = framebuffer_alloc(sizeof(struct pxa168fb_info), &pdev->dev); + if (info == NULL) { + clk_put(clk); + return -ENOMEM; + } + + /* Initialize private data */ + fbi = info->par; + fbi->info = info; + fbi->clk = clk; + fbi->dev = info->dev = &pdev->dev; + fbi->panel_rbswap = mi->panel_rbswap; + fbi->is_blanked = 0; + fbi->active = mi->active; + + /* + * Initialise static fb parameters. + */ + info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK | + FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN; + info->node = -1; + strlcpy(info->fix.id, mi->id, 16); + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.type_aux = 0; + info->fix.xpanstep = 0; + info->fix.ypanstep = 0; + info->fix.ywrapstep = 0; + info->fix.mmio_start = res->start; + info->fix.mmio_len = res->end - res->start + 1; + info->fix.accel = FB_ACCEL_NONE; + info->fbops = &pxa168fb_ops; + info->pseudo_palette = fbi->pseudo_palette; + + /* + * Map LCD controller registers. + */ + fbi->reg_base = ioremap_nocache(res->start, res->end - res->start); + if (fbi->reg_base == NULL) { + ret = -ENOMEM; + goto failed; + } + + /* + * Allocate framebuffer memory. + */ + info->fix.smem_len = PAGE_ALIGN(DEFAULT_FB_SIZE); + + info->screen_base = dma_alloc_writecombine(fbi->dev, info->fix.smem_len, + &fbi->fb_start_dma, GFP_KERNEL); + if (info->screen_base == NULL) { + ret = -ENOMEM; + goto failed; + } + + info->fix.smem_start = (unsigned long)fbi->fb_start_dma; + + /* + * Set video mode according to platform data. + */ + set_mode(fbi, &info->var, mi->modes, mi->pix_fmt, 1); + + fb_videomode_to_modelist(mi->modes, mi->num_modes, &info->modelist); + + /* + * init video mode data. + */ + pxa168fb_init_mode(info, mi); + + ret = pxa168fb_check_var(&info->var, info); + if (ret) + goto failed_free_fbmem; + + /* + * Fill in sane defaults. + */ + ret = pxa168fb_check_var(&info->var, info); + if (ret) + goto failed; + + /* + * enable controller clock + */ + clk_enable(fbi->clk); + + pxa168fb_set_par(info); + + /* + * Configure default register values. + */ + writel(0, fbi->reg_base + LCD_SPU_BLANKCOLOR); + writel(mi->io_pin_allocation_mode, fbi->reg_base + SPU_IOPAD_CONTROL); + writel(0, fbi->reg_base + LCD_CFG_GRA_START_ADDR1); + writel(0, fbi->reg_base + LCD_SPU_GRA_OVSA_HPXL_VLN); + writel(0, fbi->reg_base + LCD_SPU_SRAM_PARA0); + writel(CFG_CSB_256x32(0x1)|CFG_CSB_256x24(0x1)|CFG_CSB_256x8(0x1), + fbi->reg_base + LCD_SPU_SRAM_PARA1); + + /* + * Allocate color map. + */ + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { + ret = -ENOMEM; + goto failed_free_clk; + } + + /* + * Register irq handler. + */ + ret = request_irq(irq, pxa168fb_handle_irq, IRQF_SHARED, + info->fix.id, fbi); + if (ret < 0) { + dev_err(&pdev->dev, "unable to request IRQ\n"); + ret = -ENXIO; + goto failed_free_cmap; + } + + /* + * Enable GFX interrupt + */ + writel(GRA_FRAME_IRQ0_ENA(0x1), fbi->reg_base + SPU_IRQ_ENA); + + /* + * Register framebuffer. + */ + ret = register_framebuffer(info); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register pxa168-fb: %d\n", ret); + ret = -ENXIO; + goto failed_free_irq; + } + + platform_set_drvdata(pdev, fbi); + return 0; + +failed_free_irq: + free_irq(irq, fbi); +failed_free_cmap: + fb_dealloc_cmap(&info->cmap); +failed_free_clk: + clk_disable(fbi->clk); +failed_free_fbmem: + dma_free_coherent(fbi->dev, info->fix.smem_len, + info->screen_base, fbi->fb_start_dma); +failed: + kfree(info); + clk_put(clk); + + dev_err(&pdev->dev, "frame buffer device init failed with %d\n", ret); + return ret; +} + +static struct platform_driver pxa168fb_driver = { + .driver = { + .name = "pxa168-fb", + .owner = THIS_MODULE, + }, + .probe = pxa168fb_probe, +}; + +static int __devinit pxa168fb_init(void) +{ + return platform_driver_register(&pxa168fb_driver); +} +module_init(pxa168fb_init); + +MODULE_AUTHOR("Lennert Buytenhek <bu...@ma...> " + "Green Wan <gw...@ma...>"); +MODULE_DESCRIPTION("Framebuffer driver for PXA168/910"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/pxa168fb.h b/drivers/video/pxa168fb.h new file mode 100644 index 0000000..eee0927 --- /dev/null +++ b/drivers/video/pxa168fb.h @@ -0,0 +1,558 @@ +#ifndef __PXA168FB_H__ +#define __PXA168FB_H__ + +/* ------------< LCD register >------------ */ +/* Video Frame 0&1 start address registers */ +#define LCD_SPU_DMA_START_ADDR_Y0 0x00C0 +#define LCD_SPU_DMA_START_ADDR_U0 0x00C4 +#define LCD_SPU_DMA_START_ADDR_V0 0x00C8 +#define LCD_CFG_DMA_START_ADDR_0 0x00CC /* Cmd address */ +#define LCD_SPU_DMA_START_ADDR_Y1 0x00D0 +#define LCD_SPU_DMA_START_ADDR_U1 0x00D4 +#define LCD_SPU_DMA_START_ADDR_V1 0x00D8 +#define LCD_CFG_DMA_START_ADDR_1 0x00DC /* Cmd address */ + +/* YC & UV Pitch */ +#define LCD_SPU_DMA_PITCH_YC 0x00E0 +#define SPU_DMA_PITCH_C(c) ((c) << 16) +#define SPU_DMA_PITCH_Y(y) (y) +#define LCD_SPU_DMA_PITCH_UV 0x00E4 +#define SPU_DMA_PITCH_V(v) ((v) << 16) +#define SPU_DMA_PITCH_U(u) (u) + +/* Video Starting Point on Screen Register */ +#define LCD_SPUT_DMA_OVSA_HPXL_VLN 0x00E8 +#define CFG_DMA_OVSA_VLN(y) ((y) << 16) /* 0~0xfff */ +#define CFG_DMA_OVSA_HPXL(x) (x) /* 0~0xfff */ + +/* Video Size Register */ +#define LCD_SPU_DMA_HPXL_VLN 0x00EC +#define CFG_DMA_VLN(y) ((y) << 16) +#define CFG_DMA_HPXL(x) (x) + +/* Video Size After zooming Register */ +#define LCD_SPU_DZM_HPXL_VLN 0x00F0 +#define CFG_DZM_VLN(y) ((y) << 16) +#define CFG_DZM_HPXL(x) (x) + +/* Graphic Frame 0&1 Starting Address Register */ +#define LCD_CFG_GRA_START_ADDR0 0x00F4 +#define LCD_CFG_GRA_START_ADDR1 0x00F8 + +/* Graphic Frame Pitch */ +#define LCD_CFG_GRA_PITCH 0x00FC + +/* Graphic Starting Point on Screen Register */ +#define LCD_SPU_GRA_OVSA_HPXL_VLN 0x0100 +#define CFG_GRA_OVSA_VLN(y) ((y) << 16) +#define CFG_GRA_OVSA_HPXL(x) (x) + +/* Graphic Size Register */ +#define LCD_SPU_GRA_HPXL_VLN 0x0104 +#define CFG_GRA_VLN(y) ((y) << 16) +#define CFG_GRA_HPXL(x) (x) + +/* Graphic Size after Zooming Register */ +#define LCD_SPU_GZM_HPXL_VLN 0x0108 +#define CFG_GZM_VLN(y) ((y) << 16) +#define CFG_GZM_HPXL(x) (x) + +/* HW Cursor Starting Point on Screen Register */ +#define LCD_SPU_HWC_OVSA_HPXL_VLN 0x010C +#define CFG_HWC_OVSA_VLN(y) ((y) << 16) +#define CFG_HWC_OVSA_HPXL(x) (x) + +/* HW Cursor Size */ +#define LCD_SPU_HWC_HPXL_VLN 0x0110 +#define CFG_HWC_VLN(y) ((y) << 16) +#define CFG_HWC_HPXL(x) (x) + +/* Total Screen Size Register */ +#define LCD_SPUT_V_H_TOTAL 0x0114 +#define CFG_V_TOTAL(y) ((y) << 16) +#define CFG_H_TOTAL(x) (x) + +/* Total Screen Active Size Register */ +#define LCD_SPU_V_H_ACTIVE 0x0118 +#define CFG_V_ACTIVE(y) ((y) << 16) +#define CFG_H_ACTIVE(x) (x) + +/* Screen H&V Porch Register */ +#define LCD_SPU_H_PORCH 0x011C +#define CFG_H_BACK_PORCH(b) ((b) << 16) +#define CFG_H_FRONT_PORCH(f) (f) +#define LCD_SPU_V_PORCH 0x0120 +#define CFG_V_BACK_PORCH(b) ((b) << 16) +#define CFG_V_FRONT_PORCH(f) (f) + +/* Screen Blank Color Register */ +#define LCD_SPU_BLANKCOLOR 0x0124 +#define CFG_BLANKCOLOR_MASK 0x00FFFFFF +#define CFG_BLANKCOLOR_R_MASK 0x000000FF +#define CFG_BLANKCOLOR_G_MASK 0x0000FF00 +#define CFG_BLANKCOLOR_B_MASK 0x00FF0000 + +/* HW Cursor Color 1&2 Register */ +#define LCD_SPU_ALPHA_COLOR1 0x0128 +#define CFG_HWC_COLOR1 0x00FFFFFF +#define CFG_HWC_COLOR1_R(red) ((red) << 16) +#define CFG_HWC_COLOR1_G(green) ((green) << 8) +#define CFG_HWC_COLOR1_B(blue) (blue) +#define CFG_HWC_COLOR1_R_MASK 0x000000FF +#define CFG_HWC_COLOR1_G_MASK 0x0000FF00 +#define CFG_HWC_COLOR1_B_MASK 0x00FF0000 +#define LCD_SPU_ALPHA_COLOR2 0x012C +#define CFG_HWC_COLOR2 0x00FFFFFF +#define CFG_HWC_COLOR2_R_MASK 0x000000FF +#define CFG_HWC_COLOR2_G_MASK 0x0000FF00 +#define CFG_HWC_COLOR2_B_MASK 0x00FF0000 + +/* Video YUV Color Key Control */ +#define LCD_SPU_COLORKEY_Y 0x0130 +#define CFG_CKEY_Y2(y2) ((y2) << 24) +#define CFG_CKEY_Y2_MASK 0xFF000000 +#define CFG_CKEY_Y1(y1) ((y1) << 16) +#define CFG_CKEY_Y1_MASK 0x00FF0000 +#define CFG_CKEY_Y(y) ((y) << 8) +#define CFG_CKEY_Y_MASK 0x0000FF00 +#define CFG_ALPHA_Y(y) (y) +#define CFG_ALPHA_Y_MASK 0x000000FF +#define LCD_SPU_COLORKEY_U 0x0134 +#define CFG_CKEY_U2(u2) ((u2) << 24) +#define CFG_CKEY_U2_MASK 0xFF000000 +#define CFG_CKEY_U1(u1) ((u1) << 16) +#define CFG_CKEY_U1_MASK 0x00FF0000 +#define CFG_CKEY_U(u) ((u) << 8) +#define CFG_CKEY_U_MASK 0x0000FF00 +#define CFG_ALPHA_U(u) (u) +#define CFG_ALPHA_U_MASK 0x000000FF +#define LCD_SPU_COLORKEY_V 0x0138 +#define CFG_CKEY_V2(v2) ((v2) << 24) +#define CFG_CKEY_V2_MASK 0xFF000000 +#define CFG_CKEY_V1(v1) ((v1) << 16) +#define CFG_CKEY_V1_MASK 0x00FF0000 +#define CFG_CKEY_V(v) ((v) << 8) +#define CFG_CKEY_V_MASK 0x0000FF00 +#define CFG_ALPHA_V(v) (v) +#define CFG_ALPHA_V_MASK 0x000000FF + +/* SPI Read Data Register */ +#define LCD_SPU_SPI_RXDATA 0x0140 + +/* Smart Panel Read Data Register */ +#define LCD_SPU_ISA_RSDATA 0x0144 +#define ISA_RXDATA_16BIT_1_DATA_MASK 0x000000FF +#define ISA_RXDATA_16BIT_2_DATA_MASK 0x0000FF00 +#define ISA_RXDATA_16BIT_3_DATA_MASK 0x00FF0000 +#define ISA_RXDATA_16BIT_4_DATA_MASK 0xFF000000 +#define ISA_RXDATA_32BIT_1_DATA_MASK 0x00FFFFFF + +/* HWC SRAM Read Data Register */ +#define LCD_SPU_HWC_RDDAT 0x0158 + +/* Gamma Table SRAM Read Data Register */ +#define LCD_SPU_GAMMA_RDDAT 0x015c +#define CFG_GAMMA_RDDAT_MASK 0x000000FF + +/* Palette Table SRAM Read Data Register */ +#define LCD_SPU_PALETTE_RDDAT 0x0160 +#define CFG_PALETTE_RDDAT_MASK 0x00FFFFFF + +/* I/O Pads Input Read Only Register */ +#define LCD_SPU_IOPAD_IN 0x0178 +#define CFG_IOPAD_IN_MASK 0x0FFFFFFF + +/* Reserved Read Only Registers */ +#define LCD_CFG_RDREG5F 0x017C +#define IRE_FRAME_CNT_MASK 0x000000C0 +#define IPE_FRAME_CNT_MASK 0x00000030 +#define GRA_FRAME_CNT_MASK 0x0000000C /* Graphic */ +#define DMA_FRAME_CNT_MASK 0x00000003 /* Video */ + +/* SPI Control Register. */ +#define LCD_SPU_SPI_CTRL 0x0180 +#define CFG_SCLKCNT(div) ((div) << 24) /* 0xFF~0x2 */ +#define CFG_SCLKCNT_MASK 0xFF000000 +#define CFG_RXBITS(rx) ((rx) << 16) /* 0x1F~0x1 */ +#define CFG_RXBITS_MASK 0x00FF0000 +#define CFG_TXBITS(tx) ((tx) << 8) /* 0x1F~0x1 */ +#define CFG_TXBITS_MASK 0x0000FF00 +#define CFG_CLKINV(clk) ((clk) << 7) +#define CFG_CLKINV_MASK 0x00000080 +#define CFG_KEEPXFER(transfer) ((transfer) << 6) +#define CFG_KEEPXFER_MASK 0x00000040 +#define CFG_RXBITSTO0(rx) ((rx) << 5) +#define CFG_RXBITSTO0_MASK 0x00000020 +#define CFG_TXBITSTO0(tx) ((tx) << 4) +#define CFG_TXBITSTO0_MASK 0x00000010 +#define CFG_SPI_ENA(spi) ((spi) << 3) +#define CFG_SPI_ENA_MASK 0x00000008 +#define CFG_SPI_SEL(spi) ((spi) << 2) +#define CFG_SPI_SEL_MASK 0x00000004 +#define CFG_SPI_3W4WB(wire) ((wire) << 1) +#define CFG_SPI_3W4WB_MASK 0x00000002 +#define CFG_SPI_START(start) (start) +#define CFG_SPI_START_MASK 0x00000001 + +/* SPI Tx Data Register */ +#define LCD_SPU_SPI_TXDATA 0x0184 + +/* + 1. Smart Pannel 8-bit Bus Control Register. + 2. AHB Slave Path Data Port Register +*/ +#define LCD_SPU_SMPN_CTRL 0x0188 + +/* DMA Control 0 Register */ +#define LCD_SPU_DMA_CTRL0 0x0190 +#define CFG_NOBLENDING(nb) ((nb) << 31) +#define CFG_NOBLENDING_MASK 0x80000000 +#define CFG_GAMMA_ENA(gn) ((gn) << 30) +#define CFG_GAMMA_ENA_MASK 0x40000000 +#define CFG_CBSH_ENA(cn) ((cn) << 29) +#define CFG_CBSH_ENA_MASK 0x20000000 +#define CFG_PALETTE_ENA(pn) ((pn) << 28) +#define CFG_PALETTE_ENA_MASK 0x10000000 +#define CFG_ARBFAST_ENA(an) ((an) << 27) +#define CFG_ARBFAST_ENA_MASK 0x08000000 +#define CFG_HWC_1BITMOD(mode) ((mode) << 26) +#define CFG_HWC_1BITMOD_MASK 0x04000000 +#define CFG_HWC_1BITENA(mn) ((mn) << 25) +#define CFG_HWC_1BITENA_MASK 0x02000000 +#define CFG_HWC_ENA(cn) ((cn) << 24) +#define CFG_HWC_ENA_MASK 0x01000000 +#define CFG_DMAFORMAT(dmaformat) ((dmaformat) << 20) +#define CFG_DMAFORMAT_MASK 0x00F00000 +#define CFG_GRAFORMAT(graformat) ((graformat) << 16) +#define CFG_GRAFORMAT_MASK 0x000F0000 +/* for graphic part */ +#define CFG_GRA_FTOGGLE(toggle) ((toggle) << 15) +#define CFG_GRA_FTOGGLE_MASK 0x00008000 +#define CFG_GRA_HSMOOTH(smooth) ((smooth) << 14) +#define CFG_GRA_HSMOOTH_MASK 0x00004000 +#define CFG_GRA_TSTMODE(test) ((test) << 13) +#define CFG_GRA_TSTMODE_MASK 0x00002000 +#define CFG_GRA_SWAPRB(swap) ((swap) << 12) +#define CFG_GRA_SWAPRB_MASK 0x00001000 +#define CFG_GRA_SWAPUV(swap) ((swap) << 11) +#define CFG_GRA_SWAPUV_MASK 0x00000800 +#define CFG_GRA_SWAPYU(swap) ((swap) << 10) +#define CFG_GRA_SWAPYU_MASK 0x00000400 +#define CFG_YUV2RGB_GRA(cvrt) ((cvrt) << 9) +#define CFG_YUV2RGB_GRA_MASK 0x00000200 +#define CFG_GRA_ENA(gra) ((gra) << 8) +#define CFG_GRA_ENA_MASK 0x00000100 +/* for video part */ +#define CFG_DMA_FTOGGLE(toggle) ((toggle) << 7) +#define CFG_DMA_FTOGGLE_MASK 0x00000080 +#define CFG_DMA_HSMOOTH(smooth) ((smooth) << 6) +#define CFG_DMA_HSMOOTH_MASK 0x00000040 +#define CFG_DMA_TSTMODE(test) ((test) << 5) +#define CFG_DMA_TSTMODE_MASK 0x00000020 +#define CFG_DMA_SWAPRB(swap) ((swap) << 4) +#define CFG_DMA_SWAPRB_MASK 0x00000010 +#define CFG_DMA_SWAPUV(swap) ((swap) << 3) +#define CFG_DMA_SWAPUV_MASK 0x00000008 +#define CFG_DMA_SWAPYU(swap) ((swap) << 2) +#define CFG_DMA_SWAPYU_MASK 0x00000004 +#define CFG_DMA_SWAP_MASK 0x0000001C +#define CFG_YUV2RGB_DMA(cvrt) ((cvrt) << 1) +#define CFG_YUV2RGB_DMA_MASK 0x00000002 +#define CFG_DMA_ENA(video) (video) +#define CFG_DMA_ENA_MASK 0x00000001 + +/* DMA Control 1 Register */ +#define LCD_SPU_DMA_CTRL1 0x0194 +#define CFG_FRAME_TRIG(trig) ((trig) << 31) +#define CFG_FRAME_TRIG_MASK 0x80000000 +#define CFG_VSYNC_TRIG(trig) ((trig) << 28) +#define CFG_VSYNC_TRIG_MASK 0x70000000 +#define CFG_VSYNC_INV(inv) ((inv) << 27) +#define CFG_VSYNC_INV_MASK 0x08000000 +#define CFG_COLOR_KEY_MODE(cmode) ((cmode) << 24) +#define CFG_COLOR_KEY_MASK 0x07000000 +#define CFG_CARRY(carry) ((carry) << 23) +#define CFG_CARRY_MASK 0x00800000 +#define CFG_LNBUF_ENA(lnbuf) ((lnbuf) << 22) +#define CFG_LNBUF_ENA_MASK 0x00400000 +#define CFG_GATED_ENA(gated) ((gated) << 21) +#define CFG_GATED_ENA_MASK 0x00200000 +#define CFG_PWRDN_ENA(power) ((power) << 20) +#define CFG_PWRDN_ENA_MASK 0x00100000 +#define CFG_DSCALE(dscale) ((dscale) << 18) +#define CFG_DSCALE_MASK 0x000C0000 +#define CFG_ALPHA_MODE(amode) ((amode) << 16) +#define CFG_ALPHA_MODE_MASK 0x00030000 +#define CFG_ALPHA(alpha) ((alpha) << 8) +#define CFG_ALPHA_MASK 0x0000FF00 +#define CFG_PXLCMD(pxlcmd) (pxlcmd) +#define CFG_PXLCMD_MASK 0x000000FF + +/* SRAM Control Register */ +#define LCD_SPU_SRAM_CTRL 0x0198 +#define CFG_SRAM_INIT_WR_RD(mode) ((mode) << 14) +#define CFG_SRAM_INIT_WR_RD_MASK 0x0000C000 +#define CFG_SRAM_ADDR_LCDID(id) ((id) << 8) +#define CFG_SRAM_ADDR_LCDID_MASK 0x00000F00 +#define CFG_SRAM_ADDR(addr) (addr) +#define CFG_SRAM_ADDR_MASK 0x000000FF + +/* SRAM Write Data Register */ +#define LCD_SPU_SRAM_WRDAT 0x019C + +/* SRAM RTC/WTC Control Register */ +#define LCD_SPU_SRAM_PARA0 0x01A0 + +/* SRAM Power Down Control Register */ +#define LCD_SPU_SRAM_PARA1 0x01A4 +#define CFG_CSB_256x32(hwc) ((hwc) << 15) /* HWC */ +#define CFG_CSB_256x32_MASK 0x00008000 +#define CFG_CSB_256x24(palette) ((palette) << 14) /* Palette */ +#define CFG_CSB_256x24_MASK 0x00004000 +#define CFG_CSB_256x8(gamma) ((gamma) << 13) /* Gamma */ +#define CFG_CSB_256x8_MASK 0x00002000 +#define CFG_PDWN256x32(pdwn) ((pdwn) << 7) /* HWC */ +#define CFG_PDWN256x32_MASK 0x00000080 +#define CFG_PDWN256x24(pdwn) ((pdwn) << 6) /* Palette */ +#define CFG_PDWN256x24_MASK 0x00000040 +#define CFG_PDWN256x8(pdwn) ((pdwn) << 5) /* Gamma */ +#define CFG_PDWN256x8_MASK 0x00000020 +#define CFG_PDWN32x32(pdwn) ((pdwn) << 3) +#define CFG_PDWN32x32_MASK 0x00000008 +#define CFG_PDWN16x66(pdwn) ((pdwn) << 2) +#define CFG_PDWN16x66_MASK 0x00000004 +#define CFG_PDWN32x66(pdwn) ((pdwn) << 1) +#define CFG_PDWN32x66_MASK 0x00000002 +#define CFG_PDWN64x66(pdwn) (pdwn) +#define CFG_PDWN64x66_MASK 0x00000001 + +/* Smart or Dumb Panel Clock Divider */ +#define LCD_CFG_SCLK_DIV 0x01A8 +#define SCLK_SOURCE_SELECT(src) ((src) << 31) +#define SCLK_SOURCE_SELECT_MASK 0x80000000 +#define CLK_FRACDIV(frac) ((frac) << 16) +#define CLK_FRACDIV_MASK 0x0FFF0000 +#define CLK_INT_DIV(div) (div) +#define CLK_INT_DIV_MASK 0x0000FFFF + +/* Video Contrast Register */ +#define LCD_SPU_CONTRAST 0x01AC +#define CFG_BRIGHTNESS(bright) ((bright) << 16) +#define CFG_BRIGHTNESS_MASK 0xFFFF0000 +#define CFG_CONTRAST(contrast) (contrast) +#define CFG_CONTRAST_MASK 0x0000FFFF + +/* Video Saturation Register */ +#define LCD_SPU_SATURATION 0x01B0 +#define CFG_C_MULTS(mult) ((mult) << 16) +#define CFG_C_MULTS_MASK 0xFFFF0000 +#define CFG_SATURATION(sat) (sat) +#define CFG_SATURATION_MASK 0x0000FFFF + +/* Video Hue Adjust Register */ +#define LCD_SPU_CBSH_HUE 0x01B4 +#define CFG_SIN0(sin0) ((sin0) << 16) +#define CFG_SIN0_MASK 0xFFFF0000 +#define CFG_COS0(con0) (con0) +#define CFG_COS0_MASK 0x0000FFFF + +/* Dump LCD Panel Control Register */ +#define LCD_SPU_DUMB_CTRL 0x01B8 +#define CFG_DUMBMODE(mode) ((mode) << 28) +#define CFG_DUMBMODE_MASK 0xF0000000 +#define CFG_LCDGPIO_O(data) ((data) << 20) +#define CFG_LCDGPIO_O_MASK 0x0FF00000 +#define CFG_LCDGPIO_ENA(gpio) ((gpio) << 12) +#define CFG_LCDGPIO_ENA_MASK 0x000FF000 +#define CFG_BIAS_OUT(bias) ((bias) << 8) +#define CFG_BIAS_OUT_MASK 0x00000100 +#define CFG_REVERSE_RGB(rRGB) ((rRGB) << 7) +#define CFG_REVERSE_RGB_MASK 0x00000080 +#define CFG_INV_COMPBLANK(blank) ((blank) << 6) +#define CFG_INV_COMPBLANK_MASK 0x00000040 +#define CFG_INV_COMPSYNC(sync) ((sync) << 5) +#define CFG_INV_COMPSYNC_MASK 0x00000020 +#define CFG_INV_HENA(hena) ((hena) << 4) +#define CFG_INV_HENA_MASK 0x00000010 +#define CFG_INV_VSYNC(vsync) ((vsync) << 3) +#define CFG_INV_VSYNC_MASK 0x00000008 +#define CFG_INV_HSYNC(hsync) ((hsync) << 2) +#define CFG_INV_HSYNC_MASK 0x00000004 +#define CFG_INV_PCLK(pclk) ((pclk) << 1) +#define CFG_INV_PCLK_MASK 0x00000002 +#define CFG_DUMB_ENA(dumb) (dumb) +#define CFG_DUMB_ENA_MASK 0x00000001 + +/* LCD I/O Pads Control Register */ +#define SPU_IOPAD_CONTROL 0x01BC +#define CFG_GRA_VM_ENA(vm) ((vm) << 15) /* gfx */ +#define CFG_GRA_VM_ENA_MASK 0x00008000 +#define CFG_DMA_VM_ENA(vm) ((vm) << 13) /* video */ +#define CFG_DMA_VM_ENA_MASK 0x00002000 +#define CFG_CMD_VM_ENA(vm) ((vm) << 13) +#define CFG_CMD_VM_ENA_MASK 0x00000800 +#define CFG_CSC(csc) ((csc) << 8) /* csc */ +#define CFG_CSC_MASK 0x00000300 +#define CFG_AXICTRL(axi) ((axi) << 4) +#define CFG_AXICTRL_MASK 0x000000F0 +#define CFG_IOPADMODE(iopad) (iopad) +#define CFG_IOPADMODE_MASK 0x0000000F + +/* LCD Interrupt Control Register */ +#define SPU_IRQ_ENA 0x01C0 +#define DMA_FRAME_IRQ0_ENA(irq) ((irq) << 31) +#define DMA_FRAME_IRQ0_ENA_MASK 0x80000000 +#define DMA_FRAME_IRQ1_ENA(irq) ((irq) << 30) +#define DMA_FRAME_IRQ1_ENA_MASK 0x40000000 +#define DMA_FF_UNDERFLOW_ENA(ff) ((ff) << 29) +#define DMA_FF_UNDERFLOW_ENA_MASK 0x20000000 +#define GRA_FRAME_IRQ0_ENA(irq) ((irq) << 27) +#define GRA_FRAME_IRQ0_ENA_MASK 0x08000000 +#define GRA_FRAME_IRQ1_ENA(irq) ((irq) << 26) +#define GRA_FRAME_IRQ1_ENA_MASK 0x04000000 +#define GRA_FF_UNDERFLOW_ENA(ff) ((ff) << 25) +#define GRA_FF_UNDERFLOW_ENA_MASK 0x02000000 +#define VSYNC_IRQ_ENA(vsync_irq) ((vsync_irq) << 23) +#define VSYNC_IRQ_ENA_MASK 0x00800000 +#define DUMB_FRAMEDONE_ENA(fdone) ((fdone) << 22) +#define DUMB_FRAMEDONE_ENA_MASK 0x00400000 +#define TWC_FRAMEDONE_ENA(fdone) ((fdone) << 21) +#define TWC_FRAMEDONE_ENA_MASK 0x00200000 +#define HWC_FRAMEDONE_ENA(fdone) ((fdone) << 20) +#define HWC_FRAMEDONE_ENA_MASK 0x00100000 +#define SLV_IRQ_ENA(irq) ((irq) << 19) +#define SLV_IRQ_ENA_MASK 0x00080000 +#define SPI_IRQ_ENA(irq) ((irq) << 18) +#define SPI_IRQ_ENA_MASK 0x00040000 +#define PWRDN_IRQ_ENA(irq) ((irq) << 17) +#define PWRDN_IRQ_ENA_MASK 0x00020000 +#define ERR_IRQ_ENA(irq) ((irq) << 16) +#define ERR_IRQ_ENA_MASK 0x00010000 +#define CLEAN_SPU_IRQ_ISR(irq) (irq) +#define CLEAN_SPU_IRQ_ISR_MASK 0x0000FFFF + +/* LCD Interrupt Status Register */ +#define SPU_IRQ_ISR 0x01C4 +#define DMA_FRAME_IRQ0(irq) ((irq) << 31) +#define DMA_FRAME_IRQ0_MASK 0x80000000 +#define DMA_FRAME_IRQ1(irq) ((irq) << 30) +#define DMA_FRAME_IRQ1_MASK 0x40000000 +#define DMA_FF_UNDERFLOW(ff) ((ff) << 29) +#define DMA_FF_UNDERFLOW_MASK 0x20000000 +#define GRA_FRAME_IRQ0(irq) ((irq) << 27) +#define GRA_FRAME_IRQ0_MASK 0x08000000 +#define GRA_FRAME_IRQ1(irq) ((irq) << 26) +#define GRA_FRAME_IRQ1_MASK 0x04000000 +#define GRA_FF_UNDERFLOW(ff) ((ff) << 25) +#define GRA_FF_UNDERFLOW_MASK 0x02000000 +#define VSYNC_IRQ(vsync_irq) ((vsync_irq) << 23) +#define VSYNC_IRQ_MASK 0x00800000 +#define DUMB_FRAMEDONE(fdone) ((fdone) << 22) +#define DUMB_FRAMEDONE_MASK 0x00400000 +#define TWC_FRAMEDONE(fdone) ((fdone) << 21) +#define TWC_FRAMEDONE_MASK 0x00200000 +#define HWC_FRAMEDONE(fdone) ((fdone) << 20) +#define HWC_FRAMEDONE_MASK 0x00100000 +#define SLV_IRQ(irq) ((irq) << 19) +#define SLV_IRQ_MASK 0x00080000 +#define SPI_IRQ(irq) ((irq) << 18) +#define SPI_IRQ_MASK 0x00040000 +#define PWRDN_IRQ(irq) ((irq) << 17) +#define PWRDN_IRQ_MASK 0x00020000 +#define ERR_IRQ(irq) ((irq) << 16) +#define ERR_IRQ_MASK 0x00010000 +/* read-only */ +#define DMA_FRAME_IRQ0_LEVEL_MASK 0x00008000 +#define DMA_FRAME_IRQ1_LEVEL_MASK 0x00004000 +#define DMA_FRAME_CNT_ISR_MASK 0x00003000 +#define GRA_FRAME_IRQ0_LEVEL_MASK 0x00000800 +#define GRA_FRAME_IRQ1_LEVEL_MASK 0x00000400 +#define GRA_FRAME_CNT_ISR_MASK 0x00000300 +#define VSYNC_IRQ_LEVEL_MASK 0x00000080 +#define DUMB_FRAMEDONE_LEVEL_MASK 0x00000040 +#define TWC_FRAMEDONE_LEVEL_MASK 0x00000020 +#define HWC_FRAMEDONE_LEVEL_MASK 0x00000010 +#define SLV_FF_EMPTY_MASK 0x00000008 +#define DMA_FF_ALLEMPTY_MASK 0x00000004 +#define GRA_FF_ALLEMPTY_MASK 0x00000002 +#define PWRDN_IRQ_LEVEL_MASK 0x00000001 + + +/* + * defined Video Memory Color format for DMA control 0 register + * DMA0 bit[23:20] + */ +#define VMODE_RGB565 0x0 +#define VMODE_RGB1555 0x1 +#define VMODE_RGB888PACKED 0x2 +#define VMODE_RGB888UNPACKED 0x3 +#define VMODE_RGBA888 0x4 +#define VMODE_YUV422PACKED 0x5 +#define VMODE_YUV422PLANAR 0x6 +#define VMODE_YUV420PLANAR 0x7 +#define VMODE_SMPNCMD 0x8 +#define VMODE_PALETTE4BIT 0x9 +#define VMODE_PALETTE8BIT 0xa +#define VMODE_RESERVED 0xb + +/* + * defined Graphic Memory Color format for DMA control 0 register + * DMA0 bit[19:16] + */ +#define GMODE_RGB565 0x0 +#define GMODE_RGB1555 0x1 +#define GMODE_RGB888PACKED 0x2 +#define GMODE_RGB888UNPACKED 0x3 +#define GMODE_RGBA888 0x4 +#define GMODE_YUV422PACKED 0x5 +#define GMODE_YUV422PLANAR 0x6 +#define GMODE_YUV420PLANAR 0x7 +#define GMODE_SMPNCMD 0x8 +#define GMODE_PALETTE4BIT 0x9 +#define GMODE_PALETTE8BIT 0xa +#define GMODE_RESERVED 0xb + +/* + * define for DMA control 1 register + */ +#define DMA1_FRAME_TRIG 31 /* bit location */ +#define DMA1_VSYNC_MODE 28 +#define DMA1_VSYNC_INV 27 +#define DMA1_CKEY 24 +#define DMA1_CARRY 23 +#define DMA1_LNBUF_ENA 22 +#define DMA1_GATED_ENA 21 +#define DMA1_PWRDN_ENA 20 +#define DMA1_DSCALE 18 +#define DMA1_ALPHA_MODE 16 +#define DMA1_ALPHA 08 +#define DMA1_PXLCMD 00 + +/* + * defined for Configure Dumb Mode + * DUMB LCD Panel bit[31:28] + */ +#define DUMB16_RGB565_0 0x0 +#define DUMB16_RGB565_1 0x1 +#define DUMB18_RGB666_0 0x2 +#define DUMB18_RGB666_1 0x3 +#define DUMB12_RGB444_0 0x4 +#define DUMB12_RGB444_1 0x5 +#define DUMB24_RGB888_0 0x6 +#define DUMB_BLANK 0x7 + +/* + * defined for Configure I/O Pin Allocation Mode + * LCD LCD I/O Pads control register bit[3:0] + */ +#define IOPAD_DUMB24 0x0 +#define IOPAD_DUMB18SPI 0x1 +#define IOPAD_DUMB18GPIO 0x2 +#define IOPAD_DUMB16SPI 0x3 +#define IOPAD_DUMB16GPIO 0x4 +#define IOPAD_DUMB12 0x5 +#define IOPAD_SMART18SPI 0x6 +#define IOPAD_SMART16SPI 0x7 +#define IOPAD_SMART8BOTH 0x8 + +#endif /* __PXA168FB_H__ */ diff --git a/include/video/pxa168fb.h b/include/video/pxa168fb.h new file mode 100644 index 0000000..b5cc72f --- /dev/null +++ b/include/video/pxa168fb.h @@ -0,0 +1,127 @@ +/* + * linux/arch/arm/mach-mmp/include/mach/pxa168fb.h + * + * Copyright (C) 2009 Marvell International Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __ASM_MACH_PXA168FB_H +#define __ASM_MACH_PXA168FB_H + +#include <linux/fb.h> +#include <linux/interrupt.h> + +/* Dumb interface */ +#define PIN_MODE_DUMB_24 0 +#define PIN_MODE_DUMB_18_SPI 1 +#define PIN_MODE_DUMB_18_GPIO 2 +#define PIN_MODE_DUMB_16_SPI 3 +#define PIN_MODE_DUMB_16_GPIO 4 +#define PIN_MODE_DUMB_12_SPI_GPIO 5 +#define PIN_MODE_SMART_18_SPI 6 +#define PIN_MODE_SMART_16_SPI 7 +#define PIN_MODE_SMART_8_SPI_GPIO 8 + +/* Dumb interface pin allocation */ +#define DUMB_MODE_RGB565 0 +#define DUMB_MODE_RGB565_UPPER 1 +#define DUMB_MODE_RGB666 2 +#define DUMB_MODE_RGB666_UPPER 3 +#define DUMB_MODE_RGB444 4 +#define DUMB_MODE_RGB444_UPPER 5 +#define DUMB_MODE_RGB888 6 + +/* default fb buffer size WVGA-32bits */ +#define DEFAULT_FB_SIZE (800 * 480 * 4) + +/* + * Buffer pixel format + * bit0 is for rb swap. + * bit12 is for Y UorV swap + */ +#define PIX_FMT_RGB565 0 +#define PIX_FMT_BGR565 1 +#define PIX_FMT_RGB1555 2 +#define PIX_FMT_BGR1555 3 +#define PIX_FMT_RGB888PACK 4 +#define PIX_FMT_BGR888PACK 5 +#define PIX_FMT_RGB888UNPACK 6 +#define PIX_FMT_BGR888UNPACK 7 +#define PIX_FMT_RGBA888 8 +#define PIX_FMT_BGRA888 9 +#define PIX_FMT_YUV422PACK 10 +#define PIX_FMT_YVU422PACK 11 +#define PIX_FMT_YUV422PLANAR 12 +#define PIX_FMT_YVU422PLANAR 13 +#define PIX_FMT_YUV420PLANAR 14 +#define PIX_FMT_YVU420PLANAR 15 +#define PIX_FMT_PSEUDOCOLOR 20 +#define PIX_FMT_UYVY422PACK (0x1000|PIX_FMT_YUV422PACK) + +/* + * PXA LCD controller private state. + */ +struct pxa168fb_info { + struct device *dev; + struct clk *clk; + struct fb_info *info; + + void __iomem *reg_base; + dma_addr_t fb_start_dma; + u32 pseudo_palette[16]; + + int pix_fmt; + unsigned is_blanked:1; + unsigned panel_rbswap:1; + unsigned active:1; +}; + +/* + * PXA fb machine information + */ +struct pxa168fb_mach_info { + char id[16]; + + int num_modes; + struct fb_videomode *modes; + + /* + * Pix_fmt + */ + unsigned pix_fmt; + + /* + * I/O pin allocation. + */ + unsigned io_pin_allocation_mode:4; + + /* + * Dumb panel -- assignment of R/G/B component info to the 24 + * available external data lanes. + */ + unsigned dumb_mode:4; + unsigned panel_rgb_reverse_lanes:1; + + /* + * Dumb panel -- GPIO output data. + */ + unsigned gpio_output_mask:8; + unsigned gpio_output_data:8; + + /* + * Dumb panel -- configurable output signal polarity. + */ + unsigned invert_composite_blank:1; + unsigned invert_pix_val_ena:1; + unsigned invert_pixclock:1; + unsigned invert_vsync:1; + unsigned invert_hsync:1; + unsigned panel_rbswap:1; + unsigned active:1; + unsigned enable_lcd:1; +}; + +#endif /* __ASM_MACH_PXA168FB_H */ -- 1.6.0.4 |
From: <krz...@po...> - 2009-05-27 07:41:37
|
Andrew Morton napisał(a): > On Wed, 20 May 2009 14:27:04 +0200 Krzysztof Helt >krz...@po...> > wrote: > > > From: Krzysztof Helt >krz...@wp...> > > > > Does not allow to accept VESA modes by the "vga=" kernel parameter > > if there is no frame buffer driver compiled-in to handle it. > > > > Bug was reported by Werner Lemberg as kernel bug #13249 > > "Intel 945GM: Boot option`vga=0x31a' breaks display of TTYs". > > > > Signed-off-by: Krzysztof Helt >krz...@wp...> > > --- > > > > Werner, please test it. It should produce a correct display > > with intelfb compiled in (=y) and as a module (=m). > > > > > > diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig > > index 0048f11..c787357 100644 > > --- a/drivers/video/Kconfig > > +++ b/drivers/video/Kconfig > > @@ -1122,7 +1122,7 @@ config FB_INTEL > > select FB_CFB_FILLRECT > > select FB_CFB_COPYAREA > > select FB_CFB_IMAGEBLIT > > - select FB_BOOT_VESA_SUPPORT > > + select FB_BOOT_VESA_SUPPORT if FB_INTEL = y > > help > > This driver supports the on-board graphics built in to the Intel > > 830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/965G/965GM > chipsets. > > @@ -1460,7 +1460,7 @@ config FB_SIS > > select FB_CFB_FILLRECT > > select FB_CFB_COPYAREA > > select FB_CFB_IMAGEBLIT > > - select FB_BOOT_VESA_SUPPORT > > + select FB_BOOT_VESA_SUPPORT if FB_SIS = y > > help > > This is the frame buffer device driver for the SiS 300, 315, 330 > > and 340 series as well as XGI V3XT, V5, V8, Z7 graphics chipsets. > > I read through http://bugzilla.kernel.org/show_bug.cgi?id=13249 and am > now unsure what to do with this patch? > > Drop it. I think I know why my laptop uses PIPE_B but both pipes are active. The pipes are connected to so called planes and driver must check which plane is enabled also. Otherwise, when both pipes are enabled the driver doesn't know which one is used. Finally, I found the documentation for i845. Kind regards, Krzysztof ---------------------------------------------------------------------- Kup wlasne mieszkanie za 33 tys. zl. Sprawdz >>> http://link.interia.pl/f21a3 |
From: Andrew M. <ak...@li...> - 2009-05-27 07:16:07
|
On Wed, 20 May 2009 02:41:18 +0200 Roel Kluin <roe...@gm...> wrote: > CC: inu...@li..., Andrew Morton <ak...@li...> You mistyped the list address. > Subject: [PATCH] carminefb: beyond ARRAY_SIZE of carmine_modedb > Date: Wed, 20 May 2009 02:41:18 +0200 > User-Agent: Thunderbird 2.0.0.21 (X11/20090302) > > Do not go beyond ARRAY_SIZE ofcarmine_modedb Sort-of. I changed the title and changelog: Subject: carminefb: fix possible access beyond end of carmine_modedb[] From: Roel Kluin <roe...@gm...> This check is off-by-one. Signed-off-by: Roel Kluin <roe...@gm...> Cc: Sebastian Siewior <bi...@li...> Cc: Krzysztof Helt <krz...@po...> Signed-off-by: Andrew Morton <ak...@li...> --- drivers/video/carminefb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff -puN drivers/video/carminefb.c~carminefb-beyond-array_size-of-carmine_modedb drivers/video/carminefb.c --- a/drivers/video/carminefb.c~carminefb-beyond-array_size-of-carmine_modedb +++ a/drivers/video/carminefb.c @@ -562,7 +562,7 @@ static int __devinit alloc_carmine_fb(vo if (ret < 0) goto err_free_fb; - if (fb_mode > ARRAY_SIZE(carmine_modedb)) + if (fb_mode >= ARRAY_SIZE(carmine_modedb)) fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE; par->cur_mode = par->new_mode = ~0; _ |
From: Mike F. <va...@ge...> - 2009-05-27 06:31:22
|
*** BLURB HERE *** Mike Frysinger (3): fbdev: bfin-t350mcqb-fb: drop unused local variables fbdev: *bfin*: fix __dev{init,exit} markings fbdev: bf54x-lq043fb: use kzalloc over kmalloc/memset Vivek Kutal (1): fbdev: *bfin*: drop unnecessary calls to memset drivers/video/bf54x-lq043fb.c | 15 +++++---------- drivers/video/bfin-t350mcqb-fb.c | 15 +++------------ 2 files changed, 8 insertions(+), 22 deletions(-) |
From: Mike F. <va...@ge...> - 2009-05-27 06:31:21
|
From: Vivek Kutal <viv...@az...> The dma_alloc_* functions sets the memory to 0 before returning so there is no need to call memset after the allocation. Also no point in clearing the memory when disabling the buffer. Signed-off-by: Vivek Kutal <viv...@az...> Signed-off-by: Mike Frysinger <va...@ge...> --- drivers/video/bf54x-lq043fb.c | 3 --- drivers/video/bfin-t350mcqb-fb.c | 3 --- 2 files changed, 0 insertions(+), 6 deletions(-) diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c index 37e60b1..6439a43 100644 --- a/drivers/video/bf54x-lq043fb.c +++ b/drivers/video/bf54x-lq043fb.c @@ -323,7 +323,6 @@ static int bfin_bf54x_fb_release(struct fb_info *info, int user) bfin_write_EPPI0_CONTROL(0); SSYNC(); disable_dma(CH_EPPI0); - memset(fbi->fb_buffer, 0, info->fix.smem_len); } spin_unlock(&fbi->lock); @@ -626,8 +625,6 @@ static int __init bfin_bf54x_probe(struct platform_device *pdev) goto out3; } - memset(info->fb_buffer, 0, fbinfo->fix.smem_len); - fbinfo->screen_base = (void *)info->fb_buffer; fbinfo->fix.smem_start = (int)info->fb_buffer; diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c index 2a2e116..f40eef8 100644 --- a/drivers/video/bfin-t350mcqb-fb.c +++ b/drivers/video/bfin-t350mcqb-fb.c @@ -242,7 +242,6 @@ static int bfin_t350mcqb_fb_release(struct fb_info *info, int user) SSYNC(); disable_dma(CH_PPI); bfin_t350mcqb_stop_timers(); - memset(fbi->fb_buffer, 0, info->fix.smem_len); } spin_unlock(&fbi->lock); @@ -527,8 +526,6 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev) goto out3; } - memset(info->fb_buffer, 0, fbinfo->fix.smem_len); - fbinfo->screen_base = (void *)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; fbinfo->fix.smem_start = (int)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; -- 1.6.3.1 |
From: Mike F. <va...@ge...> - 2009-05-27 06:31:20
|
The local fbinfo/info vars in the suspend functions don't actually get used which cause ugly gcc warnings, so drop them. Signed-off-by: Mike Frysinger <va...@ge...> --- drivers/video/bfin-t350mcqb-fb.c | 6 ------ 1 files changed, 0 insertions(+), 6 deletions(-) diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c index 90cfdda..2a2e116 100644 --- a/drivers/video/bfin-t350mcqb-fb.c +++ b/drivers/video/bfin-t350mcqb-fb.c @@ -637,9 +637,6 @@ static int bfin_t350mcqb_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int bfin_t350mcqb_suspend(struct platform_device *pdev, pm_message_t state) { - struct fb_info *fbinfo = platform_get_drvdata(pdev); - struct bfin_t350mcqbfb_info *info = fbinfo->par; - bfin_t350mcqb_disable_ppi(); disable_dma(CH_PPI); bfin_write_PPI_STATUS(0xFFFF); @@ -649,9 +646,6 @@ static int bfin_t350mcqb_suspend(struct platform_device *pdev, pm_message_t stat static int bfin_t350mcqb_resume(struct platform_device *pdev) { - struct fb_info *fbinfo = platform_get_drvdata(pdev); - struct bfin_t350mcqbfb_info *info = fbinfo->par; - enable_dma(CH_PPI); bfin_t350mcqb_enable_ppi(); -- 1.6.3.1 |
From: Mike F. <va...@ge...> - 2009-05-27 06:31:18
|
Signed-off-by: Mike Frysinger <va...@ge...> --- drivers/video/bf54x-lq043fb.c | 4 +--- 1 files changed, 1 insertions(+), 3 deletions(-) diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c index 8aa67de..e49ae5e 100644 --- a/drivers/video/bf54x-lq043fb.c +++ b/drivers/video/bf54x-lq043fb.c @@ -630,7 +630,7 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev) fbinfo->fbops = &bfin_bf54x_fb_ops; - fbinfo->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); + fbinfo->pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL); if (!fbinfo->pseudo_palette) { printk(KERN_ERR DRIVER_NAME "Fail to allocate pseudo_palette\n"); @@ -639,8 +639,6 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev) goto out4; } - memset(fbinfo->pseudo_palette, 0, sizeof(u32) * 16); - if (fb_alloc_cmap(&fbinfo->cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0) < 0) { printk(KERN_ERR DRIVER_NAME -- 1.6.3.1 |
From: Mike F. <va...@ge...> - 2009-05-27 06:31:18
|
The remove member of the platform_driver bfin_t350mcqb_driver should use __devexit_p() to refer to the remove function, and that function should get __devexit markings. Likewise, the probe function should be marked with __devinit and not __init. Also, module_init() functions should be marked with __init rather than __devinit. Signed-off-by: Mike Frysinger <va...@ge...> --- drivers/video/bf54x-lq043fb.c | 8 ++++---- drivers/video/bfin-t350mcqb-fb.c | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c index 6439a43..8aa67de 100644 --- a/drivers/video/bf54x-lq043fb.c +++ b/drivers/video/bf54x-lq043fb.c @@ -529,7 +529,7 @@ static irqreturn_t bfin_bf54x_irq_error(int irq, void *dev_id) return IRQ_HANDLED; } -static int __init bfin_bf54x_probe(struct platform_device *pdev) +static int __devinit bfin_bf54x_probe(struct platform_device *pdev) { struct bfin_bf54xfb_info *info; struct fb_info *fbinfo; @@ -709,7 +709,7 @@ out1: return ret; } -static int bfin_bf54x_remove(struct platform_device *pdev) +static int __devexit bfin_bf54x_remove(struct platform_device *pdev) { struct fb_info *fbinfo = platform_get_drvdata(pdev); @@ -778,7 +778,7 @@ static int bfin_bf54x_resume(struct platform_device *pdev) static struct platform_driver bfin_bf54x_driver = { .probe = bfin_bf54x_probe, - .remove = bfin_bf54x_remove, + .remove = __devexit_p(bfin_bf54x_remove), .suspend = bfin_bf54x_suspend, .resume = bfin_bf54x_resume, .driver = { @@ -787,7 +787,7 @@ static struct platform_driver bfin_bf54x_driver = { }, }; -static int __devinit bfin_bf54x_driver_init(void) +static int __init bfin_bf54x_driver_init(void) { return platform_driver_register(&bfin_bf54x_driver); } diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c index f40eef8..5cc36cf 100644 --- a/drivers/video/bfin-t350mcqb-fb.c +++ b/drivers/video/bfin-t350mcqb-fb.c @@ -599,7 +599,7 @@ out1: return ret; } -static int bfin_t350mcqb_remove(struct platform_device *pdev) +static int __devexit bfin_t350mcqb_remove(struct platform_device *pdev) { struct fb_info *fbinfo = platform_get_drvdata(pdev); @@ -655,7 +655,7 @@ static int bfin_t350mcqb_resume(struct platform_device *pdev) static struct platform_driver bfin_t350mcqb_driver = { .probe = bfin_t350mcqb_probe, - .remove = bfin_t350mcqb_remove, + .remove = __devexit_p(bfin_t350mcqb_remove), .suspend = bfin_t350mcqb_suspend, .resume = bfin_t350mcqb_resume, .driver = { @@ -664,7 +664,7 @@ static struct platform_driver bfin_t350mcqb_driver = { }, }; -static int __devinit bfin_t350mcqb_driver_init(void) +static int __init bfin_t350mcqb_driver_init(void) { return platform_driver_register(&bfin_t350mcqb_driver); } -- 1.6.3.1 |
From: Andrew M. <ak...@li...> - 2009-05-27 06:16:07
|
On Wed, 20 May 2009 14:27:04 +0200 Krzysztof Helt <krz...@po...> wrote: > From: Krzysztof Helt <krz...@wp...> > > Does not allow to accept VESA modes by the "vga=" kernel parameter > if there is no frame buffer driver compiled-in to handle it. > > Bug was reported by Werner Lemberg as kernel bug #13249 > "Intel 945GM: Boot option`vga=0x31a' breaks display of TTYs". > > Signed-off-by: Krzysztof Helt <krz...@wp...> > --- > > Werner, please test it. It should produce a correct display > with intelfb compiled in (=y) and as a module (=m). > > > diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig > index 0048f11..c787357 100644 > --- a/drivers/video/Kconfig > +++ b/drivers/video/Kconfig > @@ -1122,7 +1122,7 @@ config FB_INTEL > select FB_CFB_FILLRECT > select FB_CFB_COPYAREA > select FB_CFB_IMAGEBLIT > - select FB_BOOT_VESA_SUPPORT > + select FB_BOOT_VESA_SUPPORT if FB_INTEL = y > help > This driver supports the on-board graphics built in to the Intel > 830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/965G/965GM chipsets. > @@ -1460,7 +1460,7 @@ config FB_SIS > select FB_CFB_FILLRECT > select FB_CFB_COPYAREA > select FB_CFB_IMAGEBLIT > - select FB_BOOT_VESA_SUPPORT > + select FB_BOOT_VESA_SUPPORT if FB_SIS = y > help > This is the frame buffer device driver for the SiS 300, 315, 330 > and 340 series as well as XGI V3XT, V5, V8, Z7 graphics chipsets. I read through http://bugzilla.kernel.org/show_bug.cgi?id=13249 and am now unsure what to do with this patch? |
From: Ryan M. <ry...@bl...> - 2009-05-27 03:03:58
|
H Hartley Sweeten wrote: > On Sunday, May 24, 2009 10:34 PM, Ryan Mallon wrote: >> This patch adds support for the ep93xx framebuffer. Patch is against >> arm ep93xx branch. >> >> Can anybody with ep93xx hardware please test, specifically with regard >> to the physical address bit 27 bug. My hardware has the bug, but I'm >> not sure about other ep93xx chips. > > I have not seen the address bit 27 bug on my custom hardware with > EP9307 Rev E0 silicon. Have you had the driver allocate a physical memory address which has bit 27 set? I'm basically wondering whether to enable the check by default or not. If the problem only exists on a few ep93xx chips then it may be better to leave the check off by default. >> + >> +static struct platform_device ep93xx_fb_device = { >> + .name = "ep93xxfb", >> + .id = 0, > > Since there can only be one framebuffer device how about using > .id = -1? This will change the clk dev_id to "ep93xxfb". Also, > maybe change the name to "ep93xx-fb", that's how the usb host is > named. Will fix both. > >> + .dev.platform_data = &ep93xxfb_data, >> + .dev.coherent_dma_mask = 0xf7ffffff, > > I think this is supposed to be > > .dev.coherent_dma_mask = DMA_BIT_MASK(32), > > Or is the missing bit due to the address bit 27 bug? Yeah, its for bit 27. Not sure how to handle this correctly if the check is a driver option. If you don't have this problem, just change it to DMA_BIT_MASK(32) for testing. ~Ryan -- Bluewater Systems Ltd - ARM Technology Solution Centre Ryan Mallon Unit 5, Amuri Park Phone: +64 3 3779127 404 Barbadoes St Fax: +64 3 3779135 PO Box 13 889 Email: ry...@bl... Christchurch, 8013 Web: http://www.bluewatersys.com New Zealand Freecall Australia 1800 148 751 USA 1800 261 2934 |
From: Ville S. <sy...@sc...> - 2009-05-26 22:08:59
|
On Tue, May 26, 2009 at 01:49:18PM -0700, Andrew Morton wrote: > On Tue, 26 May 2009 02:05:14 +0300 > Ville Syrjala <sy...@sc...> wrote: > > > Apparently HP OmniBook 500's BIOS doesn't like the way atyfb reprograms > > the hardware. The BIOS will simply hang after a reboot. Fix the problem > > by restoring the hardware to it's original state on reboot. > > > > > > ... > > > > @@ -3502,6 +3503,11 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi > > par->mmap_map[1].prot_flag = _PAGE_E; > > #endif /* __sparc__ */ > > > > + mutex_lock(&reboot_lock); > > + if (!reboot_info) > > + reboot_info = info; > > + mutex_unlock(&reboot_lock); > > This looks risky to me. We save away a pointer to a structure which > was created by framebuffer_alloc(). What guarantee is there that this > memory is still valid when the reboot happens later on? atyfb_remove() will clear the pointer before freeing the memory. The mutex is supposed to make sure that the structure won't be freed while the reboot notifier is executing. Hmm. I suppose I might have to grab the fb_info lock there too to protect against other fb activity happening at the same time. I also noticed that I managed to misplace reboot_info pointer clearing a bit. It should really be in atyfb_pci_remove() instead of atyfb_remove() since it's set in atyfb_pci_probe(). > > return 0; > > > > err_release_io: > > @@ -3613,9 +3619,14 @@ static void __devexit atyfb_remove(struct fb_info *info) > > { > > struct atyfb_par *par = (struct atyfb_par *) info->par; > > > > + mutex_lock(&reboot_lock); > > + if (reboot_info == info) > > + reboot_info = NULL; > > + mutex_unlock(&reboot_lock); > > + > > /* restore video mode */ > > - aty_set_crtc(par, &saved_crtc); > > - par->pll_ops->set_pll(info, &saved_pll); > > + aty_set_crtc(par, &par->saved_crtc); > > + par->pll_ops->set_pll(info, &par->saved_pll); > > > > unregister_framebuffer(info); > > > > @@ -3808,6 +3819,39 @@ static int __init atyfb_setup(char *options) > > } > > #endif /* MODULE */ > > > > +static int atyfb_reboot_notify(struct notifier_block *nb, > > + unsigned long code, void *unused) > > +{ > > + struct atyfb_par *par; > > + > > + if (code != SYS_RESTART) > > + return NOTIFY_DONE; > > + > > + mutex_lock(&reboot_lock); > > + > > + if (!reboot_info) > > + goto out; > > + > > + par = reboot_info->par; > > + > > + /* > > + * HP OmniBook 500's BIOS doesn't like the state of the > > + * hardware after atyfb has been used. Restore the hardware > > + * to the original state to allow succesful reboots. > > "successful" ;) Right. > > + */ > > + aty_set_crtc(par, &par->saved_crtc); > > + par->pll_ops->set_pll(reboot_info, &par->saved_pll); > > + > > + out: > > + mutex_unlock(&reboot_lock); > > + > > + return NOTIFY_DONE; > > +} > > + > > +static struct notifier_block atyfb_reboot_notifier = { > > + .notifier_call = atyfb_reboot_notify, > > +}; > > + > > static int __init atyfb_init(void) > > { > > int err1 = 1, err2 = 1; > > @@ -3826,11 +3870,18 @@ static int __init atyfb_init(void) > > err2 = atyfb_atari_probe(); > > #endif > > > > - return (err1 && err2) ? -ENODEV : 0; > > + if (err1 && err2) > > + return -ENODEV; > > + > > + register_reboot_notifier(&atyfb_reboot_notifier); > > + > > + return 0; > > } > > ick. Please feel free to repair the indenting in atyfb_init(). The indentation is broken in other parts of the driver too. I'll make a separate cosmetics patch to clean it all up. > > static void __exit atyfb_exit(void) > > { > > + unregister_reboot_notifier(&atyfb_reboot_notifier); > > + > > #ifdef CONFIG_PCI > > pci_unregister_driver(&atyfb_driver); > > #endif > > So we do the restoration for all supported devices on all machines, > even though it's only known to be needed on one card on one machine. > > Hopefully that's safe, but a more cautious approach would use a > whitelist of some form. I don't have enough experience with these > things to be able to judge the risk. It should be safe in theory :) If the restoration breaks on some system then the probe error handling and remove handling are also broken since they do the same stuff. But to be honest I didn't test it on other systems. I could do a DMI match but I'm not sure the extra complexity is actually warranted. I'll give it a spin on a few other systems in any case. -- Ville Syrjälä sy...@sc... http://www.sci.fi/~syrjala/ |
From: Geert U. <ge...@li...> - 2009-05-26 21:10:32
|
Added lin...@li... On Tue, May 26, 2009 at 21:07, <wuz...@gm...> wrote: > From: Wu Zhangjin <wu...@le...> > > yeeloong(2f) laptop has a SMI video card, need this driver. > > this source code is originally from > http://dev.lemote.com/code/linux_loongson > > tons of warnings have been fixed, the main warning is: > > warning: left shift count >= width of type > > have been fixed via the following modification: > > drivers/video/smi/smtc2d.h: > > #define _F_MASK(f) ((((1 << _F_SIZE(f)) - 1) << _F_START(f)) > #define _F_MASK(f) (((1ULL << _F_SIZE(f)) - 1) << _F_START(f)) > > besides, the coding style is changed to follow the kernel style, and two > non-used header files are removed: sm501hw.h, sm7xxhw.h. > > Signed-off-by: Wu Zhangjin <wuz...@gm...> > --- > drivers/video/Kconfig | 23 + > drivers/video/Makefile | 1 + > drivers/video/smi/Makefile | 8 + > drivers/video/smi/smtc2d.c | 979 +++++++++++++++++++++++++++++++++++++ > drivers/video/smi/smtc2d.h | 530 ++++++++++++++++++++ > drivers/video/smi/smtcfb.c | 1141 ++++++++++++++++++++++++++++++++++++++++++++ > drivers/video/smi/smtcfb.h | 793 ++++++++++++++++++++++++++++++ > 7 files changed, 3475 insertions(+), 0 deletions(-) > create mode 100644 drivers/video/smi/Makefile > create mode 100644 drivers/video/smi/smtc2d.c > create mode 100644 drivers/video/smi/smtc2d.h > create mode 100644 drivers/video/smi/smtcfb.c > create mode 100644 drivers/video/smi/smtcfb.h > > diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig > index 0048f11..b6ba27f 100644 > --- a/drivers/video/Kconfig > +++ b/drivers/video/Kconfig > @@ -1930,6 +1930,29 @@ config FB_S3C2410_DEBUG > Turn on debugging messages. Note that you can set/unset at run time > through sysfs > > +config FB_SILICONMOTION > + bool "Silicon Motion Display Support" > + depends on FB > + help > + Frame Buffer driver for the Silicon Motion serial graphic card. > + > +config FB_SM7XX > + bool "Silicon Motion SM7XX Frame Buffer Support" > + depends on FB_SILICONMOTION > + depends on FB > + select FB_CFB_FILLRECT > + select FB_CFB_COPYAREA > + select FB_CFB_IMAGEBLIT > + help > + Frame Buffer driver for the Silicon Motion SM7XX serial graphic card. > + > +config FB_SM7XX_ACCEL > + bool "Siliconmotion Acceleration functions (EXPERIMENTAL)" > + depends on FB_SM7XX && EXPERIMENTAL > + help > + This will compile the Trident frame buffer device with > + acceleration functions. > + > config FB_SM501 > tristate "Silicon Motion SM501 framebuffer support" > depends on FB && MFD_SM501 > diff --git a/drivers/video/Makefile b/drivers/video/Makefile > index d8d0be5..caf6d8c 100644 > --- a/drivers/video/Makefile > +++ b/drivers/video/Makefile > @@ -70,6 +70,7 @@ obj-$(CONFIG_FB_P9100) += p9100.o sbuslib.o > obj-$(CONFIG_FB_TCX) += tcx.o sbuslib.o > obj-$(CONFIG_FB_LEO) += leo.o sbuslib.o > obj-$(CONFIG_FB_SGIVW) += sgivwfb.o > +obj-$(CONFIG_FB_SILICONMOTION) += smi/ > obj-$(CONFIG_FB_ACORN) += acornfb.o > obj-$(CONFIG_FB_ATARI) += atafb.o c2p_iplan2.o atafb_mfb.o \ > atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o > diff --git a/drivers/video/smi/Makefile b/drivers/video/smi/Makefile > new file mode 100644 > index 0000000..0058148 > --- /dev/null > +++ b/drivers/video/smi/Makefile > @@ -0,0 +1,8 @@ > +obj-y += smi.o > + > +smi-y := $(DRIVER_OBJS) > + > +smi-y += smtcfb.o > + > +EXTRA_CFLAGS += -Werror > + > diff --git a/drivers/video/smi/smtc2d.c b/drivers/video/smi/smtc2d.c > new file mode 100644 > index 0000000..2a9c3bd > --- /dev/null > +++ b/drivers/video/smi/smtc2d.c > @@ -0,0 +1,979 @@ > +/* > + * smtc2d.c -- Silicon Motion SM501 and SM7xx 2D drawing engine functions. > + * > + * Copyright (C) 2006 Silicon Motion Technology Corp. > + * Author: Boyod boy...@si... > + * > + * Copyright (C) 2009 Lemote, Inc. & Institute of Computing Technology > + * Author: Wu Zhangjin, wu...@le... > + * > + * This file is subject to the terms and conditions of the GNU General Public > + * License. See the file COPYING in the main directory of this archive for > + * more details. > + * > + * Version 0.10.26192.21.01 > + * - Add PowerPC support > + * - Add 2D support for Lynx - > + * Verified on 2.6.19.2 > + * Boyod.yang <boy...@si...> > + */ > + > +unsigned char smtc_de_busy; > + > +void SMTC_write2Dreg(unsigned long nOffset, unsigned long nData) > +{ > + writel(nData, smtc_2DBaseAddress + nOffset); > +} > + > +unsigned long SMTC_read2Dreg(unsigned long nOffset) > +{ > + return readl(smtc_2DBaseAddress + nOffset); > +} > + > +void SMTC_write2Ddataport(unsigned long nOffset, unsigned long nData) > +{ > + writel(nData, smtc_2Ddataport + nOffset); > +} > + > +/********************************************************************** > + * > + * deInit > + * > + * Purpose > + * Drawing engine initialization. > + * > + **********************************************************************/ > + > +void deInit(unsigned int nModeWidth, unsigned int nModeHeight, > + unsigned int bpp) > +{ > + /* Get current power configuration. */ > + unsigned char clock; > + clock = smtc_seqr(0x21); > + > + /* initialize global 'mutex lock' variable */ > + smtc_de_busy = 0; > + > + /* Enable 2D Drawing Engine */ > + smtc_seqw(0x21, clock & 0xF8); > + > + SMTC_write2Dreg(DE_CLIP_TL, > + FIELD_VALUE(0, DE_CLIP_TL, TOP, 0) | > + FIELD_SET(0, DE_CLIP_TL, STATUS, DISABLE) | > + FIELD_SET(0, DE_CLIP_TL, INHIBIT, OUTSIDE) | > + FIELD_VALUE(0, DE_CLIP_TL, LEFT, 0)); > + > + if (bpp >= 24) { > + SMTC_write2Dreg(DE_PITCH, > + FIELD_VALUE(0, DE_PITCH, DESTINATION, > + nModeWidth * 3) | FIELD_VALUE(0, > + DE_PITCH, > + SOURCE, > + nModeWidth > + * 3)); > + } else { > + SMTC_write2Dreg(DE_PITCH, > + FIELD_VALUE(0, DE_PITCH, DESTINATION, > + nModeWidth) | FIELD_VALUE(0, > + DE_PITCH, > + SOURCE, > + nModeWidth)); > + } > + > + SMTC_write2Dreg(DE_WINDOW_WIDTH, > + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, > + nModeWidth) | FIELD_VALUE(0, > + DE_WINDOW_WIDTH, > + SOURCE, > + nModeWidth)); > + > + switch (bpp) { > + case 8: > + SMTC_write2Dreg(DE_STRETCH_FORMAT, > + FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY, > + NORMAL) | FIELD_VALUE(0, > + DE_STRETCH_FORMAT, > + PATTERN_Y, > + 0) | > + FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X, > + 0) | FIELD_SET(0, DE_STRETCH_FORMAT, > + PIXEL_FORMAT, > + 8) | FIELD_SET(0, > + DE_STRETCH_FORMAT, > + ADDRESSING, > + XY) | > + FIELD_VALUE(0, DE_STRETCH_FORMAT, > + SOURCE_HEIGHT, 3)); > + break; > + case 24: > + SMTC_write2Dreg(DE_STRETCH_FORMAT, > + FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY, > + NORMAL) | FIELD_VALUE(0, > + DE_STRETCH_FORMAT, > + PATTERN_Y, > + 0) | > + FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X, > + 0) | FIELD_SET(0, DE_STRETCH_FORMAT, > + PIXEL_FORMAT, > + 24) | FIELD_SET(0, > + DE_STRETCH_FORMAT, > + ADDRESSING, > + XY) | > + FIELD_VALUE(0, DE_STRETCH_FORMAT, > + SOURCE_HEIGHT, 3)); > + break; > + case 16: > + default: > + SMTC_write2Dreg(DE_STRETCH_FORMAT, > + FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY, > + NORMAL) | FIELD_VALUE(0, > + DE_STRETCH_FORMAT, > + PATTERN_Y, > + 0) | > + FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X, > + 0) | FIELD_SET(0, DE_STRETCH_FORMAT, > + PIXEL_FORMAT, > + 16) | FIELD_SET(0, > + DE_STRETCH_FORMAT, > + ADDRESSING, > + XY) | > + FIELD_VALUE(0, DE_STRETCH_FORMAT, > + SOURCE_HEIGHT, 3)); > + break; > + } > + > + SMTC_write2Dreg(DE_MASKS, > + FIELD_VALUE(0, DE_MASKS, BYTE_MASK, 0xFFFF) | > + FIELD_VALUE(0, DE_MASKS, BIT_MASK, 0xFFFF)); > + SMTC_write2Dreg(DE_COLOR_COMPARE_MASK, > + FIELD_VALUE(0, DE_COLOR_COMPARE_MASK, MASKS, \ > + 0xFFFFFF)); > + SMTC_write2Dreg(DE_COLOR_COMPARE, > + FIELD_VALUE(0, DE_COLOR_COMPARE, COLOR, 0xFFFFFF)); > +} > + > +void deVerticalLine(unsigned long dst_base, > + unsigned long dst_pitch, > + unsigned long nX, > + unsigned long nY, > + unsigned long dst_height, unsigned long nColor) > +{ > + deWaitForNotBusy(); > + > + SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, > + FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS, > + dst_base)); > + > + SMTC_write2Dreg(DE_PITCH, > + FIELD_VALUE(0, DE_PITCH, DESTINATION, dst_pitch) | > + FIELD_VALUE(0, DE_PITCH, SOURCE, dst_pitch)); > + > + SMTC_write2Dreg(DE_WINDOW_WIDTH, > + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, > + dst_pitch) | FIELD_VALUE(0, DE_WINDOW_WIDTH, > + SOURCE, > + dst_pitch)); > + > + SMTC_write2Dreg(DE_FOREGROUND, > + FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor)); > + > + SMTC_write2Dreg(DE_DESTINATION, > + FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) | > + FIELD_VALUE(0, DE_DESTINATION, X, nX) | > + FIELD_VALUE(0, DE_DESTINATION, Y, nY)); > + > + SMTC_write2Dreg(DE_DIMENSION, > + FIELD_VALUE(0, DE_DIMENSION, X, 1) | > + FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height)); > + > + SMTC_write2Dreg(DE_CONTROL, > + FIELD_SET(0, DE_CONTROL, STATUS, START) | > + FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) | > + FIELD_SET(0, DE_CONTROL, MAJOR, Y) | > + FIELD_SET(0, DE_CONTROL, STEP_X, NEGATIVE) | > + FIELD_SET(0, DE_CONTROL, STEP_Y, POSITIVE) | > + FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) | > + FIELD_SET(0, DE_CONTROL, COMMAND, SHORT_STROKE) | > + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | > + FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C)); > + > + smtc_de_busy = 1; > +} > + > +void deHorizontalLine(unsigned long dst_base, > + unsigned long dst_pitch, > + unsigned long nX, > + unsigned long nY, > + unsigned long dst_width, unsigned long nColor) > +{ > + deWaitForNotBusy(); > + > + SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, > + FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS, > + dst_base)); > + > + SMTC_write2Dreg(DE_PITCH, > + FIELD_VALUE(0, DE_PITCH, DESTINATION, dst_pitch) | > + FIELD_VALUE(0, DE_PITCH, SOURCE, dst_pitch)); > + > + SMTC_write2Dreg(DE_WINDOW_WIDTH, > + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, > + dst_pitch) | FIELD_VALUE(0, DE_WINDOW_WIDTH, > + SOURCE, > + dst_pitch)); > + SMTC_write2Dreg(DE_FOREGROUND, > + FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor)); > + SMTC_write2Dreg(DE_DESTINATION, > + FIELD_SET(0, DE_DESTINATION, WRAP, > + DISABLE) | FIELD_VALUE(0, DE_DESTINATION, X, > + nX) | FIELD_VALUE(0, > + DE_DESTINATION, > + Y, > + nY)); > + SMTC_write2Dreg(DE_DIMENSION, > + FIELD_VALUE(0, DE_DIMENSION, X, > + dst_width) | FIELD_VALUE(0, DE_DIMENSION, > + Y_ET, 1)); > + SMTC_write2Dreg(DE_CONTROL, > + FIELD_SET(0, DE_CONTROL, STATUS, START) | FIELD_SET(0, > + DE_CONTROL, > + DIRECTION, > + RIGHT_TO_LEFT) > + | FIELD_SET(0, DE_CONTROL, MAJOR, X) | FIELD_SET(0, > + DE_CONTROL, > + STEP_X, > + POSITIVE) > + | FIELD_SET(0, DE_CONTROL, STEP_Y, > + NEGATIVE) | FIELD_SET(0, DE_CONTROL, > + LAST_PIXEL, > + OFF) | FIELD_SET(0, > + DE_CONTROL, > + COMMAND, > + SHORT_STROKE) > + | FIELD_SET(0, DE_CONTROL, ROP_SELECT, > + ROP2) | FIELD_VALUE(0, DE_CONTROL, ROP, > + 0x0C)); > + > + smtc_de_busy = 1; > +} > + > +void deLine(unsigned long dst_base, > + unsigned long dst_pitch, > + unsigned long nX1, > + unsigned long nY1, > + unsigned long nX2, unsigned long nY2, unsigned long nColor) > +{ > + unsigned long nCommand = > + FIELD_SET(0, DE_CONTROL, STATUS, START) | > + FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) | > + FIELD_SET(0, DE_CONTROL, MAJOR, X) | > + FIELD_SET(0, DE_CONTROL, STEP_X, POSITIVE) | > + FIELD_SET(0, DE_CONTROL, STEP_Y, POSITIVE) | > + FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) | > + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | > + FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C); > + unsigned long DeltaX; > + unsigned long DeltaY; > + > + /* Calculate delta X */ > + if (nX1 <= nX2) > + DeltaX = nX2 - nX1; > + else { > + DeltaX = nX1 - nX2; > + nCommand = FIELD_SET(nCommand, DE_CONTROL, STEP_X, NEGATIVE); > + } > + > + /* Calculate delta Y */ > + if (nY1 <= nY2) > + DeltaY = nY2 - nY1; > + else { > + DeltaY = nY1 - nY2; > + nCommand = FIELD_SET(nCommand, DE_CONTROL, STEP_Y, NEGATIVE); > + } > + > + /* Determine the major axis */ > + if (DeltaX < DeltaY) > + nCommand = FIELD_SET(nCommand, DE_CONTROL, MAJOR, Y); > + > + /* Vertical line? */ > + if (nX1 == nX2) > + deVerticalLine(dst_base, dst_pitch, nX1, nY1, DeltaY, nColor); > + > + /* Horizontal line? */ > + else if (nY1 == nY2) > + deHorizontalLine(dst_base, dst_pitch, nX1, nY1, \ > + DeltaX, nColor); > + > + /* Diagonal line? */ > + else if (DeltaX == DeltaY) { > + deWaitForNotBusy(); > + > + SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, > + FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, > + ADDRESS, dst_base)); > + > + SMTC_write2Dreg(DE_PITCH, > + FIELD_VALUE(0, DE_PITCH, DESTINATION, > + dst_pitch) | FIELD_VALUE(0, > + DE_PITCH, > + SOURCE, > + dst_pitch)); > + > + SMTC_write2Dreg(DE_WINDOW_WIDTH, > + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, > + dst_pitch) | FIELD_VALUE(0, > + DE_WINDOW_WIDTH, > + SOURCE, > + dst_pitch)); > + > + SMTC_write2Dreg(DE_FOREGROUND, > + FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor)); > + > + SMTC_write2Dreg(DE_DESTINATION, > + FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) | > + FIELD_VALUE(0, DE_DESTINATION, X, 1) | > + FIELD_VALUE(0, DE_DESTINATION, Y, nY1)); > + > + SMTC_write2Dreg(DE_DIMENSION, > + FIELD_VALUE(0, DE_DIMENSION, X, 1) | > + FIELD_VALUE(0, DE_DIMENSION, Y_ET, DeltaX)); > + > + SMTC_write2Dreg(DE_CONTROL, > + FIELD_SET(nCommand, DE_CONTROL, COMMAND, > + SHORT_STROKE)); > + } > + > + /* Generic line */ > + else { > + unsigned int k1, k2, et, w; > + if (DeltaX < DeltaY) { > + k1 = 2 * DeltaX; > + et = k1 - DeltaY; > + k2 = et - DeltaY; > + w = DeltaY + 1; > + } else { > + k1 = 2 * DeltaY; > + et = k1 - DeltaX; > + k2 = et - DeltaX; > + w = DeltaX + 1; > + } > + > + deWaitForNotBusy(); > + > + SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, > + FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, > + ADDRESS, dst_base)); > + > + SMTC_write2Dreg(DE_PITCH, > + FIELD_VALUE(0, DE_PITCH, DESTINATION, > + dst_pitch) | FIELD_VALUE(0, > + DE_PITCH, > + SOURCE, > + dst_pitch)); > + > + SMTC_write2Dreg(DE_WINDOW_WIDTH, > + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, > + dst_pitch) | FIELD_VALUE(0, > + DE_WINDOW_WIDTH, > + SOURCE, > + dst_pitch)); > + > + SMTC_write2Dreg(DE_FOREGROUND, > + FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor)); > + > + SMTC_write2Dreg(DE_SOURCE, > + FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) | > + FIELD_VALUE(0, DE_SOURCE, X_K1, k1) | > + FIELD_VALUE(0, DE_SOURCE, Y_K2, k2)); > + > + SMTC_write2Dreg(DE_DESTINATION, > + FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) | > + FIELD_VALUE(0, DE_DESTINATION, X, nX1) | > + FIELD_VALUE(0, DE_DESTINATION, Y, nY1)); > + > + SMTC_write2Dreg(DE_DIMENSION, > + FIELD_VALUE(0, DE_DIMENSION, X, w) | > + FIELD_VALUE(0, DE_DIMENSION, Y_ET, et)); > + > + SMTC_write2Dreg(DE_CONTROL, > + FIELD_SET(nCommand, DE_CONTROL, COMMAND, > + LINE_DRAW)); > + } > + > + smtc_de_busy = 1; > +} > + > +void deFillRect(unsigned long dst_base, > + unsigned long dst_pitch, > + unsigned long dst_X, > + unsigned long dst_Y, > + unsigned long dst_width, > + unsigned long dst_height, unsigned long nColor) > +{ > + deWaitForNotBusy(); > + > + SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, > + FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS, > + dst_base)); > + > + if (dst_pitch) { > + SMTC_write2Dreg(DE_PITCH, > + FIELD_VALUE(0, DE_PITCH, DESTINATION, > + dst_pitch) | FIELD_VALUE(0, > + DE_PITCH, > + SOURCE, > + dst_pitch)); > + > + SMTC_write2Dreg(DE_WINDOW_WIDTH, > + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, > + dst_pitch) | FIELD_VALUE(0, > + DE_WINDOW_WIDTH, > + SOURCE, > + dst_pitch)); > + } > + > + SMTC_write2Dreg(DE_FOREGROUND, > + FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor)); > + > + SMTC_write2Dreg(DE_DESTINATION, > + FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) | > + FIELD_VALUE(0, DE_DESTINATION, X, dst_X) | > + FIELD_VALUE(0, DE_DESTINATION, Y, dst_Y)); > + > + SMTC_write2Dreg(DE_DIMENSION, > + FIELD_VALUE(0, DE_DIMENSION, X, dst_width) | > + FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height)); > + > + SMTC_write2Dreg(DE_CONTROL, > + FIELD_SET(0, DE_CONTROL, STATUS, START) | > + FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) | > + FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) | > + FIELD_SET(0, DE_CONTROL, COMMAND, RECTANGLE_FILL) | > + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | > + FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C)); > + > + smtc_de_busy = 1; > +} > + > +/********************************************************************** > + * > + * deRotatePattern > + * > + * Purpose > + * Rotate the given pattern if necessary > + * > + * Parameters > + * [in] > + * pPattern - Pointer to DE_SURFACE structure containing > + * pattern attributes > + * patternX - X position (0-7) of pattern origin > + * patternY - Y position (0-7) of pattern origin > + * > + * [out] > + * pattern_dstaddr - Pointer to pre-allocated buffer containing > + * rotated pattern > + * > + **********************************************************************/ > +void deRotatePattern(unsigned char *pattern_dstaddr, > + unsigned long pattern_src_addr, > + unsigned long pattern_BPP, > + unsigned long pattern_stride, int patternX, int patternY) > +{ > + unsigned int i; > + unsigned long pattern[PATTERN_WIDTH * PATTERN_HEIGHT]; > + unsigned int x, y; > + unsigned char *pjPatByte; > + > + if (pattern_dstaddr != NULL) { > + deWaitForNotBusy(); > + > + if (patternX || patternY) { > + /* Rotate pattern */ > + pjPatByte = (unsigned char *)pattern; > + > + switch (pattern_BPP) { > + case 8: > + { > + for (y = 0; y < 8; y++) { > + unsigned char *pjBuffer = > + pattern_dstaddr + > + ((patternY + y) & 7) * 8; > + for (x = 0; x < 8; x++) { > + pjBuffer[(patternX + > + x) & 7] = > + pjPatByte[x]; > + } > + pjPatByte += pattern_stride; > + } > + break; > + } > + > + case 16: > + { > + for (y = 0; y < 8; y++) { > + unsigned short *pjBuffer = > + (unsigned short *) > + pattern_dstaddr + > + ((patternY + y) & 7) * 8; > + for (x = 0; x < 8; x++) { > + pjBuffer[(patternX + > + x) & 7] = > + ((unsigned short *) > + pjPatByte)[x]; > + } > + pjPatByte += pattern_stride; > + } > + break; > + } > + > + case 32: > + { > + for (y = 0; y < 8; y++) { > + unsigned long *pjBuffer = > + (unsigned long *) > + pattern_dstaddr + > + ((patternY + y) & 7) * 8; > + for (x = 0; x < 8; x++) { > + pjBuffer[(patternX + > + x) & 7] = > + ((unsigned long *) > + pjPatByte)[x]; > + } > + pjPatByte += pattern_stride; > + } > + break; > + } > + } > + } else { > + /*Don't rotate,just copy pattern into pattern_dstaddr*/ > + for (i = 0; i < (pattern_BPP * 2); i++) { > + ((unsigned long *)pattern_dstaddr)[i] = > + pattern[i]; > + } > + } > + > + } > +} > + > +/********************************************************************** > + * > + * deCopy > + * > + * Purpose > + * Copy a rectangular area of the source surface to a destination surface > + * > + * Remarks > + * Source bitmap must have the same color depth (BPP) as the destination > + * bitmap. > + * > +**********************************************************************/ > +void deCopy(unsigned long dst_base, > + unsigned long dst_pitch, > + unsigned long dst_BPP, > + unsigned long dst_X, > + unsigned long dst_Y, > + unsigned long dst_width, > + unsigned long dst_height, > + unsigned long src_base, > + unsigned long src_pitch, > + unsigned long src_X, > + unsigned long src_Y, pTransparent pTransp, unsigned char nROP2) > +{ > + unsigned long nDirection = 0; > + unsigned long nTransparent = 0; > + /* Direction of ROP2 operation: > + * 1 = Left to Right, > + * (-1) = Right to Left > + */ > + unsigned long opSign = 1; > + /* xWidth is in pixels */ > + unsigned long xWidth = 192 / (dst_BPP / 8); > + unsigned long de_ctrl = 0; > + > + deWaitForNotBusy(); > + > + SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, > + FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS, > + dst_base)); > + > + SMTC_write2Dreg(DE_WINDOW_SOURCE_BASE, > + FIELD_VALUE(0, DE_WINDOW_SOURCE_BASE, ADDRESS, > + src_base)); > + > + if (dst_pitch && src_pitch) { > + SMTC_write2Dreg(DE_PITCH, > + FIELD_VALUE(0, DE_PITCH, DESTINATION, > + dst_pitch) | FIELD_VALUE(0, > + DE_PITCH, > + SOURCE, > + src_pitch)); > + > + SMTC_write2Dreg(DE_WINDOW_WIDTH, > + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, > + dst_pitch) | FIELD_VALUE(0, > + DE_WINDOW_WIDTH, > + SOURCE, > + src_pitch)); > + } > + > + /* Set transparent bits if necessary */ > + if (pTransp != NULL) { > + nTransparent = > + pTransp->match | pTransp->select | pTransp->control; > + > + /* Set color compare register */ > + SMTC_write2Dreg(DE_COLOR_COMPARE, > + FIELD_VALUE(0, DE_COLOR_COMPARE, COLOR, > + pTransp->color)); > + } > + > + /* Determine direction of operation */ > + if (src_Y < dst_Y) { > + /* +----------+ > + |S | > + | +----------+ > + | | | | > + | | | | > + +---|------+ | > + | D | > + +----------+ */ > + > + nDirection = BOTTOM_TO_TOP; > + } else if (src_Y > dst_Y) { > + /* +----------+ > + |D | > + | +----------+ > + | | | | > + | | | | > + +---|------+ | > + | S | > + +----------+ */ > + > + nDirection = TOP_TO_BOTTOM; > + } else { > + /* src_Y == dst_Y */ > + > + if (src_X <= dst_X) { > + /* +------+---+------+ > + |S | | D| > + | | | | > + | | | | > + | | | | > + +------+---+------+ */ > + > + nDirection = RIGHT_TO_LEFT; > + } else { > + /* src_X > dst_X */ > + > + /* +------+---+------+ > + |D | | S| > + | | | | > + | | | | > + | | | | > + +------+---+------+ */ > + > + nDirection = LEFT_TO_RIGHT; > + } > + } > + > + if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT)) { > + src_X += dst_width - 1; > + src_Y += dst_height - 1; > + dst_X += dst_width - 1; > + dst_Y += dst_height - 1; > + opSign = (-1); > + } > + > + if (dst_BPP >= 24) { > + src_X *= 3; > + src_Y *= 3; > + dst_X *= 3; > + dst_Y *= 3; > + dst_width *= 3; > + if ((nDirection == BOTTOM_TO_TOP) > + || (nDirection == RIGHT_TO_LEFT)) { > + src_X += 2; > + dst_X += 2; > + } > + } > + > + /* Workaround for 192 byte hw bug */ > + if ((nROP2 != 0x0C) && ((dst_width * (dst_BPP / 8)) >= 192)) { > + /* > + * Perform the ROP2 operation in chunks of (xWidth * > + * dst_height) > + */ > + while (1) { > + deWaitForNotBusy(); > + > + SMTC_write2Dreg(DE_SOURCE, > + FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) | > + FIELD_VALUE(0, DE_SOURCE, X_K1, src_X) | > + FIELD_VALUE(0, DE_SOURCE, Y_K2, src_Y)); > + > + SMTC_write2Dreg(DE_DESTINATION, > + FIELD_SET(0, DE_DESTINATION, WRAP, > + DISABLE) | FIELD_VALUE(0, > + DE_DESTINATION, > + X, > + dst_X) > + | FIELD_VALUE(0, DE_DESTINATION, Y, > + dst_Y)); > + > + SMTC_write2Dreg(DE_DIMENSION, > + FIELD_VALUE(0, DE_DIMENSION, X, > + xWidth) | FIELD_VALUE(0, > + DE_DIMENSION, > + Y_ET, > + dst_height)); > + > + de_ctrl = > + FIELD_VALUE(0, DE_CONTROL, ROP, > + nROP2) | nTransparent | FIELD_SET(0, > + DE_CONTROL, > + ROP_SELECT, > + ROP2) > + | FIELD_SET(0, DE_CONTROL, COMMAND, > + BITBLT) | ((nDirection == > + 1) ? FIELD_SET(0, > + DE_CONTROL, > + DIRECTION, > + RIGHT_TO_LEFT) > + : FIELD_SET(0, DE_CONTROL, > + DIRECTION, > + LEFT_TO_RIGHT)) | > + FIELD_SET(0, DE_CONTROL, STATUS, START); > + > + SMTC_write2Dreg(DE_CONTROL, de_ctrl); > + > + src_X += (opSign * xWidth); > + dst_X += (opSign * xWidth); > + dst_width -= xWidth; > + > + if (dst_width <= 0) { > + /* ROP2 operation is complete */ > + break; > + } > + > + if (xWidth > dst_width) > + xWidth = dst_width; > + } > + } else { > + deWaitForNotBusy(); > + SMTC_write2Dreg(DE_SOURCE, > + FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) | > + FIELD_VALUE(0, DE_SOURCE, X_K1, src_X) | > + FIELD_VALUE(0, DE_SOURCE, Y_K2, src_Y)); > + > + SMTC_write2Dreg(DE_DESTINATION, > + FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) | > + FIELD_VALUE(0, DE_DESTINATION, X, dst_X) | > + FIELD_VALUE(0, DE_DESTINATION, Y, dst_Y)); > + > + SMTC_write2Dreg(DE_DIMENSION, > + FIELD_VALUE(0, DE_DIMENSION, X, dst_width) | > + FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height)); > + > + de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, nROP2) | > + nTransparent | > + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | > + FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) | > + ((nDirection == 1) ? FIELD_SET(0, DE_CONTROL, DIRECTION, > + RIGHT_TO_LEFT) > + : FIELD_SET(0, DE_CONTROL, DIRECTION, > + LEFT_TO_RIGHT)) | FIELD_SET(0, DE_CONTROL, > + STATUS, START); > + SMTC_write2Dreg(DE_CONTROL, de_ctrl); > + } > + > + smtc_de_busy = 1; > +} > + > +/* > + * This function sets the pixel format that will apply to the 2D Engine. > + */ > +void deSetPixelFormat(unsigned long bpp) > +{ > + unsigned long de_format; > + > + de_format = SMTC_read2Dreg(DE_STRETCH_FORMAT); > + > + switch (bpp) { > + case 8: > + de_format = > + FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 8); > + break; > + default: > + case 16: > + de_format = > + FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 16); > + break; > + case 32: > + de_format = > + FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 32); > + break; > + } > + > + SMTC_write2Dreg(DE_STRETCH_FORMAT, de_format); > +} > + > +/* > + * System memory to Video memory monochrome expansion. > + * > + * Source is monochrome image in system memory. This function expands the > + * monochrome data to color image in video memory. > + */ > + > +long deSystemMem2VideoMemMonoBlt(const char *pSrcbuf, > + long srcDelta, > + unsigned long startBit, > + unsigned long dBase, > + unsigned long dPitch, > + unsigned long bpp, > + unsigned long dx, unsigned long dy, > + unsigned long width, unsigned long height, > + unsigned long fColor, > + unsigned long bColor, > + unsigned long rop2) { > + unsigned long bytePerPixel; > + unsigned long ulBytesPerScan; > + unsigned long ul4BytesPerScan; > + unsigned long ulBytesRemain; > + unsigned long de_ctrl = 0; > + unsigned char ajRemain[4]; > + long i, j; > + > + bytePerPixel = bpp / 8; > + > + /* Just make sure the start bit is within legal range */ > + startBit &= 7; > + > + ulBytesPerScan = (width + startBit + 7) / 8; > + ul4BytesPerScan = ulBytesPerScan & ~3; > + ulBytesRemain = ulBytesPerScan & 3; > + > + if (smtc_de_busy) > + deWaitForNotBusy(); > + > + /* > + * 2D Source Base. Use 0 for HOST Blt. > + */ > + > + SMTC_write2Dreg(DE_WINDOW_SOURCE_BASE, 0); > + > + /* > + * 2D Destination Base. > + * > + * It is an address offset (128 bit aligned) from the beginning of > + * frame buffer. > + */ > + > + SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, dBase); > + > + if (dPitch) { > + > + /* > + * Program pitch (distance between the 1st points of two > + * adjacent lines). > + * > + * Note that input pitch is BYTE value, but the 2D Pitch > + * register uses pixel values. Need Byte to pixel convertion. > + */ > + > + SMTC_write2Dreg(DE_PITCH, > + FIELD_VALUE(0, DE_PITCH, DESTINATION, > + dPitch / > + bytePerPixel) | FIELD_VALUE(0, > + DE_PITCH, > + SOURCE, > + dPitch / > + bytePerPixel)); > + > + /* Screen Window width in Pixels. > + * > + * 2D engine uses this value to calculate the linear address in > + * frame buffer for a given point. > + */ > + > + SMTC_write2Dreg(DE_WINDOW_WIDTH, > + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, > + (dPitch / > + bytePerPixel)) | FIELD_VALUE(0, > + DE_WINDOW_WIDTH, > + SOURCE, > + (dPitch > + / > + bytePerPixel))); > + } > + /* Note: For 2D Source in Host Write, only X_K1 field is needed, and > + * Y_K2 field is not used. For mono bitmap, use startBit for X_K1. > + */ > + > + SMTC_write2Dreg(DE_SOURCE, > + FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) | > + FIELD_VALUE(0, DE_SOURCE, X_K1, startBit) | > + FIELD_VALUE(0, DE_SOURCE, Y_K2, 0)); > + > + SMTC_write2Dreg(DE_DESTINATION, > + FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) | > + FIELD_VALUE(0, DE_DESTINATION, X, dx) | > + FIELD_VALUE(0, DE_DESTINATION, Y, dy)); > + > + SMTC_write2Dreg(DE_DIMENSION, > + FIELD_VALUE(0, DE_DIMENSION, X, width) | > + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); > + > + SMTC_write2Dreg(DE_FOREGROUND, fColor); > + SMTC_write2Dreg(DE_BACKGROUND, bColor); > + > + if (bpp) > + deSetPixelFormat(bpp); > + /* Set the pixel format of the destination */ > + > + de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | > + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | > + FIELD_SET(0, DE_CONTROL, COMMAND, HOST_WRITE) | > + FIELD_SET(0, DE_CONTROL, HOST, MONO) | > + FIELD_SET(0, DE_CONTROL, STATUS, START); > + > + SMTC_write2Dreg(DE_CONTROL, de_ctrl | deGetTransparency()); > + > + /* Write MONO data (line by line) to 2D Engine data port */ > + for (i = 0; i < height; i++) { > + /* For each line, send the data in chunks of 4 bytes */ > + for (j = 0; j < (ul4BytesPerScan / 4); j++) > + SMTC_write2Ddataport(0, > + *(unsigned long *)(pSrcbuf + > + (j * 4))); > + > + if (ulBytesRemain) { > + memcpy(ajRemain, pSrcbuf + ul4BytesPerScan, > + ulBytesRemain); > + SMTC_write2Ddataport(0, *(unsigned long *)ajRemain); > + } > + > + pSrcbuf += srcDelta; > + } > + smtc_de_busy = 1; > + > + return 0; > +} > + > +/* > + * This function gets the transparency status from DE_CONTROL register. > + * It returns a double word with the transparent fields properly set, > + * while other fields are 0. > + */ > +unsigned long deGetTransparency(void) > +{ > + unsigned long de_ctrl; > + > + de_ctrl = SMTC_read2Dreg(DE_CONTROL); > + > + de_ctrl &= > + FIELD_MASK(DE_CONTROL_TRANSPARENCY_MATCH) | > + FIELD_MASK(DE_CONTROL_TRANSPARENCY_SELECT) | > + FIELD_MASK(DE_CONTROL_TRANSPARENCY); > + > + return de_ctrl; > +} > diff --git a/drivers/video/smi/smtc2d.h b/drivers/video/smi/smtc2d.h > new file mode 100644 > index 0000000..3cd640c > --- /dev/null > +++ b/drivers/video/smi/smtc2d.h > @@ -0,0 +1,530 @@ > +/* > + * smtc2d.h -- Silicon Motion SM501 and SM7xx 2D drawing engine functions. > + * > + * Copyright (C) 2006 Silicon Motion Technology Corp. > + * Author: Ge Wang, ge...@si... > + * > + * Copyright (C) 2009 Lemote, Inc. & Institute of Computing Technology > + * Author: Wu Zhangjin, wu...@le... > + * > + * This file is subject to the terms and conditions of the GNU General Public > + * License. See the file COPYING in the main directory of this archive for > + * more details. > + */ > + > +#ifndef NULL > +#define NULL 0 > +#endif > + > +/* Internal macros */ > + > +#define _F_START(f) (0 ? f) > +#define _F_END(f) (1 ? f) > +#define _F_SIZE(f) (1 + _F_END(f) - _F_START(f)) > +#define _F_MASK(f) (((1ULL << _F_SIZE(f)) - 1) << _F_START(f)) > +#define _F_NORMALIZE(v, f) (((v) & _F_MASK(f)) >> _F_START(f)) > +#define _F_DENORMALIZE(v, f) (((v) << _F_START(f)) & _F_MASK(f)) > + > +/* Global macros */ > + > +#define FIELD_GET(x, reg, field) \ > +( \ > + _F_NORMALIZE((x), reg ## _ ## field) \ > +) > + > +#define FIELD_SET(x, reg, field, value) \ > +( \ > + (x & ~_F_MASK(reg ## _ ## field)) \ > + | _F_DENORMALIZE(reg ## _ ## field ## _ ## value, reg ## _ ## field) \ > +) > + > +#define FIELD_VALUE(x, reg, field, value) \ > +( \ > + (x & ~_F_MASK(reg ## _ ## field)) \ > + | _F_DENORMALIZE(value, reg ## _ ## field) \ > +) > + > +#define FIELD_CLEAR(reg, field) \ > +( \ > + ~_F_MASK(reg ## _ ## field) \ > +) > + > +/* Field Macros */ > + > +#define FIELD_START(field) (0 ? field) > +#define FIELD_END(field) (1 ? field) > +#define FIELD_SIZE(field) \ > + (1 + FIELD_END(field) - FIELD_START(field)) > + > +#define FIELD_MASK(field) \ > + (((1 << (FIELD_SIZE(field)-1)) \ > + | ((1 << (FIELD_SIZE(field)-1)) - 1)) \ > + << FIELD_START(field)) > + > +#define FIELD_NORMALIZE(reg, field) \ > + (((reg) & FIELD_MASK(field)) >> FIELD_START(field)) > + > +#define FIELD_DENORMALIZE(field, value) \ > + (((value) << FIELD_START(field)) & FIELD_MASK(field)) > + > +#define FIELD_INIT(reg, field, value) \ > + FIELD_DENORMALIZE(reg ## _ ## field, \ > + reg ## _ ## field ## _ ## value) > + > +#define FIELD_INIT_VAL(reg, field, value) \ > + (FIELD_DENORMALIZE(reg ## _ ## field, value)) > + > +#define FIELD_VAL_SET(x, r, f, v) ({ \ > + x = (x & ~FIELD_MASK(r ## _ ## f)) \ > + | FIELD_DENORMALIZE(r ## _ ## f, r ## _ ## f ## _ ## v) \ > +}) > + > +#define RGB(r, g, b) ((unsigned long)(((r) << 16) | ((g) << 8) | (b))) > + > +/* Transparent info definition */ > +typedef struct { > + unsigned long match; /* Matching pixel is OPAQUE/TRANSPARENT */ > + unsigned long select; /* Transparency controlled by SRC/DST */ > + unsigned long control; /* ENABLE/DISABLE transparency */ > + unsigned long color; /* Transparent color */ > +} Transparent, *pTransparent; > + > +#define PIXEL_DEPTH_1_BP 0 /* 1 bit per pixel */ > +#define PIXEL_DEPTH_8_BPP 1 /* 8 bits per pixel */ > +#define PIXEL_DEPTH_16_BPP 2 /* 16 bits per pixel */ > +#define PIXEL_DEPTH_32_BPP 3 /* 32 bits per pixel */ > +#define PIXEL_DEPTH_YUV422 8 /* 16 bits per pixel YUV422 */ > +#define PIXEL_DEPTH_YUV420 9 /* 16 bits per pixel YUV420 */ > + > +#define PATTERN_WIDTH 8 > +#define PATTERN_HEIGHT 8 > + > +#define TOP_TO_BOTTOM 0 > +#define BOTTOM_TO_TOP 1 > +#define RIGHT_TO_LEFT BOTTOM_TO_TOP > +#define LEFT_TO_RIGHT TOP_TO_BOTTOM > + > +/* Constants used in Transparent structure */ > +#define MATCH_OPAQUE 0x00000000 > +#define MATCH_TRANSPARENT 0x00000400 > +#define SOURCE 0x00000000 > +#define DESTINATION 0x00000200 > + > +/* 2D registers. */ > + > +#define DE_SOURCE 0x000000 > +#define DE_SOURCE_WRAP 31 : 31 > +#define DE_SOURCE_WRAP_DISABLE 0 > +#define DE_SOURCE_WRAP_ENABLE 1 > +#define DE_SOURCE_X_K1 29 : 16 > +#define DE_SOURCE_Y_K2 15 : 0 > + > +#define DE_DESTINATION 0x000004 > +#define DE_DESTINATION_WRAP 31 : 31 > +#define DE_DESTINATION_WRAP_DISABLE 0 > +#define DE_DESTINATION_WRAP_ENABLE 1 > +#define DE_DESTINATION_X 28 : 16 > +#define DE_DESTINATION_Y 15 : 0 > + > +#define DE_DIMENSION 0x000008 > +#define DE_DIMENSION_X 28 : 16 > +#define DE_DIMENSION_Y_ET 15 : 0 > + > +#define DE_CONTROL 0x00000C > +#define DE_CONTROL_STATUS 31 : 31 > +#define DE_CONTROL_STATUS_STOP 0 > +#define DE_CONTROL_STATUS_START 1 > +#define DE_CONTROL_PATTERN 30 : 30 > +#define DE_CONTROL_PATTERN_MONO 0 > +#define DE_CONTROL_PATTERN_COLOR 1 > +#define DE_CONTROL_UPDATE_DESTINATION_X 29 : 29 > +#define DE_CONTROL_UPDATE_DESTINATION_X_DISABLE 0 > +#define DE_CONTROL_UPDATE_DESTINATION_X_ENABLE 1 > +#define DE_CONTROL_QUICK_START 28 : 28 > +#define DE_CONTROL_QUICK_START_DISABLE 0 > +#define DE_CONTROL_QUICK_START_ENABLE 1 > +#define DE_CONTROL_DIRECTION 27 : 27 > +#define DE_CONTROL_DIRECTION_LEFT_TO_RIGHT 0 > +#define DE_CONTROL_DIRECTION_RIGHT_TO_LEFT 1 > +#define DE_CONTROL_MAJOR 26 : 26 > +#define DE_CONTROL_MAJOR_X 0 > +#define DE_CONTROL_MAJOR_Y 1 > +#define DE_CONTROL_STEP_X 25 : 25 > +#define DE_CONTROL_STEP_X_POSITIVE 1 > +#define DE_CONTROL_STEP_X_NEGATIVE 0 > +#define DE_CONTROL_STEP_Y 24 : 24 > +#define DE_CONTROL_STEP_Y_POSITIVE 1 > +#define DE_CONTROL_STEP_Y_NEGATIVE 0 > +#define DE_CONTROL_STRETCH 23 : 23 > +#define DE_CONTROL_STRETCH_DISABLE 0 > +#define DE_CONTROL_STRETCH_ENABLE 1 > +#define DE_CONTROL_HOST 22 : 22 > +#define DE_CONTROL_HOST_COLOR 0 > +#define DE_CONTROL_HOST_MONO 1 > +#define DE_CONTROL_LAST_PIXEL 21 : 21 > +#define DE_CONTROL_LAST_PIXEL_OFF 0 > +#define DE_CONTROL_LAST_PIXEL_ON 1 > +#define DE_CONTROL_COMMAND 20 : 16 > +#define DE_CONTROL_COMMAND_BITBLT 0 > +#define DE_CONTROL_COMMAND_RECTANGLE_FILL 1 > +#define DE_CONTROL_COMMAND_DE_TILE 2 > +#define DE_CONTROL_COMMAND_TRAPEZOID_FILL 3 > +#define DE_CONTROL_COMMAND_ALPHA_BLEND 4 > +#define DE_CONTROL_COMMAND_RLE_STRIP 5 > +#define DE_CONTROL_COMMAND_SHORT_STROKE 6 > +#define DE_CONTROL_COMMAND_LINE_DRAW 7 > +#define DE_CONTROL_COMMAND_HOST_WRITE 8 > +#define DE_CONTROL_COMMAND_HOST_READ 9 > +#define DE_CONTROL_COMMAND_HOST_WRITE_BOTTOM_UP 10 > +#define DE_CONTROL_COMMAND_ROTATE 11 > +#define DE_CONTROL_COMMAND_FONT 12 > +#define DE_CONTROL_COMMAND_TEXTURE_LOAD 15 > +#define DE_CONTROL_ROP_SELECT 15 : 15 > +#define DE_CONTROL_ROP_SELECT_ROP3 0 > +#define DE_CONTROL_ROP_SELECT_ROP2 1 > +#define DE_CONTROL_ROP2_SOURCE 14 : 14 > +#define DE_CONTROL_ROP2_SOURCE_BITMAP 0 > +#define DE_CONTROL_ROP2_SOURCE_PATTERN 1 > +#define DE_CONTROL_MONO_DATA 13 : 12 > +#define DE_CONTROL_MONO_DATA_NOT_PACKED 0 > +#define DE_CONTROL_MONO_DATA_8_PACKED 1 > +#define DE_CONTROL_MONO_DATA_16_PACKED 2 > +#define DE_CONTROL_MONO_DATA_32_PACKED 3 > +#define DE_CONTROL_REPEAT_ROTATE 11 : 11 > +#define DE_CONTROL_REPEAT_ROTATE_DISABLE 0 > +#define DE_CONTROL_REPEAT_ROTATE_ENABLE 1 > +#define DE_CONTROL_TRANSPARENCY_MATCH 10 : 10 > +#define DE_CONTROL_TRANSPARENCY_MATCH_OPAQUE 0 > +#define DE_CONTROL_TRANSPARENCY_MATCH_TRANSPARENT 1 > +#define DE_CONTROL_TRANSPARENCY_SELECT 9 : 9 > +#define DE_CONTROL_TRANSPARENCY_SELECT_SOURCE 0 > +#define DE_CONTROL_TRANSPARENCY_SELECT_DESTINATION 1 > +#define DE_CONTROL_TRANSPARENCY 8 : 8 > +#define DE_CONTROL_TRANSPARENCY_DISABLE 0 > +#define DE_CONTROL_TRANSPARENCY_ENABLE 1 > +#define DE_CONTROL_ROP 7 : 0 > + > +/* Pseudo fields. */ > + > +#define DE_CONTROL_SHORT_STROKE_DIR 27 : 24 > +#define DE_CONTROL_SHORT_STROKE_DIR_225 0 > +#define DE_CONTROL_SHORT_STROKE_DIR_135 1 > +#define DE_CONTROL_SHORT_STROKE_DIR_315 2 > +#define DE_CONTROL_SHORT_STROKE_DIR_45 3 > +#define DE_CONTROL_SHORT_STROKE_DIR_270 4 > +#define DE_CONTROL_SHORT_STROKE_DIR_90 5 > +#define DE_CONTROL_SHORT_STROKE_DIR_180 8 > +#define DE_CONTROL_SHORT_STROKE_DIR_0 10 > +#define DE_CONTROL_ROTATION 25 : 24 > +#define DE_CONTROL_ROTATION_0 0 > +#define DE_CONTROL_ROTATION_270 1 > +#define DE_CONTROL_ROTATION_90 2 > +#define DE_CONTROL_ROTATION_180 3 > + > +#define DE_PITCH 0x000010 > +#define DE_PITCH_DESTINATION 28 : 16 > +#define DE_PITCH_SOURCE 12 : 0 > + > +#define DE_FOREGROUND 0x000014 > +#define DE_FOREGROUND_COLOR 31 : 0 > + > +#define DE_BACKGROUND 0x000018 > +#define DE_BACKGROUND_COLOR 31 : 0 > + > +#define DE_STRETCH_FORMAT 0x00001C > +#define DE_STRETCH_FORMAT_PATTERN_XY 30 : 30 > +#define DE_STRETCH_FORMAT_PATTERN_XY_NORMAL 0 > +#define DE_STRETCH_FORMAT_PATTERN_XY_OVERWRITE 1 > +#define DE_STRETCH_FORMAT_PATTERN_Y 29 : 27 > +#define DE_STRETCH_FORMAT_PATTERN_X 25 : 23 > +#define DE_STRETCH_FORMAT_PIXEL_FORMAT 21 : 20 > +#define DE_STRETCH_FORMAT_PIXEL_FORMAT_8 0 > +#define DE_STRETCH_FORMAT_PIXEL_FORMAT_16 1 > +#define DE_STRETCH_FORMAT_PIXEL_FORMAT_24 3 > +#define DE_STRETCH_FORMAT_PIXEL_FORMAT_32 2 > +#define DE_STRETCH_FORMAT_ADDRESSING 19 : 16 > +#define DE_STRETCH_FORMAT_ADDRESSING_XY 0 > +#define DE_STRETCH_FORMAT_ADDRESSING_LINEAR 15 > +#define DE_STRETCH_FORMAT_SOURCE_HEIGHT 11 : 0 > + > +#define DE_COLOR_COMPARE 0x000020 > +#define DE_COLOR_COMPARE_COLOR 23 : 0 > + > +#define DE_COLOR_COMPARE_MASK 0x000024 > +#define DE_COLOR_COMPARE_MASK_MASKS 23 : 0 > + > +#define DE_MASKS 0x000028 > +#define DE_MASKS_BYTE_MASK 31 : 16 > +#define DE_MASKS_BIT_MASK 15 : 0 > + > +#define DE_CLIP_TL 0x00002C > +#define DE_CLIP_TL_TOP 31 : 16 > +#define DE_CLIP_TL_STATUS 13 : 13 > +#define DE_CLIP_TL_STATUS_DISABLE 0 > +#define DE_CLIP_TL_STATUS_ENABLE 1 > +#define DE_CLIP_TL_INHIBIT 12 : 12 > +#define DE_CLIP_TL_INHIBIT_OUTSIDE... [truncated message content] |
From: Andrew M. <ak...@li...> - 2009-05-26 20:49:25
|
On Tue, 26 May 2009 02:05:14 +0300 Ville Syrjala <sy...@sc...> wrote: > Apparently HP OmniBook 500's BIOS doesn't like the way atyfb reprograms > the hardware. The BIOS will simply hang after a reboot. Fix the problem > by restoring the hardware to it's original state on reboot. > > > ... > > @@ -3502,6 +3503,11 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi > par->mmap_map[1].prot_flag = _PAGE_E; > #endif /* __sparc__ */ > > + mutex_lock(&reboot_lock); > + if (!reboot_info) > + reboot_info = info; > + mutex_unlock(&reboot_lock); This looks risky to me. We save away a pointer to a structure which was created by framebuffer_alloc(). What guarantee is there that this memory is still valid when the reboot happens later on? > return 0; > > err_release_io: > @@ -3613,9 +3619,14 @@ static void __devexit atyfb_remove(struct fb_info *info) > { > struct atyfb_par *par = (struct atyfb_par *) info->par; > > + mutex_lock(&reboot_lock); > + if (reboot_info == info) > + reboot_info = NULL; > + mutex_unlock(&reboot_lock); > + > /* restore video mode */ > - aty_set_crtc(par, &saved_crtc); > - par->pll_ops->set_pll(info, &saved_pll); > + aty_set_crtc(par, &par->saved_crtc); > + par->pll_ops->set_pll(info, &par->saved_pll); > > unregister_framebuffer(info); > > @@ -3808,6 +3819,39 @@ static int __init atyfb_setup(char *options) > } > #endif /* MODULE */ > > +static int atyfb_reboot_notify(struct notifier_block *nb, > + unsigned long code, void *unused) > +{ > + struct atyfb_par *par; > + > + if (code != SYS_RESTART) > + return NOTIFY_DONE; > + > + mutex_lock(&reboot_lock); > + > + if (!reboot_info) > + goto out; > + > + par = reboot_info->par; > + > + /* > + * HP OmniBook 500's BIOS doesn't like the state of the > + * hardware after atyfb has been used. Restore the hardware > + * to the original state to allow succesful reboots. "successful" ;) > + */ > + aty_set_crtc(par, &par->saved_crtc); > + par->pll_ops->set_pll(reboot_info, &par->saved_pll); > + > + out: > + mutex_unlock(&reboot_lock); > + > + return NOTIFY_DONE; > +} > + > +static struct notifier_block atyfb_reboot_notifier = { > + .notifier_call = atyfb_reboot_notify, > +}; > + > static int __init atyfb_init(void) > { > int err1 = 1, err2 = 1; > @@ -3826,11 +3870,18 @@ static int __init atyfb_init(void) > err2 = atyfb_atari_probe(); > #endif > > - return (err1 && err2) ? -ENODEV : 0; > + if (err1 && err2) > + return -ENODEV; > + > + register_reboot_notifier(&atyfb_reboot_notifier); > + > + return 0; > } ick. Please feel free to repair the indenting in atyfb_init(). > static void __exit atyfb_exit(void) > { > + unregister_reboot_notifier(&atyfb_reboot_notifier); > + > #ifdef CONFIG_PCI > pci_unregister_driver(&atyfb_driver); > #endif So we do the restoration for all supported devices on all machines, even though it's only known to be needed on one card on one machine. Hopefully that's safe, but a more cautious approach would use a whitelist of some form. I don't have enough experience with these things to be able to judge the risk. |
From: H H. S. <har...@vi...> - 2009-05-26 16:29:58
|
On Sunday, May 24, 2009 10:34 PM, Ryan Mallon wrote: > This patch adds support for the ep93xx framebuffer. Patch is against > arm ep93xx branch. > > Can anybody with ep93xx hardware please test, specifically with regard > to the physical address bit 27 bug. My hardware has the bug, but I'm > not sure about other ep93xx chips. I have not seen the address bit 27 bug on my custom hardware with EP9307 Rev E0 silicon. > Signed-off-by: Ryan Mallon <ry...@bl...> > > --- > > diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c > index c535e88..885786c 100644 > --- a/arch/arm/mach-ep93xx/core.c > +++ b/arch/arm/mach-ep93xx/core.c > @@ -53,6 +53,7 @@ > > #include <asm/hardware/vic.h> > > +#include <mach/fb.h> > > /************************************************************************* > * Static I/O mappings that are needed for all EP93xx platforms > @@ -546,6 +547,34 @@ void __init ep93xx_register_i2c(struct i2c_board_info *devices, int num) > platform_device_register(&ep93xx_i2c_device); > } > > +/************************************************************************* > + * EP93xx video peripheral handling > + *************************************************************************/ > +static struct ep93xxfb_mach_info ep93xxfb_data; > + > +static struct resource ep93xx_fb_resource[] = { > + { > + .start = EP93XX_RASTER_PHYS_BASE, > + .end = EP93XX_RASTER_PHYS_BASE + 0x800 - 1, > + .flags = IORESOURCE_MEM, > + }, > +}; > + > +static struct platform_device ep93xx_fb_device = { > + .name = "ep93xxfb", > + .id = 0, Since there can only be one framebuffer device how about using .id = -1? This will change the clk dev_id to "ep93xxfb". Also, maybe change the name to "ep93xx-fb", that's how the usb host is named. > + .dev.platform_data = &ep93xxfb_data, > + .dev.coherent_dma_mask = 0xf7ffffff, I think this is supposed to be .dev.coherent_dma_mask = DMA_BIT_MASK(32), Or is the missing bit due to the address bit 27 bug? > + .num_resources = ARRAY_SIZE(ep93xx_fb_resource), > + .resource = ep93xx_fb_resource, > +}; > + > +void __init ep93xx_register_fb(struct ep93xxfb_mach_info *data) > +{ > + ep93xxfb_data = *data; > + platform_device_register(&ep93xx_fb_device); > +} > + > extern void ep93xx_gpio_init(void); > > void __init ep93xx_init_devices(void) I will test the remainder of this patch later this week and comment then. Regards, Hartley |
From: Ville S. <sy...@sc...> - 2009-05-25 23:06:40
|
Apparently HP OmniBook 500's BIOS doesn't like the way atyfb reprograms the hardware. The BIOS will simply hang after a reboot. Fix the problem by restoring the hardware to it's original state on reboot. Signed-off-by: Ville Syrjala <sy...@sc...> --- drivers/video/aty/atyfb.h | 2 + drivers/video/aty/atyfb_base.c | 69 ++++++++++++++++++++++++++++++++++----- 2 files changed, 62 insertions(+), 9 deletions(-) diff --git a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h index 7691e73..0369653 100644 --- a/drivers/video/aty/atyfb.h +++ b/drivers/video/aty/atyfb.h @@ -187,6 +187,8 @@ struct atyfb_par { int mtrr_reg; #endif u32 mem_cntl; + struct crtc saved_crtc; + union aty_pll saved_pll; }; /* diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 1207c20..305f7c8 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -66,6 +66,7 @@ #include <linux/spinlock.h> #include <linux/wait.h> #include <linux/backlight.h> +#include <linux/reboot.h> #include <asm/io.h> #include <linux/uaccess.h> @@ -249,8 +250,6 @@ static int aty_init(struct fb_info *info); static int store_video_par(char *videopar, unsigned char m64_num); #endif -static struct crtc saved_crtc; -static union aty_pll saved_pll; static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc); static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc); @@ -261,6 +260,8 @@ static void set_off_pitch(struct atyfb_par *par, const struct fb_info *info); static int read_aty_sense(const struct atyfb_par *par); #endif +static DEFINE_MUTEX(reboot_lock); +static struct fb_info *reboot_info; /* * Interface used by the world @@ -2390,9 +2391,9 @@ static int __devinit aty_init(struct fb_info *info) #endif /* CONFIG_FB_ATY_CT */ /* save previous video mode */ - aty_get_crtc(par, &saved_crtc); + aty_get_crtc(par, &par->saved_crtc); if(par->pll_ops->get_pll) - par->pll_ops->get_pll(info, &saved_pll); + par->pll_ops->get_pll(info, &par->saved_pll); par->mem_cntl = aty_ld_le32(MEM_CNTL, par); gtb_memsize = M64_HAS(GTB_DSP); @@ -2667,8 +2668,8 @@ static int __devinit aty_init(struct fb_info *info) aty_init_exit: /* restore video mode */ - aty_set_crtc(par, &saved_crtc); - par->pll_ops->set_pll(info, &saved_pll); + aty_set_crtc(par, &par->saved_crtc); + par->pll_ops->set_pll(info, &par->saved_pll); #ifdef CONFIG_MTRR if (par->mtrr_reg >= 0) { @@ -3502,6 +3503,11 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi par->mmap_map[1].prot_flag = _PAGE_E; #endif /* __sparc__ */ + mutex_lock(&reboot_lock); + if (!reboot_info) + reboot_info = info; + mutex_unlock(&reboot_lock); + return 0; err_release_io: @@ -3613,9 +3619,14 @@ static void __devexit atyfb_remove(struct fb_info *info) { struct atyfb_par *par = (struct atyfb_par *) info->par; + mutex_lock(&reboot_lock); + if (reboot_info == info) + reboot_info = NULL; + mutex_unlock(&reboot_lock); + /* restore video mode */ - aty_set_crtc(par, &saved_crtc); - par->pll_ops->set_pll(info, &saved_pll); + aty_set_crtc(par, &par->saved_crtc); + par->pll_ops->set_pll(info, &par->saved_pll); unregister_framebuffer(info); @@ -3808,6 +3819,39 @@ static int __init atyfb_setup(char *options) } #endif /* MODULE */ +static int atyfb_reboot_notify(struct notifier_block *nb, + unsigned long code, void *unused) +{ + struct atyfb_par *par; + + if (code != SYS_RESTART) + return NOTIFY_DONE; + + mutex_lock(&reboot_lock); + + if (!reboot_info) + goto out; + + par = reboot_info->par; + + /* + * HP OmniBook 500's BIOS doesn't like the state of the + * hardware after atyfb has been used. Restore the hardware + * to the original state to allow succesful reboots. + */ + aty_set_crtc(par, &par->saved_crtc); + par->pll_ops->set_pll(reboot_info, &par->saved_pll); + + out: + mutex_unlock(&reboot_lock); + + return NOTIFY_DONE; +} + +static struct notifier_block atyfb_reboot_notifier = { + .notifier_call = atyfb_reboot_notify, +}; + static int __init atyfb_init(void) { int err1 = 1, err2 = 1; @@ -3826,11 +3870,18 @@ static int __init atyfb_init(void) err2 = atyfb_atari_probe(); #endif - return (err1 && err2) ? -ENODEV : 0; + if (err1 && err2) + return -ENODEV; + + register_reboot_notifier(&atyfb_reboot_notifier); + + return 0; } static void __exit atyfb_exit(void) { + unregister_reboot_notifier(&atyfb_reboot_notifier); + #ifdef CONFIG_PCI pci_unregister_driver(&atyfb_driver); #endif -- 1.6.0.6 |
From: Tony L. <to...@at...> - 2009-05-25 17:42:40
|
Hi all, Here are few omap entries to MAINTAINERS as discussed several times before. Regards, Tony |
From: Andrew de Q. <ad...@li...> - 2009-05-25 16:41:02
|
Quoting Andrew de Quincey <ad...@li...>: > Quoting Russell King - ARM Linux <li...@ar...>: > >> On Tue, May 19, 2009 at 04:37:32PM -0700, Tony Lindgren wrote: >>> Make 770 LCD work by passing the clock from platform data. >>> Also remove the old unused functions. >> >> I don't like this - because its passing struct clk's through platform >> data. That's not how things are supposed to work. >> >> The way PXA solves this problem is to have clock aliases - see >> clk_add_alias(). > > Interesting idea - I now have a prototype patch implementing this, > which I'll send when I get home (otherwise it would be an "it > compiles" "test" :) > > There isn't a common definition of clk_add_alias() though - that > symbol is defined in arch/arm/mach-pxa/clock.c, so I had to copy it > into arch/arm/plat-omap/clock.c Attached is a patch implementing this method. I don't like the duplication of the clk_alias code, but I imagine that could be resolved if this method was chosen.... |
From: Andrew de Q. <ad...@li...> - 2009-05-25 14:37:28
|
Quoting Russell King - ARM Linux <li...@ar...>: > On Tue, May 19, 2009 at 04:37:32PM -0700, Tony Lindgren wrote: >> Make 770 LCD work by passing the clock from platform data. >> Also remove the old unused functions. > > I don't like this - because its passing struct clk's through platform > data. That's not how things are supposed to work. > > The way PXA solves this problem is to have clock aliases - see > clk_add_alias(). Interesting idea - I now have a prototype patch implementing this, which I'll send when I get home (otherwise it would be an "it compiles" "test" :) There isn't a common definition of clk_add_alias() though - that symbol is defined in arch/arm/mach-pxa/clock.c, so I had to copy it into arch/arm/plat-omap/clock.c |
From: Russell K. - A. L. <li...@ar...> - 2009-05-25 09:29:53
|
On Tue, May 19, 2009 at 04:37:32PM -0700, Tony Lindgren wrote: > Make 770 LCD work by passing the clock from platform data. > Also remove the old unused functions. I don't like this - because its passing struct clk's through platform data. That's not how things are supposed to work. The way PXA solves this problem is to have clock aliases - see clk_add_alias(). |
From: Ryan M. <ry...@bl...> - 2009-05-25 05:59:38
|
This patch adds support for the ep93xx framebuffer. Patch is against arm ep93xx branch. Can anybody with ep93xx hardware please test, specifically with regard to the physical address bit 27 bug. My hardware has the bug, but I'm not sure about other ep93xx chips. Signed-off-by: Ryan Mallon <ry...@bl...> --- diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index c535e88..885786c 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c @@ -53,6 +53,7 @@ #include <asm/hardware/vic.h> +#include <mach/fb.h> /************************************************************************* * Static I/O mappings that are needed for all EP93xx platforms @@ -546,6 +547,34 @@ void __init ep93xx_register_i2c(struct i2c_board_info *devices, int num) platform_device_register(&ep93xx_i2c_device); } +/************************************************************************* + * EP93xx video peripheral handling + *************************************************************************/ +static struct ep93xxfb_mach_info ep93xxfb_data; + +static struct resource ep93xx_fb_resource[] = { + { + .start = EP93XX_RASTER_PHYS_BASE, + .end = EP93XX_RASTER_PHYS_BASE + 0x800 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device ep93xx_fb_device = { + .name = "ep93xxfb", + .id = 0, + .dev.platform_data = &ep93xxfb_data, + .dev.coherent_dma_mask = 0xf7ffffff, + .num_resources = ARRAY_SIZE(ep93xx_fb_resource), + .resource = ep93xx_fb_resource, +}; + +void __init ep93xx_register_fb(struct ep93xxfb_mach_info *data) +{ + ep93xxfb_data = *data; + platform_device_register(&ep93xx_fb_device); +} + extern void ep93xx_gpio_init(void); void __init ep93xx_init_devices(void) diff --git a/arch/arm/mach-ep93xx/include/mach/fb.h b/arch/arm/mach-ep93xx/include/mach/fb.h new file mode 100644 index 0000000..3bb9f04 --- /dev/null +++ b/arch/arm/mach-ep93xx/include/mach/fb.h @@ -0,0 +1,56 @@ +/* + * arch/arm/mach-ep93xx/include/mach/fb.h + */ + +#ifndef __ASM_ARCH_EP93XXFB_H +#define __ASM_ARCH_EP93XXFB_H + +struct fb_videomode; +struct fb_info; + +#define EP93XXFB_USE_MODEDB 0 + +/* VideoAttributes flags */ +#define EP93XXFB_STATE_MACHINE_ENABLE (1 << 0) +#define EP93XXFB_PIXEL_CLOCK_ENABLE (1 << 1) +#define EP93XXFB_VSYNC_ENABLE (1 << 2) +#define EP93XXFB_PIXEL_DATA_ENABLE (1 << 3) +#define EP93XXFB_COMPOSITE_SYNC (1 << 4) +#define EP93XXFB_SYNC_VERT_HIGH (1 << 5) +#define EP93XXFB_SYNC_HORIZ_HIGH (1 << 6) +#define EP93XXFB_SYNC_BLANK_HIGH (1 << 7) +#define EP93XXFB_PCLK_FALLING (1 << 8) +#define EP93XXFB_ENABLE_AC (1 << 9) +#define EP93XXFB_ENABLE_LCD (1 << 10) +#define EP93XXFB_ENABLE_CCIR (1 << 12) +#define EP93XXFB_USE_PARALLEL_INTERFACE (1 << 13) +#define EP93XXFB_ENABLE_INTERRUPT (1 << 14) +#define EP93XXFB_USB_INTERLACE (1 << 16) +#define EP93XXFB_USE_EQUALIZATION (1 << 17) +#define EP93XXFB_USE_DOUBLE_HORZ (1 << 18) +#define EP93XXFB_USE_DOUBLE_VERT (1 << 19) +#define EP93XXFB_USE_BLANK_PIXEL (1 << 20) +#define EP93XXFB_USE_SDCSN0 (0 << 21) +#define EP93XXFB_USE_SDCSN1 (1 << 21) +#define EP93XXFB_USE_SDCSN2 (2 << 21) +#define EP93XXFB_USE_SDCSN3 (3 << 21) + +#define EP93XXFB_ENABLE (EP93XXFB_STATE_MACHINE_ENABLE | \ + EP93XXFB_PIXEL_CLOCK_ENABLE | \ + EP93XXFB_VSYNC_ENABLE | \ + EP93XXFB_PIXEL_DATA_ENABLE) + +struct ep93xxfb_mach_info { + unsigned int num_modes; + const struct fb_videomode *modes; + const struct fb_videomode *default_mode; + int bpp; + unsigned int flags; + + int (*setup)(struct fb_info *info); + void (*teardown)(struct fb_info *info); + void (*blank)(int blank_mode, + struct fb_info *info); +}; + +#endif /* __ASM_ARCH_EP93XXFB_H */ diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h index 05f0f4f..99fcef2 100644 --- a/arch/arm/mach-ep93xx/include/mach/platform.h +++ b/arch/arm/mach-ep93xx/include/mach/platform.h @@ -5,6 +5,7 @@ #ifndef __ASSEMBLY__ struct i2c_board_info; +struct ep93xxfb_mach_info; struct ep93xx_eth_data { @@ -17,6 +18,7 @@ void ep93xx_init_irq(void); void ep93xx_init_time(unsigned long); void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr); void ep93xx_register_i2c(struct i2c_board_info *devices, int num); +void ep93xx_register_fb(struct ep93xxfb_mach_info *data); void ep93xx_init_devices(void); extern struct sys_timer ep93xx_timer; diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 7826bdc..1e54bf3 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -2114,6 +2114,17 @@ config FB_MB862XX_LIME ---help--- Framebuffer support for Fujitsu Lime GDC on host CPU bus. +config FB_EP93XX + tristate "EP93XX frame buffer support" + depends on FB && ARCH_EP93XX + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + Framebuffer driver for the Cirrus Logic EP93XX series of processors. + This driver is also available as a module. The module will be called + ep93xxfb. + config FB_PRE_INIT_FB bool "Don't reinitialize, use bootloader's GDC/Display configuration" depends on FB_MB862XX_LIME diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 0dbd6c6..f8c1bd4 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -126,6 +126,7 @@ obj-$(CONFIG_FB_OMAP) += omap/ obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o obj-$(CONFIG_FB_CARMINE) += carminefb.o obj-$(CONFIG_FB_MB862XX) += mb862xx/ +obj-$(CONFIG_FB_EP93XX) += ep93xxfb.o # Platform or fallback drivers go here obj-$(CONFIG_FB_UVESA) += uvesafb.o diff --git a/drivers/video/ep93xxfb.c b/drivers/video/ep93xxfb.c new file mode 100644 index 0000000..6c02520 --- /dev/null +++ b/drivers/video/ep93xxfb.c @@ -0,0 +1,658 @@ +/* + * linux/drivers/video/ep93xxfb.c + * + * Framebuffer support for the EP93xx series. + * + * Copyright (C) 2007 Bluewater Systems + * Author: Ryan Mallon <ry...@bl...> + * + * Copyright (c) 2009 H Hartley Sweeten <hsw...@vi...> + * + * Based on the Cirrus Logic ep93xxfb driver, and various other ep93xxfb + * drivers. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/clk.h> +#include <linux/fb.h> + +#include <mach/fb.h> + +/* Vertical Frame Timing Registers */ +#define EP93XXFB_VLINES_TOTAL 0x0000 /* SW locked */ +#define EP93XXFB_VSYNC 0x0004 /* SW locked */ +#define EP93XXFB_VACTIVE 0x0008 /* SW locked */ +#define EP93XXFB_VBLANK 0x0228 /* SW locked */ +#define EP93XXFB_VCLK 0x000c /* SW locked */ + +/* Horizontal Frame Timing Registers */ +#define EP93XXFB_HCLKS_TOTAL 0x0010 /* SW locked */ +#define EP93XXFB_HSYNC 0x0014 /* SW locked */ +#define EP93XXFB_HACTIVE 0x0018 /* SW locked */ +#define EP93XXFB_HBLANK 0x022c /* SW locked */ +#define EP93XXFB_HCLK 0x001c /* SW locked */ + +/* Frame Buffer Memory Configuration Registers */ +#define EP93XXFB_SCREEN_PAGE 0x0028 +#define EP93XXFB_SCREEN_HPAGE 0x002c +#define EP93XXFB_SCREEN_LINES 0x0030 +#define EP93XXFB_LINE_LENGTH 0x0034 +#define EP93XXFB_VLINE_STEP 0x0038 +#define EP93XXFB_LINE_CARRY 0x003c /* SW locked */ +#define EP93XXFB_EOL_OFFSET 0x0230 + +/* Other Video Registers */ +#define EP93XXFB_BRIGHTNESS 0x0020 +#define EP93XXFB_ATTRIBS 0x0024 /* SW locked */ +#define EP93XXFB_SWLOCK 0x007c /* SW locked */ +#define EP93XXFB_AC_RATE 0x0214 +#define EP93XXFB_FIFO_LEVEL 0x0234 +#define EP93XXFB_PIXELMODE 0x0054 +#define EP93XXFB_PARL_IF_OUT 0x0058 +#define EP93XXFB_PARL_IF_IN 0x005c + +/* Blink Control Registers */ +#define EP93XXFB_BLINK_RATE 0x0040 +#define EP93XXFB_BLINK_MASK 0x0044 +#define EP93XXFB_BLINK_PATTRN 0x0048 +#define EP93XXFB_PATTRN_MASK 0x004c +#define EP93XXFB_BKGRND_OFFSET 0x0050 + +/* Hardware Cursor Registers */ +#define EP93XXFB_CURSOR_ADR_START 0x0060 +#define EP93XXFB_CURSOR_ADR_RESET 0x0064 +#define EP93XXFB_CURSOR_SIZE 0x0068 +#define EP93XXFB_CURSOR_COLOR1 0x006c +#define EP93XXFB_CURSOR_COLOR2 0x0070 +#define EP93XXFB_CURSOR_BLINK_COLOR1 0x021c +#define EP93XXFB_CURSOR_BLINK_COLOR2 0x0220 +#define EP93XXFB_CURSOR_XY_LOC 0x0074 +#define EP93XXFB_CURSOR_DSCAN_HY_LOC 0x0078 +#define EP93XXFB_CURSOR_BLINK_RATE_CTRL 0x0224 + +/* LUT Registers */ +#define EP93XXFB_GRY_SCL_LUTR 0x0080 +#define EP93XXFB_GRY_SCL_LUTG 0x0280 +#define EP93XXFB_GRY_SCL_LUTB 0x0300 +#define EP93XXFB_LUT_SW_CONTROL 0x0218 +#define EP93XXFB_COLOR_LUT 0x0400 + +/* Video Signature Registers */ +#define EP93XXFB_VID_SIG_RSLT_VAL 0x0200 +#define EP93XXFB_VID_SIG_CTRL 0x0204 +#define EP93XXFB_VSIG 0x0208 +#define EP93XXFB_HSIG 0x020c +#define EP93XXFB_SIG_CLR_STR 0x0210 + +/* Minimum / Maximum resolutions supported */ +#define EP93XXFB_MIN_XRES 64 +#define EP93XXFB_MIN_YRES 64 +#define EP93XXFB_MAX_XRES 1024 +#define EP93XXFB_MAX_YRES 768 + +struct ep93xx_fbi { + struct ep93xxfb_mach_info *mach_info; + struct clk *clk; + struct resource *res; + void __iomem *mmio_base; + unsigned int pseudo_palette[256]; +}; + +static int check_screenpage_bug = 1; +module_param(check_screenpage_bug, int, 0644); +MODULE_PARM_DESC(check_screenpage_bug, + "Check for bit 27 screen page bug. Default = 1"); + +static inline unsigned int ep93xxfb_readl(struct ep93xx_fbi *fbi, + unsigned int off) +{ + return __raw_readl(fbi->mmio_base + off); +} + +static inline void ep93xxfb_writel(struct ep93xx_fbi *fbi, unsigned int val, + unsigned int off) +{ + __raw_writel(val, fbi->mmio_base + off); +} + +/* + * Write to one of the locked raster registers. + */ +static inline void ep93xxfb_out_locked(struct ep93xx_fbi *fbi, + unsigned int val, unsigned int reg) +{ + /* + * We don't need a lock or delay here since the raster register + * block will remain unlocked until the next access. + */ + ep93xxfb_writel(fbi, 0xaa, EP93XXFB_SWLOCK); + ep93xxfb_writel(fbi, val, reg); +} + +static void ep93xxfb_set_video_attribs(struct fb_info *info) +{ + struct ep93xx_fbi *fbi = info->par; + unsigned int attribs; + + attribs = EP93XXFB_ENABLE; + attribs |= fbi->mach_info->flags; + ep93xxfb_out_locked(fbi, attribs, EP93XXFB_ATTRIBS); +} + +static int ep93xxfb_set_pixelmode(struct fb_info *info) +{ + struct ep93xx_fbi *fbi = info->par; + unsigned int val; + + info->var.transp.offset = 0; + info->var.transp.length = 0; + + switch (info->var.bits_per_pixel) { + case 8: + /* + * TRBSW = 0 Normal Red/Green/Blue + * DSCAN = 0 Single Scan + * C = 0 Use LUT Data + * M = 0 Blink Mode Disabled + * S = 1 1 pixel mapped to 18-bits per clock + * P = 2 8-bits/pixel + */ + val = (0<<15) | (0<<14) | (0<<10) | (0<<6) | (1<<3) | (2<<0); + + info->var.red.offset = 0; + info->var.red.length = 8; + info->var.green.offset = 0; + info->var.green.length = 8; + info->var.blue.offset = 0; + info->var.blue.length = 8; + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + break; + + case 16: + /* + * TRBSW = 0 Normal Red/Green/Blue + * DSCAN = 0 Single Scan + * C = 5 16-bit 555 color mode + * M = 0 Blink Mode Disabled + * S = 1 1 pixel mapped to 18-bits per clock + * P = 4 16-bits/pixel + */ + val = (0<<15) | (0<<14) | (5<<10) | (0<<6) | (1<<3) | (4<<0); + + info->var.red.offset = 11; + info->var.red.length = 5; + info->var.green.offset = 5; + info->var.green.length = 6; + info->var.blue.offset = 0; + info->var.blue.length = 5; + info->fix.visual = FB_VISUAL_TRUECOLOR; + break; + + case 24: + /* + * TRBSW = 0 Normal Red/Green/Blue + * DSCAN = 0 Single Scan + * C = 4 Triple 8-bits per channel + * M = 0 Blink Mode Disabled + * S = 0 1 pixel per clock (up to 24-bits) + * P = 6 24-bits/pixel packed + */ + val = (0<<15) | (0<<14) | (4<<10) | (0<<6) | (0<<3) | (6<<0); + + info->var.red.offset = 16; + info->var.red.length = 8; + info->var.green.offset = 8; + info->var.green.length = 8; + info->var.blue.offset = 0; + info->var.blue.length = 8; + info->fix.visual = FB_VISUAL_TRUECOLOR; + break; + + case 32: + /* + * TRBSW = 0 Normal Red/Green/Blue + * DSCAN = 0 Single Scan + * C = 4 Triple 8-bits per channel + * M = 0 Blink Mode Disabled + * S = 0 1 pixel per clock (up to 24-bits) + * P = 7 32-bits per pixel (24-bits/pixel unpacked) + */ + val = (0<<15) | (0<<14) | (4<<10) | (0<<6) | (0<<3) | (7<<0); + + info->var.red.offset = 16; + info->var.red.length = 8; + info->var.green.offset = 8; + info->var.green.length = 8; + info->var.blue.offset = 0; + info->var.blue.length = 8; + info->fix.visual = FB_VISUAL_TRUECOLOR; + break; + + default: + return -EINVAL; + } + + ep93xxfb_writel(fbi, val, EP93XXFB_PIXELMODE); + return 0; +} + +static void ep93xxfb_set_timing(struct fb_info *info) +{ + struct ep93xx_fbi *fbi = info->par; + unsigned int vlines_total, hclks_total, start, stop; + + vlines_total = info->var.yres + info->var.upper_margin + + info->var.lower_margin + info->var.vsync_len - 1; + + hclks_total = info->var.xres + info->var.left_margin + + info->var.right_margin + info->var.hsync_len - 1; + + ep93xxfb_out_locked(fbi, vlines_total, EP93XXFB_VLINES_TOTAL); + ep93xxfb_out_locked(fbi, hclks_total, EP93XXFB_HCLKS_TOTAL); + + start = vlines_total; + stop = vlines_total - info->var.vsync_len; + ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VSYNC); + + start = vlines_total - info->var.vsync_len - info->var.upper_margin; + stop = info->var.lower_margin - 1; + ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VBLANK); + ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VACTIVE); + + start = vlines_total; + stop = vlines_total + 1; + ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VCLK); + + start = hclks_total; + stop = hclks_total - info->var.hsync_len; + ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HSYNC); + + start = hclks_total - info->var.hsync_len - info->var.left_margin; + stop = info->var.right_margin - 1; + ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HBLANK); + ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HACTIVE); + + start = hclks_total; + stop = hclks_total; + ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HCLK); + + ep93xxfb_out_locked(fbi, 0x0, EP93XXFB_LINE_CARRY); +} + +static int ep93xxfb_set_par(struct fb_info *info) +{ + struct ep93xx_fbi *fbi = info->par; + + clk_set_rate(fbi->clk, 1000 * PICOS2KHZ(info->var.pixclock)); + + ep93xxfb_set_timing(info); + + info->fix.line_length = info->var.xres_virtual * + info->var.bits_per_pixel / 8; + + ep93xxfb_writel(fbi, info->fix.smem_start, EP93XXFB_SCREEN_PAGE); + ep93xxfb_writel(fbi, info->var.yres - 1, EP93XXFB_SCREEN_LINES); + ep93xxfb_writel(fbi, ((info->var.xres * info->var.bits_per_pixel) + / 32) - 1, EP93XXFB_LINE_LENGTH); + ep93xxfb_writel(fbi, info->fix.line_length / 4, EP93XXFB_VLINE_STEP); + ep93xxfb_set_video_attribs(info); + return 0; +} + +static int ep93xxfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + int err; + + err = ep93xxfb_set_pixelmode(info); + if (err) + return err; + + var->xres = max(var->xres, (unsigned int)EP93XXFB_MIN_XRES); + var->xres = min(var->xres, (unsigned int)EP93XXFB_MAX_XRES); + var->xres_virtual = max(var->xres_virtual, var->xres); + + var->yres = max(var->yres, (unsigned int)EP93XXFB_MIN_YRES); + var->yres = min(var->yres, (unsigned int)EP93XXFB_MAX_YRES); + var->yres_virtual = max(var->yres_virtual, var->yres); + + return 0; +} + +static int ep93xxfb_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + unsigned int offset = vma->vm_pgoff << PAGE_SHIFT; + + if (offset < info->fix.smem_len) { + return dma_mmap_writecombine(info->dev, vma, info->screen_base, + info->fix.smem_start, + info->fix.smem_len); + } + + return -EINVAL; +} + +static int ep93xxfb_blank(int blank_mode, struct fb_info *info) +{ + struct ep93xx_fbi *fbi = info->par; + unsigned int attribs = ep93xxfb_readl(fbi, EP93XXFB_ATTRIBS); + + if (blank_mode) { + if (fbi->mach_info->blank) + fbi->mach_info->blank(blank_mode, info); + ep93xxfb_out_locked(fbi, attribs & ~EP93XXFB_ENABLE, + EP93XXFB_ATTRIBS); + clk_disable(fbi->clk); + } else { + clk_enable(fbi->clk); + ep93xxfb_out_locked(fbi, attribs | EP93XXFB_ENABLE, + EP93XXFB_ATTRIBS); + if (fbi->mach_info->blank) + fbi->mach_info->blank(blank_mode, info); + } + + return 0; +} + +static inline int ep93xxfb_convert_color(int val, int width) +{ + return ((val << width) + 0x7fff - val) >> 16; +} + +static int ep93xxfb_setcolreg(unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + unsigned int transp, struct fb_info *info) +{ + struct ep93xx_fbi *fbi = info->par; + unsigned int *pal = info->pseudo_palette; + unsigned int ctrl, i, rgb; + + switch (info->fix.visual) { + case FB_VISUAL_PSEUDOCOLOR: + rgb = ((red & 0xff00) << 8) | (green & 0xff00) | + ((blue & 0xff00) >> 8); + + pal[regno] = rgb; + ep93xxfb_writel(fbi, rgb, (EP93XXFB_COLOR_LUT + (regno << 2))); + ctrl = ep93xxfb_readl(fbi, EP93XXFB_LUT_SW_CONTROL); + + if (!!(ctrl & (1 << 1)) == !!(ctrl & (1 << 0))) { + for (i = 0; i < 256; i++) { + ep93xxfb_writel(fbi, pal[i], + EP93XXFB_COLOR_LUT + (i << 2)); + } + + ep93xxfb_writel(fbi, ctrl ^ (1<<0), + EP93XXFB_LUT_SW_CONTROL); + } + break; + + case FB_VISUAL_TRUECOLOR: + if (regno > 16) + return 1; + + red = ep93xxfb_convert_color(red, info->var.red.length); + green = ep93xxfb_convert_color(green, info->var.green.length); + blue = ep93xxfb_convert_color(blue, info->var.blue.length); + transp = ep93xxfb_convert_color(transp, + info->var.transp.length); + + pal[regno] = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset) | + (transp << info->var.transp.offset); + break; + + default: + return 1; + } + + return 0; +} + +static struct fb_ops ep93xxfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = ep93xxfb_check_var, + .fb_set_par = ep93xxfb_set_par, + .fb_blank = ep93xxfb_blank, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_setcolreg = ep93xxfb_setcolreg, + .fb_mmap = ep93xxfb_mmap, +}; + +static int __init ep93xxfb_calc_fbsize(struct ep93xxfb_mach_info *mach_info) +{ + int i, fb_size = 0; + + if (mach_info->num_modes == EP93XXFB_USE_MODEDB) { + fb_size = EP93XXFB_MAX_XRES * EP93XXFB_MAX_YRES * + mach_info->bpp / 8; + } else { + for (i = 0; i < mach_info->num_modes; i++) { + const struct fb_videomode *mode; + int size; + + mode = &mach_info->modes[i]; + size = mode->xres * mode->yres * mach_info->bpp / 8; + if (size > fb_size) + fb_size = size; + } + } + + return fb_size; +} + +static int __init ep93xxfb_alloc_videomem(struct fb_info *info) +{ + struct ep93xx_fbi *fbi = info->par; + char __iomem *virt_addr; + dma_addr_t phys_addr; + unsigned int fb_size; + + fb_size = ep93xxfb_calc_fbsize(fbi->mach_info); + virt_addr = dma_alloc_writecombine(info->dev, fb_size, + &phys_addr, GFP_KERNEL); + if (!virt_addr) + return -ENOMEM; + + /* + * There is a bug in the ep93xx framebuffer which causes problems + * if bit 27 of the physical address is set. + * See: http://marc.info/?l=linux-arm-kernel&m=110061245502000&w=2 + * There does not seem to be any offical errata for this, but I + * have confirmed the problem exists on my hardware (ep9315) at + * least. + */ + if (check_screenpage_bug && phys_addr & (1 << 27)) { + dev_err(info->dev, "ep93xx framebuffer bug. phys addr (0x%x) " + "has bit 27 set: cannot init framebuffer\n", + phys_addr); + + dma_free_coherent(info->dev, fb_size, virt_addr, phys_addr); + return -ENOMEM; + } + + info->fix.smem_start = phys_addr; + info->fix.smem_len = fb_size; + info->screen_base = virt_addr; + + return 0; +} + +static void ep93xxfb_dealloc_videomem(struct fb_info *info) +{ + if (info->screen_base) + dma_free_coherent(info->dev, info->fix.smem_len, + info->screen_base, info->fix.smem_start); +} + +static int __init ep93xxfb_probe(struct platform_device *pdev) +{ + struct ep93xxfb_mach_info *mach_info = pdev->dev.platform_data; + struct fb_info *info; + struct ep93xx_fbi *fbi; + struct resource *res; + char *video_mode; + int err; + + if (!mach_info) + return -EINVAL; + + info = framebuffer_alloc(sizeof(struct ep93xx_fbi), &pdev->dev); + if (!info) + return -ENOMEM; + + info->dev = &pdev->dev; + platform_set_drvdata(pdev, info); + fbi = info->par; + fbi->mach_info = mach_info; + + err = fb_alloc_cmap(&info->cmap, 256, 0); + if (err) + goto failed; + + err = ep93xxfb_alloc_videomem(info); + if (err) + goto failed; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + err = -ENXIO; + goto failed; + } + res = request_mem_region(res->start, resource_size(res), pdev->name); + if (res == NULL) { + err = -EBUSY; + goto failed; + } + fbi->res = res; + fbi->mmio_base = ioremap(res->start, resource_size(res)); + if (fbi->mmio_base == NULL) { + err = -ENXIO; + goto failed; + } + + strcpy(info->fix.id, pdev->name); + info->fbops = &ep93xxfb_ops; + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.accel = FB_ACCEL_NONE; + info->var.activate = FB_ACTIVATE_NOW; + info->var.vmode = FB_VMODE_NONINTERLACED; + info->flags = FBINFO_DEFAULT; + info->node = -1; + info->state = FBINFO_STATE_RUNNING; + info->pseudo_palette = &fbi->pseudo_palette; + + fb_get_options("ep93xxfb", &video_mode); + err = fb_find_mode(&info->var, info, video_mode, + fbi->mach_info->modes, fbi->mach_info->num_modes, + fbi->mach_info->default_mode, fbi->mach_info->bpp); + if (err == 0) { + dev_err(info->dev, "No suitable video mode found\n"); + err = -EINVAL; + goto failed; + } + + if (mach_info->setup) { + err = mach_info->setup(info); + if (err) + return err; + } + + err = ep93xxfb_check_var(&info->var, info); + if (err) + goto failed; + + fbi->clk = clk_get(info->dev, NULL); + if (IS_ERR(fbi->clk)) { + err = PTR_ERR(fbi->clk); + fbi->clk = NULL; + goto failed; + } + + ep93xxfb_set_par(info); + clk_enable(fbi->clk); + + err = register_framebuffer(info); + if (err) + goto failed; + + dev_info(info->dev, "registered. Mode = %dx%d-%d\n", + info->var.xres, info->var.yres, info->var.bits_per_pixel); + return 0; + +failed: + if (fbi->clk) + clk_put(fbi->clk); + if (fbi->mmio_base) + iounmap(fbi->mmio_base); + if (fbi->res) + release_mem_region(fbi->res->start, resource_size(fbi->res)); + ep93xxfb_dealloc_videomem(info); + if (&info->cmap) + fb_dealloc_cmap(&info->cmap); + if (fbi->mach_info->teardown) + fbi->mach_info->teardown(info); + kfree(info); + platform_set_drvdata(pdev, NULL); + + return err; +} + +static int ep93xxfb_remove(struct platform_device *pdev) +{ + struct fb_info *info = platform_get_drvdata(pdev); + struct ep93xx_fbi *fbi = info->par; + + unregister_framebuffer(info); + clk_disable(fbi->clk); + clk_put(fbi->clk); + iounmap(fbi->mmio_base); + release_mem_region(fbi->res->start, resource_size(fbi->res)); + ep93xxfb_dealloc_videomem(info); + fb_dealloc_cmap(&info->cmap); + + if (fbi->mach_info->teardown) + fbi->mach_info->teardown(info); + + kfree(info); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver ep93xxfb_driver = { + .probe = ep93xxfb_probe, + .remove = ep93xxfb_remove, + .driver = { + .name = "ep93xxfb", + .owner = THIS_MODULE, + }, +}; + +static int __devinit ep93xxfb_init(void) +{ + return platform_driver_register(&ep93xxfb_driver); +} + +static void __exit ep93xxfb_exit(void) +{ + platform_driver_unregister(&ep93xxfb_driver); +} + +module_init(ep93xxfb_init); +module_exit(ep93xxfb_exit); + +MODULE_DESCRIPTION("EP93XX Framebuffer Driver"); +MODULE_ALIAS("platform:ep93xxfb"); +MODULE_AUTHOR("Ryan Mallon <ryan&bluewatersys.com>, " + "H Hartley Sweeten <hsw...@vi..."); +MODULE_LICENSE("GPL"); |
From: Krzysztof H. <krz...@po...> - 2009-05-24 11:36:56
|
Hi Eric, My comments are below. Kind regards, Krzysztof On Thu, 21 May 2009 22:28:14 +0800 Eric Miao <eri...@gm...> wrote: > Incorporated all the feedback, except for the duplicated fbi->dev with > info->dev, which could be easier for some function to do dev_xxx() > message output. > > ===========>8=========== > > This driver is originally written by Lennert, modified by Green to be > feature complete, and ported by Jun Nie and Kevin Liu for pxa168/910 > processors. > > The patch adds support for the on-chip LCD display controller, it > currently supports the base (graphics) layer only. > > Signed-off-by: Lennert Buytenhek <bu...@ma...> > Signed-off-by: Green Wan <gw...@ma...> > Cc: Peter Liao <pl...@ma...> > Signed-off-by: Jun Nie <nj...@ma...> > Signed-off-by: Kevin Liu <kl...@ma...> > Signed-off-by: Eric Miao <eri...@ma...> > --- > drivers/video/Kconfig | 10 + > drivers/video/Makefile | 1 + > drivers/video/pxa168fb.c | 798 ++++++++++++++++++++++++++++++++++++++++++++++ > drivers/video/pxa168fb.h | 558 ++++++++++++++++++++++++++++++++ > include/video/pxa168fb.h | 128 ++++++++ > 5 files changed, 1495 insertions(+), 0 deletions(-) > create mode 100644 drivers/video/pxa168fb.c > create mode 100644 drivers/video/pxa168fb.h > create mode 100644 include/video/pxa168fb.h > > diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig > index 0048f11..13fd66a 100644 > --- a/drivers/video/Kconfig > +++ b/drivers/video/Kconfig > @@ -1759,6 +1759,16 @@ config FB_68328 > Say Y here if you want to support the built-in frame buffer of > the Motorola 68328 CPU family. > > +config FB_PXA168 > + tristate "PXA168/910 LCD framebuffer support" > + depends on FB && (CPU_PXA168 || CPU_PXA910) > + select FB_CFB_FILLRECT > + select FB_CFB_COPYAREA > + select FB_CFB_IMAGEBLIT > + ---help--- > + Frame buffer driver for the built-in LCD controller in the Marvell > + MMP processor. > + > config FB_PXA > tristate "PXA LCD framebuffer support" > depends on FB && ARCH_PXA > diff --git a/drivers/video/Makefile b/drivers/video/Makefile > index d8d0be5..01a819f 100644 > --- a/drivers/video/Makefile > +++ b/drivers/video/Makefile > @@ -97,6 +97,7 @@ obj-$(CONFIG_FB_GBE) += gbefb.o > obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o > obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o > obj-$(CONFIG_FB_PXA) += pxafb.o > +obj-$(CONFIG_FB_PXA168) += pxa168fb.o > obj-$(CONFIG_FB_W100) += w100fb.o > obj-$(CONFIG_FB_TMIO) += tmiofb.o > obj-$(CONFIG_FB_AU1100) += au1100fb.o > diff --git a/drivers/video/pxa168fb.c b/drivers/video/pxa168fb.c > new file mode 100644 > index 0000000..707f20c > --- /dev/null > +++ b/drivers/video/pxa168fb.c > @@ -0,0 +1,798 @@ > +/* > + * linux/drivers/video/pxa168fb.c -- Marvell PXA168 LCD Controller > + * > + * Copyright (C) 2008 Marvell International Ltd. > + * All rights reserved. > + * > + * 2009-02-16 adapted from original version for PXA168/910 > + * Jun Nie <nj...@ma...> > + * > + * This file is subject to the terms and conditions of the GNU General Public > + * License. See the file COPYING in the main directory of this archive for > + * more details. > + */ > + > +#include <linux/module.h> > +#include <linux/kernel.h> > +#include <linux/sched.h> > +#include <linux/string.h> > +#include <linux/interrupt.h> > +#include <linux/slab.h> > +#include <linux/fb.h> > +#include <linux/delay.h> > +#include <linux/init.h> > +#include <linux/ioport.h> > +#include <linux/platform_device.h> > +#include <linux/dma-mapping.h> > +#include <linux/clk.h> > +#include <linux/err.h> > +#include <linux/uaccess.h> > +#include <video/pxa168fb.h> > + > +#include "pxa168fb.h" > + > +#define DEFAULT_REFRESH 60 /* Hz */ > + > +static int determine_best_pix_fmt(struct fb_var_screeninfo *var) > +{ > + /* > + * Pseudocolor mode? > + */ > + if (var->bits_per_pixel == 8) > + return PIX_FMT_PSEUDOCOLOR; > + > + /* > + * Check for 565/1555. > + */ > + if (var->bits_per_pixel == 16 && var->red.length <= 5 && > + var->green.length <= 6 && var->blue.length <= 5) { > + if (var->transp.length == 0) { > + if (var->red.offset >= var->blue.offset) > + return PIX_FMT_RGB565; > + else > + return PIX_FMT_BGR565; > + } > + > + if (var->transp.length == 1 && var->green.length <= 5) { > + if (var->red.offset >= var->blue.offset) > + return PIX_FMT_RGB1555; > + else > + return PIX_FMT_BGR1555; > + } > + > + /* fall through */ > + } > + > + /* > + * Check for 888/A888. > + */ > + if (var->bits_per_pixel <= 32 && var->red.length <= 8 && > + var->green.length <= 8 && var->blue.length <= 8) { > + if (var->bits_per_pixel == 24 && var->transp.length == 0) { > + if (var->red.offset >= var->blue.offset) > + return PIX_FMT_RGB888PACK; > + else > + return PIX_FMT_BGR888PACK; > + } > + > + if (var->bits_per_pixel == 32 && var->transp.length == 8) { > + if (var->red.offset >= var->blue.offset) > + return PIX_FMT_RGBA888; > + else > + return PIX_FMT_BGRA888; > + } else { > + if (var->red.offset >= var->blue.offset) > + return PIX_FMT_RGB888UNPACK; > + else > + return PIX_FMT_BGR888UNPACK; > + } > + > + /* fall through */ > + } > + > + return -EINVAL; > +} > + > +static void set_pix_fmt(struct fb_var_screeninfo *var, int pix_fmt) > +{ > + switch (pix_fmt) { > + case PIX_FMT_RGB565: > + var->bits_per_pixel = 16; > + var->red.offset = 11; var->red.length = 5; > + var->green.offset = 5; var->green.length = 6; > + var->blue.offset = 0; var->blue.length = 5; > + var->transp.offset = 0; var->transp.length = 0; > + break; > + case PIX_FMT_BGR565: > + var->bits_per_pixel = 16; > + 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; > + case PIX_FMT_RGB1555: > + var->bits_per_pixel = 16; > + var->red.offset = 10; var->red.length = 5; > + var->green.offset = 5; var->green.length = 5; > + var->blue.offset = 0; var->blue.length = 5; > + var->transp.offset = 15; var->transp.length = 1; > + break; > + case PIX_FMT_BGR1555: > + var->bits_per_pixel = 16; > + var->red.offset = 0; var->red.length = 5; > + var->green.offset = 5; var->green.length = 5; > + var->blue.offset = 10; var->blue.length = 5; > + var->transp.offset = 15; var->transp.length = 1; > + break; > + case PIX_FMT_RGB888PACK: > + var->bits_per_pixel = 24; > + var->red.offset = 16; var->red.length = 8; > + var->green.offset = 8; var->green.length = 8; > + var->blue.offset = 0; var->blue.length = 8; > + var->transp.offset = 0; var->transp.length = 0; > + break; > + case PIX_FMT_BGR888PACK: > + var->bits_per_pixel = 24; > + var->red.offset = 0; var->red.length = 8; > + var->green.offset = 8; var->green.length = 8; > + var->blue.offset = 16; var->blue.length = 8; > + var->transp.offset = 0; var->transp.length = 0; > + break; > + case PIX_FMT_RGBA888: > + var->bits_per_pixel = 32; > + var->red.offset = 16; var->red.length = 8; > + var->green.offset = 8; var->green.length = 8; > + var->blue.offset = 0; var->blue.length = 8; > + var->transp.offset = 24; var->transp.length = 8; > + break; > + case PIX_FMT_BGRA888: > + var->bits_per_pixel = 32; > + var->red.offset = 0; var->red.length = 8; > + var->green.offset = 8; var->green.length = 8; > + var->blue.offset = 16; var->blue.length = 8; > + var->transp.offset = 24; var->transp.length = 8; > + break; > + case PIX_FMT_PSEUDOCOLOR: > + var->bits_per_pixel = 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; > + } > +} > + > +static void set_mode(struct pxa168fb_info *fbi, struct fb_var_screeninfo *var, > + struct fb_videomode *mode, int pix_fmt, int ystretch) > +{ > + set_pix_fmt(var, pix_fmt); > + > + var->xres = mode->xres; > + var->yres = mode->yres; > + var->xres_virtual = max(var->xres, var->xres_virtual); > + if (ystretch) > + var->yres_virtual = fbi->fb_size / > + (var->xres_virtual * (var->bits_per_pixel >> 3)); > + else > + var->yres_virtual = max(var->yres, var->yres_virtual); > + var->grayscale = 0; > + var->accel_flags = FB_ACCEL_NONE; > + var->pixclock = mode->pixclock; > + var->left_margin = mode->left_margin; > + var->right_margin = mode->right_margin; > + var->upper_margin = mode->upper_margin; > + var->lower_margin = mode->lower_margin; > + var->hsync_len = mode->hsync_len; > + var->vsync_len = mode->vsync_len; > + var->sync = mode->sync; > + var->vmode = FB_VMODE_NONINTERLACED; > + var->rotate = FB_ROTATE_UR; > +} > + > +static int pxa168fb_check_var(struct fb_var_screeninfo *var, > + struct fb_info *info) > +{ > + struct pxa168fb_info *fbi = info->par; > + > + if (var->bits_per_pixel == 8) > + return -EINVAL; This blocks 8bpp (pseudocolor) mode which is handled in all switches. Also, there is no check here for modes above 8 bpp. The best solution is to call the set_pix_fmt() here and check its return value. Additional advantage is to update the var settings (it should be done in the check_var() not in the set_par() function). > + /* > + * Basic geometry sanity checks. > + */ > + if (var->xoffset + var->xres > var->xres_virtual) > + return -EINVAL; > + if (var->yoffset + var->yres > var->yres_virtual) > + return -EINVAL; > + if (var->xres + var->right_margin + > + var->hsync_len + var->left_margin > 2048) > + return -EINVAL; > + if (var->yres + var->lower_margin + > + var->vsync_len + var->upper_margin > 2048) > + return -EINVAL; > + > + /* > + * Check size of framebuffer. > + */ > + if (var->xres_virtual * var->yres_virtual * > + (var->bits_per_pixel >> 3) > fbi->fb_size) > + return -EINVAL; > + > + return 0; > +} > + > +/* > + * The hardware clock divider has an integer and a fractional > + * stage: > + * > + * clk2 = clk_in / integer_divider > + * clk_out = clk2 * (1 - (fractional_divider >> 12)) > + * > + * Calculate integer and fractional divider for given clk_in > + * and clk_out. > + */ > +static void set_clock_divider(struct pxa168fb_info *fbi, > + const struct fb_videomode *m) > +{ > + int divider_int; > + int needed_pixclk; > + u64 div_result; > + u32 x = 0; > + > + /* > + * Notice: The field pixclock is used by linux fb > + * is in pixel second. E.g. struct fb_videomode & > + * struct fb_var_screeninfo > + */ > + > + /* > + * Check input values. > + */ > + if (!m || !m->pixclock || !m->refresh) { > + dev_err(fbi->dev, "Input refresh or pixclock is wrong.\n"); > + return; > + } > + > + /* > + * Using PLL/AXI clock. > + */ > + x = 0x80000000; > + > + /* > + * Calc divider according to refresh rate. > + */ > + div_result = 1000000000000ll; > + do_div(div_result, m->pixclock); > + needed_pixclk = (u32)div_result; > + > + divider_int = clk_get_rate(fbi->clk) / needed_pixclk; > + > + /* check whether divisor is too small. */ > + if (divider_int < 2) { > + dev_warn(fbi->dev, "Warning: clock source is too slow." > + "Try smaller resolution\n"); > + divider_int = 2; > + } > + > + /* > + * Set setting to reg. > + */ > + x |= divider_int; > + writel(x, fbi->reg_base + LCD_CFG_SCLK_DIV); > +} > + > +static void set_dma_control0(struct pxa168fb_info *fbi) > +{ > + u32 x; > + > + /* > + * Set bit to enable graphics DMA. > + */ > + x = readl(fbi->reg_base + LCD_SPU_DMA_CTRL0); > + x |= fbi->active ? 0x00000100 : 0; > + fbi->active = 0; > + > + /* > + * If we are in a pseudo-color mode, we need to enable > + * palette lookup. > + */ > + if (fbi->pix_fmt == PIX_FMT_PSEUDOCOLOR) > + x |= 0x10000000; > + > + /* > + * Configure hardware pixel format. > + */ > + x &= ~(0xF << 16); > + x |= (fbi->pix_fmt >> 1) << 16; > + > + /* > + * Check red and blue pixel swap. > + * 1. source data swap > + * 2. panel output data swap > + */ > + x &= ~(1 << 12); > + x |= ((fbi->pix_fmt & 1) ^ (fbi->panel_rbswap)) << 12; > + > + writel(x, fbi->reg_base + LCD_SPU_DMA_CTRL0); > +} > + > +static void set_dma_control1(struct pxa168fb_info *fbi, int sync) > +{ > + u32 x; > + > + /* > + * Configure default bits: vsync triggers DMA, gated clock > + * enable, power save enable, configure alpha registers to > + * display 100% graphics, and set pixel command. > + */ > + x = readl(fbi->reg_base + LCD_SPU_DMA_CTRL1); > + x |= 0x2032ff81; > + > + /* > + * We trigger DMA on the falling edge of vsync if vsync is > + * active low, or on the rising edge if vsync is active high. > + */ > + if (!(sync & FB_SYNC_VERT_HIGH_ACT)) > + x |= 0x08000000; > + > + writel(x, fbi->reg_base + LCD_SPU_DMA_CTRL1); > +} > + > +static void set_graphics_start(struct fb_info *info, int xoffset, int yoffset) > +{ > + struct pxa168fb_info *fbi = info->par; > + struct fb_var_screeninfo *var = &info->var; > + int pixel_offset; > + unsigned long addr; > + > + pixel_offset = (yoffset * var->xres_virtual) + xoffset; > + > + addr = fbi->fb_start_dma + (pixel_offset * (var->bits_per_pixel >> 3)); > + writel(addr, fbi->reg_base + LCD_CFG_GRA_START_ADDR0); > +} > + > +static void set_dumb_panel_control(struct fb_info *info) > +{ > + struct pxa168fb_info *fbi = info->par; > + struct pxa168fb_mach_info *mi = fbi->dev->platform_data; > + u32 x; > + > + /* > + * Preserve enable flag. > + */ > + x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL) & 0x00000001; > + > + x |= (fbi->is_blanked ? 0x7 : mi->dumb_mode) << 28; > + x |= mi->gpio_output_data << 20; > + x |= mi->gpio_output_mask << 12; > + x |= mi->panel_rgb_reverse_lanes ? 0x00000080 : 0; > + x |= mi->invert_composite_blank ? 0x00000040 : 0; > + x |= (info->var.sync & FB_SYNC_COMP_HIGH_ACT) ? 0x00000020 : 0; > + x |= mi->invert_pix_val_ena ? 0x00000010 : 0; > + x |= (info->var.sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 0x00000008; > + x |= (info->var.sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 0x00000004; > + x |= mi->invert_pixclock ? 0x00000002 : 0; > + > + writel(x, fbi->reg_base + LCD_SPU_DUMB_CTRL); > +} > + > +static void set_dumb_screen_dimensions(struct fb_info *info) > +{ > + struct pxa168fb_info *fbi = info->par; > + struct fb_var_screeninfo *v = &info->var; > + int x; > + int y; > + > + x = v->xres + v->right_margin + v->hsync_len + v->left_margin; > + y = v->yres + v->lower_margin + v->vsync_len + v->upper_margin; > + > + writel((y << 16) | x, fbi->reg_base + LCD_SPUT_V_H_TOTAL); > +} > + > +static int pxa168fb_set_par(struct fb_info *info) > +{ > + struct pxa168fb_info *fbi = info->par; > + struct fb_var_screeninfo *var = &info->var; > + struct fb_videomode mode; > + int pix_fmt; > + u32 x; > + struct pxa168fb_mach_info *mi; > + > + mi = fbi->dev->platform_data; > + /* > + * Determine which pixel format we're going to use. > + */ > + pix_fmt = determine_best_pix_fmt(&info->var); > + if (pix_fmt < 0) > + return pix_fmt; > + fbi->pix_fmt = pix_fmt; > + > + /* > + * Set additional mode info. > + */ > + if (pix_fmt == PIX_FMT_PSEUDOCOLOR) > + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; > + else > + info->fix.visual = FB_VISUAL_TRUECOLOR; > + info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8; > + info->fix.ypanstep = var->yres; > + > + /* > + * Disable panel output while we setup the display. > + */ > + x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL); > + writel(x & ~1, fbi->reg_base + LCD_SPU_DUMB_CTRL); > + > + /* > + * Configure global panel parameters. > + */ > + writel((var->yres << 16) | var->xres, > + fbi->reg_base + LCD_SPU_V_H_ACTIVE); > + > + /* > + * convet var to video mode > + */ > + fb_var_to_videomode(&mode, &info->var); > + > + /* Calculate clock divisor. */ > + set_clock_divider(fbi, &mode); > + > + /* Configure dma ctrl regs. */ > + set_dma_control0(fbi); > + set_dma_control1(fbi, info->var.sync); > + > + /* > + * Configure graphics DMA parameters. > + */ > + set_graphics_start(info, info->var.xoffset, info->var.yoffset); The fb_pan_display() is called after the set_par() by a higher layer. There is no need to pan display here. > + x = readl(fbi->reg_base + LCD_CFG_GRA_PITCH); > + x = (x & ~0xFFFF) | ((var->xres_virtual * var->bits_per_pixel) >> 3); > + writel(x, fbi->reg_base + LCD_CFG_GRA_PITCH); > + writel((var->yres << 16) | var->xres, > + fbi->reg_base + LCD_SPU_GRA_HPXL_VLN); > + writel((var->yres << 16) | var->xres, > + fbi->reg_base + LCD_SPU_GZM_HPXL_VLN); > + > + /* > + * Configure dumb panel ctrl regs & timings. > + */ > + set_dumb_panel_control(info); > + set_dumb_screen_dimensions(info); > + > + writel((var->left_margin << 16) | var->right_margin, > + fbi->reg_base + LCD_SPU_H_PORCH); > + writel((var->upper_margin << 16) | var->lower_margin, > + fbi->reg_base + LCD_SPU_V_PORCH); > + > + /* > + * Re-enable panel output. > + */ > + x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL); > + writel(x | 1, fbi->reg_base + LCD_SPU_DUMB_CTRL); > + > + return 0; > +} > + > +static unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf) > +{ > + return ((chan & 0xffff) >> (16 - bf->length)) << bf->offset; > +} > + > +static u32 to_rgb(u16 red, u16 green, u16 blue) > +{ > + red >>= 8; > + green >>= 8; > + blue >>= 8; > + > + return (red << 16) | (green << 8) | blue; > +} > + > +static int > +pxa168fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, > + unsigned int blue, unsigned int trans, struct fb_info *info) > +{ > + struct pxa168fb_info *fbi = info->par; > + u32 val; > + > + if (info->var.grayscale) > + red = green = blue = (19595 * red + 38470 * green + > + 7471 * blue) >> 16; > + > + if (info->fix.visual == FB_VISUAL_TRUECOLOR && regno < 16) { > + val = chan_to_field(red, &info->var.red); > + val |= chan_to_field(green, &info->var.green); > + val |= chan_to_field(blue , &info->var.blue); > + fbi->pseudo_palette[regno] = val; > + } > + > + if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) { > + val = to_rgb(red, green, blue); > + writel(val, fbi->reg_base + LCD_SPU_SRAM_WRDAT); > + writel(0x8300 | regno, fbi->reg_base + LCD_SPU_SRAM_CTRL); > + } > + > + return 0; > +} > + > +static int pxa168fb_blank(int blank, struct fb_info *info) > +{ > + struct pxa168fb_info *fbi = info->par; > + > + fbi->is_blanked = (blank == FB_BLANK_UNBLANK) ? 0 : 1; > + set_dumb_panel_control(info); > + > + return 0; > +} > + > +static int pxa168fb_pan_display(struct fb_var_screeninfo *var, > + struct fb_info *info) > +{ > + set_graphics_start(info, var->xoffset, var->yoffset); > + The set_graphics_start() can be moved here. > + return 0; > +} > + > +static irqreturn_t pxa168fb_handle_irq(int irq, void *dev_id) > +{ > + struct pxa168fb_info *fbi = dev_id; > + u32 isr = readl(fbi->reg_base + SPU_IRQ_ISR); > + > + if ((isr & GRA_FRAME_IRQ0_ENA_MASK)) { > + > + writel(isr & (~GRA_FRAME_IRQ0_ENA_MASK), > + fbi->reg_base + SPU_IRQ_ISR); > + > + return IRQ_HANDLED; > + } > + return IRQ_NONE; > +} > + > +static struct fb_ops pxa168fb_ops = { > + .owner = THIS_MODULE, > + .fb_check_var = pxa168fb_check_var, > + .fb_set_par = pxa168fb_set_par, > + .fb_setcolreg = pxa168fb_setcolreg, > + .fb_blank = pxa168fb_blank, > + .fb_pan_display = pxa168fb_pan_display, > + .fb_fillrect = cfb_fillrect, > + .fb_copyarea = cfb_copyarea, > + .fb_imageblit = cfb_imageblit, > +}; > + > +static int pxa168fb_init_mode(struct fb_info *info, > + struct pxa168fb_mach_info *mi) > +{ It can be __init function. > + struct pxa168fb_info *fbi = info->par; > + struct fb_var_screeninfo *var = &info->var; > + int ret = 0; > + u32 total_w, total_h, refresh; > + u64 div_result; > + const struct fb_videomode *m; > + > + /* > + * Set default value > + */ > + refresh = DEFAULT_REFRESH; > + > + /* try to find best video mode. */ > + m = fb_find_best_mode(&info->var, &info->modelist); > + if (m) > + fb_videomode_to_var(&info->var, m); > + > + /* Init settings. */ > + var->xres_virtual = var->xres; > + var->yres_virtual = fbi->fb_size / > + (var->xres_virtual * (var->bits_per_pixel >> 3)); > + dev_dbg(fbi->dev, "pxa168fb: find best mode: res = %dx%d\n", > + var->xres, var->yres); > + > + /* correct pixclock. */ > + total_w = var->xres + var->left_margin + var->right_margin + > + var->hsync_len; > + total_h = var->yres + var->upper_margin + var->lower_margin + > + var->vsync_len; > + > + div_result = 1000000000000ll; > + do_div(div_result, total_w * total_h * refresh); > + var->pixclock = (u32)div_result; > + > + return ret; > +} > + > +static int __init pxa168fb_probe(struct platform_device *pdev) > +{ > + struct pxa168fb_mach_info *mi; > + struct fb_info *info = 0; > + struct pxa168fb_info *fbi = 0; > + struct resource *res; > + struct clk *clk; > + int irq, ret; > + > + mi = pdev->dev.platform_data; > + if (mi == NULL) { > + dev_err(&pdev->dev, "no platform data defined\n"); > + return -EINVAL; > + } > + > + clk = clk_get(&pdev->dev, "LCDCLK"); > + if (IS_ERR(clk)) { > + dev_err(&pdev->dev, "unable to get LCDCLK"); > + return PTR_ERR(clk); > + } > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (res == NULL) { > + dev_err(&pdev->dev, "no IO memory defined\n"); > + return -ENOENT; > + } > + > + irq = platform_get_irq(pdev, 0); > + if (irq < 0) { > + dev_err(&pdev->dev, "no IRQ defined\n"); > + return -ENOENT; > + } > + > + info = framebuffer_alloc(sizeof(struct pxa168fb_info), &pdev->dev); > + if (info == NULL) > + return -ENOMEM; > + > + /* Initialize private data */ > + fbi = info->par; > + platform_set_drvdata(pdev, fbi); > + fbi->clk = clk; > + fbi->dev = info->dev = &pdev->dev; > + fbi->panel_rbswap = mi->panel_rbswap; > + fbi->is_blanked = 0; > + fbi->active = mi->active; > + > + /* > + * Initialise static fb parameters. > + */ > + info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK | > + FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN; > + info->node = -1; > + strlcpy(info->fix.id, mi->id, 16); > + info->fix.type = FB_TYPE_PACKED_PIXELS; > + info->fix.type_aux = 0; > + info->fix.xpanstep = 0; > + info->fix.ypanstep = 0; > + info->fix.ywrapstep = 0; > + info->fix.mmio_start = res->start; > + info->fix.mmio_len = res->end - res->start + 1; > + info->fix.accel = FB_ACCEL_NONE; > + info->fbops = &pxa168fb_ops; > + info->pseudo_palette = fbi->pseudo_palette; > + > + /* > + * Map LCD controller registers. > + */ > + fbi->reg_base = ioremap_nocache(res->start, res->end - res->start); > + if (fbi->reg_base == NULL) { > + ret = -ENOMEM; > + goto failed; > + } > + > + /* > + * Allocate framebuffer memory. > + */ > + fbi->fb_size = PAGE_ALIGN(DEFAULT_FB_SIZE); > + > + fbi->fb_start = dma_alloc_writecombine(fbi->dev, fbi->fb_size, > + &fbi->fb_start_dma, > + GFP_KERNEL); > + if (fbi->fb_start == NULL) { > + ret = -ENOMEM; > + goto failed; > + } > + > + info->fix.smem_start = fbi->fb_start_dma; > + info->fix.smem_len = fbi->fb_size; > + info->screen_base = fbi->fb_start; > + info->screen_size = fbi->fb_size; > + Please do not duplicate standard fb_info fields. Just use the screen_base, screen_size and the smem_len. The smem_start is only unsigned long type so it may be not the same as the dma_addr_t. > + /* > + * Set video mode according to platform data. > + */ > + set_mode(fbi, &info->var, mi->modes, mi->pix_fmt, 1); > + > + fb_videomode_to_modelist(mi->modes, mi->num_modes, &info->modelist); > + > + /* > + * init video mode data. > + */ > + pxa168fb_init_mode(info, mi); > + > + /* > + * enable controller clock > + */ > + clk_enable(fbi->clk); > + > + /* > + * Fill in sane defaults. > + */ > + pxa168fb_set_par(info); The check_var() function should fill the sane defaults. The set_par() sends them to hardware's registers. This call is probably not needed here (the set_par() is usually called by the framebuffer_register()). > + > + /* > + * Configure default register values. > + */ > + writel(0, fbi->reg_base + LCD_SPU_BLANKCOLOR); > + writel(mi->io_pin_allocation_mode, fbi->reg_base + SPU_IOPAD_CONTROL); > + writel(0, fbi->reg_base + LCD_CFG_GRA_START_ADDR1); > + writel(0, fbi->reg_base + LCD_SPU_GRA_OVSA_HPXL_VLN); > + writel(0, fbi->reg_base + LCD_SPU_SRAM_PARA0); > + writel(CFG_CSB_256x32(0x1)|CFG_CSB_256x24(0x1)|CFG_CSB_256x8(0x1), > + fbi->reg_base + LCD_SPU_SRAM_PARA1); > + > + /* > + * Allocate color map. > + */ > + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { > + ret = -ENOMEM; > + goto failed_free_clk; > + } > + > + /* > + * Register irq handler. > + */ > + ret = request_irq(irq, pxa168fb_handle_irq, IRQF_SHARED, > + info->fix.id, fbi); > + if (ret < 0) { > + dev_err(&pdev->dev, "unable to request IRQ\n"); > + ret = -ENXIO; > + goto failed_free_cmap; > + } > + > + /* > + * Enable GFX interrupt > + */ > + writel(GRA_FRAME_IRQ0_ENA(0x1), fbi->reg_base + SPU_IRQ_ENA); > + > + /* > + * Register framebuffer. > + */ > + ret = register_framebuffer(info); > + if (ret < 0) { > + dev_err(&pdev->dev, "Failed to register pxa168-fb: %d\n", ret); > + ret = -ENXIO; > + goto failed_free_irq; > + } > + > + return 0; > + > +failed_free_irq: > + free_irq(irq, fbi); > +failed_free_cmap: > + fb_dealloc_cmap(&info->cmap); > +failed_free_clk: > + clk_disable(fbi->clk); > + clk_put(fbi->clk); > +failed: > + pr_err("pxa168-fb: frame buffer device init failed\n"); > + platform_set_drvdata(pdev, NULL); > + fb_dealloc_cmap(&info->cmap); It is deallocated here the second time. > + > + if (fbi && fbi->reg_base) { > + iounmap(fbi->reg_base); > + kfree(fbi); The info structure is not deallocated here. Releasing the fbi pointer is an error. > + } > + > + return ret; > +} > + > +static struct platform_driver pxa168fb_driver = { > + .driver = { > + .name = "pxa168-fb", > + .owner = THIS_MODULE, > + }, > + .probe = pxa168fb_probe, > +}; > + > +static int __devinit pxa168fb_init(void) > +{ > + return platform_driver_register(&pxa168fb_driver); > +} > +module_init(pxa168fb_init); > + > +MODULE_AUTHOR("Lennert Buytenhek <bu...@ma...> " > + "Green Wan <gw...@ma...>"); > +MODULE_DESCRIPTION("Framebuffer driver for PXA168/910"); > +MODULE_LICENSE("GPL"); > diff --git a/drivers/video/pxa168fb.h b/drivers/video/pxa168fb.h > new file mode 100644 > index 0000000..eee0927 > --- /dev/null > +++ b/drivers/video/pxa168fb.h > @@ -0,0 +1,558 @@ > +#ifndef __PXA168FB_H__ > +#define __PXA168FB_H__ > + > +/* ------------< LCD register >------------ */ > +/* Video Frame 0&1 start address registers */ > +#define LCD_SPU_DMA_START_ADDR_Y0 0x00C0 > +#define LCD_SPU_DMA_START_ADDR_U0 0x00C4 > +#define LCD_SPU_DMA_START_ADDR_V0 0x00C8 > +#define LCD_CFG_DMA_START_ADDR_0 0x00CC /* Cmd address */ > +#define LCD_SPU_DMA_START_ADDR_Y1 0x00D0 > +#define LCD_SPU_DMA_START_ADDR_U1 0x00D4 > +#define LCD_SPU_DMA_START_ADDR_V1 0x00D8 > +#define LCD_CFG_DMA_START_ADDR_1 0x00DC /* Cmd address */ > + > +/* YC & UV Pitch */ > +#define LCD_SPU_DMA_PITCH_YC 0x00E0 > +#define SPU_DMA_PITCH_C(c) ((c) << 16) > +#define SPU_DMA_PITCH_Y(y) (y) > +#define LCD_SPU_DMA_PITCH_UV 0x00E4 > +#define SPU_DMA_PITCH_V(v) ((v) << 16) > +#define SPU_DMA_PITCH_U(u) (u) > + > +/* Video Starting Point on Screen Register */ > +#define LCD_SPUT_DMA_OVSA_HPXL_VLN 0x00E8 > +#define CFG_DMA_OVSA_VLN(y) ((y) << 16) /* 0~0xfff */ > +#define CFG_DMA_OVSA_HPXL(x) (x) /* 0~0xfff */ > + > +/* Video Size Register */ > +#define LCD_SPU_DMA_HPXL_VLN 0x00EC > +#define CFG_DMA_VLN(y) ((y) << 16) > +#define CFG_DMA_HPXL(x) (x) > + > +/* Video Size After zooming Register */ > +#define LCD_SPU_DZM_HPXL_VLN 0x00F0 > +#define CFG_DZM_VLN(y) ((y) << 16) > +#define CFG_DZM_HPXL(x) (x) > + > +/* Graphic Frame 0&1 Starting Address Register */ > +#define LCD_CFG_GRA_START_ADDR0 0x00F4 > +#define LCD_CFG_GRA_START_ADDR1 0x00F8 > + > +/* Graphic Frame Pitch */ > +#define LCD_CFG_GRA_PITCH 0x00FC > + > +/* Graphic Starting Point on Screen Register */ > +#define LCD_SPU_GRA_OVSA_HPXL_VLN 0x0100 > +#define CFG_GRA_OVSA_VLN(y) ((y) << 16) > +#define CFG_GRA_OVSA_HPXL(x) (x) > + > +/* Graphic Size Register */ > +#define LCD_SPU_GRA_HPXL_VLN 0x0104 > +#define CFG_GRA_VLN(y) ((y) << 16) > +#define CFG_GRA_HPXL(x) (x) > + > +/* Graphic Size after Zooming Register */ > +#define LCD_SPU_GZM_HPXL_VLN 0x0108 > +#define CFG_GZM_VLN(y) ((y) << 16) > +#define CFG_GZM_HPXL(x) (x) > + > +/* HW Cursor Starting Point on Screen Register */ > +#define LCD_SPU_HWC_OVSA_HPXL_VLN 0x010C > +#define CFG_HWC_OVSA_VLN(y) ((y) << 16) > +#define CFG_HWC_OVSA_HPXL(x) (x) > + > +/* HW Cursor Size */ > +#define LCD_SPU_HWC_HPXL_VLN 0x0110 > +#define CFG_HWC_VLN(y) ((y) << 16) > +#define CFG_HWC_HPXL(x) (x) > + > +/* Total Screen Size Register */ > +#define LCD_SPUT_V_H_TOTAL 0x0114 > +#define CFG_V_TOTAL(y) ((y) << 16) > +#define CFG_H_TOTAL(x) (x) > + > +/* Total Screen Active Size Register */ > +#define LCD_SPU_V_H_ACTIVE 0x0118 > +#define CFG_V_ACTIVE(y) ((y) << 16) > +#define CFG_H_ACTIVE(x) (x) > + > +/* Screen H&V Porch Register */ > +#define LCD_SPU_H_PORCH 0x011C > +#define CFG_H_BACK_PORCH(b) ((b) << 16) > +#define CFG_H_FRONT_PORCH(f) (f) > +#define LCD_SPU_V_PORCH 0x0120 > +#define CFG_V_BACK_PORCH(b) ((b) << 16) > +#define CFG_V_FRONT_PORCH(f) (f) > + > +/* Screen Blank Color Register */ > +#define LCD_SPU_BLANKCOLOR 0x0124 > +#define CFG_BLANKCOLOR_MASK 0x00FFFFFF > +#define CFG_BLANKCOLOR_R_MASK 0x000000FF > +#define CFG_BLANKCOLOR_G_MASK 0x0000FF00 > +#define CFG_BLANKCOLOR_B_MASK 0x00FF0000 > + > +/* HW Cursor Color 1&2 Register */ > +#define LCD_SPU_ALPHA_COLOR1 0x0128 > +#define CFG_HWC_COLOR1 0x00FFFFFF > +#define CFG_HWC_COLOR1_R(red) ((red) << 16) > +#define CFG_HWC_COLOR1_G(green) ((green) << 8) > +#define CFG_HWC_COLOR1_B(blue) (blue) > +#define CFG_HWC_COLOR1_R_MASK 0x000000FF > +#define CFG_HWC_COLOR1_G_MASK 0x0000FF00 > +#define CFG_HWC_COLOR1_B_MASK 0x00FF0000 > +#define LCD_SPU_ALPHA_COLOR2 0x012C > +#define CFG_HWC_COLOR2 0x00FFFFFF > +#define CFG_HWC_COLOR2_R_MASK 0x000000FF > +#define CFG_HWC_COLOR2_G_MASK 0x0000FF00 > +#define CFG_HWC_COLOR2_B_MASK 0x00FF0000 > + > +/* Video YUV Color Key Control */ > +#define LCD_SPU_COLORKEY_Y 0x0130 > +#define CFG_CKEY_Y2(y2) ((y2) << 24) > +#define CFG_CKEY_Y2_MASK 0xFF000000 > +#define CFG_CKEY_Y1(y1) ((y1) << 16) > +#define CFG_CKEY_Y1_MASK 0x00FF0000 > +#define CFG_CKEY_Y(y) ((y) << 8) > +#define CFG_CKEY_Y_MASK 0x0000FF00 > +#define CFG_ALPHA_Y(y) (y) > +#define CFG_ALPHA_Y_MASK 0x000000FF > +#define LCD_SPU_COLORKEY_U 0x0134 > +#define CFG_CKEY_U2(u2) ((u2) << 24) > +#define CFG_CKEY_U2_MASK 0xFF000000 > +#define CFG_CKEY_U1(u1) ((u1) << 16) > +#define CFG_CKEY_U1_MASK 0x00FF0000 > +#define CFG_CKEY_U(u) ((u) << 8) > +#define CFG_CKEY_U_MASK 0x0000FF00 > +#define CFG_ALPHA_U(u) (u) > +#define CFG_ALPHA_U_MASK 0x000000FF > +#define LCD_SPU_COLORKEY_V 0x0138 > +#define CFG_CKEY_V2(v2) ((v2) << 24) > +#define CFG_CKEY_V2_MASK 0xFF000000 > +#define CFG_CKEY_V1(v1) ((v1) << 16) > +#define CFG_CKEY_V1_MASK 0x00FF0000 > +#define CFG_CKEY_V(v) ((v) << 8) > +#define CFG_CKEY_V_MASK 0x0000FF00 > +#define CFG_ALPHA_V(v) (v) > +#define CFG_ALPHA_V_MASK 0x000000FF > + > +/* SPI Read Data Register */ > +#define LCD_SPU_SPI_RXDATA 0x0140 > + > +/* Smart Panel Read Data Register */ > +#define LCD_SPU_ISA_RSDATA 0x0144 > +#define ISA_RXDATA_16BIT_1_DATA_MASK 0x000000FF > +#define ISA_RXDATA_16BIT_2_DATA_MASK 0x0000FF00 > +#define ISA_RXDATA_16BIT_3_DATA_MASK 0x00FF0000 > +#define ISA_RXDATA_16BIT_4_DATA_MASK 0xFF000000 > +#define ISA_RXDATA_32BIT_1_DATA_MASK 0x00FFFFFF > + > +/* HWC SRAM Read Data Register */ > +#define LCD_SPU_HWC_RDDAT 0x0158 > + > +/* Gamma Table SRAM Read Data Register */ > +#define LCD_SPU_GAMMA_RDDAT 0x015c > +#define CFG_GAMMA_RDDAT_MASK 0x000000FF > + > +/* Palette Table SRAM Read Data Register */ > +#define LCD_SPU_PALETTE_RDDAT 0x0160 > +#define CFG_PALETTE_RDDAT_MASK 0x00FFFFFF > + > +/* I/O Pads Input Read Only Register */ > +#define LCD_SPU_IOPAD_IN 0x0178 > +#define CFG_IOPAD_IN_MASK 0x0FFFFFFF > + > +/* Reserved Read Only Registers */ > +#define LCD_CFG_RDREG5F 0x017C > +#define IRE_FRAME_CNT_MASK 0x000000C0 > +#define IPE_FRAME_CNT_MASK 0x00000030 > +#define GRA_FRAME_CNT_MASK 0x0000000C /* Graphic */ > +#define DMA_FRAME_CNT_MASK 0x00000003 /* Video */ > + > +/* SPI Control Register. */ > +#define LCD_SPU_SPI_CTRL 0x0180 > +#define CFG_SCLKCNT(div) ((div) << 24) /* 0xFF~0x2 */ > +#define CFG_SCLKCNT_MASK 0xFF000000 > +#define CFG_RXBITS(rx) ((rx) << 16) /* 0x1F~0x1 */ > +#define CFG_RXBITS_MASK 0x00FF0000 > +#define CFG_TXBITS(tx) ((tx) << 8) /* 0x1F~0x1 */ > +#define CFG_TXBITS_MASK 0x0000FF00 > +#define CFG_CLKINV(clk) ((clk) << 7) > +#define CFG_CLKINV_MASK 0x00000080 > +#define CFG_KEEPXFER(transfer) ((transfer) << 6) > +#define CFG_KEEPXFER_MASK 0x00000040 > +#define CFG_RXBITSTO0(rx) ((rx) << 5) > +#define CFG_RXBITSTO0_MASK 0x00000020 > +#define CFG_TXBITSTO0(tx) ((tx) << 4) > +#define CFG_TXBITSTO0_MASK 0x00000010 > +#define CFG_SPI_ENA(spi) ((spi) << 3) > +#define CFG_SPI_ENA_MASK 0x00000008 > +#define CFG_SPI_SEL(spi) ((spi) << 2) > +#define CFG_SPI_SEL_MASK 0x00000004 > +#define CFG_SPI_3W4WB(wire) ((wire) << 1) > +#define CFG_SPI_3W4WB_MASK 0x00000002 > +#define CFG_SPI_START(start) (start) > +#define CFG_SPI_START_MASK 0x00000001 > + > +/* SPI Tx Data Register */ > +#define LCD_SPU_SPI_TXDATA 0x0184 > + > +/* > + 1. Smart Pannel 8-bit Bus Control Register. > + 2. AHB Slave Path Data Port Register > +*/ > +#define LCD_SPU_SMPN_CTRL 0x0188 > + > +/* DMA Control 0 Register */ > +#define LCD_SPU_DMA_CTRL0 0x0190 > +#define CFG_NOBLENDING(nb) ((nb) << 31) > +#define CFG_NOBLENDING_MASK 0x80000000 > +#define CFG_GAMMA_ENA(gn) ((gn) << 30) > +#define CFG_GAMMA_ENA_MASK 0x40000000 > +#define CFG_CBSH_ENA(cn) ((cn) << 29) > +#define CFG_CBSH_ENA_MASK 0x20000000 > +#define CFG_PALETTE_ENA(pn) ((pn) << 28) > +#define CFG_PALETTE_ENA_MASK 0x10000000 > +#define CFG_ARBFAST_ENA(an) ((an) << 27) > +#define CFG_ARBFAST_ENA_MASK 0x08000000 > +#define CFG_HWC_1BITMOD(mode) ((mode) << 26) > +#define CFG_HWC_1BITMOD_MASK 0x04000000 > +#define CFG_HWC_1BITENA(mn) ((mn) << 25) > +#define CFG_HWC_1BITENA_MASK 0x02000000 > +#define CFG_HWC_ENA(cn) ((cn) << 24) > +#define CFG_HWC_ENA_MASK 0x01000000 > +#define CFG_DMAFORMAT(dmaformat) ((dmaformat) << 20) > +#define CFG_DMAFORMAT_MASK 0x00F00000 > +#define CFG_GRAFORMAT(graformat) ((graformat) << 16) > +#define CFG_GRAFORMAT_MASK 0x000F0000 > +/* for graphic part */ > +#define CFG_GRA_FTOGGLE(toggle) ((toggle) << 15) > +#define CFG_GRA_FTOGGLE_MASK 0x00008000 > +#define CFG_GRA_HSMOOTH(smooth) ((smooth) << 14) > +#define CFG_GRA_HSMOOTH_MASK 0x00004000 > +#define CFG_GRA_TSTMODE(test) ((test) << 13) > +#define CFG_GRA_TSTMODE_MASK 0x00002000 > +#define CFG_GRA_SWAPRB(swap) ((swap) << 12) > +#define CFG_GRA_SWAPRB_MASK 0x00001000 > +#define CFG_GRA_SWAPUV(swap) ((swap) << 11) > +#define CFG_GRA_SWAPUV_MASK 0x00000800 > +#define CFG_GRA_SWAPYU(swap) ((swap) << 10) > +#define CFG_GRA_SWAPYU_MASK 0x00000400 > +#define CFG_YUV2RGB_GRA(cvrt) ((cvrt) << 9) > +#define CFG_YUV2RGB_GRA_MASK 0x00000200 > +#define CFG_GRA_ENA(gra) ((gra) << 8) > +#define CFG_GRA_ENA_MASK 0x00000100 > +/* for video part */ > +#define CFG_DMA_FTOGGLE(toggle) ((toggle) << 7) > +#define CFG_DMA_FTOGGLE_MASK 0x00000080 > +#define CFG_DMA_HSMOOTH(smooth) ((smooth) << 6) > +#define CFG_DMA_HSMOOTH_MASK 0x00000040 > +#define CFG_DMA_TSTMODE(test) ((test) << 5) > +#define CFG_DMA_TSTMODE_MASK 0x00000020 > +#define CFG_DMA_SWAPRB(swap) ((swap) << 4) > +#define CFG_DMA_SWAPRB_MASK 0x00000010 > +#define CFG_DMA_SWAPUV(swap) ((swap) << 3) > +#define CFG_DMA_SWAPUV_MASK 0x00000008 > +#define CFG_DMA_SWAPYU(swap) ((swap) << 2) > +#define CFG_DMA_SWAPYU_MASK 0x00000004 > +#define CFG_DMA_SWAP_MASK 0x0000001C > +#define CFG_YUV2RGB_DMA(cvrt) ((cvrt) << 1) > +#define CFG_YUV2RGB_DMA_MASK 0x00000002 > +#define CFG_DMA_ENA(video) (video) > +#define CFG_DMA_ENA_MASK 0x00000001 > + > +/* DMA Control 1 Register */ > +#define LCD_SPU_DMA_CTRL1 0x0194 > +#define CFG_FRAME_TRIG(trig) ((trig) << 31) > +#define CFG_FRAME_TRIG_MASK 0x80000000 > +#define CFG_VSYNC_TRIG(trig) ((trig) << 28) > +#define CFG_VSYNC_TRIG_MASK 0x70000000 > +#define CFG_VSYNC_INV(inv) ((inv) << 27) > +#define CFG_VSYNC_INV_MASK 0x08000000 > +#define CFG_COLOR_KEY_MODE(cmode) ((cmode) << 24) > +#define CFG_COLOR_KEY_MASK 0x07000000 > +#define CFG_CARRY(carry) ((carry) << 23) > +#define CFG_CARRY_MASK 0x00800000 > +#define CFG_LNBUF_ENA(lnbuf) ((lnbuf) << 22) > +#define CFG_LNBUF_ENA_MASK 0x00400000 > +#define CFG_GATED_ENA(gated) ((gated) << 21) > +#define CFG_GATED_ENA_MASK 0x00200000 > +#define CFG_PWRDN_ENA(power) ((power) << 20) > +#define CFG_PWRDN_ENA_MASK 0x00100000 > +#define CFG_DSCALE(dscale) ((dscale) << 18) > +#define CFG_DSCALE_MASK 0x000C0000 > +#define CFG_ALPHA_MODE(amode) ((amode) << 16) > +#define CFG_ALPHA_MODE_MASK 0x00030000 > +#define CFG_ALPHA(alpha) ((alpha) << 8) > +#define CFG_ALPHA_MASK 0x0000FF00 > +#define CFG_PXLCMD(pxlcmd) (pxlcmd) > +#define CFG_PXLCMD_MASK 0x000000FF > + > +/* SRAM Control Register */ > +#define LCD_SPU_SRAM_CTRL 0x0198 > +#define CFG_SRAM_INIT_WR_RD(mode) ((mode) << 14) > +#define CFG_SRAM_INIT_WR_RD_MASK 0x0000C000 > +#define CFG_SRAM_ADDR_LCDID(id) ((id) << 8) > +#define CFG_SRAM_ADDR_LCDID_MASK 0x00000F00 > +#define CFG_SRAM_ADDR(addr) (addr) > +#define CFG_SRAM_ADDR_MASK 0x000000FF > + > +/* SRAM Write Data Register */ > +#define LCD_SPU_SRAM_WRDAT 0x019C > + > +/* SRAM RTC/WTC Control Register */ > +#define LCD_SPU_SRAM_PARA0 0x01A0 > + > +/* SRAM Power Down Control Register */ > +#define LCD_SPU_SRAM_PARA1 0x01A4 > +#define CFG_CSB_256x32(hwc) ((hwc) << 15) /* HWC */ > +#define CFG_CSB_256x32_MASK 0x00008000 > +#define CFG_CSB_256x24(palette) ((palette) << 14) /* Palette */ > +#define CFG_CSB_256x24_MASK 0x00004000 > +#define CFG_CSB_256x8(gamma) ((gamma) << 13) /* Gamma */ > +#define CFG_CSB_256x8_MASK 0x00002000 > +#define CFG_PDWN256x32(pdwn) ((pdwn) << 7) /* HWC */ > +#define CFG_PDWN256x32_MASK 0x00000080 > +#define CFG_PDWN256x24(pdwn) ((pdwn) << 6) /* Palette */ > +#define CFG_PDWN256x24_MASK 0x00000040 > +#define CFG_PDWN256x8(pdwn) ((pdwn) << 5) /* Gamma */ > +#define CFG_PDWN256x8_MASK 0x00000020 > +#define CFG_PDWN32x32(pdwn) ((pdwn) << 3) > +#define CFG_PDWN32x32_MASK 0x00000008 > +#define CFG_PDWN16x66(pdwn) ((pdwn) << 2) > +#define CFG_PDWN16x66_MASK 0x00000004 > +#define CFG_PDWN32x66(pdwn) ((pdwn) << 1) > +#define CFG_PDWN32x66_MASK 0x00000002 > +#define CFG_PDWN64x66(pdwn) (pdwn) > +#define CFG_PDWN64x66_MASK 0x00000001 > + > +/* Smart or Dumb Panel Clock Divider */ > +#define LCD_CFG_SCLK_DIV 0x01A8 > +#define SCLK_SOURCE_SELECT(src) ((src) << 31) > +#define SCLK_SOURCE_SELECT_MASK 0x80000000 > +#define CLK_FRACDIV(frac) ((frac) << 16) > +#define CLK_FRACDIV_MASK 0x0FFF0000 > +#define CLK_INT_DIV(div) (div) > +#define CLK_INT_DIV_MASK 0x0000FFFF > + > +/* Video Contrast Register */ > +#define LCD_SPU_CONTRAST 0x01AC > +#define CFG_BRIGHTNESS(bright) ((bright) << 16) > +#define CFG_BRIGHTNESS_MASK 0xFFFF0000 > +#define CFG_CONTRAST(contrast) (contrast) > +#define CFG_CONTRAST_MASK 0x0000FFFF > + > +/* Video Saturation Register */ > +#define LCD_SPU_SATURATION 0x01B0 > +#define CFG_C_MULTS(mult) ((mult) << 16) > +#define CFG_C_MULTS_MASK 0xFFFF0000 > +#define CFG_SATURATION(sat) (sat) > +#define CFG_SATURATION_MASK 0x0000FFFF > + > +/* Video Hue Adjust Register */ > +#define LCD_SPU_CBSH_HUE 0x01B4 > +#define CFG_SIN0(sin0) ((sin0) << 16) > +#define CFG_SIN0_MASK 0xFFFF0000 > +#define CFG_COS0(con0) (con0) > +#define CFG_COS0_MASK 0x0000FFFF > + > +/* Dump LCD Panel Control Register */ > +#define LCD_SPU_DUMB_CTRL 0x01B8 > +#define CFG_DUMBMODE(mode) ((mode) << 28) > +#define CFG_DUMBMODE_MASK 0xF0000000 > +#define CFG_LCDGPIO_O(data) ((data) << 20) > +#define CFG_LCDGPIO_O_MASK 0x0FF00000 > +#define CFG_LCDGPIO_ENA(gpio) ((gpio) << 12) > +#define CFG_LCDGPIO_ENA_MASK 0x000FF000 > +#define CFG_BIAS_OUT(bias) ((bias) << 8) > +#define CFG_BIAS_OUT_MASK 0x00000100 > +#define CFG_REVERSE_RGB(rRGB) ((rRGB) << 7) > +#define CFG_REVERSE_RGB_MASK 0x00000080 > +#define CFG_INV_COMPBLANK(blank) ((blank) << 6) > +#define CFG_INV_COMPBLANK_MASK 0x00000040 > +#define CFG_INV_COMPSYNC(sync) ((sync) << 5) > +#define CFG_INV_COMPSYNC_MASK 0x00000020 > +#define CFG_INV_HENA(hena) ((hena) << 4) > +#define CFG_INV_HENA_MASK 0x00000010 > +#define CFG_INV_VSYNC(vsync) ((vsync) << 3) > +#define CFG_INV_VSYNC_MASK 0x00000008 > +#define CFG_INV_HSYNC(hsync) ((hsync) << 2) > +#define CFG_INV_HSYNC_MASK 0x00000004 > +#define CFG_INV_PCLK(pclk) ((pclk) << 1) > +#define CFG_INV_PCLK_MASK 0x00000002 > +#define CFG_DUMB_ENA(dumb) (dumb) > +#define CFG_DUMB_ENA_MASK 0x00000001 > + > +/* LCD I/O Pads Control Register */ > +#define SPU_IOPAD_CONTROL 0x01BC > +#define CFG_GRA_VM_ENA(vm) ((vm) << 15) /* gfx */ > +#define CFG_GRA_VM_ENA_MASK 0x00008000 > +#define CFG_DMA_VM_ENA(vm) ((vm) << 13) /* video */ > +#define CFG_DMA_VM_ENA_MASK 0x00002000 > +#define CFG_CMD_VM_ENA(vm) ((vm) << 13) > +#define CFG_CMD_VM_ENA_MASK 0x00000800 > +#define CFG_CSC(csc) ((csc) << 8) /* csc */ > +#define CFG_CSC_MASK 0x00000300 > +#define CFG_AXICTRL(axi) ((axi) << 4) > +#define CFG_AXICTRL_MASK 0x000000F0 > +#define CFG_IOPADMODE(iopad) (iopad) > +#define CFG_IOPADMODE_MASK 0x0000000F > + > +/* LCD Interrupt Control Register */ > +#define SPU_IRQ_ENA 0x01C0 > +#define DMA_FRAME_IRQ0_ENA(irq) ((irq) << 31) > +#define DMA_FRAME_IRQ0_ENA_MASK 0x80000000 > +#define DMA_FRAME_IRQ1_ENA(irq) ((irq) << 30) > +#define DMA_FRAME_IRQ1_ENA_MASK 0x40000000 > +#define DMA_FF_UNDERFLOW_ENA(ff) ((ff) << 29) > +#define DMA_FF_UNDERFLOW_ENA_MASK 0x20000000 > +#define GRA_FRAME_IRQ0_ENA(irq) ((irq) << 27) > +#define GRA_FRAME_IRQ0_ENA_MASK 0x08000000 > +#define GRA_FRAME_IRQ1_ENA(irq) ((irq) << 26) > +#define GRA_FRAME_IRQ1_ENA_MASK 0x04000000 > +#define GRA_FF_UNDERFLOW_ENA(ff) ((ff) << 25) > +#define GRA_FF_UNDERFLOW_ENA_MASK 0x02000000 > +#define VSYNC_IRQ_ENA(vsync_irq) ((vsync_irq) << 23) > +#define VSYNC_IRQ_ENA_MASK 0x00800000 > +#define DUMB_FRAMEDONE_ENA(fdone) ((fdone) << 22) > +#define DUMB_FRAMEDONE_ENA_MASK 0x00400000 > +#define TWC_FRAMEDONE_ENA(fdone) ((fdone) << 21) > +#define TWC_FRAMEDONE_ENA_MASK 0x00200000 > +#define HWC_FRAMEDONE_ENA(fdone) ((fdone) << 20) > +#define HWC_FRAMEDONE_ENA_MASK 0x00100000 > +#define SLV_IRQ_ENA(irq) ((irq) << 19) > +#define SLV_IRQ_ENA_MASK 0x00080000 > +#define SPI_IRQ_ENA(irq) ((irq) << 18) > +#define SPI_IRQ_ENA_MASK 0x00040000 > +#define PWRDN_IRQ_ENA(irq) ((irq) << 17) > +#define PWRDN_IRQ_ENA_MASK 0x00020000 > +#define ERR_IRQ_ENA(irq) ((irq) << 16) > +#define ERR_IRQ_ENA_MASK 0x00010000 > +#define CLEAN_SPU_IRQ_ISR(irq) (irq) > +#define CLEAN_SPU_IRQ_ISR_MASK 0x0000FFFF > + > +/* LCD Interrupt Status Register */ > +#define SPU_IRQ_ISR 0x01C4 > +#define DMA_FRAME_IRQ0(irq) ((irq) << 31) > +#define DMA_FRAME_IRQ0_MASK 0x80000000 > +#define DMA_FRAME_IRQ1(irq) ((irq) << 30) > +#define DMA_FRAME_IRQ1_MASK 0x40000000 > +#define DMA_FF_UNDERFLOW(ff) ((ff) << 29) > +#define DMA_FF_UNDERFLOW_MASK 0x20000000 > +#define GRA_FRAME_IRQ0(irq) ((irq) << 27) > +#define GRA_FRAME_IRQ0_MASK 0x08000000 > +#define GRA_FRAME_IRQ1(irq) ((irq) << 26) > +#define GRA_FRAME_IRQ1_MASK 0x04000000 > +#define GRA_FF_UNDERFLOW(ff) ((ff) << 25) > +#define GRA_FF_UNDERFLOW_MASK 0x02000000 > +#define VSYNC_IRQ(vsync_irq) ((vsync_irq) << 23) > +#define VSYNC_IRQ_MASK 0x00800000 > +#define DUMB_FRAMEDONE(fdone) ((fdone) << 22) > +#define DUMB_FRAMEDONE_MASK 0x00400000 > +#define TWC_FRAMEDONE(fdone) ((fdone) << 21) > +#define TWC_FRAMEDONE_MASK 0x00200000 > +#define HWC_FRAMEDONE(fdone) ((fdone) << 20) > +#define HWC_FRAMEDONE_MASK 0x00100000 > +#define SLV_IRQ(irq) ((irq) << 19) > +#define SLV_IRQ_MASK 0x00080000 > +#define SPI_IRQ(irq) ((irq) << 18) > +#define SPI_IRQ_MASK 0x00040000 > +#define PWRDN_IRQ(irq) ((irq) << 17) > +#define PWRDN_IRQ_MASK 0x00020000 > +#define ERR_IRQ(irq) ((irq) << 16) > +#define ERR_IRQ_MASK 0x00010000 > +/* read-only */ > +#define DMA_FRAME_IRQ0_LEVEL_MASK 0x00008000 > +#define DMA_FRAME_IRQ1_LEVEL_MASK 0x00004000 > +#define DMA_FRAME_CNT_ISR_MASK 0x00003000 > +#define GRA_FRAME_IRQ0_LEVEL_MASK 0x00000800 > +#define GRA_FRAME_IRQ1_LEVEL_MASK 0x00000400 > +#define GRA_FRAME_CNT_ISR_MASK 0x00000300 > +#define VSYNC_IRQ_LEVEL_MASK 0x00000080 > +#define DUMB_FRAMEDONE_LEVEL_MASK 0x00000040 > +#define TWC_FRAMEDONE_LEVEL_MASK 0x00000020 > +#define HWC_FRAMEDONE_LEVEL_MASK 0x00000010 > +#define SLV_FF_EMPTY_MASK 0x00000008 > +#define DMA_FF_ALLEMPTY_MASK 0x00000004 > +#define GRA_FF_ALLEMPTY_MASK 0x00000002 > +#define PWRDN_IRQ_LEVEL_MASK 0x00000001 > + > + > +/* > + * defined Video Memory Color format for DMA control 0 register > + * DMA0 bit[23:20] > + */ > +#define VMODE_RGB565 0x0 > +#define VMODE_RGB1555 0x1 > +#define VMODE_RGB888PACKED 0x2 > +#define VMODE_RGB888UNPACKED 0x3 > +#define VMODE_RGBA888 0x4 > +#define VMODE_YUV422PACKED 0x5 > +#define VMODE_YUV422PLANAR 0x6 > +#define VMODE_YUV420PLANAR 0x7 > +#define VMODE_SMPNCMD 0x8 > +#define VMODE_PALETTE4BIT 0x9 > +#define VMODE_PALETTE8BIT 0xa > +#define VMODE_RESERVED 0xb > + > +/* > + * defined Graphic Memory Color format for DMA control 0 register > + * DMA0 bit[19:16] > + */ > +#define GMODE_RGB565 0x0 > +#define GMODE_RGB1555 0x1 > +#define GMODE_RGB888PACKED 0x2 > +#define GMODE_RGB888UNPACKED 0x3 > +#define GMODE_RGBA888 0x4 > +#define GMODE_YUV422PACKED 0x5 > +#define GMODE_YUV422PLANAR 0x6 > +#define GMODE_YUV420PLANAR 0x7 > +#define GMODE_SMPNCMD 0x8 > +#define GMODE_PALETTE4BIT 0x9 > +#define GMODE_PALETTE8BIT 0xa > +#define GMODE_RESERVED 0xb > + > +/* > + * define for DMA control 1 register > + */ > +#define DMA1_FRAME_TRIG 31 /* bit location */ > +#define DMA1_VSYNC_MODE 28 > +#define DMA1_VSYNC_INV 27 > +#define DMA1_CKEY 24 > +#define DMA1_CARRY 23 > +#define DMA1_LNBUF_ENA 22 > +#define DMA1_GATED_ENA 21 > +#define DMA1_PWRDN_ENA 20 > +#define DMA1_DSCALE 18 > +#define DMA1_ALPHA_MODE 16 > +#define DMA1_ALPHA 08 > +#define DMA1_PXLCMD 00 > + > +/* > + * defined for Configure Dumb Mode > + * DUMB LCD Panel bit[31:28] > + */ > +#define DUMB16_RGB565_0 0x0 > +#define DUMB16_RGB565_1 0x1 > +#define DUMB18_RGB666_0 0x2 > +#define DUMB18_RGB666_1 0x3 > +#define DUMB12_RGB444_0 0x4 > +#define DUMB12_RGB444_1 0x5 > +#define DUMB24_RGB888_0 0x6 > +#define DUMB_BLANK 0x7 > + > +/* > + * defined for Configure I/O Pin Allocation Mode > + * LCD LCD I/O Pads control register bit[3:0] > + */ > +#define IOPAD_DUMB24 0x0 > +#define IOPAD_DUMB18SPI 0x1 > +#define IOPAD_DUMB18GPIO 0x2 > +#define IOPAD_DUMB16SPI 0x3 > +#define IOPAD_DUMB16GPIO 0x4 > +#define IOPAD_DUMB12 0x5 > +#define IOPAD_SMART18SPI 0x6 > +#define IOPAD_SMART16SPI 0x7 > +#define IOPAD_SMART8BOTH 0x8 > + > +#endif /* __PXA168FB_H__ */ > diff --git a/include/video/pxa168fb.h b/include/video/pxa168fb.h > new file mode 100644 > index 0000000..65324e3 > --- /dev/null > +++ b/include/video/pxa168fb.h > @@ -0,0 +1,128 @@ > +/* > + * linux/arch/arm/mach-mmp/include/mach/pxa168fb.h > + * > + * Copyright (C) 2009 Marvell International Ltd. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + */ > + > +#ifndef __ASM_MACH_PXA168FB_H > +#define __ASM_MACH_PXA168FB_H > + > +#include <linux/fb.h> > +#include <linux/interrupt.h> > + > +/* Dumb interface */ > +#define PIN_MODE_DUMB_24 0 > +#define PIN_MODE_DUMB_18_SPI 1 > +#define PIN_MODE_DUMB_18_GPIO 2 > +#define PIN_MODE_DUMB_16_SPI 3 > +#define PIN_MODE_DUMB_16_GPIO 4 > +#define PIN_MODE_DUMB_12_SPI_GPIO 5 > +#define PIN_MODE_SMART_18_SPI 6 > +#define PIN_MODE_SMART_16_SPI 7 > +#define PIN_MODE_SMART_8_SPI_GPIO 8 > + > +/* Dumb interface pin allocation */ > +#define DUMB_MODE_RGB565 0 > +#define DUMB_MODE_RGB565_UPPER 1 > +#define DUMB_MODE_RGB666 2 > +#define DUMB_MODE_RGB666_UPPER 3 > +#define DUMB_MODE_RGB444 4 > +#define DUMB_MODE_RGB444_UPPER 5 > +#define DUMB_MODE_RGB888 6 > + > +/* default fb buffer size WVGA-32bits */ > +#define DEFAULT_FB_SIZE (800 * 480 * 4) > + > +/* > + * Buffer pixel format > + * bit0 is for rb swap. > + * bit12 is for Y UorV swap > + */ > +#define PIX_FMT_RGB565 0 > +#define PIX_FMT_BGR565 1 > +#define PIX_FMT_RGB1555 2 > +#define PIX_FMT_BGR1555 3 > +#define PIX_FMT_RGB888PACK 4 > +#define PIX_FMT_BGR888PACK 5 > +#define PIX_FMT_RGB888UNPACK 6 > +#define PIX_FMT_BGR888UNPACK 7 > +#define PIX_FMT_RGBA888 8 > +#define PIX_FMT_BGRA888 9 > +#define PIX_FMT_YUV422PACK 10 > +#define PIX_FMT_YVU422PACK 11 > +#define PIX_FMT_YUV422PLANAR 12 > +#define PIX_FMT_YVU422PLANAR 13 > +#define PIX_FMT_YUV420PLANAR 14 > +#define PIX_FMT_YVU420PLANAR 15 > +#define PIX_FMT_PSEUDOCOLOR 20 > +#define PIX_FMT_UYVY422PACK (0x1000|PIX_FMT_YUV422PACK) > + > +/* > + * PXA LCD controller private state. > + */ > +struct pxa168fb_info { > + struct device *dev; > + struct clk *clk; > + > + void __iomem *reg_base; > + dma_addr_t fb_start_dma; > + void *fb_start; > + int fb_size; > + u32 pseudo_palette[16]; > + > + int pix_fmt; > + unsigned is_blanked:1; > + unsigned panel_rbswap:1; > + unsigned active:1; > +}; > + > +/* > + * PXA fb machine information > + */ > +struct pxa168fb_mach_info { > + char id[16]; > + > + int num_modes; > + struct fb_videomode *modes; > + > + /* > + * Pix_fmt > + */ > + unsigned pix_fmt; > + > + /* > + * I/O pin allocation. > + */ > + unsigned io_pin_allocation_mode:4; > + > + /* > + * Dumb panel -- assignment of R/G/B component info to the 24 > + * available external data lanes. > + */ > + unsigned dumb_mode:4; > + unsigned panel_rgb_reverse_lanes:1; > + > + /* > + * Dumb panel -- GPIO output data. > + */ > + unsigned gpio_output_mask:8; > + unsigned gpio_output_data:8; > + > + /* > + * Dumb panel -- configurable output signal polarity. > + */ > + unsigned invert_composite_blank:1; > + unsigned invert_pix_val_ena:1; > + unsigned invert_pixclock:1; > + unsigned invert_vsync:1; > + unsigned invert_hsync:1; > + unsigned panel_rbswap:1; > + unsigned active:1; > + unsigned enable_lcd:1; > +}; > + > +#endif /* __ASM_MACH_PXA168FB_H */ > -- > 1.6.0.4 > > ------------------------------------------------------------------- > List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel > FAQ: http://www.arm.linux.org.uk/mailinglists/faq.php > Etiquette: http://www.arm.linux.org.uk/mailinglists/etiquette.php > ---------------------------------------------------------------------- Zrob sobie prezent. Wygraj nagrode! Sprawdz >> http://link.interia.pl/f2176 |
From: Krzysztof H. <krz...@po...> - 2009-05-24 06:39:11
|
On Fri, 22 May 2009 16:29:30 +0200 Thierry Reding <thi...@av...> wrote: > This patch adds support for the Avionic Design Xanthos framebuffer. > > Signed-off-by: Thierry Reding <thi...@av...> > --- Acked-by: Krzysztof Helt <krz...@wp...> > drivers/video/Kconfig | 12 ++ > drivers/video/Makefile | 1 + > drivers/video/adxfb/Makefile | 1 + > drivers/video/adxfb/adxfb.h | 118 ++++++++++++ > drivers/video/adxfb/fb.c | 411 +++++++++++++++++++++++++++++++++++++++++ > drivers/video/adxfb/overlay.c | 190 +++++++++++++++++++ > drivers/video/adxfb/scaler.c | 231 +++++++++++++++++++++++ > include/video/Kbuild | 1 + > include/video/adxfb.h | 128 +++++++++++++ > 9 files changed, 1093 insertions(+), 0 deletions(-) > create mode 100644 drivers/video/adxfb/Makefile > create mode 100644 drivers/video/adxfb/adxfb.h > create mode 100644 drivers/video/adxfb/fb.c > create mode 100644 drivers/video/adxfb/overlay.c > create mode 100644 drivers/video/adxfb/scaler.c > create mode 100644 include/video/adxfb.h > > diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig > index 0048f11..49e1b69 100644 > --- a/drivers/video/Kconfig > +++ b/drivers/video/Kconfig > @@ -1663,6 +1663,18 @@ config CARMINE_DRAM_CUSTOM > Use custom board timings. > endchoice > > +config FB_ADX > + tristate "Avionic Design Xanthos framebuffer support" > + depends on FB > + select FB_CFB_FILLRECT > + select FB_CFB_COPYAREA > + select FB_CFB_IMAGEBLIT > + help > + Framebuffer driver for the LCD controller in Avionic Design > + Xanthos boards. > + > + If in doubt, say N. > + > config FB_AU1100 > bool "Au1100 LCD Driver" > depends on (FB = y) && MIPS && SOC_AU1100 > diff --git a/drivers/video/Makefile b/drivers/video/Makefile > index d8d0be5..4de52a5 100644 > --- a/drivers/video/Makefile > +++ b/drivers/video/Makefile > @@ -125,6 +125,7 @@ obj-$(CONFIG_FB_OMAP) += omap/ > obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o > obj-$(CONFIG_FB_CARMINE) += carminefb.o > obj-$(CONFIG_FB_MB862XX) += mb862xx/ > +obj-$(CONFIG_FB_ADX) += adxfb/ > > # Platform or fallback drivers go here > obj-$(CONFIG_FB_UVESA) += uvesafb.o > diff --git a/drivers/video/adxfb/Makefile b/drivers/video/adxfb/Makefile > new file mode 100644 > index 0000000..389d65c > --- /dev/null > +++ b/drivers/video/adxfb/Makefile > @@ -0,0 +1 @@ > +obj-y += fb.o overlay.o scaler.o > diff --git a/drivers/video/adxfb/adxfb.h b/drivers/video/adxfb/adxfb.h > new file mode 100644 > index 0000000..8238bf3 > --- /dev/null > +++ b/drivers/video/adxfb/adxfb.h > @@ -0,0 +1,118 @@ > +/* > + * linux/drivers/video/adxfb/adxfb.h > + * > + * Copyright (C) 2007-2008 Avionic Design Development GmbH > + * Copyright (C) 2008-2009 Avionic Design GmbH > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * > + * Written by Thierry Reding <thi...@av...> > + */ > + > +#ifndef _DRIVERS_VIDEO_ADXFB_ADXFB_H > +#define _DRIVERS_VIDEO_ADXFB_ADXFB_H 1 > + > +#include <linux/spinlock.h> > +#include <video/adxfb.h> > + > +/** > + * struct adxfb_info - Avionic Design Xanthos framebuffer info structure > + * @palette: VGA palette storage > + * @io_base: memory-mapped base address for graphics controller > + * @scaler_base: memory-mapped base address for scaler > + * @ioctl: machine-specific I/O control handler > + */ > +struct adxfb_info { > + u32 palette[16]; > + > + void __iomem *io_base; > + void __iomem *scaler_base; > + spinlock_t lock; > + > + int (*ioctl)(struct fb_info *info, unsigned int command, > + unsigned long arg); > +}; > + > +/* register definitions */ > +#define ADXFB_CONTROL 0x000 > +#define ADXFB_CONTROL_ENABLE (1 << 0) > +#define ADXFB_CONTROL_SYNC (1 << 1) > +#define ADXFB_CONTROL_DOUBLE_Y (1 << 2) > +#define ADXFB_CONTROL_HALVE_X (1 << 3) > +#define ADXFB_CONTROL_TRIPLE_Y (1 << 4) > +#define ADXFB_CONTROL_LOCK (1 << 31) > +#define ADXFB_OVERLAY_CONTROL 0x008 > +#define ADXFB_OVERLAY_CONTROL_OVERLAY (1 << 0) > +#define ADXFB_OVERLAY_CONTROL_ALPHA (1 << 1) > +#define ADXFB_OVERLAY_START 0x010 > +#define ADXFB_OVERLAY_END 0x018 > +#define ADXFB_OVERLAY_PAGE0_START 0x020 > +#define ADXFB_OVERLAY_PAGE0_END 0x028 > +#define ADXFB_OVERLAY_PAGE0_SIZE 0x030 > +#define ADXFB_OVERLAY_PAGE1_START 0x038 > +#define ADXFB_OVERLAY_PAGE1_END 0x040 > +#define ADXFB_OVERLAY_PAGE1_SIZE 0x048 > +#define ADXFB_OVERLAY_LEVEL 0x050 > +#define ADXFB_ALPHA_START 0x058 > +#define ADXFB_ALPHA_END 0x060 > +#define ADXFB_ALPHA_PAGE1_START 0x068 > +#define ADXFB_ALPHA_PAGE1_END 0x070 > +#define ADXFB_ALPHA_PAGE1_SIZE 0x078 > +#define ADXFB_PAGE0_BASE 0x080 > +#define ADXFB_PAGE0_FORMAT 0x088 > +#define ADXFB_PAGE0_RESOLUTION 0x090 > +#define ADXFB_PAGE0_RESOLUTION_BYTE 0x098 > +#define ADXFB_PAGE0_SIZE 0x0a0 > +#define ADXFB_PAGE1_BASE 0x0b0 > +#define ADXFB_PAGE1_FORMAT 0x0b8 > +#define ADXFB_PAGE1_RESOLUTION 0x0c0 > +#define ADXFB_PAGE1_RESOLUTION_PHYSICAL 0x0c8 > +#define ADXFB_PAGE1_RESOLUTION_VIRTUAL 0x0d0 > +#define ADXFB_PAGE1_SIZE_PHYSICAL 0x0d8 > +#define ADXFB_PAGE1_SIZE_VIRTUAL 0x0e0 > +#define ADXFB_PAGE1_OFFSET 0x0e8 > +#define ADXFB_PAGE1_SECONDARY_BASE 0x0f0 > +#define ADXFB_COLOR_OFFSET 0x100 > +#define ADXFB_COLOR_MUL 0x108 > + > +/* page format (ADXFB_PAGE0_FORMAT, ADXFB_PAGE1_FORMAT) */ > +#define ADXFB_FMT_NONE 0 > +#define ADXFB_FMT_GRAYSCALE_8 1 > +#define ADXFB_FMT_RGB_565 2 > +#define ADXFB_FMT_RGB_888 3 > +#define ADXFB_FMT_RGBA_8888 4 > + > +/** > + * adxfb_r32() - read 32-bit register > + * @fb: framebuffer context > + * @offset: relative register offset > + */ > +static inline u32 adxfb_r32(struct adxfb_info *fb, unsigned long offset) > +{ > + return readl(fb->io_base + offset); > +} > + > +/** > + * adxfb_w32() - write 32-bit register > + * @fb: framebuffer context > + * @offset: relative register offset > + * @value: value to write to register > + */ > +static inline void adxfb_w32(struct adxfb_info *fb, unsigned long offset, > + u32 value) > +{ > + writel(value, fb->io_base + offset); > +} > + > +extern int adxfb_scaler_set_mode(struct fb_info *info, > + struct adxfb_scaler_mode *mode); > +extern int adxfb_scaler_get_mode(struct fb_info *info, > + struct adxfb_scaler_mode *mode); > + > +extern int adxfb_overlay_enable(struct fb_info *info, unsigned long flags); > +extern int adxfb_overlay_set_viewport(struct fb_info *info, > + struct adxfb_viewport *viewport); > + > +#endif /* !_DRIVERS_VIDEO_ADXFB_ADXFB_H */ > diff --git a/drivers/video/adxfb/fb.c b/drivers/video/adxfb/fb.c > new file mode 100644 > index 0000000..7b6f0a5 > --- /dev/null > +++ b/drivers/video/adxfb/fb.c > @@ -0,0 +1,411 @@ > +/* > + * linux/drivers/video/adxfb/fb.c > + * > + * Copyright (C) 2007-2008 Avionic Design Development GmbH > + * Copyright (C) 2008-2009 Avionic Design GmbH > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * > + * Written by Thierry Reding <thi...@av...> > + */ > + > +#include <linux/fb.h> > +#include <linux/io.h> > +#include <linux/mm.h> > +#include <linux/platform_device.h> > +#include <linux/uaccess.h> > + > +#include "adxfb.h" > + > +/** > + * adxfb_setcolreg() - set color register > + * @regno: register number to set > + * @red: red color component > + * @green: green color component > + * @blue: blue color component > + * @transp: transparency component > + * @info: framebuffer context > + */ > +static int adxfb_setcolreg(unsigned regno, unsigned red, unsigned green, > + unsigned blue, unsigned transp, struct fb_info *info) > +{ > + if ((regno >= info->cmap.len) || (regno > 255)) > + return 1; > + > +#define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16) > + switch (info->fix.visual) { > + case FB_VISUAL_TRUECOLOR: > + if (regno < 16) { > + ((struct adxfb_info *)info->par)->palette[regno] = > + (CNVT_TOHW(red, info->var.red.length) > + << info->var.red.offset) | > + (CNVT_TOHW(green, info->var.green.length) > + << info->var.green.offset) | > + (CNVT_TOHW(blue, info->var.blue.length) > + << info->var.blue.offset) | > + (CNVT_TOHW(transp, info->var.transp.length) > + << info->var.transp.offset); > + } > + break; > + > + default: > + dev_err(info->dev, "bad depth: %u\n", info->var.bits_per_pixel); > + break; > + } > +#undef CNVT_TOHW > + > + return 0; > +} > + > +/** > + * adxfb_ioctl() - handle I/O controls > + * @info: framebuffer context > + * @command: I/O control code > + * @arg: I/O control argument > + */ > +static int adxfb_ioctl(struct fb_info *info, unsigned int command, > + unsigned long arg) > +{ > + struct adxfb_info *fb = info->par; > + void __user *argp = (void __user *)arg; > + struct adxfb_scaler_mode mode; > + struct adxfb_viewport viewport; > + int err = 0; > + > + switch (command) { > + case ADXFB_IOCTL_SCALER_SET_MODE: > + if (copy_from_user(&mode, argp, sizeof(mode))) > + return -EFAULT; > + > + err = adxfb_scaler_set_mode(info, &mode); > + if (err < 0) > + return err; > + > + break; > + > + case ADXFB_IOCTL_SCALER_GET_MODE: > + err = adxfb_scaler_get_mode(info, &mode); > + if (err < 0) > + return err; > + > + if (copy_to_user(argp, &mode, sizeof(mode))) > + return -EFAULT; > + > + break; > + > + case ADXFB_IOCTL_OVERLAY_ENABLE: > + err = adxfb_overlay_enable(info, arg); > + if (err < 0) > + return err; > + > + break; > + > + case ADXFB_IOCTL_OVERLAY_SET_VIEWPORT: > + if (copy_from_user(&viewport, argp, sizeof(viewport))) > + return -EFAULT; > + > + err = adxfb_overlay_set_viewport(info, &viewport); > + if (err < 0) > + return err; > + > + break; > + > + default: > + if (fb && fb->ioctl) > + return fb->ioctl(info, command, arg); > + > + break; > + } > + > + return 0; > +} > + > +/* framebuffer operations */ > +static struct fb_ops adxfb_ops = { > + .owner = THIS_MODULE, > + .fb_setcolreg = adxfb_setcolreg, > + .fb_ioctl = adxfb_ioctl, > + .fb_fillrect = cfb_fillrect, > + .fb_copyarea = cfb_copyarea, > + .fb_imageblit = cfb_imageblit, > +}; > + > +/** > + * adxfb_set_bitfield() - initialize a bitfield structure > + * @bf: bitfield structure to fill > + * @offset: value for offset field > + * @length: value for length field > + * @msb_right: value for msb_right field > + */ > +static void adxfb_set_bitfield(struct fb_bitfield *bf, u32 offset, u32 length, > + u32 msb_right) > +{ > + bf->offset = offset; > + bf->length = length; > + bf->msb_right = msb_right; > +} > + > +/** > + * adxfb_fmt_to_mode() - convert format type to video mode parameters > + * @fmt: ADXFB format type > + * @mode: video mode > + */ > +static int adxfb_fmt_to_mode(u8 fmt, struct adxfb_mode_info *mode) > +{ > + switch (fmt) { > + case ADXFB_FMT_GRAYSCALE_8: > + /* FIXME: use correct values here */ > + adxfb_set_bitfield(&mode->red, 5, 3, 0); > + adxfb_set_bitfield(&mode->green, 3, 2, 0); > + adxfb_set_bitfield(&mode->blue, 0, 3, 0); > + mode->bpp = 8; > + break; > + > + case ADXFB_FMT_RGB_565: > + adxfb_set_bitfield(&mode->red, 11, 5, 0); > + adxfb_set_bitfield(&mode->green, 5, 6, 0); > + adxfb_set_bitfield(&mode->blue, 0, 5, 0); > + mode->bpp = 16; > + break; > + > + case ADXFB_FMT_RGB_888: > + /* FIXME: verify that these are correct values */ > + adxfb_set_bitfield(&mode->red, 16, 8, 0); > + adxfb_set_bitfield(&mode->green, 8, 8, 0); > + adxfb_set_bitfield(&mode->blue, 0, 8, 0); > + mode->bpp = 24; > + break; > + > + case ADXFB_FMT_RGBA_8888: > + /* FIXME: verify that these are correct values */ > + adxfb_set_bitfield(&mode->red, 16, 8, 0); > + adxfb_set_bitfield(&mode->green, 8, 8, 0); > + adxfb_set_bitfield(&mode->blue, 0, 8, 0); > + mode->bpp = 32; > + break; > + > + default: > + return -EINVAL; > + } > + > + return 0; > +} > + > +/** > + * adxfb_get_mach_mode() - obtain the current video mode > + * @fb: framebuffer context > + * @mode: structure to return the video mode in > + */ > +static int adxfb_get_mach_mode(struct adxfb_info *fb, > + struct adxfb_mode_info *mode) > +{ > + u32 size; > + u16 resx; > + u16 resy; > + u8 fmt; > + > + size = adxfb_r32(fb, ADXFB_PAGE0_RESOLUTION); > + resx = (size >> 16) & 0x7ff; > + resy = (size >> 0) & 0x7ff; > + > + fmt = adxfb_r32(fb, ADXFB_PAGE0_FORMAT) & 0xff; > + > + mode->xres = resx; > + mode->yres = resy; > + > + return adxfb_fmt_to_mode(fmt, mode); > +} > + > +/** > + * adxfb_probe() - initialize the framebuffer device > + * @pdev: platform device > + */ > +static int __init adxfb_probe(struct platform_device *pdev) > +{ > + struct adxfb_mach_info *mach_info = pdev->dev.platform_data; > + struct adxfb_mode_info mode; > + struct adxfb_info *fb; > + struct fb_info *info; > + struct resource *res; > + int err = 0; > + > + info = framebuffer_alloc(sizeof(struct adxfb_info), &pdev->dev); > + if (!info) { > + dev_err(&pdev->dev, "failed to allocate framebuffer device\n"); > + return -ENOMEM; > + } > + > + fb = info->par; > + spin_lock_init(&fb->lock); > + > + if (mach_info) > + fb->ioctl = mach_info->ioctl; > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (!res) { > + dev_err(&pdev->dev, "failed to get graphics controller I/O " > + "memory resource\n"); > + err = -ENXIO; > + goto free; > + } > + > + res = devm_request_mem_region(&pdev->dev, res->start, > + res->end - res->start + 1, res->name); > + if (!res) { > + dev_err(&pdev->dev, "failed to request graphics controller " > + "I/O memory region\n"); > + err = -ENXIO; > + goto free; > + } > + > + fb->io_base = devm_ioremap_nocache(&pdev->dev, res->start, > + res->end - res->start + 1); > + if (!fb->io_base) { > + err = -ENXIO; > + goto free; > + } > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); > + if (!res) { > + dev_err(&pdev->dev, "failed to get scaler I/O memory " > + "resource\n"); > + err = -ENXIO; > + goto free; > + } > + > + res = devm_request_mem_region(&pdev->dev, res->start, > + res->end - res->start + 1, res->name); > + if (!res) { > + dev_err(&pdev->dev, "failed to request scaler I/O memory " > + "region\n"); > + err = -ENXIO; > + goto free; > + } > + > + fb->scaler_base = devm_ioremap_nocache(&pdev->dev, res->start, > + res->end - res->start + 1); > + if (!fb->scaler_base) { > + err = -ENXIO; > + goto free; > + } > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 2); > + if (!res) { > + dev_err(&pdev->dev, "failed to get framebuffer I/O memory " > + "resource\n"); > + err = -ENXIO; > + goto free; > + } > + > + res = devm_request_mem_region(&pdev->dev, res->start, > + res->end - res->start + 1, res->name); > + if (!res) { > + dev_err(&pdev->dev, "failed to request framebuffer I/O " > + "memory region\n"); > + err = -ENXIO; > + goto free; > + } > + > + info->screen_base = devm_ioremap_nocache(&pdev->dev, res->start, > + res->end - res->start + 1); > + if (!info->screen_base) { > + err = -ENXIO; > + goto free; > + } > + > + /* TODO: add some checking for these parameters */ > + memset(&mode, 0, sizeof(mode)); > + adxfb_get_mach_mode(fb, &mode); > + > + snprintf(info->fix.id, sizeof(info->fix.id), "adxfb"); > + info->fix.type = FB_TYPE_PACKED_PIXELS; > + info->fix.visual = FB_VISUAL_TRUECOLOR; > + info->fix.accel = FB_ACCEL_NONE; > + info->fix.line_length = mode.xres * (mode.bpp / 8); > + info->fix.smem_start = res->start; > + info->fix.smem_len = res->end - res->start + 1; > + > + info->var.activate = FB_ACTIVATE_NOW; > + info->var.vmode = FB_VMODE_NONINTERLACED; > + info->var.xres = mode.xres; > + info->var.yres = mode.yres; > + info->var.xres_virtual = mode.xres; > + info->var.yres_virtual = mode.yres; > + info->var.bits_per_pixel = mode.bpp; > + info->var.red = mode.red; > + info->var.green = mode.green; > + info->var.blue = mode.blue; > + info->var.width = mode.xres; > + info->var.height = mode.yres; > + > + info->fbops = &adxfb_ops; > + info->flags = FBINFO_DEFAULT; > + info->pseudo_palette = fb->palette; > + > + err = fb_alloc_cmap(&info->cmap, 256, 0); > + if (err < 0) { > + err = -ENOMEM; > + goto free; > + } > + > + err = register_framebuffer(info); > + if (err < 0) { > + dev_err(&pdev->dev, "failed to register framebuffer\n"); > + goto cmap; > + } > + > + dev_info(info->dev, "ADX framebuffer initialized\n"); > + platform_set_drvdata(pdev, info); > + return 0; > + > +cmap: > + fb_dealloc_cmap(&info->cmap); > +free: > + framebuffer_release(info); > + return err; > +} > + > +/** > + * adxfb_remove() - shutdown the framebuffer device > + * @pdev: platform device > + */ > +static int adxfb_remove(struct platform_device *pdev) > +{ > + struct fb_info *info = platform_get_drvdata(pdev); > + unregister_framebuffer(info); > + return 0; > +} > + > +/* ADXFB platform driver */ > +static struct platform_driver adxfb_driver = { > + .probe = adxfb_probe, > + .remove = adxfb_remove, > + .driver = { > + .name = "adxfb", > + }, > +}; > + > +/** > + * adxfb_init() - module initialization > + */ > +int __init adxfb_init(void) > +{ > + return platform_driver_register(&adxfb_driver); > +} > + > +/** > + * adxfb_exit() - module cleanup > + */ > +void __exit adxfb_exit(void) > +{ > + platform_driver_unregister(&adxfb_driver); > +} > + > +module_init(adxfb_init); > +module_exit(adxfb_exit); > + > +MODULE_AUTHOR("Thierry Reding <thi...@av...>"); > +MODULE_DESCRIPTION("Avionic Design Xanthos framebuffer driver"); > +MODULE_LICENSE("GPL v2"); > diff --git a/drivers/video/adxfb/overlay.c b/drivers/video/adxfb/overlay.c > new file mode 100644 > index 0000000..f114a54 > --- /dev/null > +++ b/drivers/video/adxfb/overlay.c > @@ -0,0 +1,190 @@ > +/* > + * linux/drivers/video/adxfb/overlay.c > + * > + * Copyright (C) 2008 Avionic Design Development GmbH > + * Copyright (C) 2008 Avionic Design GmbH > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * > + * Written by Thierry Reding <thi...@av...> > + */ > + > +#include <linux/fb.h> > +#include "adxfb.h" > + > +/* format to bit-depth table */ > +struct fmt_bpp { > + u8 fmt; > + int bpp; > +}; > + > +static struct fmt_bpp formats[] = { > + { ADXFB_FMT_GRAYSCALE_8, 8 }, > + { ADXFB_FMT_RGB_565, 16 }, > + { ADXFB_FMT_RGB_888, 24 }, > + { ADXFB_FMT_RGBA_8888, 32 }, > +}; > + > +/** > + * fmt_to_bpp() - obtain the bit-depth for a given page format > + * @fmt: format of which to retrieve the bit-depth > + */ > +static int fmt_to_bpp(u8 fmt) > +{ > + int bpp = 0, i; > + > + for (i = 0; i < ARRAY_SIZE(formats); i++) { > + if (fmt == formats[i].fmt) { > + bpp = formats[i].bpp; > + break; > + } > + } > + > + return bpp; > +} > + > +/** > + * adxfb_disable() - disable the graphics controller > + * @fb: framebuffer context > + */ > +static inline void adxfb_disable(struct adxfb_info *fb) > +{ > + u32 ctrl; > + > + spin_lock(&fb->lock); > + > + ctrl = adxfb_r32(fb, ADXFB_CONTROL); > + ctrl &= ~ADXFB_CONTROL_ENABLE; > + ctrl |= ADXFB_CONTROL_LOCK; > + adxfb_w32(fb, ADXFB_CONTROL, ctrl); > + > + spin_unlock(&fb->lock); > +} > + > +/** > + * adxfb_enable() - enable the graphics controller > + * @fb: framebuffer context > + */ > +static inline void adxfb_enable(struct adxfb_info *fb) > +{ > + u32 ctrl; > + > + spin_lock(&fb->lock); > + > + ctrl = adxfb_r32(fb, ADXFB_CONTROL); > + ctrl &= ~ADXFB_CONTROL_LOCK; > + ctrl |= ADXFB_CONTROL_ENABLE; > + adxfb_w32(fb, ADXFB_CONTROL, ctrl); > + > + spin_unlock(&fb->lock); > +} > + > +/** > + * adxfb_overlay_enable() - enable the overlay window > + * @info: framebuffer context > + * @flags: flags for enabling/disabling > + */ > +int adxfb_overlay_enable(struct fb_info *info, unsigned long flags) > +{ > + struct adxfb_info *fb = info->par; > + u32 ctrl; > + > + if (!info) > + return -EINVAL; > + > + spin_lock(&fb->lock); > + > + ctrl = adxfb_r32(fb, ADXFB_OVERLAY_CONTROL); > + > + if (flags & ADXFB_OVERLAY_ENABLE) > + ctrl |= ADXFB_OVERLAY_CONTROL_OVERLAY; > + else > + ctrl &= ~ADXFB_OVERLAY_CONTROL_OVERLAY; > + > + adxfb_w32(fb, ADXFB_OVERLAY_CONTROL, ctrl); > + > + spin_unlock(&fb->lock); > + return 0; > +} > + > +/** > + * adxfb_overlay_set_viewport() - set the region for the overlay window > + * @info: framebuffer context > + * @viewport: new screen region for the overlay window > + */ > +int adxfb_overlay_set_viewport(struct fb_info *info, > + struct adxfb_viewport *viewport) > +{ > + struct adxfb_info *fb = info->par; > + int sx, sy, dx, dy, ex, ey; > + int p0dx, p0dy; > + int p0ps, p1ps; > + u32 size; > + > + if (!info || !viewport) > + return -EINVAL; > + > + sx = viewport->x & ~0x3; > + sy = viewport->y & ~0x3; > + dx = viewport->width & ~0x3; > + dy = viewport->height & ~0x3; > + ex = sx + dx - 1; > + ey = sy + dy - 1; > + > + size = adxfb_r32(fb, ADXFB_PAGE0_RESOLUTION); > + p0dx = (size >> 16) & 0x7ff; > + p0dy = (size >> 0) & 0x7ff; > + > + size = adxfb_r32(fb, ADXFB_PAGE0_FORMAT) & 0xff; > + p0ps = fmt_to_bpp(size) / 8; > + > + size = adxfb_r32(fb, ADXFB_PAGE1_FORMAT) & 0xff; > + p1ps = fmt_to_bpp(size) / 8; > + > + adxfb_disable(fb); > + spin_lock(&fb->lock); > + > + size = (((dx + 0) & 0x7ff) << 16) | (dy & 0x7ff); > + adxfb_w32(fb, ADXFB_PAGE1_RESOLUTION, size); > + > + /* FIXME: (dx + 4) is a hack! */ > + size = ((((dx + 4) * p1ps) & 0x1fff) << 16) | (dy & 0x7ff); > + adxfb_w32(fb, ADXFB_PAGE1_RESOLUTION_PHYSICAL, size); > + > + size = ((((p0dx + 0) * p1ps) & 0x1fff) << 16) | (p0dy & 0x7ff); > + adxfb_w32(fb, ADXFB_PAGE1_RESOLUTION_VIRTUAL, size); > + > + adxfb_w32(fb, ADXFB_PAGE1_SIZE_PHYSICAL, dx * dy * p1ps); > + adxfb_w32(fb, ADXFB_PAGE1_SIZE_VIRTUAL, p0dx * p0dy * p1ps); > + > + size = ((sx & 0x7ff) << 16) | (sy & 0x7ff); > + adxfb_w32(fb, ADXFB_OVERLAY_START, size); > + > + size = ((ex & 0x7ff) << 16) | (ey & 0x7ff); > + adxfb_w32(fb, ADXFB_OVERLAY_END, size); > + > + size = (((sx * p0ps) & 0x1fff) << 16) | (sy & 0x7ff); > + adxfb_w32(fb, ADXFB_OVERLAY_PAGE0_START, size); > + adxfb_w32(fb, ADXFB_PAGE1_OFFSET, size); > + > + size = (((ex * p0ps) & 0x1fff) << 16) | (ey & 0x7ff); > + adxfb_w32(fb, ADXFB_OVERLAY_PAGE0_END, size); > + > + size = (((sx * p1ps) & 0x1fff) << 16) | (sy & 0x7ff); > + adxfb_w32(fb, ADXFB_OVERLAY_PAGE1_START, size); > + > + size = (((ex * p1ps) & 0x1fff) << 16) | (ey & 0x7ff); > + adxfb_w32(fb, ADXFB_OVERLAY_PAGE1_END, size); > + > + adxfb_w32(fb, ADXFB_OVERLAY_PAGE0_SIZE, dx * dy * p0ps); > + adxfb_w32(fb, ADXFB_OVERLAY_PAGE1_SIZE, dx * dy * p1ps); > + > + adxfb_w32(fb, ADXFB_OVERLAY_LEVEL, 0xff); > + > + spin_unlock(&fb->lock); > + adxfb_enable(fb); > + > + return 0; > +} > diff --git a/drivers/video/adxfb/scaler.c b/drivers/video/adxfb/scaler.c > new file mode 100644 > index 0000000..96e5796 > --- /dev/null > +++ b/drivers/video/adxfb/scaler.c > @@ -0,0 +1,231 @@ > +/* > + * linux/drivers/video/adxfb/fb.c > + * > + * Copyright (C) 2007-2008 Avionic Design Development GmbH > + * Copyright (C) 2008 Avionic Design GmbH > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * > + * Written by Thierry Reding <thi...@av...> > + */ > + > +#include <linux/fb.h> > +#include "adxfb.h" > + > +/** > + * struct scaler_mode - scaler mode values > + * @uh: horizontal up scaling factor > + * @dh: horizontal down scaling factor > + * @uv: vertical up scaling factor > + * @dv: vertical down scaling factor > + * @ox: original horizontal resolution > + * @oy: original vertical resolution > + * @tx: target horizontal resolution > + * @ty: target vertical resolution > + */ > +struct scaler_mode { > + u16 uh, dh; > + u16 uv, dv; > + u16 ox, oy; > + u16 tx, ty; > +}; > + > +/* register definitions */ > +#define SCALER_MODE 0x000 > +#define SCALER_MODE_ENABLE_X (1 << 0) > +#define SCALER_MODE_ENABLE_Y (1 << 1) > +#define SCALER_MODE_BYPASS_X (1 << 2) > +#define SCALER_MODE_BYPASS_Y (1 << 3) > +#define SCALER_MODE_RGB_888 (1 << 4) > +#define SCALER_MODE_LOWPASS (1 << 7) > +#define SCALER_MODE_SYNC (1 << 8) > +#define SCALER_MODE_RESET (1 << 15) > +#define SCALER_MODE_LOCK (1 << 31) > +#define SCALER_UH 0x008 > +#define SCALER_DH 0x010 > +#define SCALER_UV 0x030 > +#define SCALER_DV 0x038 > +#define SCALER_ORIGIN_X 0x040 > +#define SCALER_ORIGIN_Y 0x048 > +#define SCALER_OFFSET_X 0x050 > +#define SCALER_OFFSET_Y 0x058 > +#define SCALER_TARGET_X 0x060 > +#define SCALER_TARGET_Y 0x068 > +#define SCALER_ORIGIN_STRIDE 0x070 > +#define SCALER_TARGET_STRIDE 0x078 > +#define SCALER_ORIGIN_SIZE 0x080 > +#define SCALER_TARGET_SIZE 0x088 > +#define SCALER_PRIMARY_PRE_TARGET_ADDR 0x090 > +#define SCALER_PRIMARY_TARGET_ADDR 0x098 > +#define SCALER_SECONDARY_PRE_TARGET_ADDR 0x0a0 > +#define SCALER_SECONDARY_TARGET_ADDR 0x0a8 > + > +/** > + * scaler_r32() - read a 32-bit register > + * @fb: framebuffer context > + * @offset: relative register offset > + */ > +static inline u32 scaler_r32(struct adxfb_info *fb, unsigned long offset) > +{ > + return readl(fb->scaler_base + offset); > +} > + > +/** > + * scaler_w32() - write a 32-bit register > + * @fb: framebuffer context > + * @offset: relative register offset > + * @value: value to write to the register > + */ > +static inline void scaler_w32(struct adxfb_info *fb, unsigned long offset, > + u32 value) > +{ > + writel(value, fb->scaler_base + offset); > +} > + > +/** > + * scaler_enable() - enable the scaling unit > + * @fb: framebuffer context > + */ > +static inline void scaler_enable(struct adxfb_info *fb) > +{ > + u32 mode; > + > + spin_lock(&fb->lock); > + > + mode = scaler_r32(fb, SCALER_MODE); > + mode |= SCALER_MODE_ENABLE_X; > + mode |= SCALER_MODE_ENABLE_Y; > + mode &= ~SCALER_MODE_LOCK; > + scaler_w32(fb, SCALER_MODE, mode); > + > + spin_unlock(&fb->lock); > +} > + > +/** > + * scaler_disable() - disable the scaling unit > + * @fb: framebuffer context > + */ > +static inline void scaler_disable(struct adxfb_info *fb) > +{ > + u32 mode; > + > + spin_lock(&fb->lock); > + > + mode = scaler_r32(fb, SCALER_MODE); > + mode |= SCALER_MODE_LOCK; > + mode &= ~SCALER_MODE_ENABLE_Y; > + mode &= ~SCALER_MODE_ENABLE_X; > + scaler_w32(fb, SCALER_MODE, mode); > + > + spin_unlock(&fb->lock); > +} > + > +/** > + * find_mode() - match a request to the best mode that can be achieved > + * @fb: framebuffer context > + * @mode: requested mode > + */ > +static int find_mode(struct adxfb_info *fb, struct scaler_mode *mode) > +{ > + if (!fb || !mode) > + return -EINVAL; > + > + if ((mode->tx == 0) || (mode->ty == 0)) > + return 0; > + > + mode->uh = scaler_r32(fb, SCALER_UH) & 0x7ff; > + mode->uh = 128; /* FIXME: don't hardcode */ > + mode->uv = scaler_r32(fb, SCALER_UV) & 0x7ff; > + mode->uv = 128; /* FIXME: don't hardcode */ > + > + mode->dh = (mode->ox * mode->uh) / mode->tx; > + mode->dv = (mode->oy * mode->uv) / mode->ty; > + > + mode->tx = (mode->ox * mode->uh) / mode->dh; > + mode->ty = (mode->oy * mode->uv) / mode->dv; > + > + /* TODO: check the parameters */ > + > + return 0; > +} > + > +/** > + * adxfb_scaler_set_mode() - set a given scaler mode > + * @info: framebuffer context > + * @modep: scaler mode > + */ > +int adxfb_scaler_set_mode(struct fb_info *info, > + struct adxfb_scaler_mode *modep) > +{ > + struct adxfb_info *fb = info->par; > + struct scaler_mode mode; > + int err, bpp; > + u32 ctrl; > + > + memset(&mode, 0, sizeof(mode)); > + mode.ox = modep->origin_x; > + mode.oy = modep->origin_y; > + mode.tx = modep->target_x; > + mode.ty = modep->target_y; > + > + scaler_disable(fb); > + spin_lock(&fb->lock); > + > + err = find_mode(fb, &mode); > + if (err < 0) { > + spin_unlock(&fb->lock); > + scaler_enable(fb); > + return err; > + } > + > + ctrl = scaler_r32(fb, SCALER_MODE); > + if (ctrl & SCALER_MODE_RGB_888) > + bpp = 24; > + else > + bpp = 16; > + > + scaler_w32(fb, SCALER_UH, mode.uh); > + scaler_w32(fb, SCALER_DH, mode.dh); > + scaler_w32(fb, SCALER_UV, mode.uv); > + scaler_w32(fb, SCALER_DV, mode.dv); > + > + scaler_w32(fb, SCALER_OFFSET_X, 0); > + scaler_w32(fb, SCALER_OFFSET_Y, 0); > + > + scaler_w32(fb, SCALER_ORIGIN_X, mode.ox); > + scaler_w32(fb, SCALER_ORIGIN_Y, mode.oy); > + scaler_w32(fb, SCALER_TARGET_X, mode.tx); > + scaler_w32(fb, SCALER_TARGET_Y, mode.ty); > + > + scaler_w32(fb, SCALER_ORIGIN_STRIDE, mode.ox * (bpp / 8)); > + scaler_w32(fb, SCALER_TARGET_STRIDE, mode.tx * (bpp / 8)); > + > + scaler_w32(fb, SCALER_ORIGIN_SIZE, mode.ox * mode.oy * (bpp / 8)); > + scaler_w32(fb, SCALER_TARGET_SIZE, mode.tx * mode.ty * (bpp / 8)); > + > + spin_unlock(&fb->lock); > + scaler_enable(fb); > + return 0; > +} > + > +/** > + * adxfb_scaler_mode() - obtain the current scaler mode > + * @info: framebuffer context > + * @modep: structure to return the mode in > + */ > +int adxfb_scaler_get_mode(struct fb_info *info, struct adxfb_scaler_mode *modep) > +{ > + struct adxfb_info *fb = info->par; > + > + spin_lock(&fb->lock); > + > + modep->origin_x = scaler_r32(fb, SCALER_ORIGIN_X) & 0x7ff; > + modep->origin_y = scaler_r32(fb, SCALER_ORIGIN_Y) & 0x7ff; > + modep->target_x = scaler_r32(fb, SCALER_TARGET_X) & 0x7ff; > + modep->target_y = scaler_r32(fb, SCALER_TARGET_Y) & 0x7ff; > + > + spin_unlock(&fb->lock); > + return 0; > +} > diff --git a/include/video/Kbuild b/include/video/Kbuild > index 0e406f7..72fc9b0 100644 > --- a/include/video/Kbuild > +++ b/include/video/Kbuild > @@ -1,2 +1,3 @@ > unifdef-y += sisfb.h uvesafb.h > unifdef-y += edid.h > +unifdef-y += adxfb.h > diff --git a/include/video/adxfb.h b/include/video/adxfb.h > new file mode 100644 > index 0000000..e7ef6d0 > --- /dev/null > +++ b/include/video/adxfb.h > @@ -0,0 +1,128 @@ > +/* > + * linux/include/video/adxfb.h > + * > + * Copyright (C) 2007-2008 Avionic Design Development GmbH > + * Copyright (C) 2008-2009 Avionic Design GmbH > + * > + * This file is subject to the terms and conditions of the GNU General Public > + * License. See the file COPYING in the main directory of this archive for > + * more details. > + * > + * Written by Thierry Reding <thi...@av...> > + */ > + > +#ifndef _VIDEO_ADXFB_H > +#define _VIDEO_ADXFB_H > + > +#include <linux/ioctl.h> > +#include <linux/types.h> > + > +#ifdef __KERNEL__ > +/* overlay control register */ > +#define ADXFB_OVERLAY_CONTROL 0x008 > +#define ADXFB_OVERLAY_CONTROL_OVERLAY_ENABLE (1 << 0) > +#define ADXFB_OVERLAY_CONTROL_ALPHA_ENABLE (1 << 1) > + > +#define ADXFB_PAGE0_BASE 0x080 > + > +/* color correction (brightness) register */ > +#define ADXFB_COLOR_BRIGHTNESS 0x100 > +#define ADXFB_COLOR_BRIGHTNESS_MIN 0x00 > +#define ADXFB_COLOR_BRIGHTNESS_MAX 0x7f > + > +/* color correction (contrast) register */ > +#define ADXFB_COLOR_CONTRAST 0x108 > +#define ADXFB_COLOR_CONTRAST_MIN 0x48 > +#define ADXFB_COLOR_CONTRAST_MAX 0x7f > + > +/** > + * struct adxfb_mode_info - video mode information structure > + * @xres: horizontal resolution > + * @yres: vertical resolution > + * @bpp: pixel depth > + * @red: packing for red color component > + * @green: packing for green color component > + * @blue: packing for blue color component > + */ > +struct adxfb_mode_info { > + /* mode resolution */ > + u_short xres; > + u_short yres; > + u_short bpp; > + > + /* color packing specification */ > + struct fb_bitfield red; > + struct fb_bitfield green; > + struct fb_bitfield blue; > +}; > + > +/** > + * struct adxfb_mach_info - machine-specific information structure > + * @ioctl: machine-specific I/O control handler > + */ > +struct adxfb_mach_info { > + int (*ioctl)(struct fb_info *info, unsigned int command, > + unsigned long arg); > +}; > +#endif /* __KERNEL__ */ > + > +/** > + * struct adxfb_scaler_mode - scaler mode definition structure > + * @origin_x: original horizontal resolution > + * @origin_y: original vertical resolution > + * @target_x: targetted horizontal resolution > + * @target_y: targetted vertical resolution > + */ > +struct adxfb_scaler_mode { > + /* original resolution */ > + __u16 origin_x; > + __u16 origin_y; > + /* target resolution */ > + __u16 target_x; > + __u16 target_y; > +}; > + > +/** > + * struct adxfb_viewport - overlay viewport structure > + * @x: horizontal start position of the overlay window > + * @y: vertical start position of the overlay window > + * @width: width of the overlay window > + * @height: height of the overlay window > + */ > +struct adxfb_viewport { > + /* viewport position */ > + __u16 x; > + __u16 y; > + /* viewport resolution */ > + __u16 width; > + __u16 height; > +}; > + > +/* I/O control codes */ > +#define ADXFB_IOC_MAGIC 'a' > + > +/* set a new scaler mode */ > +#define ADXFB_IOCTL_SCALER_SET_MODE \ > + _IOW(ADXFB_IOC_MAGIC, 0, struct adxfb_scaler_mode) > +/* obtain the current scaler mode */ > +#define ADXFB_IOCTL_SCALER_GET_MODE \ > + _IOR(ADXFB_IOC_MAGIC, 1, struct adxfb_scaler_mode) > +/* enable/disable the overlay window */ > +#define ADXFB_IOCTL_OVERLAY_ENABLE \ > + _IOW(ADXFB_IOC_MAGIC, 2, unsigned long) > +/* set a new region for the overlay window */ > +#define ADXFB_IOCTL_OVERLAY_SET_VIEWPORT \ > + _IOW(ADXFB_IOC_MAGIC, 3, struct adxfb_viewport) > +/* set a new input video standard */ > +#define ADXFB_IOCTL_SET_INPUT \ > + _IOW(ADXFB_IOC_MAGIC, 4, unsigned long) > + > +/* ADXFB_IOCTL_OVERLAY_ENABLE flags */ > +#define ADXFB_OVERLAY_ENABLE (1 << 0) /* enable/disable overlay */ > + > +/* ADXFB_IOCTL_SET_INPUT parameters */ > +#define ADXFB_INPUT_PAL (0x00) /* input is PAL standard */ > +#define ADXFB_INPUT_NTSC (0x01) /* input is NTSC stardard */ > +#define ADXFB_INPUT_MASK (0xff) /* mask to extract input */ > + > +#endif /* !_VIDEO_ADXFB_H */ > -- > 1.6.3.1 > > > ------------------------------------------------------------------- > List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel > FAQ: http://www.arm.linux.org.uk/mailinglists/faq.php > Etiquette: http://www.arm.linux.org.uk/mailinglists/etiquette.php > ---------------------------------------------------------------------- Zrob sobie prezent. Wygraj nagrode! Sprawdz >> http://link.interia.pl/f2176 |
From: Harald W. <Har...@vi...> - 2009-05-23 09:50:44
|
From: Harald Welte <la...@gn...> There are four parts of the viafb code who initialize the bitblit screen base and pitch, some of them actually broken. This patch unifies them in one function called viafb_set_2d_mode() which replaces and enhances the old function to just set the bpp. Signed-off-by: Harald Welte <Har...@vi...> Acked-by: Krzysztof Helt <krz...@wp...> --- drivers/video/via/accel.c | 35 ++++++++++++----------- drivers/video/via/accel.h | 2 +- drivers/video/via/viafbdev.c | 62 +++++------------------------------------- 3 files changed, 26 insertions(+), 73 deletions(-) diff --git a/drivers/video/via/accel.c b/drivers/video/via/accel.c index 45c54bf..4a1183f 100644 --- a/drivers/video/via/accel.c +++ b/drivers/video/via/accel.c @@ -191,26 +191,18 @@ void viafb_init_2d_engine(void) } } - viafb_set_2d_color_depth(viaparinfo->bpp); - - writel(0x0, viaparinfo->io_virt + VIA_REG_SRCBASE); - writel(0x0, viaparinfo->io_virt + VIA_REG_DSTBASE); - - writel(VIA_PITCH_ENABLE | - (((viaparinfo->hres * - viaparinfo->bpp >> 3) >> 3) | (((viaparinfo->hres * - viaparinfo-> - bpp >> 3) >> 3) << 16)), - viaparinfo->io_virt + VIA_REG_PITCH); + viafb_set_2d_mode(viafbinfo); } -void viafb_set_2d_color_depth(int bpp) +/* Set the mode-specific parameters for the 2D acceleration, such as + * BPP, source and destination base, as well as pitch */ +void viafb_set_2d_mode(struct fb_info *info) { - u32 dwGEMode; + u32 dwGEMode, pitch, pitch_reg, base; + /* Set BPP */ dwGEMode = readl(viaparinfo->io_virt + 0x04) & 0xFFFFFCFF; - - switch (bpp) { + switch (viaparinfo->bpp) { case 16: dwGEMode |= VIA_GEM_16bpp; break; @@ -221,9 +213,18 @@ void viafb_set_2d_color_depth(int bpp) dwGEMode |= VIA_GEM_8bpp; break; } - - /* Set BPP and Pitch */ writel(dwGEMode, viaparinfo->io_virt + VIA_REG_GEMODE); + + /* Set source and destination base */ + base = ((void *)info->screen_base - viafb_FB_MM); + writel(base >> 3, viaparinfo->io_virt + VIA_REG_SRCBASE); + writel(base >> 3, viaparinfo->io_virt + VIA_REG_DSTBASE); + + /* Set source and destination pitch (128bit aligned) */ + pitch = (viaparinfo->hres * viaparinfo->bpp >> 3) >> 3; + pitch_reg = pitch | (pitch << 16); + pitch_reg |= VIA_PITCH_ENABLE; + writel(pitch_reg, viaparinfo->io_virt + VIA_REG_PITCH); } void viafb_hw_cursor_init(void) diff --git a/drivers/video/via/accel.h b/drivers/video/via/accel.h index 29bf854..bef3134 100644 --- a/drivers/video/via/accel.h +++ b/drivers/video/via/accel.h @@ -161,7 +161,7 @@ void viafb_init_accel(void); void viafb_init_2d_engine(void); -void set_2d_color_depth(int); +void viafb_set_2d_mode(struct fb_info *info); void viafb_hw_cursor_init(void); void viafb_show_hw_cursor(struct fb_info *info, int Status); int viafb_wait_engine_idle(void); void viafb_set_2d_color_depth(int bpp); diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index 2e93f71..fbc0da4 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -264,7 +264,7 @@ static int viafb_set_par(struct fb_info *info) viafb_accel = info->var.accel_flags; if (viafb_accel) - viafb_set_2d_color_depth(info->var.bits_per_pixel); + viafb_set_2d_mode(info); } return 0; @@ -865,7 +865,6 @@ static void viafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { u32 col = 0, rop = 0; - int pitch; if (!viafb_accel) { cfb_fillrect(info, rect); @@ -897,22 +896,8 @@ static void viafb_fillrect(struct fb_info *info, break; } - /* BitBlt Source Address */ - writel(0x0, viaparinfo->io_virt + VIA_REG_SRCPOS); - /* Source Base Address */ - writel(0x0, viaparinfo->io_virt + VIA_REG_SRCBASE); - /* Destination Base Address */ - writel(((unsigned long) (info->screen_base) - - (unsigned long) viafb_FB_MM) >> 3, - viaparinfo->io_virt + VIA_REG_DSTBASE); - /* Pitch */ - pitch = (info->var.xres_virtual + 7) & ~7; - writel(VIA_PITCH_ENABLE | - (((pitch * - info->var.bits_per_pixel >> 3) >> 3) | - (((pitch * info-> - var.bits_per_pixel >> 3) >> 3) << 16)), - viaparinfo->io_virt + VIA_REG_PITCH); + viafb_set_2d_mode(info); + /* BitBlt Destination Address */ writel(((rect->dy << 16) | rect->dx), viaparinfo->io_virt + VIA_REG_DSTPOS); @@ -932,7 +917,6 @@ static void viafb_copyarea(struct fb_info *info, { u32 dy = area->dy, sy = area->sy, direction = 0x0; u32 sx = area->sx, dx = area->dx, width = area->width; - int pitch; DEBUG_MSG(KERN_INFO "viafb_copyarea!!\n"); @@ -956,25 +940,8 @@ static void viafb_copyarea(struct fb_info *info, direction |= 0x8000; } - /* Source Base Address */ - writel(((unsigned long) (info->screen_base) - - (unsigned long) viafb_FB_MM) >> 3, - viaparinfo->io_virt + VIA_REG_SRCBASE); - /* Destination Base Address */ - writel(((unsigned long) (info->screen_base) - - (unsigned long) viafb_FB_MM) >> 3, - viaparinfo->io_virt + VIA_REG_DSTBASE); - /* Pitch */ - pitch = (info->var.xres_virtual + 7) & ~7; - /* VIA_PITCH_ENABLE can be omitted now. */ - writel(VIA_PITCH_ENABLE | - (((pitch * - info->var.bits_per_pixel >> 3) >> 3) | (((pitch * - info->var. - bits_per_pixel - >> 3) >> 3) - << 16)), - viaparinfo->io_virt + VIA_REG_PITCH); + viafb_set_2d_mode(info); + /* BitBlt Source Address */ writel(((sy << 16) | sx), viaparinfo->io_virt + VIA_REG_SRCPOS); /* BitBlt Destination Address */ @@ -993,7 +960,6 @@ static void viafb_imageblit(struct fb_info *info, { u32 size, bg_col = 0, fg_col = 0, *udata; int i; - int pitch; if (!viafb_accel) { cfb_imageblit(info, image); @@ -1018,22 +984,8 @@ static void viafb_imageblit(struct fb_info *info, } size = image->width * image->height; - /* Source Base Address */ - writel(0x0, viaparinfo->io_virt + VIA_REG_SRCBASE); - /* Destination Base Address */ - writel(((unsigned long) (info->screen_base) - - (unsigned long) viafb_FB_MM) >> 3, - viaparinfo->io_virt + VIA_REG_DSTBASE); - /* Pitch */ - pitch = (info->var.xres_virtual + 7) & ~7; - writel(VIA_PITCH_ENABLE | - (((pitch * - info->var.bits_per_pixel >> 3) >> 3) | (((pitch * - info->var. - bits_per_pixel - >> 3) >> 3) - << 16)), - viaparinfo->io_virt + VIA_REG_PITCH); + viafb_set_2d_mode(info); + /* BitBlt Source Address */ writel(0x0, viaparinfo->io_virt + VIA_REG_SRCPOS); /* BitBlt Destination Address */ -- 1.6.2.4 |