diff options
Diffstat (limited to 'packages/linux/linux-2.6.18/atmel-lcdc-framebuffer-driver.patch')
-rw-r--r-- | packages/linux/linux-2.6.18/atmel-lcdc-framebuffer-driver.patch | 1192 |
1 files changed, 1192 insertions, 0 deletions
diff --git a/packages/linux/linux-2.6.18/atmel-lcdc-framebuffer-driver.patch b/packages/linux/linux-2.6.18/atmel-lcdc-framebuffer-driver.patch new file mode 100644 index 0000000000..d4c9204059 --- /dev/null +++ b/packages/linux/linux-2.6.18/atmel-lcdc-framebuffer-driver.patch @@ -0,0 +1,1192 @@ +--- + drivers/video/Kconfig | 22 + + drivers/video/Makefile | 1 + drivers/video/fbmem.c | 6 + drivers/video/sidsafb.c | 805 ++++++++++++++++++++++++++++++++++++++++ + include/asm-avr32/periph/lcdc.h | 271 +++++++++++++ + include/linux/fb.h | 3 + 6 files changed, 1107 insertions(+), 1 deletion(-) + +Index: linux-2.6.18-avr32/drivers/video/Kconfig +=================================================================== +--- linux-2.6.18-avr32.orig/drivers/video/Kconfig 2006-11-02 15:54:18.000000000 +0100 ++++ linux-2.6.18-avr32/drivers/video/Kconfig 2006-11-02 15:56:20.000000000 +0100 +@@ -271,6 +271,28 @@ config FB_SA1100 + If you plan to use the LCD display with your SA-1100 system, say + Y here. + ++config FB_SIDSA ++ tristate "SIDSA LCDC support" ++ select FB_CFB_FILLRECT ++ select FB_CFB_COPYAREA ++ select FB_CFB_IMAGEBLIT ++ depends on FB && AVR32 ++ help ++ This enables support for the SIDSA LCD Controller. ++ ++config FB_SIDSA_DEFAULT_BPP ++ int "SIDSA LCDC default color depth" ++ default 24 ++ depends on FB_SIDSA ++ help ++ Specify the maximum color depth you want to be able to ++ support. This, together with the resolution of the LCD ++ panel, determines the amount of framebuffer memory allocated ++ when the driver is initialized. ++ ++ Allowable values are 1, 2, 4, 8, 16, 24 and 32. If unsure, ++ say 24. ++ + config FB_IMX + tristate "Motorola i.MX LCD support" + depends on FB && ARM && ARCH_IMX +Index: linux-2.6.18-avr32/drivers/video/Makefile +=================================================================== +--- linux-2.6.18-avr32.orig/drivers/video/Makefile 2006-11-02 15:54:18.000000000 +0100 ++++ linux-2.6.18-avr32/drivers/video/Makefile 2006-11-02 15:56:20.000000000 +0100 +@@ -75,6 +75,7 @@ obj-$(CONFIG_FB_HP300) += hpf + obj-$(CONFIG_FB_G364) += g364fb.o + obj-$(CONFIG_FB_SA1100) += sa1100fb.o + obj-$(CONFIG_FB_SUN3) += sun3fb.o ++obj-$(CONFIG_FB_SIDSA) += sidsafb.o + obj-$(CONFIG_FB_HIT) += hitfb.o + obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o + obj-$(CONFIG_FB_PVR2) += pvr2fb.o +Index: linux-2.6.18-avr32/drivers/video/fbmem.c +=================================================================== +--- linux-2.6.18-avr32.orig/drivers/video/fbmem.c 2006-11-02 15:54:18.000000000 +0100 ++++ linux-2.6.18-avr32/drivers/video/fbmem.c 2006-11-02 15:56:20.000000000 +0100 +@@ -1153,6 +1153,7 @@ fb_mmap(struct file *file, struct vm_are + /* frame buffer memory */ + start = info->fix.smem_start; + len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len); ++ pr_debug("fb_mmap: start = 0x%08lx, len = 0x%08lx\n", start, len); + if (off >= len) { + /* memory mapped io */ + off -= len; +@@ -1168,6 +1169,7 @@ fb_mmap(struct file *file, struct vm_are + if ((vma->vm_end - vma->vm_start + off) > len) + return -EINVAL; + off += start; ++ pr_debug("fb_mmap: off = 0x%08lx\n", off); + vma->vm_pgoff = off >> PAGE_SHIFT; + /* This is an IO map - tell maydump to skip this VMA */ + vma->vm_flags |= VM_IO | VM_RESERVED; +@@ -1198,6 +1200,10 @@ fb_mmap(struct file *file, struct vm_are + pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; + #elif defined(__arm__) || defined(__sh__) || defined(__m32r__) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); ++#elif defined(__avr32__) ++ vma->vm_page_prot = __pgprot((pgprot_val(vma->vm_page_prot) ++ & ~_PAGE_CACHABLE) ++ | (_PAGE_BUFFER | _PAGE_DIRTY)); + #elif defined(__ia64__) + if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start)) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); +Index: linux-2.6.18-avr32/drivers/video/sidsafb.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.18-avr32/drivers/video/sidsafb.c 2006-11-02 16:07:55.000000000 +0100 +@@ -0,0 +1,805 @@ ++/* ++ * Framebuffer Driver for Atmel/SIDSA LCD Controller ++ * ++ * Copyright (C) 2004-2006 Atmel Corporation ++ * ++ * 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. ++ */ ++#undef DEBUG ++ ++#include <linux/config.h> ++#include <linux/clk.h> ++#include <linux/kernel.h> ++#include <linux/dma-mapping.h> ++#include <linux/interrupt.h> ++#include <linux/fb.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/platform_device.h> ++ ++#include <asm/arch/board.h> ++ ++#include <asm/periph/lcdc.h> ++ ++/* More or less configurable parameters */ ++#define SIDSAFB_FIFO_SIZE 512 ++#define SIDSAFB_DMA_BURST_LEN 8 ++ ++/* TODO: These should be autogenerated from part description file */ ++#define LCDC_DISTYPE_STN_MONO 0 ++#define LCDC_DISTYPE_STN_COLOR 1 ++#define LCDC_DISTYPE_TFT 2 ++#define LCDC_LUT 0xc00 ++ ++struct sidsafb_info { ++ spinlock_t lock; ++ struct fb_info * info; ++ void __iomem * regs; ++ unsigned long irq_base; ++ wait_queue_head_t vsync_wait; ++ unsigned int guard_time; ++ struct clk *hclk; ++ struct clk *pixclk; ++ struct platform_device *pdev; ++ u32 pseudo_palette[16]; ++}; ++ ++/* ++ * How large framebuffer to allocate if none was provided by the ++ * platform. This default is the smallest we can possibly get away ++ * with. ++ */ ++static unsigned long fb_size = (320 * 240); ++ ++#if 0 ++static struct fb_videomode sony_modes[] = { ++ { ++ .refresh = 48, ++ .xres = 240, .yres = 160, ++ .pixclock = 520833, ++ ++ .left_margin = 7, .right_margin = 9, ++ .upper_margin = 19, .lower_margin = 20, ++ .hsync_len = 9, .vsync_len = 2, ++ ++ .sync = 0, ++ .vmode = FB_VMODE_NONINTERLACED, ++ }, ++}; ++#endif ++ ++#if 0 ++static struct fb_videomode vga_modes[] = { ++ { ++ .refresh = 122, ++ .xres = 320, .yres = 240, ++ .pixclock = 80000, ++ ++ .left_margin = 10, .right_margin = 20, ++ .upper_margin = 30, .lower_margin = 5, ++ .hsync_len = 20, .vsync_len = 3, ++ ++ .sync = 0, ++ .vmode = FB_VMODE_NONINTERLACED, ++ }, ++ { ++ .refresh = 70, ++ .xres = 640, .yres = 480, ++ .pixclock = 40000, ++ ++ .left_margin = 10, .right_margin = 20, ++ .upper_margin = 30, .lower_margin = 5, ++ .hsync_len = 20, .vsync_len = 3, ++ ++ .sync = 0, ++ .vmode = FB_VMODE_NONINTERLACED, ++ }, ++}; ++#else ++static struct fb_videomode samsung_modes[] = { ++ { ++ .refresh = 75, ++ .xres = 320, .yres = 240, ++ .pixclock = 145111, ++ ++ .left_margin = 17, .right_margin = 33, ++ .upper_margin = 8, .lower_margin = 10, ++ .hsync_len = 16, .vsync_len = 1, ++ ++ .sync = FB_SYNC_PCLK_RISING, ++ .vmode = FB_VMODE_NONINTERLACED, ++ }, ++}; ++#endif ++ ++#if 1 ++static struct fb_monspecs default_monspecs = { ++ .modedb = samsung_modes, ++ .manufacturer = "SNG", ++ .monitor = "LCD panel", ++ .serial_no = "xxxx", ++ .ascii = "yyyy", ++ .modedb_len = ARRAY_SIZE(samsung_modes), ++ .hfmin = 14820, ++ .hfmax = 22230, ++ .vfmin = 60, ++ .vfmax = 90, ++ .dclkmax = 30000000, ++}; ++#endif ++ ++#if 0 ++static struct fb_monspecs default_monspecs = { ++ .modedb = sony_modes, ++ .manufacturer = "SNY", /* 4 chars?!? */ ++ .monitor = "LCD panel", ++ .serial_no = "xxxx", ++ .ascii = "yyyy", ++ .modedb_len = ARRAY_SIZE(sony_modes), ++ .hfmin = 7000, ++ .hfmax = 8000, ++ .vfmin = 45, ++ .vfmax = 50, ++}; ++// #else ++static struct fb_monspecs default_monspecs = { ++ .modedb = vga_modes, ++ .manufacturer = "VGA", ++ .monitor = "Generic VGA", ++ .serial_no = "xxxx", ++ .ascii = "yyyy", ++ .modedb_len = ARRAY_SIZE(vga_modes), ++ .hfmin = 30000, ++ .hfmax = 64000, ++ .vfmin = 50, ++ .vfmax = 150, ++}; ++#endif ++ ++/* Driver defaults */ ++static struct fb_fix_screeninfo sidsafb_fix __devinitdata = { ++ .id = "sidsafb", ++ .type = FB_TYPE_PACKED_PIXELS, ++ .visual = FB_VISUAL_TRUECOLOR, ++ .xpanstep = 1, ++ .ypanstep = 1, ++ .ywrapstep = 0, ++ .accel = FB_ACCEL_NONE, ++}; ++ ++static void sidsafb_update_dma(struct fb_info *info, ++ struct fb_var_screeninfo *var) ++{ ++ struct sidsafb_info *sinfo = info->par; ++ struct fb_fix_screeninfo *fix = &info->fix; ++ unsigned long dma_addr; ++ unsigned long pixeloff; ++ unsigned long dma2dcfg; ++ ++ dma_addr = (fix->smem_start + var->yoffset * fix->line_length ++ + var->xoffset * var->bits_per_pixel / 8); ++ ++ dma_addr &= ~3UL; ++ pixeloff = LCDC_MKBF(DMA2DCFG_PIXELOFF, var->xoffset * var->bits_per_pixel); ++ ++ /* Set framebuffer DMA base address and pixel offset */ ++ lcdc_writel(sinfo, DMABADDR1, dma_addr); ++ dma2dcfg = lcdc_readl(sinfo, DMA2DCFG); ++ dma2dcfg = LCDC_INSBF(DMA2DCFG_PIXELOFF, pixeloff, dma2dcfg); ++ lcdc_writel(sinfo, DMA2DCFG, dma2dcfg); ++ ++ /* Update configuration */ ++ lcdc_writel(sinfo, DMACON, (lcdc_readl(sinfo, DMACON) ++ | LCDC_BIT(DMACON_DMAUPDT))); ++} ++ ++/** ++ * sidsafb_check_var - Validates a var passed in. ++ * @var: frame buffer variable screen structure ++ * @info: frame buffer structure that represents a single frame buffer ++ * ++ * Checks to see if the hardware supports the state requested by ++ * var passed in. This function does not alter the hardware ++ * state!!! This means the data stored in struct fb_info and ++ * struct sidsafb_info do not change. This includes the var ++ * inside of struct fb_info. Do NOT change these. This function ++ * can be called on its own if we intent to only test a mode and ++ * not actually set it. The stuff in modedb.c is a example of ++ * this. If the var passed in is slightly off by what the ++ * hardware can support then we alter the var PASSED in to what ++ * we can do. If the hardware doesn't support mode change a ++ * -EINVAL will be returned by the upper layers. You don't need ++ * to implement this function then. If you hardware doesn't ++ * support changing the resolution then this function is not ++ * needed. In this case the driver would just provide a var that ++ * represents the static state the screen is in. ++ * ++ * Returns negative errno on error, or zero on success. ++ */ ++static int sidsafb_check_var(struct fb_var_screeninfo *var, ++ struct fb_info *info) ++{ ++ unsigned long new_fb_size; ++ ++ pr_debug("sidsafb_check_var:\n"); ++ pr_debug(" resolution: %ux%u\n", var->xres, var->yres); ++ pr_debug(" pixclk: %llu Hz\n", 1000000000000ULL / var->pixclock); ++ pr_debug(" bpp: %u\n", var->bits_per_pixel); ++ ++ new_fb_size = (var->xres_virtual * var->yres_virtual ++ * ((var->bits_per_pixel + 7) / 8)); ++ if (new_fb_size > info->fix.smem_len) { ++ printk(KERN_NOTICE ++ "sidsafb: %uB framebuffer too small for %ux%ux%u\n", ++ info->fix.smem_len, var->xres_virtual, ++ var->yres_virtual, var->bits_per_pixel); ++ return -EINVAL; ++ } ++ ++ /* Force same alignment for each line */ ++ var->xres = (var->xres + 3) & ~3UL; ++ var->xres_virtual = (var->xres_virtual + 3) & ~3UL; ++ ++ var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0; ++ var->transp.offset = var->transp.length = 0; ++ ++ switch (var->bits_per_pixel) { ++ case 2: ++ case 4: ++ case 8: ++ var->red.offset = var->green.offset = var->blue.offset = 0; ++ var->red.length = var->green.length = var->blue.length ++ = var->bits_per_pixel; ++ break; ++ case 15: ++ case 16: ++ /* ++ * Bit 16 is the "intensity" bit, I think. Not sure ++ * what we're going to use that for... ++ */ ++ var->red.offset = 0; ++ var->green.offset = 5; ++ var->blue.offset = 10; ++ var->red.length = 5; ++ var->green.length = 5; ++ var->blue.length = 5; ++ break; ++ case 24: ++ case 32: ++ var->red.offset = 16; ++ var->green.offset = 8; ++ var->blue.offset = 0; ++ var->red.length = var->green.length = var->blue.length = 8; ++ break; ++ default: ++ printk(KERN_NOTICE "sidsafb: color depth %d not supported\n", ++ var->bits_per_pixel); ++ return -EINVAL; ++ } ++ ++ var->xoffset = var->yoffset = 0; ++ var->red.msb_right = var->green.msb_right = var->blue.msb_right = ++ var->transp.msb_right = 0; ++ ++ return 0; ++} ++ ++/** ++ * sidsafb_set_par - Alters the hardware state. ++ * @info: frame buffer structure that represents a single frame buffer ++ * ++ * Using the fb_var_screeninfo in fb_info we set the resolution ++ * of the this particular framebuffer. This function alters the ++ * par AND the fb_fix_screeninfo stored in fb_info. It doesn't ++ * not alter var in fb_info since we are using that data. This ++ * means we depend on the data in var inside fb_info to be ++ * supported by the hardware. sidsafb_check_var is always called ++ * before sidsafb_set_par to ensure this. Again if you can't ++ * change the resolution you don't need this function. ++ * ++ */ ++static int sidsafb_set_par(struct fb_info *info) ++{ ++ struct sidsafb_info *sinfo = info->par; ++ unsigned long value; ++ ++ pr_debug("sidsafb_set_par:\n"); ++ pr_debug(" * resolution: %ux%u (%ux%u virtual)\n", ++ info->var.xres, info->var.yres, ++ info->var.xres_virtual, info->var.yres_virtual); ++ ++ /* Turn off the LCD controller and the DMA controller */ ++ pr_debug("writing 0x%08x to %p\n", ++ LCDC_MKBF(PWRCON_GUARD_TIME, sinfo->guard_time), ++ sinfo->regs + LCDC_PWRCON); ++ lcdc_writel(sinfo, PWRCON, ++ LCDC_MKBF(PWRCON_GUARD_TIME, sinfo->guard_time)); ++ pr_debug("writing 0 to %p\n", sinfo->regs + LCDC_DMACON); ++ lcdc_writel(sinfo, DMACON, 0); ++ ++ info->fix.line_length = (info->var.xres_virtual ++ * (info->var.bits_per_pixel / 8)); ++ ++ if (info->var.bits_per_pixel <= 8) ++ info->fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ else ++ info->fix.visual = FB_VISUAL_TRUECOLOR; ++ ++ /* Re-initialize the DMA engine... */ ++ pr_debug(" * update DMA engine\n"); ++ sidsafb_update_dma(info, &info->var); ++ ++ /* ...set frame size and burst length = 8 words (?) */ ++ value = LCDC_MKBF(DMAFRMCFG_FRMSIZE, ++ (info->var.yres * info->fix.line_length + 3) / 4); ++ value |= LCDC_MKBF(DMAFRMCFG_BRSTLEN, (SIDSAFB_DMA_BURST_LEN - 1)); ++ lcdc_writel(sinfo, DMAFRMCFG, value); ++ ++ /* ...set 2D configuration (necessary for xres_virtual != xres) */ ++ value = LCDC_MKBF(DMA2DCFG_ADDRINC, ++ info->var.xres_virtual - info->var.xres); ++ lcdc_writel(sinfo, DMA2DCFG, value); ++ ++ /* ...wait for DMA engine to become idle... */ ++ while (lcdc_readl(sinfo, DMACON) & LCDC_BIT(DMACON_DMABUSY)) ++ msleep(10); ++ ++ pr_debug(" * re-enable DMA engine\n"); ++ /* ...and enable it with updated configuration */ ++ lcdc_writel(sinfo, DMACON, (LCDC_BIT(DMACON_DMAEN) ++ | LCDC_BIT(DMACON_DMAUPDT) ++ | LCDC_BIT(DMACON_DMA2DEN))); ++ ++ /* Now, the LCD core... */ ++ ++ /* Set pixel clock. */ ++ value = (clk_get_rate(sinfo->pixclk) / 100000) * info->var.pixclock; ++ value /= 10000000; ++ value = (value + 1) / 2; ++ if (value == 0) { ++ printk("sidsafb: Bypassing lcdc_pclk divider\n"); ++ lcdc_writel(sinfo, LCDCON1, LCDC_BIT(LCDCON1_BYPASS)); ++ } else { ++ lcdc_writel(sinfo, LCDCON1, LCDC_MKBF(LCDCON1_CLKVAL, value - 1)); ++ } ++ ++ /* Initialize control register 2 */ ++ value = (LCDC_BIT(LCDCON2_CLKMOD) ++ | LCDC_MKBF(LCDCON2_DISTYPE, LCDC_DISTYPE_TFT)); ++ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) ++ value |= LCDC_BIT(LCDCON2_INVLINE); ++ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) ++ value |= LCDC_BIT(LCDCON2_INVFRAME); ++ if (info->var.sync & FB_SYNC_PCLK_RISING) ++ value |= LCDC_BIT(LCDCON2_INVCLK); ++ ++ switch (info->var.bits_per_pixel) { ++ case 1: value |= LCDC_MKBF(LCDCON2_PIXELSIZE, 0); break; ++ case 2: value |= LCDC_MKBF(LCDCON2_PIXELSIZE, 1); break; ++ case 4: value |= LCDC_MKBF(LCDCON2_PIXELSIZE, 2); break; ++ case 8: value |= LCDC_MKBF(LCDCON2_PIXELSIZE, 3); break; ++ case 15: /* fall through */ ++ case 16: value |= LCDC_MKBF(LCDCON2_PIXELSIZE, 4); break; ++ case 24: value |= LCDC_MKBF(LCDCON2_PIXELSIZE, 5); break; ++ case 32: value |= LCDC_MKBF(LCDCON2_PIXELSIZE, 6); break; ++ default: BUG(); break; ++ } ++ pr_debug(" * LCDCON2 = %08lx\n", value); ++ lcdc_writel(sinfo, LCDCON2, value); ++ ++ /* Vertical timing */ ++ value = LCDC_MKBF(LCDTIM1_VPW, info->var.vsync_len - 1); ++ value |= LCDC_MKBF(LCDTIM1_VBP, info->var.upper_margin); ++ value |= LCDC_MKBF(LCDTIM1_VFP, info->var.lower_margin); ++ pr_debug(" * LCDTIM1 = %08lx\n", value); ++ lcdc_writel(sinfo, LCDTIM1, value); ++ ++ /* Horizontal timing */ ++ value = LCDC_MKBF(LCDTIM2_HFP, info->var.right_margin - 1); ++ value |= LCDC_MKBF(LCDTIM2_HPW, info->var.hsync_len - 1); ++ value |= LCDC_MKBF(LCDTIM2_HBP, info->var.left_margin - 1); ++ pr_debug(" * LCDTIM2 = %08lx\n", value); ++ lcdc_writel(sinfo, LCDTIM2, value); ++ ++ /* Display size */ ++ value = LCDC_MKBF(LCDFRMCFG_LINESIZE, info->var.xres - 1); ++ value |= LCDC_MKBF(LCDFRMCFG_LINEVAL, info->var.yres - 1); ++ lcdc_writel(sinfo, LCDFRMCFG, value); ++ ++ /* FIFO Threshold: Use formula from data sheet */ ++ value = SIDSAFB_FIFO_SIZE - (2 * SIDSAFB_DMA_BURST_LEN + 3); ++ lcdc_writel(sinfo, LCDFIFO, value); ++ ++ /* Toggle LCD_MODE every frame */ ++ lcdc_writel(sinfo, LCDMVAL, 0); ++ ++ /* Disable all interrupts */ ++ lcdc_writel(sinfo, LCD_IDR, ~0UL); ++ ++ /* Wait for the LCDC core to become idle and enable it */ ++ while(lcdc_readl(sinfo, PWRCON) & LCDC_BIT(PWRCON_LCD_BUSY)) ++ msleep(10); ++ ++ pr_debug(" * re-enable LCD core\n"); ++ lcdc_writel(sinfo, PWRCON, ++ LCDC_MKBF(PWRCON_GUARD_TIME, sinfo->guard_time) ++ | LCDC_BIT(PWRCON_LCD_PWR)); ++ ++ pr_debug(" * DONE\n"); ++ return 0; ++} ++ ++static inline u_int chan_to_field(u_int chan, const struct fb_bitfield *bf) ++{ ++ chan &= 0xffff; ++ chan >>= 16 - bf->length; ++ return chan << bf->offset; ++} ++ ++/** ++ * sidsafb_setcolreg - Optional function. Sets a color register. ++ * @regno: Which register in the CLUT we are programming ++ * @red: The red value which can be up to 16 bits wide ++ * @green: The green value which can be up to 16 bits wide ++ * @blue: The blue value which can be up to 16 bits wide. ++ * @transp: If supported the alpha value which can be up to 16 bits wide. ++ * @info: frame buffer info structure ++ * ++ * Set a single color register. The values supplied have a 16 bit ++ * magnitude which needs to be scaled in this function for the hardware. ++ * Things to take into consideration are how many color registers, if ++ * any, are supported with the current color visual. With truecolor mode ++ * no color palettes are supported. Here a psuedo palette is created ++ * which we store the value in pseudo_palette in struct fb_info. For ++ * pseudocolor mode we have a limited color palette. To deal with this ++ * we can program what color is displayed for a particular pixel value. ++ * DirectColor is similar in that we can program each color field. If ++ * we have a static colormap we don't need to implement this function. ++ * ++ * Returns negative errno on error, or zero on success. In an ++ * ideal world, this would have been the case, but as it turns ++ * out, the other drivers return 1 on failure, so that's what ++ * we're going to do. ++ */ ++static int sidsafb_setcolreg(unsigned int regno, unsigned int red, ++ unsigned int green, unsigned int blue, ++ unsigned int transp, struct fb_info *info) ++{ ++ struct sidsafb_info *sinfo = info->par; ++ unsigned int val; ++ u32 *pal; ++ int ret = 1; ++ ++ if (info->var.grayscale) ++ red = green = blue = (19595 * red + 38470 * green ++ + 7471 * blue) >> 16; ++ ++ switch (info->fix.visual) { ++ case FB_VISUAL_TRUECOLOR: ++ if (regno < 16) { ++ pal = info->pseudo_palette; ++ ++ val = chan_to_field(red, &info->var.red); ++ val |= chan_to_field(green, &info->var.green); ++ val |= chan_to_field(blue, &info->var.blue); ++ ++ pal[regno] = val; ++ ret = 0; ++ } ++ break; ++ ++ case FB_VISUAL_PSEUDOCOLOR: ++ if (regno < 256) { ++ val = ((red >> 11) & 0x001f); ++ val |= ((green >> 6) & 0x03e0); ++ val |= ((blue >> 1) & 0x7c00); ++ ++ /* ++ * TODO: intensity bit. Maybe something like ++ * ~(red[10] ^ green[10] ^ blue[10]) & 1 ++ */ ++ ++ lcdc_writel(sinfo, LUT + regno * 4, val); ++ ret = 0; ++ } ++ break; ++ } ++ ++ return ret; ++} ++ ++static int sidsafb_pan_display(struct fb_var_screeninfo *var, ++ struct fb_info *info) ++{ ++ pr_debug("sidsafb_pan_display\n"); ++ ++ sidsafb_update_dma(info, var); ++ ++ return 0; ++} ++ ++static struct fb_ops sidsafb_ops = { ++ .owner = THIS_MODULE, ++ .fb_check_var = sidsafb_check_var, ++ .fb_set_par = sidsafb_set_par, ++ .fb_setcolreg = sidsafb_setcolreg, ++ .fb_pan_display = sidsafb_pan_display, ++ .fb_fillrect = cfb_fillrect, ++ .fb_copyarea = cfb_copyarea, ++ .fb_imageblit = cfb_imageblit, ++}; ++ ++static irqreturn_t sidsafb_interrupt(int irq, void *dev_id, ++ struct pt_regs *regs) ++{ ++ struct fb_info *info = dev_id; ++ struct sidsafb_info *sinfo = info->par; ++ u32 status; ++ ++ status = lcdc_readl(sinfo, LCD_ISR); ++ while (status) { ++ if (status & LCDC_BIT(LCD_ISR_EOFIS)) { ++ pr_debug("sidsafb: DMA End Of Frame interrupt\n"); ++ ++ lcdc_writel(sinfo, LCD_ICR, LCDC_BIT(LCD_ICR_EOFIC)); ++ status &= ~LCDC_BIT(LCD_ISR_EOFIS); ++ wake_up(&sinfo->vsync_wait); ++ } ++ ++ if (status) { ++ printk(KERN_ERR ++ "LCDC: Interrupts still pending: 0x%x\n", ++ status); ++ lcdc_writel(sinfo, LCD_IDR, status); ++ } ++ ++ status = lcdc_readl(sinfo, LCD_ISR); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static void __devinit init_pseudo_palette(u32 *palette) ++{ ++ static const u32 init_palette[16] = { ++ 0x000000, ++ 0xaa0000, ++ 0x00aa00, ++ 0xaa5500, ++ 0x0000aa, ++ 0xaa00aa, ++ 0x00aaaa, ++ 0xaaaaaa, ++ 0x555555, ++ 0xff5555, ++ 0x55ff55, ++ 0xffff55, ++ 0x5555ff, ++ 0xff55ff, ++ 0x55ffff, ++ 0xffffff ++ }; ++ ++ memcpy(palette, init_palette, sizeof(init_palette)); ++} ++ ++static int __devinit sidsafb_set_fbinfo(struct sidsafb_info *sinfo) ++{ ++ struct fb_info *info = sinfo->info; ++ ++ init_pseudo_palette(sinfo->pseudo_palette); ++ ++ info->flags = (FBINFO_DEFAULT ++ | FBINFO_PARTIAL_PAN_OK ++ | FBINFO_HWACCEL_XPAN ++ | FBINFO_HWACCEL_YPAN); ++ memcpy(&info->fix, &sidsafb_fix, sizeof(info->fix)); ++ memcpy(&info->monspecs, &default_monspecs, sizeof(info->monspecs)); ++ info->fbops = &sidsafb_ops; ++ info->pseudo_palette = sinfo->pseudo_palette; ++ ++ init_waitqueue_head(&sinfo->vsync_wait); ++ ++ return 0; ++} ++ ++static int __devinit sidsafb_probe(struct platform_device *pdev) ++{ ++ struct lcdc_platform_data *fb_data = pdev->dev.platform_data; ++ struct fb_info *info; ++ struct sidsafb_info *sinfo; ++ const struct resource *mmio_resource; ++ int ret; ++ ++ pr_debug("sidsafb_probe BEGIN\n"); ++ ++ mmio_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!mmio_resource) { ++ dev_err(&pdev->dev, "no MMIO resource found\n"); ++ return -ENXIO; ++ } ++ ++ ret = -ENOMEM; ++ info = framebuffer_alloc(sizeof(struct sidsafb_info), &pdev->dev); ++ if (!info) { ++ dev_err(&pdev->dev, "failed to allocate memory\n"); ++ goto out; ++ } ++ ++ sinfo = info->par; ++ sinfo->info = info; ++ sinfo->pdev = pdev; ++ sinfo->guard_time = 1; ++ ++ spin_lock_init(&sinfo->lock); ++ sidsafb_set_fbinfo(sinfo); ++ info->fix.mmio_start = mmio_resource->start; ++ info->fix.mmio_len = mmio_resource->end - mmio_resource->start + 1; ++ sinfo->irq_base = platform_get_irq(pdev, 0); ++ ++ sinfo->hclk = clk_get(&pdev->dev, "hclk"); ++ if (IS_ERR(sinfo->hclk)) { ++ dev_err(&pdev->dev, "failed to get hclk\n"); ++ ret = PTR_ERR(sinfo->hclk); ++ goto free_info; ++ } ++ sinfo->pixclk = clk_get(&pdev->dev, "pixclk"); ++ if (IS_ERR(sinfo->pixclk)) { ++ dev_err(&pdev->dev, "failed to get pixel clock\n"); ++ ret = PTR_ERR(sinfo->hclk); ++ goto put_hclk; ++ } ++ ++ clk_enable(sinfo->hclk); ++ clk_enable(sinfo->pixclk); ++ ++ /* Use platform-supplied framebuffer memory if available */ ++ if (fb_data && fb_data->fbmem_size != 0) { ++ info->fix.smem_start = fb_data->fbmem_start; ++ info->fix.smem_len = fb_data->fbmem_size; ++ info->screen_base = ioremap(info->fix.smem_start, ++ info->fix.smem_len); ++ } else { ++ dma_addr_t paddr; ++ ++ info->fix.smem_len = fb_size; ++ info->screen_base = dma_alloc_coherent(&pdev->dev, fb_size, ++ &paddr, GFP_KERNEL); ++ info->fix.smem_start = paddr; ++ } ++ ++ if (!info->screen_base) { ++ printk(KERN_ERR "sidsafb: Could not allocate framebuffer\n"); ++ goto disable_clocks; ++ } ++ ++ sinfo->regs = ioremap(info->fix.mmio_start, info->fix.mmio_len); ++ if (!sinfo->regs) { ++ printk(KERN_ERR "sidsafb: Could not map LCDC registers\n"); ++ goto free_fb; ++ } ++ ++ ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb, ++ info->monspecs.modedb_len, info->monspecs.modedb, ++ CONFIG_FB_SIDSA_DEFAULT_BPP); ++ if (!ret) { ++ printk(KERN_ERR "sidsafb: No suitable video mode found\n"); ++ goto unmap_regs; ++ } ++ ++ ret = request_irq(sinfo->irq_base, sidsafb_interrupt, 0, ++ "sidsafb", info); ++ if (ret) ++ goto unmap_regs; ++ ++ /* Allocate colormap */ ++ if (fb_alloc_cmap(&info->cmap, 256, 0)) { ++ ret = -ENOMEM; ++ goto unregister_irqs; ++ } ++ ++ /* ++ * Tell the world that we're ready to go ++ */ ++ ret = register_framebuffer(info); ++ if (ret) ++ goto free_cmap; ++ ++ printk("fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %lu\n", ++ info->node, info->fix.mmio_start, sinfo->regs, sinfo->irq_base); ++ ++ platform_set_drvdata(pdev, info); ++ ++ memset_io(info->screen_base, 0, info->fix.smem_len); ++ info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW; ++ ret = fb_set_var(info, &info->var); ++ if (ret) ++ printk(KERN_WARNING ++ "sidsafb: Unable to set display parameters\n"); ++ info->var.activate &= ~(FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW); ++ ++ pr_debug("sidsafb_probe SUCCESS\n"); ++ return 0; ++ ++ ++free_cmap: ++ fb_dealloc_cmap(&info->cmap); ++unregister_irqs: ++ free_irq(sinfo->irq_base, info); ++unmap_regs: ++ iounmap(sinfo->regs); ++free_fb: ++ if (!fb_data || fb_data->fbmem_size == 0) ++ dma_free_coherent(&pdev->dev, info->fix.smem_len, ++ (void __force *)info->screen_base, ++ info->fix.smem_start); ++disable_clocks: ++ clk_disable(sinfo->pixclk); ++ clk_disable(sinfo->hclk); ++ clk_put(sinfo->pixclk); ++put_hclk: ++ clk_put(sinfo->hclk); ++free_info: ++ framebuffer_release(info); ++out: ++ pr_debug("sidsafb_probe FAILED\n"); ++ return ret; ++} ++ ++static int __devexit sidsafb_remove(struct platform_device *pdev) ++{ ++ struct lcdc_platform_data *fb_data = pdev->dev.platform_data; ++ struct fb_info *info = platform_get_drvdata(pdev); ++ struct sidsafb_info *sinfo; ++ ++ if (!info) ++ return 0; ++ sinfo = info->par; ++ ++ /* TODO: Restore original state */ ++ unregister_framebuffer(info); ++ ++ fb_dealloc_cmap(&info->cmap); ++ free_irq(sinfo->irq_base, info); ++ iounmap(sinfo->regs); ++ if (!fb_data || fb_data->fbmem_size == 0) ++ dma_free_coherent(&pdev->dev, info->fix.smem_len, ++ (void __force *)info->screen_base, ++ info->fix.smem_start); ++ clk_disable(sinfo->hclk); ++ clk_put(sinfo->hclk); ++ platform_set_drvdata(pdev, NULL); ++ framebuffer_release(info); ++ ++ return 0; ++} ++ ++static struct platform_driver sidsafb_driver = { ++ .probe = sidsafb_probe, ++ .remove = __devexit_p(sidsafb_remove), ++ .driver = { ++ .name = "lcdc", ++ }, ++}; ++ ++int __init sidsafb_init(void) ++{ ++ return platform_driver_register(&sidsafb_driver); ++} ++ ++static void __exit sidsafb_exit(void) ++{ ++ platform_driver_unregister(&sidsafb_driver); ++} ++ ++module_init(sidsafb_init); ++module_exit(sidsafb_exit); ++ ++module_param(fb_size, ulong, 0644); ++MODULE_PARM_DESC(fb_size, "Minimum framebuffer size to allocate"); ++ ++MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>"); ++MODULE_DESCRIPTION("Atmel/SIDSA LCD Controller framebuffer driver"); ++MODULE_LICENSE("GPL"); +Index: linux-2.6.18-avr32/include/asm-avr32/periph/lcdc.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.18-avr32/include/asm-avr32/periph/lcdc.h 2006-11-02 16:08:35.000000000 +0100 +@@ -0,0 +1,271 @@ ++/* ++ * Register definitions for Atmel/SIDSA LCD Controller ++ * ++ * Copyright (C) 2004-2006 Atmel Corporation ++ * ++ * 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_AVR32_PERIPH_LCDC_H__ ++#define __ASM_AVR32_PERIPH_LCDC_H__ ++ ++#define LCDC_CONTRAST_CTR 0x00000840 ++# define LCDC_CONTRAST_CTR_ENA_OFFSET 3 ++# define LCDC_CONTRAST_CTR_ENA_SIZE 1 ++# define LCDC_CONTRAST_CTR_POL_OFFSET 2 ++# define LCDC_CONTRAST_CTR_POL_SIZE 1 ++# define LCDC_CONTRAST_CTR_PS_OFFSET 0 ++# define LCDC_CONTRAST_CTR_PS_SIZE 2 ++#define LCDC_CONTRAST_VAL 0x00000844 ++# define LCDC_CONTRAST_VAL_CVAL_OFFSET 0 ++# define LCDC_CONTRAST_VAL_CVAL_SIZE 8 ++#define LCDC_DMABADDR1 0x00000000 ++# define LCDC_DMABADDR1_BADDR_U_OFFSET 0 ++# define LCDC_DMABADDR1_BADDR_U_SIZE 32 ++#define LCDC_DMABADDR2 0x00000004 ++# define LCDC_DMABADDR2_BADDR_L_OFFSET 0 ++# define LCDC_DMABADDR2_BADDR_L_SIZE 32 ++#define LCDC_DMACON 0x0000001C ++# define LCDC_DMACON_DMABUSY_OFFSET 2 ++# define LCDC_DMACON_DMABUSY_SIZE 1 ++# define LCDC_DMACON_DMAEN_OFFSET 0 ++# define LCDC_DMACON_DMAEN_SIZE 1 ++# define LCDC_DMACON_DMARST_OFFSET 1 ++# define LCDC_DMACON_DMARST_SIZE 1 ++# define LCDC_DMACON_DMAUPDT_OFFSET 3 ++# define LCDC_DMACON_DMAUPDT_SIZE 1 ++# define LCDC_DMACON_DMA2DEN_OFFSET 4 ++# define LCDC_DMACON_DMA2DEN_SIZE 1 ++#define LCDC_DMAFRMADD1 0x00000010 ++# define LCDC_DMAFRMADD1_FRMADD_U_OFFSET 0 ++# define LCDC_DMAFRMADD1_FRMADD_U_SIZE 32 ++#define LCDC_DMAFRMADD2 0x00000014 ++# define LCDC_DMAFRMADD2_FRMADD_L_OFFSET 0 ++# define LCDC_DMAFRMADD2_FRMADD_L_SIZE 32 ++#define LCDC_DMAFRMCFG 0x00000018 ++# define LCDC_DMAFRMCFG_BRSTLEN_OFFSET 24 ++# define LCDC_DMAFRMCFG_BRSTLEN_SIZE 7 ++# define LCDC_DMAFRMCFG_FRMSIZE_OFFSET 0 ++# define LCDC_DMAFRMCFG_FRMSIZE_SIZE 23 ++#define LCDC_DMAFRMPT1 0x00000008 ++# define LCDC_DMAFRMPT1_FRMPT_U_OFFSET 0 ++# define LCDC_DMAFRMPT1_FRMPT_U_SIZE 23 ++#define LCDC_DMAFRMPT2 0x0000000C ++# define LCDC_DMAFRMPT2_FRMPT_L_OFFSET 0 ++# define LCDC_DMAFRMPT2_FRMPT_L_SIZE 23 ++#define LCDC_DMA2DCFG 0x00000020 ++# define LCDC_DMA2DCFG_ADDRINC_OFFSET 0 ++# define LCDC_DMA2DCFG_ADDRINC_SIZE 16 ++# define LCDC_DMA2DCFG_PIXELOFF_OFFSET 24 ++# define LCDC_DMA2DCFG_PIXELOFF_SIZE 5 ++#define LCDC_DP1_2 0x0000081C ++# define LCDC_DP1_2_DP1_2_OFFSET 0 ++# define LCDC_DP1_2_DP1_2_SIZE 8 ++#define LCDC_DP2_3 0x00000828 ++# define LCDC_DP2_3_DP2_3_OFFSET 0 ++# define LCDC_DP2_3_DP2_3_SIZE 12 ++#define LCDC_DP3_4 0x00000830 ++# define LCDC_DP3_4_DP3_4_OFFSET 0 ++# define LCDC_DP3_4_DP3_4_SIZE 16 ++#define LCDC_DP3_5 0x00000824 ++# define LCDC_DP3_5_DP3_5_OFFSET 0 ++# define LCDC_DP3_5_DP3_5_SIZE 20 ++#define LCDC_DP4_5 0x00000834 ++# define LCDC_DP4_5_DP4_5_OFFSET 0 ++# define LCDC_DP4_5_DP4_5_SIZE 20 ++#define LCDC_DP4_7 0x00000820 ++# define LCDC_DP4_7_DP4_7_OFFSET 0 ++# define LCDC_DP4_7_DP4_7_SIZE 28 ++#define LCDC_DP5_7 0x0000082C ++# define LCDC_DP5_7_DP5_7_OFFSET 0 ++# define LCDC_DP5_7_DP5_7_SIZE 28 ++#define LCDC_DP6_7 0x00000838 ++# define LCDC_DP6_7_DP6_7_OFFSET 0 ++# define LCDC_DP6_7_DP6_7_SIZE 28 ++#define LCDC_LCDCON1 0x00000800 ++# define LCDC_LCDCON1_BYPASS_OFFSET 0 ++# define LCDC_LCDCON1_BYPASS_SIZE 1 ++# define LCDC_LCDCON1_CLKVAL_OFFSET 12 ++# define LCDC_LCDCON1_CLKVAL_SIZE 9 ++# define LCDC_LCDCON1_LINECNT_OFFSET 21 ++# define LCDC_LCDCON1_LINECNT_SIZE 11 ++#define LCDC_LCDCON2 0x00000804 ++# define LCDC_LCDCON2_CLKMOD_OFFSET 15 ++# define LCDC_LCDCON2_CLKMOD_SIZE 1 ++# define LCDC_LCDCON2_DISTYPE_OFFSET 0 ++# define LCDC_LCDCON2_DISTYPE_SIZE 2 ++# define LCDC_LCDCON2_IFWIDTH_OFFSET 3 ++# define LCDC_LCDCON2_IFWIDTH_SIZE 2 ++# define LCDC_LCDCON2_INVCLK_OFFSET 11 ++# define LCDC_LCDCON2_INVCLK_SIZE 1 ++# define LCDC_LCDCON2_INVDVAL_OFFSET 12 ++# define LCDC_LCDCON2_INVDVAL_SIZE 1 ++# define LCDC_LCDCON2_INVFRAME_OFFSET 9 ++# define LCDC_LCDCON2_INVFRAME_SIZE 1 ++# define LCDC_LCDCON2_INVLINE_OFFSET 10 ++# define LCDC_LCDCON2_INVLINE_SIZE 1 ++# define LCDC_LCDCON2_INVVD_OFFSET 8 ++# define LCDC_LCDCON2_INVVD_SIZE 1 ++# define LCDC_LCDCON2_MEMOR_OFFSET 30 ++# define LCDC_LCDCON2_MEMOR_SIZE 2 ++# define LCDC_LCDCON2_PIXELSIZE_OFFSET 5 ++# define LCDC_LCDCON2_PIXELSIZE_SIZE 3 ++# define LCDC_LCDCON2_SCANMOD_OFFSET 2 ++# define LCDC_LCDCON2_SCANMOD_SIZE 1 ++#define LCDC_LCDFIFO 0x00000814 ++# define LCDC_LCDFIFO_FIFOTH_OFFSET 0 ++# define LCDC_LCDFIFO_FIFOTH_SIZE 16 ++#define LCDC_LCDFRMCFG 0x00000810 ++# define LCDC_LCDFRMCFG_LINESIZE_OFFSET 21 ++# define LCDC_LCDFRMCFG_LINESIZE_SIZE 11 ++# define LCDC_LCDFRMCFG_LINEVAL_OFFSET 0 ++# define LCDC_LCDFRMCFG_LINEVAL_SIZE 11 ++#define LCDC_LCDMVAL 0x00000818 ++# define LCDC_LCDMVAL_MMODE_OFFSET 31 ++# define LCDC_LCDMVAL_MMODE_SIZE 1 ++# define LCDC_LCDMVAL_MVAL_OFFSET 0 ++# define LCDC_LCDMVAL_MVAL_SIZE 8 ++#define LCDC_LCDTIM1 0x00000808 ++# define LCDC_LCDTIM1_VBP_OFFSET 8 ++# define LCDC_LCDTIM1_VBP_SIZE 8 ++# define LCDC_LCDTIM1_VFP_OFFSET 0 ++# define LCDC_LCDTIM1_VFP_SIZE 8 ++# define LCDC_LCDTIM1_VHDLY_OFFSET 24 ++# define LCDC_LCDTIM1_VHDLY_SIZE 4 ++# define LCDC_LCDTIM1_VPW_OFFSET 16 ++# define LCDC_LCDTIM1_VPW_SIZE 6 ++#define LCDC_LCDTIM2 0x0000080C ++# define LCDC_LCDTIM2_HBP_OFFSET 0 ++# define LCDC_LCDTIM2_HBP_SIZE 8 ++# define LCDC_LCDTIM2_HFP_OFFSET 21 ++# define LCDC_LCDTIM2_HFP_SIZE 11 ++# define LCDC_LCDTIM2_HPW_OFFSET 8 ++# define LCDC_LCDTIM2_HPW_SIZE 6 ++#define LCDC_LCD_GPR 0x0000085C ++# define LCDC_LCD_GPR_GPRB0_OFFSET 0 ++# define LCDC_LCD_GPR_GPRB0_SIZE 1 ++# define LCDC_LCD_GPR_GPRB1_OFFSET 1 ++# define LCDC_LCD_GPR_GPRB1_SIZE 1 ++# define LCDC_LCD_GPR_GPRB2_OFFSET 2 ++# define LCDC_LCD_GPR_GPRB2_SIZE 1 ++# define LCDC_LCD_GPR_GPRB3_OFFSET 3 ++# define LCDC_LCD_GPR_GPRB3_SIZE 1 ++# define LCDC_LCD_GPR_GPRB4_OFFSET 4 ++# define LCDC_LCD_GPR_GPRB4_SIZE 1 ++# define LCDC_LCD_GPR_GPRB5_OFFSET 5 ++# define LCDC_LCD_GPR_GPRB5_SIZE 1 ++# define LCDC_LCD_GPR_GPRB6_OFFSET 6 ++# define LCDC_LCD_GPR_GPRB6_SIZE 1 ++# define LCDC_LCD_GPR_GPRB7_OFFSET 7 ++# define LCDC_LCD_GPR_GPRB7_SIZE 1 ++#define LCDC_LCD_ICR 0x00000858 ++# define LCDC_LCD_ICR_EOFIC_OFFSET 2 ++# define LCDC_LCD_ICR_EOFIC_SIZE 1 ++# define LCDC_LCD_ICR_LNIC_OFFSET 0 ++# define LCDC_LCD_ICR_LNIC_SIZE 1 ++# define LCDC_LCD_ICR_LSTLNIC_OFFSET 1 ++# define LCDC_LCD_ICR_LSTLNIC_SIZE 1 ++# define LCDC_LCD_ICR_MERIC_OFFSET 6 ++# define LCDC_LCD_ICR_MERIC_SIZE 1 ++# define LCDC_LCD_ICR_OWRIC_OFFSET 5 ++# define LCDC_LCD_ICR_OWRIC_SIZE 1 ++# define LCDC_LCD_ICR_UFLWIC_OFFSET 4 ++# define LCDC_LCD_ICR_UFLWIC_SIZE 1 ++#define LCDC_LCD_IDR 0x0000084C ++# define LCDC_LCD_IDR_EOFID_OFFSET 2 ++# define LCDC_LCD_IDR_EOFID_SIZE 1 ++# define LCDC_LCD_IDR_LNID_OFFSET 0 ++# define LCDC_LCD_IDR_LNID_SIZE 1 ++# define LCDC_LCD_IDR_LSTLNID_OFFSET 1 ++# define LCDC_LCD_IDR_LSTLNID_SIZE 1 ++# define LCDC_LCD_IDR_MERID_OFFSET 6 ++# define LCDC_LCD_IDR_MERID_SIZE 1 ++# define LCDC_LCD_IDR_OWRID_OFFSET 5 ++# define LCDC_LCD_IDR_OWRID_SIZE 1 ++# define LCDC_LCD_IDR_UFLWID_OFFSET 4 ++# define LCDC_LCD_IDR_UFLWID_SIZE 1 ++#define LCDC_LCD_IER 0x00000848 ++# define LCDC_LCD_IER_EOFIE_OFFSET 2 ++# define LCDC_LCD_IER_EOFIE_SIZE 1 ++# define LCDC_LCD_IER_LNIE_OFFSET 0 ++# define LCDC_LCD_IER_LNIE_SIZE 1 ++# define LCDC_LCD_IER_LSTLNIE_OFFSET 1 ++# define LCDC_LCD_IER_LSTLNIE_SIZE 1 ++# define LCDC_LCD_IER_MERIE_OFFSET 6 ++# define LCDC_LCD_IER_MERIE_SIZE 1 ++# define LCDC_LCD_IER_OWRIE_OFFSET 5 ++# define LCDC_LCD_IER_OWRIE_SIZE 1 ++# define LCDC_LCD_IER_UFLWIE_OFFSET 4 ++# define LCDC_LCD_IER_UFLWIE_SIZE 1 ++#define LCDC_LCD_IMR 0x00000850 ++# define LCDC_LCD_IMR_EOFIM_OFFSET 2 ++# define LCDC_LCD_IMR_EOFIM_SIZE 1 ++# define LCDC_LCD_IMR_LNIM_OFFSET 0 ++# define LCDC_LCD_IMR_LNIM_SIZE 1 ++# define LCDC_LCD_IMR_LSTLNIM_OFFSET 1 ++# define LCDC_LCD_IMR_LSTLNIM_SIZE 1 ++# define LCDC_LCD_IMR_MERIM_OFFSET 6 ++# define LCDC_LCD_IMR_MERIM_SIZE 1 ++# define LCDC_LCD_IMR_OWRIM_OFFSET 5 ++# define LCDC_LCD_IMR_OWRIM_SIZE 1 ++# define LCDC_LCD_IMR_UFLWIM_OFFSET 4 ++# define LCDC_LCD_IMR_UFLWIM_SIZE 1 ++#define LCDC_LCD_IRR 0x00000864 ++# define LCDC_LCD_IRR_EOFIR_OFFSET 2 ++# define LCDC_LCD_IRR_EOFIR_SIZE 1 ++# define LCDC_LCD_IRR_LNIR_OFFSET 0 ++# define LCDC_LCD_IRR_LNIR_SIZE 1 ++# define LCDC_LCD_IRR_LSTLNIR_OFFSET 1 ++# define LCDC_LCD_IRR_LSTLNIR_SIZE 1 ++# define LCDC_LCD_IRR_MERIR_OFFSET 6 ++# define LCDC_LCD_IRR_MERIR_SIZE 1 ++# define LCDC_LCD_IRR_OWRIR_OFFSET 5 ++# define LCDC_LCD_IRR_OWRIR_SIZE 1 ++# define LCDC_LCD_IRR_UFLWIR_OFFSET 4 ++# define LCDC_LCD_IRR_UFLWIR_SIZE 1 ++#define LCDC_LCD_ISR 0x00000854 ++# define LCDC_LCD_ISR_EOFIS_OFFSET 2 ++# define LCDC_LCD_ISR_EOFIS_SIZE 1 ++# define LCDC_LCD_ISR_LNIS_OFFSET 0 ++# define LCDC_LCD_ISR_LNIS_SIZE 1 ++# define LCDC_LCD_ISR_LSTLNIS_OFFSET 1 ++# define LCDC_LCD_ISR_LSTLNIS_SIZE 1 ++# define LCDC_LCD_ISR_MERIS_OFFSET 6 ++# define LCDC_LCD_ISR_MERIS_SIZE 1 ++# define LCDC_LCD_ISR_OWRIS_OFFSET 5 ++# define LCDC_LCD_ISR_OWRIS_SIZE 1 ++# define LCDC_LCD_ISR_UFLWIS_OFFSET 4 ++# define LCDC_LCD_ISR_UFLWIS_SIZE 1 ++#define LCDC_LCD_ITR 0x00000860 ++# define LCDC_LCD_ITR_EOFIT_OFFSET 2 ++# define LCDC_LCD_ITR_EOFIT_SIZE 1 ++# define LCDC_LCD_ITR_LNIT_OFFSET 0 ++# define LCDC_LCD_ITR_LNIT_SIZE 1 ++# define LCDC_LCD_ITR_LSTLNIT_OFFSET 1 ++# define LCDC_LCD_ITR_LSTLNIT_SIZE 1 ++# define LCDC_LCD_ITR_MERIT_OFFSET 6 ++# define LCDC_LCD_ITR_MERIT_SIZE 1 ++# define LCDC_LCD_ITR_OWRIT_OFFSET 5 ++# define LCDC_LCD_ITR_OWRIT_SIZE 1 ++# define LCDC_LCD_ITR_UFLWIT_OFFSET 4 ++# define LCDC_LCD_ITR_UFLWIT_SIZE 1 ++#define LCDC_PWRCON 0x0000083C ++# define LCDC_PWRCON_GUARD_TIME_OFFSET 1 ++# define LCDC_PWRCON_GUARD_TIME_SIZE 7 ++# define LCDC_PWRCON_LCD_BUSY_OFFSET 31 ++# define LCDC_PWRCON_LCD_BUSY_SIZE 1 ++# define LCDC_PWRCON_LCD_PWR_OFFSET 0 ++# define LCDC_PWRCON_LCD_PWR_SIZE 1 ++ ++#define LCDC_BIT(name) (1 << LCDC_##name##_OFFSET) ++#define LCDC_MKBF(name,value) (((value) & ((1 << LCDC_##name##_SIZE) - 1)) << LCDC_##name##_OFFSET) ++#define LCDC_GETBF(name,value) (((value) >> LCDC_##name##_OFFSET) & ((1 << LCDC_##name##_SIZE) - 1)) ++#define LCDC_INSBF(name,value,old) (((old) & ~(((1 << LCDC_##name##_SIZE) - 1) << LCDC_##name##_OFFSET)) | LCDC_MKBF(name, value)) ++ ++#define lcdc_readl(port,reg) \ ++ __raw_readl((port)->regs + LCDC_##reg) ++#define lcdc_writel(port,reg,value) \ ++ __raw_writel((value), (port)->regs + LCDC_##reg) ++ ++#endif /* __ASM_AVR32_PERIPH_LCDC_H__ */ +Index: linux-2.6.18-avr32/include/linux/fb.h +=================================================================== +--- linux-2.6.18-avr32.orig/include/linux/fb.h 2006-11-02 15:54:18.000000000 +0100 ++++ linux-2.6.18-avr32/include/linux/fb.h 2006-11-02 15:56:20.000000000 +0100 +@@ -191,6 +191,7 @@ struct fb_bitfield { + /* vtotal = 144d/288n/576i => PAL */ + /* vtotal = 121d/242n/484i => NTSC */ + #define FB_SYNC_ON_GREEN 32 /* sync on green */ ++#define FB_SYNC_PCLK_RISING 64 /* pixel data sampled on rising pclk */ + + #define FB_VMODE_NONINTERLACED 0 /* non interlaced */ + #define FB_VMODE_INTERLACED 1 /* interlaced */ +@@ -825,7 +826,7 @@ struct fb_info { + #define fb_writeq sbus_writeq + #define fb_memset sbus_memset_io + +-#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || (defined(__sh__) && !defined(__SH5__)) || defined(__powerpc__) ++#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || (defined(__sh__) && !defined(__SH5__)) || defined(__powerpc__) || defined(__avr32__) + + #define fb_readb __raw_readb + #define fb_readw __raw_readw |