Hi, works in 16bpp, anyone with a system that works in 8bbp can give me a hand to test this mode? -- Christian <c.pellegrin@xxxxxxxxxxx>
Index: drivers/video/Kconfig =================================================================== RCS file: /home/cvs/linux/drivers/video/Kconfig,v retrieving revision 1.31 diff -u -r1.31 Kconfig --- drivers/video/Kconfig 24 Nov 2004 09:03:40 -0000 1.31 +++ drivers/video/Kconfig 12 Jan 2005 09:05:16 -0000 @@ -973,7 +973,7 @@ config FB_AU1100 bool "Au1100 LCD Driver" - depends on FB && EXPERIMENTAL && PCI && MIPS && MIPS_PB1100=y + depends on FB && EXPERIMENTAL && MIPS && SOC_AU1X00 config FB_SBUS bool "SBUS and UPA framebuffers" Index: drivers/video/Makefile =================================================================== RCS file: /home/cvs/linux/drivers/video/Makefile,v retrieving revision 1.85 diff -u -r1.85 Makefile --- drivers/video/Makefile 15 Nov 2004 11:49:34 -0000 1.85 +++ drivers/video/Makefile 12 Jan 2005 09:05:21 -0000 @@ -94,7 +94,7 @@ obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_MAXINE) += maxinefb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_TX3912) += tx3912fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_AU1100) += au1100fb.o fbgen.o +obj-$(CONFIG_FB_AU1100) += au1100fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o # Platform or fallback drivers go here Index: drivers/video/au1100fb.c =================================================================== RCS file: /home/cvs/linux/drivers/video/au1100fb.c,v retrieving revision 1.3 diff -u -r1.3 au1100fb.c --- drivers/video/au1100fb.c 26 Oct 2004 02:23:08 -0000 1.3 +++ drivers/video/au1100fb.c 12 Jan 2005 09:05:26 -0000 @@ -2,16 +2,28 @@ * BRIEF MODULE DESCRIPTION * Au1100 LCD Driver. * + * Adapted by <c.pellegrin@xxxxxxxxxxx> for kernel 2.6 + * + * TODO: + * 8bpp support ASA I get hardware for testing + * + * based on code: + ****** 2.4 au1100fb.c * Copyright 2002 MontaVista Software * Author: MontaVista Software, Inc. * ppopov@xxxxxxxxxx or source@xxxxxxxxxx * * Copyright 2002 Alchemy Semiconductor * Author: Alchemy Semiconductor + ****** 2.6 vesafb.c + * framebuffer driver for VBE 2.0 compliant graphic boards + * + * switching to graphics mode happens at boot time (while + * running in real mode, see arch/i386/boot/video.S). + * + * (c) 1998 Gerd Knorr <kraxel@xxxxxxxxxxxxxxxxxxxxx> * - * Based on: - * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device - * Created 28 Dec 1997 by Geert Uytterhoeven + ****** * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -43,37 +55,18 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/fb.h> +#include <linux/ioport.h> #include <linux/init.h> -#include <linux/pci.h> -#include <asm/au1000.h> -#include <asm/pb1100.h> +#include <asm/mach-au1x00/au1000.h> +#include <asm/mach-pb1x00/pb1100.h> #include "au1100fb.h" -#include <video/fbcon.h> -#include <video/fbcon-mfb.h> -#include <video/fbcon-cfb2.h> -#include <video/fbcon-cfb4.h> -#include <video/fbcon-cfb8.h> -#include <video/fbcon-cfb16.h> - -/* - * Sanity check. If this is a new Au1100 based board, search for - * the PB1100 ifdefs to make sure you modify the code accordingly. - */ -#if defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_DB1100) || defined(CONFIG_MIPS_HYDROGEN3) -#else -error Unknown Au1100 board -#endif - -#define CMAPSIZE 16 -static int my_lcd_index; /* default is zero */ -struct known_lcd_panels *p_lcd; -AU1100_LCD *p_lcd_reg = (AU1100_LCD *)AU1100_LCD_ADDR; +/* --------------------------------------------------------------------- */ struct au1100fb_info { - struct fb_info_gen gen; + struct fb_info gen; unsigned long fb_virt_start; unsigned long fb_size; unsigned long fb_phys; @@ -88,192 +81,53 @@ }; -struct au1100fb_par { - struct fb_var_screeninfo var; - - int line_length; // in bytes - int cmap_len; // color-map length -}; - +/* --------------------------------------------------------------------- */ -static struct au1100fb_info fb_info; -static struct au1100fb_par current_par; -static struct display disp; - -int au1100fb_init(void); -void au1100fb_setup(char *options, int *ints); -static int au1100fb_mmap(struct fb_info *fb, struct file *file, - struct vm_area_struct *vma); -static int au1100_blank(int blank_mode, struct fb_info_gen *info); -static int au1100fb_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg, int con, struct fb_info *info); +static int my_lcd_index; /* default is zero */ +struct known_lcd_panels *p_lcd; +AU1100_LCD *p_lcd_reg = (AU1100_LCD *)AU1100_LCD_ADDR; +static int depth; +static int nohwcursor; -void au1100_nocursor(struct display *p, int mode, int xx, int yy){}; +static struct au1100fb_info *my_fb_info; /* the info for the current driver */ -static struct fb_ops au1100fb_ops = { - owner: THIS_MODULE, - fb_get_fix: fbgen_get_fix, - fb_get_var: fbgen_get_var, - fb_set_var: fbgen_set_var, - fb_get_cmap: fbgen_get_cmap, - fb_set_cmap: fbgen_set_cmap, - fb_pan_display: fbgen_pan_display, - fb_ioctl: au1100fb_ioctl, - fb_mmap: au1100fb_mmap, +static struct fb_var_screeninfo au1100fb_defined __initdata = { + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .right_margin = 32, + .upper_margin = 16, + .lower_margin = 4, + .vsync_len = 4, + .vmode = FB_VMODE_NONINTERLACED, }; -static void au1100_detect(void) -{ - /* - * This function should detect the current video mode settings - * and store it as the default video mode - */ - - /* - * Yeh, well, we're not going to change any settings so we're - * always stuck with the default ... - */ +static struct fb_fix_screeninfo au1100fb_fix __initdata = { + .id = "AU1100 FB", + .type = FB_TYPE_PACKED_PIXELS, + .accel = FB_ACCEL_NONE, +}; -} +/* --------------------------------------------------------------------- */ -static int au1100_encode_fix(struct fb_fix_screeninfo *fix, - const void *_par, struct fb_info_gen *_info) +static int au1100fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) { - struct au1100fb_info *info = (struct au1100fb_info *) _info; - struct au1100fb_par *par = (struct au1100fb_par *) _par; - struct fb_var_screeninfo *var = &par->var; - - memset(fix, 0, sizeof(struct fb_fix_screeninfo)); - - fix->smem_start = info->fb_phys; - fix->smem_len = info->fb_size; - fix->type = FB_TYPE_PACKED_PIXELS; - fix->type_aux = 0; - fix->visual = (var->bits_per_pixel == 8) ? - FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; - fix->ywrapstep = 0; - fix->xpanstep = 1; - fix->ypanstep = 1; - fix->line_length = current_par.line_length; return 0; } -static void set_color_bitfields(struct fb_var_screeninfo *var) +static int au1100fb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) { - switch (var->bits_per_pixel) { - case 8: - var->red.offset = 0; - var->red.length = 8; - var->green.offset = 0; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 0; - var->transp.length = 0; - break; - case 16: /* RGB 565 */ - 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; - } - - var->red.msb_right = 0; - var->green.msb_right = 0; - var->blue.msb_right = 0; - var->transp.msb_right = 0; -} - -static int au1100_decode_var(const struct fb_var_screeninfo *var, - void *_par, struct fb_info_gen *_info) -{ - - struct au1100fb_par *par = (struct au1100fb_par *)_par; - /* - * Don't allow setting any of these yet: xres and yres don't - * make sense for LCD panels. + * Set a single color register. The values supplied are + * already rounded down to the hardware's capabilities + * (according to the entries in the `var' structure). Return + * != 0 for invalid regno. */ - if (var->xres != p_lcd->xres || - var->yres != p_lcd->yres || - var->xres != p_lcd->xres || - var->yres != p_lcd->yres) { - return -EINVAL; - } - if(var->bits_per_pixel != p_lcd->bpp) { - return -EINVAL; - } - - memset(par, 0, sizeof(struct au1100fb_par)); - par->var = *var; - /* FIXME */ - switch (var->bits_per_pixel) { - case 8: - par->var.bits_per_pixel = 8; - break; - case 16: - par->var.bits_per_pixel = 16; - break; - default: - printk("color depth %d bpp not supported\n", - var->bits_per_pixel); - return -EINVAL; - - } - set_color_bitfields(&par->var); - par->cmap_len = (par->var.bits_per_pixel == 8) ? 256 : 16; - return 0; -} - -static int au1100_encode_var(struct fb_var_screeninfo *var, - const void *par, struct fb_info_gen *_info) -{ - - *var = ((struct au1100fb_par *)par)->var; - return 0; -} - -static void -au1100_get_par(void *_par, struct fb_info_gen *_info) -{ - *(struct au1100fb_par *)_par = current_par; -} - -static void au1100_set_par(const void *par, struct fb_info_gen *info) -{ - /* nothing to do: we don't change any settings */ -} - -static int au1100_getcolreg(unsigned regno, unsigned *red, unsigned *green, - unsigned *blue, unsigned *transp, - struct fb_info *info) -{ - - struct au1100fb_info* i = (struct au1100fb_info*)info; - - if (regno > 255) - return 1; - - *red = i->palette[regno].red; - *green = i->palette[regno].green; - *blue = i->palette[regno].blue; - *transp = 0; - - return 0; -} - -static int au1100_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *info) -{ struct au1100fb_info* i = (struct au1100fb_info *)info; - u32 rgbcol; if (regno > 255) return 1; @@ -307,75 +161,6 @@ return 0; } - -static int au1100_blank(int blank_mode, struct fb_info_gen *_info) -{ - - switch (blank_mode) { - case VESA_NO_BLANKING: - /* turn on panel */ - //printk("turn on panel\n"); -#ifdef CONFIG_MIPS_PB1100 - p_lcd_reg->lcd_control |= LCD_CONTROL_GO; - au_writew(au_readw(PB1100_G_CONTROL) | p_lcd->mode_backlight, - PB1100_G_CONTROL); -#endif -#ifdef CONFIG_MIPS_HYDROGEN3 - /* Turn controller & power supply on, GPIO213 */ - au_writel(0x20002000, 0xB1700008); - au_writel(0x00040000, 0xB1900108); - au_writel(0x01000100, 0xB1700008); -#endif - au_sync(); - break; - - case VESA_VSYNC_SUSPEND: - case VESA_HSYNC_SUSPEND: - case VESA_POWERDOWN: - /* turn off panel */ - //printk("turn off panel\n"); -#ifdef CONFIG_MIPS_PB1100 - au_writew(au_readw(PB1100_G_CONTROL) & ~p_lcd->mode_backlight, - PB1100_G_CONTROL); - p_lcd_reg->lcd_control &= ~LCD_CONTROL_GO; -#endif - au_sync(); - break; - default: - break; - - } - return 0; -} - -static void au1100_set_disp(const void *unused, struct display *disp, - struct fb_info_gen *info) -{ - disp->screen_base = (char *)fb_info.fb_virt_start; - - switch (disp->var.bits_per_pixel) { -#ifdef FBCON_HAS_CFB8 - case 8: - disp->dispsw = &fbcon_cfb8; - if (fb_info.nohwcursor) - fbcon_cfb8.cursor = au1100_nocursor; - break; -#endif -#ifdef FBCON_HAS_CFB16 - case 16: - disp->dispsw = &fbcon_cfb16; - disp->dispsw_data = fb_info.fbcon_cmap16; - if (fb_info.nohwcursor) - fbcon_cfb16.cursor = au1100_nocursor; - break; -#endif - default: - disp->dispsw = &fbcon_dummy; - disp->dispsw_data = NULL; - break; - } -} - static int au1100fb_mmap(struct fb_info *_fb, struct file *file, @@ -389,8 +174,8 @@ return -EINVAL; } - start = fb_info.fb_phys & PAGE_MASK; - len = PAGE_ALIGN((start & ~PAGE_MASK) + fb_info.fb_size); + start = my_fb_info->fb_phys & PAGE_MASK; + len = PAGE_ALIGN((start & ~PAGE_MASK) + my_fb_info->fb_size); off = vma->vm_pgoff << PAGE_SHIFT; @@ -408,7 +193,7 @@ /* This is an IO map - tell maydump to skip this VMA */ vma->vm_flags |= VM_IO; - if (io_remap_page_range(vma->vm_start, off, + if (io_remap_page_range(vma, vma->vm_start, off, vma->vm_end - vma->vm_start, vma->vm_page_prot)) { return -EAGAIN; @@ -418,33 +203,68 @@ return 0; } -int au1100_pan_display(const struct fb_var_screeninfo *var, - struct fb_info_gen *info) -{ - return 0; -} +static struct fb_ops au1100fb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = au1100fb_setcolreg, + .fb_pan_display = au1100fb_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, + .fb_mmap = au1100fb_mmap, +}; -static int au1100fb_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg, int con, struct fb_info *info) +void au1100fb_setup(char *options) { - /* nothing to do yet */ - return -EINVAL; -} + char* this_opt; +#ifndef CONFIG_WWPC + int i; + int num_panels = sizeof(panels)/sizeof(struct known_lcd_panels); +#endif -static struct fbgen_hwswitch au1100_switch = { - au1100_detect, - au1100_encode_fix, - au1100_decode_var, - au1100_encode_var, - au1100_get_par, - au1100_set_par, - au1100_getcolreg, - au1100_setcolreg, - au1100_pan_display, - au1100_blank, - au1100_set_disp -}; + + if (!options || !*options) + return; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!strncmp(this_opt, "panel:", 6)) { +#ifdef CONFIG_WWPC + /* we have just one fixed LCD */ + my_lcd_index = 0; +#else +#if defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_DB1100) + /* Read Pb1100 Switch S10 ? */ + if (!strncmp(this_opt+6, "s10", 3)) + { + int panel; + panel = *(volatile int *)0xAE000008; /* BCSR SWITCHES */ + panel >>= 8; + panel &= 0x0F; + if (panel >= num_panels) panel = 0; + my_lcd_index = panel; + } + else +#endif + /* Get the panel name, everything else if fixed */ + for (i=0; i<num_panels; i++) { + if (!strncmp(this_opt+6, panels[i].panel_name, + strlen(this_opt))) { + my_lcd_index = i; + break; + } + } +#endif /* CONFIG_WWPC */ + } + else if (!strncmp(this_opt, "nohwcursor", 10)) { + printk("nohwcursor\n"); + nohwcursor = 1; + } + } + printk("au1100fb: Panel %d %s\n", my_lcd_index, + panels[my_lcd_index].panel_name); + p_lcd = &panels[my_lcd_index]; +} int au1100_setmode(void) { @@ -478,7 +298,7 @@ p_lcd_reg->lcd_verttiming = p_lcd->mode_verttiming; p_lcd_reg->lcd_clkcontrol = p_lcd->mode_clkcontrol; p_lcd_reg->lcd_words = words - 1; - p_lcd_reg->lcd_dmaaddr0 = fb_info.fb_phys; + p_lcd_reg->lcd_dmaaddr0 = my_fb_info->fb_phys; /* turn on panel */ #ifdef CONFIG_MIPS_PB1100 @@ -491,23 +311,49 @@ au_writel(0x00040000, 0xB1900108); au_writel(0x01000100, 0xB1700008); #endif +#ifdef CONFIG_WWPC + au_writel(0x000221A1, 0xB190002C); + + au_writel(0x40228000, 0xB1900108); + au_writel(0x001D0000, 0xB190010C); + au_writel(0x403F8000, 0xB1900100); + + /* TODO: move in the right place */ + + au_writel(0x00000001, 0xB1700014); + au_writel(0x0000060F, 0xB1700000); + au_writel(0x060F0400, 0xB1700008); + + /* turn on LCD */ + { + unsigned long t; + + t = au_readl(0xB1900108); + t |= (1 << 20); + au_writel(t, 0xB1900108); + udelay(1000); + t |= (1 << 19); + au_writel(t, 0xB1900108); + printk("LCD ON: 0xB1900108 is %08lx\n", t); + } + +#endif p_lcd_reg->lcd_control |= LCD_CONTROL_GO; return 0; } - -int __init au1100fb_init(void) +static int __init au1100fb_probe(struct device *device) { - uint32 sys_clksrc; + struct platform_device *dev = to_platform_device(device); + struct fb_info *info; + int err; unsigned long page; + unsigned int size_vmode; + uint32 sys_clksrc; - /* - * Get the panel information/display mode and update the registry - */ - p_lcd = &panels[my_lcd_index]; - + /* verify LCD rotation */ switch (p_lcd->mode_control & LCD_CONTROL_SM) { case LCD_CONTROL_SM_0: @@ -526,6 +372,17 @@ break; } + /* alloc info struct */ + info = framebuffer_alloc(sizeof(struct au1100fb_info), &dev->dev); + if (!info) { + printk("Cannot allocate FB\n"); + return -ENOMEM; + } + my_fb_info = (struct au1100fb_info *) info; + info->pseudo_palette = info->par; + info->par = NULL; + my_fb_info->nohwcursor = nohwcursor; + /* * Panel dimensions x bpp must be divisible by 32 */ @@ -534,143 +391,225 @@ if (((p_lcd->xres * p_lcd->bpp) % 32) != 0) printk("HORZ %% 32\n"); - /* - * Allocate LCD framebuffer from system memory - */ - fb_info.fb_size = (p_lcd->xres * p_lcd->yres * p_lcd->bpp) / 8; - - current_par.var.xres = p_lcd->xres; - current_par.var.xres_virtual = p_lcd->xres; - current_par.var.yres = p_lcd->yres; - current_par.var.yres_virtual = p_lcd->yres; - current_par.var.bits_per_pixel = p_lcd->bpp; - - /* FIX!!! only works for 8/16 bpp */ - current_par.line_length = p_lcd->xres * p_lcd->bpp / 8; /* in bytes */ - fb_info.fb_virt_start = (unsigned long ) + /* determine start address of the FB */ + my_fb_info->fb_size = (p_lcd->xres * p_lcd->yres * p_lcd->bpp) / 8; + my_fb_info->fb_virt_start = (unsigned long ) __get_free_pages(GFP_ATOMIC | GFP_DMA, - get_order(fb_info.fb_size + 0x1000)); - if (!fb_info.fb_virt_start) { + get_order(my_fb_info->fb_size + 0x1000)); + if (!my_fb_info->fb_virt_start) { printk("Unable to allocate fb memory\n"); return -ENOMEM; } - fb_info.fb_phys = virt_to_bus((void *)fb_info.fb_virt_start); - + info->screen_base = my_fb_info->fb_virt_start; + my_fb_info->fb_phys = virt_to_bus((void *)my_fb_info->fb_virt_start); + au1100fb_fix.smem_start = my_fb_info->fb_virt_start; /* * Set page reserved so that mmap will work. This is necessary * since we'll be remapping normal memory. */ - for (page = fb_info.fb_virt_start; - page < PAGE_ALIGN(fb_info.fb_virt_start + fb_info.fb_size); + for (page = my_fb_info->fb_virt_start; + page < PAGE_ALIGN(my_fb_info->fb_virt_start + my_fb_info->fb_size); page += PAGE_SIZE) { SetPageReserved(virt_to_page(page)); } - memset((void *)fb_info.fb_virt_start, 0, fb_info.fb_size); + /* setup bpp */ + au1100fb_defined.bits_per_pixel = p_lcd->bpp; + if (15 == au1100fb_defined.bits_per_pixel) + au1100fb_defined.bits_per_pixel = 16; + au1100fb_fix.visual = (au1100fb_defined.bits_per_pixel == 8) ? + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + + /* setup geometry */ + au1100fb_defined.xres = p_lcd->xres; + au1100fb_defined.yres = p_lcd->yres; + au1100fb_fix.line_length = p_lcd->xres * p_lcd->bpp / 8; + + /* size_vmode -- that is the amount of memory needed for the + * used video mode, i.e. the minimum amount of + * memory we need. */ + size_vmode = au1100fb_defined.yres * au1100fb_fix.line_length; + + au1100fb_fix.smem_len = my_fb_info->fb_size; + + printk(KERN_INFO "au1100fb: framebuffer at 0x%lx, mapped to 0x%p\n", + au1100fb_fix.smem_start, info->screen_base); + printk(KERN_INFO "au1100fb: mode is %dx%dx%d, linelength=%d\n", + au1100fb_defined.xres, au1100fb_defined.yres, au1100fb_defined.bits_per_pixel, au1100fb_fix.line_length); + + au1100fb_defined.xres_virtual = au1100fb_defined.xres; + au1100fb_defined.yres_virtual = au1100fb_fix.smem_len / au1100fb_fix.line_length; + + /* some dummy values for timing to make fbset happy */ + au1100fb_defined.pixclock = 10000000 / au1100fb_defined.xres * 1000 / au1100fb_defined.yres; + au1100fb_defined.left_margin = (au1100fb_defined.xres / 8) & 0xf8; + au1100fb_defined.hsync_len = (au1100fb_defined.xres / 8) & 0xf8; + + /* TODO, 8bpp */ + au1100fb_defined.red.offset = 11; + au1100fb_defined.red.length = 5; + au1100fb_defined.green.offset = 5; + au1100fb_defined.green.length = 6; + au1100fb_defined.blue.offset = 0; + au1100fb_defined.blue.length = 5; + au1100fb_defined.transp.offset = 0; + au1100fb_defined.transp.length = 0; + +#if 0 + /* test pattern */ +#define BLOCK 16 + { + int x,y,xx,yy,i; + unsigned short c; + unsigned short *p = (unsigned short *) my_fb_info->fb_virt_start; + int mx = p_lcd->xres / BLOCK; + int my = p_lcd->yres / BLOCK;; + i = 0; + for(x=0; x<mx; x++) + for(y=0; y<my; y++) { + switch (i%3) { + case 0: + c = (0x1f << au1100fb_defined.red.offset); + break; + case 1: + c = (0x3f << au1100fb_defined.green.offset); + break; + case 2: + c = (0x1f << au1100fb_defined.blue.offset); + break; + default: + c = 0; + break; + } + for(xx = x*BLOCK ; xx < (x+1)*BLOCK; xx++) + for(yy = y*BLOCK ; yy < (y+1)*BLOCK; yy++) + p[xx+yy*p_lcd->xres] = c; + i++; + } + } +#undef BLOCK +#else + memset((void *)my_fb_info->fb_virt_start, 0, my_fb_info->fb_size); +#endif + + screen_info.rsvd_size = 0; + screen_info.red_size = au1100fb_defined.red.length; + screen_info.green_size = au1100fb_defined.green.length; + screen_info.blue_size = au1100fb_defined.blue.length; + screen_info.rsvd_pos = 0; + screen_info.red_pos = au1100fb_defined.red.offset; + screen_info.green_pos = au1100fb_defined.green.offset; + screen_info.blue_pos = au1100fb_defined.blue.offset; + screen_info.lfb_base = my_fb_info->fb_virt_start; + screen_info.lfb_width = au1100fb_defined.xres; + screen_info.lfb_height = au1100fb_defined.yres; + screen_info.lfb_depth = au1100fb_defined.bits_per_pixel; + screen_info.lfb_linelength = au1100fb_fix.line_length; + screen_info.lfb_size = my_fb_info->fb_size; + + if (au1100fb_defined.bits_per_pixel <= 8) { + depth = au1100fb_defined.green.length; + au1100fb_defined.red.length = + au1100fb_defined.green.length = + au1100fb_defined.blue.length = + au1100fb_defined.bits_per_pixel; + } + + printk(KERN_INFO "au1100fb: %s: " + "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n", + (au1100fb_defined.bits_per_pixel > 8) ? + "Truecolor" : "Pseudocolor", + screen_info.rsvd_size, + screen_info.red_size, + screen_info.green_size, + screen_info.blue_size, + screen_info.rsvd_pos, + screen_info.red_pos, + screen_info.green_pos, + screen_info.blue_pos); + + info->fbops = &au1100fb_ops; + info->var = au1100fb_defined; + info->fix = au1100fb_fix; + info->flags = FBINFO_FLAG_DEFAULT; + + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { + err = -ENXIO; + goto err; + } + if (register_framebuffer(info)<0) { + err = -EINVAL; + fb_dealloc_cmap(&info->cmap); + goto err; + } + printk(KERN_INFO "fb%d: %s frame buffer device\n", + info->node, info->fix.id); /* set freqctrl now to allow more time to stabilize */ /* zero-out out LCD bits */ +#ifdef CONFIG_WWPC + { + unsigned long t; + + t = au_readl(SYS_FREQCTRL1) & ~(0x3ff); + printk("before SYS_FREQCTRL1 is %08lx\n", t); + t |= (1 << 1) | (9 << 2); + au_writel(t, SYS_FREQCTRL1); + printk("after SYS_FREQCTRL1 is %08lx\n", t); + } + sys_clksrc = au_readl(SYS_CLKSRC) & ~( (1<<9) | (1<<8) | (1<<7) | (1<<6) | (1<<5) ); + sys_clksrc |= (1<<9) | (1<<7); + au_writel(sys_clksrc, SYS_CLKSRC); +#else sys_clksrc = au_readl(SYS_CLKSRC) & ~0x000003e0; sys_clksrc |= p_lcd->mode_toyclksrc; au_writel(sys_clksrc, SYS_CLKSRC); +#endif - /* FIXME add check to make sure auxpll is what is expected! */ + /* setup LCD */ au1100_setmode(); - fb_info.gen.parsize = sizeof(struct au1100fb_par); - fb_info.gen.fbhw = &au1100_switch; - - strcpy(fb_info.gen.info.modename, "Au1100 LCD"); - fb_info.gen.info.changevar = NULL; - fb_info.gen.info.node = -1; - - fb_info.gen.info.fbops = &au1100fb_ops; - fb_info.gen.info.disp = &disp; - fb_info.gen.info.switch_con = &fbgen_switch; - fb_info.gen.info.updatevar = &fbgen_update_var; - fb_info.gen.info.blank = &fbgen_blank; - fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT; - - /* This should give a reasonable default video mode */ - fbgen_get_var(&disp.var, -1, &fb_info.gen.info); - fbgen_do_set_var(&disp.var, 1, &fb_info.gen); - fbgen_set_disp(-1, &fb_info.gen); - fbgen_install_cmap(0, &fb_info.gen); - if (register_framebuffer(&fb_info.gen.info) < 0) - return -EINVAL; - printk(KERN_INFO "fb%d: %s frame buffer device\n", - GET_FB_IDX(fb_info.gen.info.node), - fb_info.gen.info.modename); - return 0; +err: + framebuffer_release(info); + return err; } +static struct device_driver au1100fb_driver = { + .name = "au1100fb", + .bus = &platform_bus_type, + .probe = au1100fb_probe, +}; -void au1100fb_cleanup(struct fb_info *info) -{ - unregister_framebuffer(info); -} - +static struct platform_device au1100fb_device = { + .name = "au1100fb", +}; -void au1100fb_setup(char *options, int *ints) +int __init au1100fb_init(void) { - char* this_opt; - int i; - int num_panels = sizeof(panels)/sizeof(struct known_lcd_panels); - - - if (!options || !*options) - return; - - for(this_opt=strtok(options, ","); this_opt; - this_opt=strtok(NULL, ",")) { - if (!strncmp(this_opt, "panel:", 6)) { -#if defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_DB1100) - /* Read Pb1100 Switch S10 ? */ - if (!strncmp(this_opt+6, "s10", 3)) - { - int panel; - panel = *(volatile int *)0xAE000008; /* BCSR SWITCHES */ - panel >>= 8; - panel &= 0x0F; - if (panel >= num_panels) panel = 0; - my_lcd_index = panel; - } - else -#endif - /* Get the panel name, everything else if fixed */ - for (i=0; i<num_panels; i++) { - if (!strncmp(this_opt+6, panels[i].panel_name, - strlen(this_opt))) { - my_lcd_index = i; - break; - } - } - } - else if (!strncmp(this_opt, "nohwcursor", 10)) { - printk("nohwcursor\n"); - fb_info.nohwcursor = 1; - } - } - - printk("au1100fb: Panel %d %s\n", my_lcd_index, - panels[my_lcd_index].panel_name); -} - + int ret; + char *option = NULL; + /* ignore error return of fb_get_options */ + fb_get_options("au1100fb", &option); + au1100fb_setup(option); + ret = driver_register(&au1100fb_driver); + + if (!ret) { + ret = platform_device_register(&au1100fb_device); + if (ret) + driver_unregister(&au1100fb_driver); + } + return ret; +} +module_init(au1100fb_init); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ -#ifdef MODULE MODULE_LICENSE("GPL"); -int init_module(void) -{ - return au1100fb_init(); -} - -void cleanup_module(void) -{ - au1100fb_cleanup(void); -} - -MODULE_AUTHOR("Pete Popov <ppopov@xxxxxxxxxx>"); -MODULE_DESCRIPTION("Au1100 LCD framebuffer device driver"); -#endif /* MODULE */ Index: drivers/video/au1100fb.h =================================================================== RCS file: /home/cvs/linux/drivers/video/au1100fb.h,v retrieving revision 1.1 diff -u -r1.1 au1100fb.h --- drivers/video/au1100fb.h 14 Jul 2002 21:33:34 -0000 1.1 +++ drivers/video/au1100fb.h 12 Jan 2005 09:05:31 -0000 @@ -191,6 +191,39 @@ */ struct known_lcd_panels panels[] = { +#ifdef CONFIG_WWPC + { /* just the standard LCD */ + 240, /* xres */ + 320, /* yres */ + 16, /* bpp */ + + "WWPC LCD", + + /* mode_control */ + 0x0006806A, + + /* mode_horztiming */ + 0x0A1010EF, + + /* mode_verttiming */ + 0x0301013F, + + /* mode_clkcontrol */ + 0x00018001, + + /* mode_pwmdiv */ + 0, + + /* mode_pwmhi */ + 0, + + /* mode_toyclksrc */ + 0, /* not used */ + + /* mode_backlight */ + 0 /* not used */ + } +#else { /* 0: Pb1100 LCDA: Sharp 320x240 TFT panel */ 320, /* xres */ 240, /* yres */ @@ -377,5 +410,6 @@ /* mode_backlight */ 7 }, +#endif }; #endif /* _AU1100LCD_H */
Attachment:
signature.asc
Description: This is a digitally signed message part