diff options
author | Richard Purdie <rpurdie@rpsys.net> | 2005-09-06 15:19:03 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-07 16:57:53 -0700 |
commit | aac51f09d96a0acfb73c1d1c0796358bb47ea07b (patch) | |
tree | 46fcabaac554971b8efb7f069a0a1a1cc29ed239 /drivers/video | |
parent | 8cc3c7af42aa826d413e3134628d85f3920457d8 (diff) |
[PATCH] w100fb: Rewrite for platform independence
The code w100fb was based on was horribly Sharp SL-C7x0 specific and there
was little else that could be done as I had no access to anything else with
a w100 in it. There is no real documentation about this chipset available.
Ian Molton has access to other platforms with the w100 (Toshiba e-series)
and so between us, we've improved w100fb and made it platform independent.
Ian Molton also added support for the very similar w3220 and w3200
chipsets.
There are a lot of changes here and it nearly amounts to a rewrite of the
driver but it has been extensively tested and is being used in preference
to the original driver in the Zaurus community. I'd therefore like to
update the mainline code to reflect this.
Signed-off-by: Richard Purdie <rpurdie@rpsys.net>
Acked-by: Antonino Daplas <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/w100fb.c | 1912 | ||||
-rw-r--r-- | drivers/video/w100fb.h | 777 |
2 files changed, 1224 insertions, 1465 deletions
diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c index adcda697ea60..0030c071da8f 100644 --- a/drivers/video/w100fb.c +++ b/drivers/video/w100fb.c @@ -5,9 +5,15 @@ * * Copyright (C) 2002, ATI Corp. * Copyright (C) 2004-2005 Richard Purdie + * Copyright (c) 2005 Ian Molton * * Rewritten for 2.6 by Richard Purdie <rpurdie@rpsys.net> * + * Generic platform support by Ian Molton <spyro@f2s.com> + * and Richard Purdie <rpurdie@rpsys.net> + * + * w32xx support by Ian Molton + * * 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. @@ -21,7 +27,7 @@ #include <linux/mm.h> #include <linux/device.h> #include <linux/string.h> -#include <linux/proc_fs.h> +#include <linux/vmalloc.h> #include <asm/io.h> #include <asm/uaccess.h> #include <video/w100fb.h> @@ -30,114 +36,78 @@ /* * Prototypes */ -static void w100fb_save_buffer(void); -static void w100fb_clear_buffer(void); -static void w100fb_restore_buffer(void); -static void w100fb_clear_screen(u32 mode, long int offset); -static void w100_resume(void); static void w100_suspend(u32 mode); -static void w100_init_qvga_rotation(u16 deg); -static void w100_init_vga_rotation(u16 deg); static void w100_vsync(void); -static void w100_init_sharp_lcd(u32 mode); -static void w100_pwm_setup(void); -static void w100_InitExtMem(u32 mode); -static void w100_hw_init(void); -static u16 w100_set_fastsysclk(u16 Freq); - -static void lcdtg_hw_init(u32 mode); -static void lcdtg_lcd_change(u32 mode); -static void lcdtg_resume(void); -static void lcdtg_suspend(void); - - -/* Register offsets & lengths */ -#define REMAPPED_FB_LEN 0x15ffff - -#define BITS_PER_PIXEL 16 +static void w100_hw_init(struct w100fb_par*); +static void w100_pwm_setup(struct w100fb_par*); +static void w100_init_clocks(struct w100fb_par*); +static void w100_setup_memory(struct w100fb_par*); +static void w100_init_lcd(struct w100fb_par*); +static void w100_set_dispregs(struct w100fb_par*); +static void w100_update_enable(void); +static void w100_update_disable(void); +static void calc_hsync(struct w100fb_par *par); +struct w100_pll_info *w100_get_xtal_table(unsigned int freq); /* Pseudo palette size */ #define MAX_PALETTES 16 -/* for resolution change */ -#define LCD_MODE_INIT (-1) -#define LCD_MODE_480 0 -#define LCD_MODE_320 1 -#define LCD_MODE_240 2 -#define LCD_MODE_640 3 - -#define LCD_SHARP_QVGA 0 -#define LCD_SHARP_VGA 1 - -#define LCD_MODE_PORTRAIT 0 -#define LCD_MODE_LANDSCAPE 1 - #define W100_SUSPEND_EXTMEM 0 #define W100_SUSPEND_ALL 1 -/* General frame buffer data structures */ -struct w100fb_par { - u32 xres; - u32 yres; - int fastsysclk_mode; - int lcdMode; - int rotation_flag; - int blanking_flag; - int comadj; - int phadadj; -}; - -static struct w100fb_par *current_par; +#define BITS_PER_PIXEL 16 /* Remapped addresses for base cfg, memmapped regs and the frame buffer itself */ static void *remapped_base; static void *remapped_regs; static void *remapped_fbuf; -/* External Function */ -static void(*w100fb_ssp_send)(u8 adrs, u8 data); +#define REMAPPED_FB_LEN 0x15ffff + +/* This is the offset in the w100's address space we map the current + framebuffer memory to. We use the position of external memory as + we can remap internal memory to there if external isn't present. */ +#define W100_FB_BASE MEM_EXT_BASE_VALUE + /* * Sysfs functions */ - -static ssize_t rotation_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t flip_show(struct device *dev, struct device_attribute *attr, char *buf) { struct fb_info *info = dev_get_drvdata(dev); struct w100fb_par *par=info->par; - return sprintf(buf, "%d\n",par->rotation_flag); + return sprintf(buf, "%d\n",par->flip); } -static ssize_t rotation_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t flip_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - unsigned int rotate; + unsigned int flip; struct fb_info *info = dev_get_drvdata(dev); struct w100fb_par *par=info->par; - rotate = simple_strtoul(buf, NULL, 10); + flip = simple_strtoul(buf, NULL, 10); + + if (flip > 0) + par->flip = 1; + else + par->flip = 0; - if (rotate > 0) par->rotation_flag = 1; - else par->rotation_flag = 0; + w100_update_disable(); + w100_set_dispregs(par); + w100_update_enable(); - if (par->lcdMode == LCD_MODE_320) - w100_init_qvga_rotation(par->rotation_flag ? 270 : 90); - else if (par->lcdMode == LCD_MODE_240) - w100_init_qvga_rotation(par->rotation_flag ? 180 : 0); - else if (par->lcdMode == LCD_MODE_640) - w100_init_vga_rotation(par->rotation_flag ? 270 : 90); - else if (par->lcdMode == LCD_MODE_480) - w100_init_vga_rotation(par->rotation_flag ? 180 : 0); + calc_hsync(par); return count; } -static DEVICE_ATTR(rotation, 0644, rotation_show, rotation_store); +static DEVICE_ATTR(flip, 0644, flip_show, flip_store); static ssize_t w100fb_reg_read(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - unsigned long param; - unsigned long regs; + unsigned long regs, param; regs = simple_strtoul(buf, NULL, 16); param = readl(remapped_regs + regs); printk("Read Register 0x%08lX: 0x%08lX\n", regs, param); @@ -148,8 +118,7 @@ static DEVICE_ATTR(reg_read, 0200, NULL, w100fb_reg_read); static ssize_t w100fb_reg_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - unsigned long regs; - unsigned long param; + unsigned long regs, param; sscanf(buf, "%lx %lx", ®s, ¶m); if (regs <= 0x2000) { @@ -163,54 +132,56 @@ static ssize_t w100fb_reg_write(struct device *dev, struct device_attribute *att static DEVICE_ATTR(reg_write, 0200, NULL, w100fb_reg_write); -static ssize_t fastsysclk_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t fastpllclk_show(struct device *dev, struct device_attribute *attr, char *buf) { struct fb_info *info = dev_get_drvdata(dev); struct w100fb_par *par=info->par; - return sprintf(buf, "%d\n",par->fastsysclk_mode); + return sprintf(buf, "%d\n",par->fastpll_mode); } -static ssize_t fastsysclk_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t fastpllclk_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int param; struct fb_info *info = dev_get_drvdata(dev); struct w100fb_par *par=info->par; - param = simple_strtoul(buf, NULL, 10); - - if (param == 75) { - printk("Set fastsysclk %d\n", param); - par->fastsysclk_mode = param; - w100_set_fastsysclk(par->fastsysclk_mode); - } else if (param == 100) { - printk("Set fastsysclk %d\n", param); - par->fastsysclk_mode = param; - w100_set_fastsysclk(par->fastsysclk_mode); + if (simple_strtoul(buf, NULL, 10) > 0) { + par->fastpll_mode=1; + printk("w100fb: Using fast system clock (if possible)\n"); + } else { + par->fastpll_mode=0; + printk("w100fb: Using normal system clock\n"); } + + w100_init_clocks(par); + calc_hsync(par); + return count; } -static DEVICE_ATTR(fastsysclk, 0644, fastsysclk_show, fastsysclk_store); +static DEVICE_ATTR(fastpllclk, 0644, fastpllclk_show, fastpllclk_store); /* - * The touchscreen on this device needs certain information - * from the video driver to function correctly. We export it here. + * Some touchscreens need hsync information from the video driver to + * function correctly. We export it here. */ -int w100fb_get_xres(void) { - return current_par->xres; -} +unsigned long w100fb_get_hsynclen(struct device *dev) +{ + struct fb_info *info = dev_get_drvdata(dev); + struct w100fb_par *par=info->par; -int w100fb_get_blanking(void) { - return current_par->blanking_flag; + /* If display is blanked/suspended, hsync isn't active */ + if (par->blanked) + return 0; + else + return par->hsync_len; } +EXPORT_SYMBOL(w100fb_get_hsynclen); -int w100fb_get_fastsysclk(void) { - return current_par->fastsysclk_mode; +static void w100fb_clear_screen(struct w100fb_par *par) +{ + memset_io(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), 0, (par->xres * par->yres * BITS_PER_PIXEL/8)); } -EXPORT_SYMBOL(w100fb_get_xres); -EXPORT_SYMBOL(w100fb_get_blanking); -EXPORT_SYMBOL(w100fb_get_fastsysclk); /* @@ -234,7 +205,6 @@ static int w100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, * according to the RGB bitfield information. */ if (regno < MAX_PALETTES) { - u32 *pal = info->pseudo_palette; val = (red & 0xf800) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); @@ -250,115 +220,90 @@ static int w100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, */ static int w100fb_blank(int blank_mode, struct fb_info *info) { - struct w100fb_par *par; - par=info->par; + struct w100fb_par *par = info->par; + struct w100_tg_info *tg = par->mach->tg; switch(blank_mode) { - case FB_BLANK_NORMAL: /* Normal blanking */ - case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ - case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ - case FB_BLANK_POWERDOWN: /* Poweroff */ - if (par->blanking_flag == 0) { - w100fb_save_buffer(); - lcdtg_suspend(); - par->blanking_flag = 1; + case FB_BLANK_NORMAL: /* Normal blanking */ + case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ + case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ + case FB_BLANK_POWERDOWN: /* Poweroff */ + if (par->blanked == 0) { + if(tg && tg->suspend) + tg->suspend(par); + par->blanked = 1; } break; case FB_BLANK_UNBLANK: /* Unblanking */ - if (par->blanking_flag != 0) { - w100fb_restore_buffer(); - lcdtg_resume(); - par->blanking_flag = 0; + if (par->blanked != 0) { + if(tg && tg->resume) + tg->resume(par); + par->blanked = 0; } break; } return 0; } + /* * Change the resolution by calling the appropriate hardware functions */ -static void w100fb_changeres(int rotate_mode, u32 mode) +static void w100fb_activate_var(struct w100fb_par *par) { - u16 rotation=0; - - switch(rotate_mode) { - case LCD_MODE_LANDSCAPE: - rotation=(current_par->rotation_flag ? 270 : 90); - break; - case LCD_MODE_PORTRAIT: - rotation=(current_par->rotation_flag ? 180 : 0); - break; - } + struct w100_tg_info *tg = par->mach->tg; - w100_pwm_setup(); - switch(mode) { - case LCD_SHARP_QVGA: - w100_vsync(); - w100_suspend(W100_SUSPEND_EXTMEM); - w100_init_sharp_lcd(LCD_SHARP_QVGA); - w100_init_qvga_rotation(rotation); - w100_InitExtMem(LCD_SHARP_QVGA); - w100fb_clear_screen(LCD_SHARP_QVGA, 0); - lcdtg_lcd_change(LCD_SHARP_QVGA); - break; - case LCD_SHARP_VGA: - w100fb_clear_screen(LCD_SHARP_QVGA, 0); - writel(0xBFFFA000, remapped_regs + mmMC_EXT_MEM_LOCATION); - w100_InitExtMem(LCD_SHARP_VGA); - w100fb_clear_screen(LCD_SHARP_VGA, 0x200000); - w100_vsync(); - w100_init_sharp_lcd(LCD_SHARP_VGA); - if (rotation != 0) - w100_init_vga_rotation(rotation); - lcdtg_lcd_change(LCD_SHARP_VGA); - break; - } + w100_pwm_setup(par); + w100_setup_memory(par); + w100_init_clocks(par); + w100fb_clear_screen(par); + w100_vsync(); + + w100_update_disable(); + w100_init_lcd(par); + w100_set_dispregs(par); + w100_update_enable(); + + calc_hsync(par); + + if (!par->blanked && tg && tg->change) + tg->change(par); } -/* - * Set up the display for the fb subsystem + +/* Select the smallest mode that allows the desired resolution to be + * displayed. If desired, the x and y parameters can be rounded up to + * match the selected mode. */ -static void w100fb_activate_var(struct fb_info *info) +static struct w100_mode *w100fb_get_mode(struct w100fb_par *par, unsigned int *x, unsigned int *y, int saveval) { - u32 temp32; - struct w100fb_par *par=info->par; - struct fb_var_screeninfo *var = &info->var; + struct w100_mode *mode = NULL; + struct w100_mode *modelist = par->mach->modelist; + unsigned int best_x = 0xffffffff, best_y = 0xffffffff; + unsigned int i; + + for (i = 0 ; i < par->mach->num_modes ; i++) { + if (modelist[i].xres >= *x && modelist[i].yres >= *y && + modelist[i].xres < best_x && modelist[i].yres < best_y) { + best_x = modelist[i].xres; + best_y = modelist[i].yres; + mode = &modelist[i]; + } else if(modelist[i].xres >= *y && modelist[i].yres >= *x && + modelist[i].xres < best_y && modelist[i].yres < best_x) { + best_x = modelist[i].yres; + best_y = modelist[i].xres; + mode = &modelist[i]; + } + } - /* Set the hardware to 565 */ - temp32 = readl(remapped_regs + mmDISP_DEBUG2); - temp32 &= 0xff7fffff; - temp32 |= 0x00800000; - writel(temp32, remapped_regs + mmDISP_DEBUG2); + if (mode && saveval) { + *x = best_x; + *y = best_y; + } - if (par->lcdMode == LCD_MODE_INIT) { - w100_init_sharp_lcd(LCD_SHARP_VGA); - w100_init_vga_rotation(par->rotation_flag ? 270 : 90); - par->lcdMode = LCD_MODE_640; - lcdtg_hw_init(LCD_SHARP_VGA); - } else if (var->xres == 320 && var->yres == 240) { - if (par->lcdMode != LCD_MODE_320) { - w100fb_changeres(LCD_MODE_LANDSCAPE, LCD_SHARP_QVGA); - par->lcdMode = LCD_MODE_320; - } - } else if (var->xres == 240 && var->yres == 320) { - if (par->lcdMode != LCD_MODE_240) { - w100fb_changeres(LCD_MODE_PORTRAIT, LCD_SHARP_QVGA); - par->lcdMode = LCD_MODE_240; - } - } else if (var->xres == 640 && var->yres == 480) { - if (par->lcdMode != LCD_MODE_640) { - w100fb_changeres(LCD_MODE_LANDSCAPE, LCD_SHARP_VGA); - par->lcdMode = LCD_MODE_640; - } - } else if (var->xres == 480 && var->yres == 640) { - if (par->lcdMode != LCD_MODE_480) { - w100fb_changeres(LCD_MODE_PORTRAIT, LCD_SHARP_VGA); - par->lcdMode = LCD_MODE_480; - } - } else printk(KERN_ERR "W100FB: Resolution error!\n"); + return mode; } @@ -366,31 +311,19 @@ static void w100fb_activate_var(struct fb_info *info) * w100fb_check_var(): * Get the video params out of 'var'. If a value doesn't fit, round it up, * if it's too big, return -EINVAL. - * */ static int w100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { - if (var->xres < var->yres) { /* Portrait mode */ - if ((var->xres > 480) || (var->yres > 640)) { - return -EINVAL; - } else if ((var->xres > 240) || (var->yres > 320)) { - var->xres = 480; - var->yres = 640; - } else { - var->xres = 240; - var->yres = 320; - } - } else { /* Landscape mode */ - if ((var->xres > 640) || (var->yres > 480)) { - return -EINVAL; - } else if ((var->xres > 320) || (var->yres > 240)) { - var->xres = 640; - var->yres = 480; - } else { - var->xres = 320; - var->yres = 240; - } - } + struct w100fb_par *par=info->par; + + if(!w100fb_get_mode(par, &var->xres, &var->yres, 1)) + return -EINVAL; + + if (par->mach->mem && ((var->xres*var->yres*BITS_PER_PIXEL/8) > (par->mach->mem->size+1))) + return -EINVAL; + + if (!par->mach->mem && ((var->xres*var->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1))) + return -EINVAL; var->xres_virtual = max(var->xres_virtual, var->xres); var->yres_virtual = max(var->yres_virtual, var->yres); @@ -409,13 +342,11 @@ static int w100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) var->transp.offset = var->transp.length = 0; var->nonstd = 0; - var->height = -1; var->width = -1; var->vmode = FB_VMODE_NONINTERLACED; - var->sync = 0; - var->pixclock = 0x04; /* 171521; */ + var->pixclock = 0x04; /* 171521; */ return 0; } @@ -430,274 +361,286 @@ static int w100fb_set_par(struct fb_info *info) { struct w100fb_par *par=info->par; - par->xres = info->var.xres; - par->yres = info->var.yres; - - info->fix.visual = FB_VISUAL_TRUECOLOR; - - info->fix.ypanstep = 0; - info->fix.ywrapstep = 0; + if (par->xres != info->var.xres || par->yres != info->var.yres) { + par->xres = info->var.xres; + par->yres = info->var.yres; + par->mode = w100fb_get_mode(par, &par->xres, &par->yres, 0); - if (par->blanking_flag) - w100fb_clear_buffer(); + info->fix.visual = FB_VISUAL_TRUECOLOR; + info->fix.ypanstep = 0; + info->fix.ywrapstep = 0; + info->fix.line_length = par->xres * BITS_PER_PIXEL / 8; - w100fb_activate_var(info); + if ((par->xres*par->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1)) { + par->extmem_active = 1; + info->fix.smem_len = par->mach->mem->size+1; + } else { + par->extmem_active = 0; + info->fix.smem_len = MEM_INT_SIZE+1; + } - if (par->lcdMode == LCD_MODE_480) { - info->fix.line_length = (480 * BITS_PER_PIXEL) / 8; - info->fix.smem_len = 0x200000; - } else if (par->lcdMode == LCD_MODE_320) { - info->fix.line_length = (320 * BITS_PER_PIXEL) / 8; - info->fix.smem_len = 0x60000; - } else if (par->lcdMode == LCD_MODE_240) { - info->fix.line_length = (240 * BITS_PER_PIXEL) / 8; - info->fix.smem_len = 0x60000; - } else if (par->lcdMode == LCD_MODE_INIT || par->lcdMode == LCD_MODE_640) { - info->fix.line_length = (640 * BITS_PER_PIXEL) / 8; - info->fix.smem_len = 0x200000; + w100fb_activate_var(par); } - return 0; } /* - * Frame buffer operations + * Frame buffer operations */ static struct fb_ops w100fb_ops = { - .owner = THIS_MODULE, + .owner = THIS_MODULE, .fb_check_var = w100fb_check_var, - .fb_set_par = w100fb_set_par, + .fb_set_par = w100fb_set_par, .fb_setcolreg = w100fb_setcolreg, - .fb_blank = w100fb_blank, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, + .fb_blank = w100fb_blank, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, + .fb_cursor = soft_cursor, }; - -static void w100fb_clear_screen(u32 mode, long int offset) +#ifdef CONFIG_PM +static void w100fb_save_vidmem(struct w100fb_par *par) { - int i, numPix = 0; - - if (mode == LCD_SHARP_VGA) - numPix = 640 * 480; - else if (mode == LCD_SHARP_QVGA) - numPix = 320 * 240; + int memsize; - for (i = 0; i < numPix; i++) - writew(0xffff, remapped_fbuf + offset + (2*i)); -} - - -/* Need to split up the buffers to stay within the limits of kmalloc */ -#define W100_BUF_NUM 6 -static uint32_t *gSaveImagePtr[W100_BUF_NUM] = { NULL }; - -static void w100fb_save_buffer(void) -{ - int i, j, bufsize; - - bufsize=(current_par->xres * current_par->yres * BITS_PER_PIXEL / 8) / W100_BUF_NUM; - for (i = 0; i < W100_BUF_NUM; i++) { - if (gSaveImagePtr[i] == NULL) - gSaveImagePtr[i] = kmalloc(bufsize, GFP_KERNEL); - if (gSaveImagePtr[i] == NULL) { - w100fb_clear_buffer(); - printk(KERN_WARNING "can't alloc pre-off image buffer %d\n", i); - break; - } - for (j = 0; j < bufsize/4; j++) - *(gSaveImagePtr[i] + j) = readl(remapped_fbuf + (bufsize*i) + j*4); + if (par->extmem_active) { + memsize=par->mach->mem->size; + par->saved_extmem = vmalloc(memsize); + if (par->saved_extmem) + memcpy_fromio(par->saved_extmem, remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), memsize); } + memsize=MEM_INT_SIZE; + par->saved_intmem = vmalloc(memsize); + if (par->saved_intmem && par->extmem_active) + memcpy_fromio(par->saved_intmem, remapped_fbuf + (W100_FB_BASE-MEM_INT_BASE_VALUE), memsize); + else if (par->saved_intmem) + memcpy_fromio(par->saved_intmem, remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), memsize); } - -static void w100fb_restore_buffer(void) +static void w100fb_restore_vidmem(struct w100fb_par *par) { - int i, j, bufsize; + int memsize; - bufsize=(current_par->xres * current_par->yres * BITS_PER_PIXEL / 8) / W100_BUF_NUM; - for (i = 0; i < W100_BUF_NUM; i++) { - if (gSaveImagePtr[i] == NULL) { - printk(KERN_WARNING "can't find pre-off image buffer %d\n", i); - w100fb_clear_buffer(); - break; - } - for (j = 0; j < (bufsize/4); j++) - writel(*(gSaveImagePtr[i] + j),remapped_fbuf + (bufsize*i) + (j*4)); - kfree(gSaveImagePtr[i]); - gSaveImagePtr[i] = NULL; + if (par->extmem_active && par->saved_extmem) { + memsize=par->mach->mem->size; + memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_extmem, memsize); + vfree(par->saved_extmem); } -} - - -static void w100fb_clear_buffer(void) -{ - int i; - for (i = 0; i < W100_BUF_NUM; i++) { - kfree(gSaveImagePtr[i]); - gSaveImagePtr[i] = NULL; + if (par->saved_intmem) { + memsize=MEM_INT_SIZE; + if (par->extmem_active) + memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_INT_BASE_VALUE), par->saved_intmem, memsize); + else + memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_intmem, memsize); + vfree(par->saved_intmem); } } - -#ifdef CONFIG_PM -static int w100fb_suspend(struct device *dev, pm_message_t state, u32 level) +static int w100fb_suspend(struct device *dev, pm_message_t state, uint32_t level) { if (level == SUSPEND_POWER_DOWN) { struct fb_info *info = dev_get_drvdata(dev); struct w100fb_par *par=info->par; + struct w100_tg_info *tg = par->mach->tg; - w100fb_save_buffer(); - lcdtg_suspend(); + w100fb_save_vidmem(par); + if(tg && tg->suspend) + tg->suspend(par); w100_suspend(W100_SUSPEND_ALL); - par->blanking_flag = 1; + par->blanked = 1; } return 0; } -static int w100fb_resume(struct device *dev, u32 level) +static int w100fb_resume(struct device *dev, uint32_t level) { if (level == RESUME_POWER_ON) { struct fb_info *info = dev_get_drvdata(dev); struct w100fb_par *par=info->par; - - w100_resume(); - w100fb_restore_buffer(); - lcdtg_resume(); - par->blanking_flag = 0; + struct w100_tg_info *tg = par->mach->tg; + + w100_hw_init(par); + w100fb_activate_var(par); + w100fb_restore_vidmem(par); + if(tg && tg->resume) + tg->resume(par); + par->blanked = 0; } return 0; } #else -#define w100fb_suspend NULL -#define w100fb_resume NULL +#define w100fb_suspend NULL +#define w100fb_resume NULL #endif int __init w100fb_probe(struct device *dev) { + int err = -EIO; struct w100fb_mach_info *inf; - struct fb_info *info; + struct fb_info *info = NULL; struct w100fb_par *par; struct platform_device *pdev = to_platform_device(dev); struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + unsigned int chip_id; if (!mem) return -EINVAL; - /* remap the areas we're going to use */ + /* Remap the chip base address */ remapped_base = ioremap_nocache(mem->start+W100_CFG_BASE, W100_CFG_LEN); if (remapped_base == NULL) - return -EIO; + goto out; + /* Map the register space */ remapped_regs = ioremap_nocache(mem->start+W100_REG_BASE, W100_REG_LEN); - if (remapped_regs == NULL) { - iounmap(remapped_base); - return -EIO; + if (remapped_regs == NULL) + goto out; + + /* Identify the chip */ + printk("Found "); + chip_id = readl(remapped_regs + mmCHIP_ID); + switch(chip_id) { + case CHIP_ID_W100: printk("w100"); break; + case CHIP_ID_W3200: printk("w3200"); break; + case CHIP_ID_W3220: printk("w3220"); break; + default: + printk("Unknown imageon chip ID\n"); + err = -ENODEV; + goto out; } + printk(" at 0x%08lx.\n", mem->start+W100_CFG_BASE); - remapped_fbuf = ioremap_nocache(mem->start+MEM_EXT_BASE_VALUE, REMAPPED_FB_LEN); - if (remapped_fbuf == NULL) { - iounmap(remapped_base); - iounmap(remapped_regs); - return -EIO; - } + /* Remap the framebuffer */ + remapped_fbuf = ioremap_nocache(mem->start+MEM_WINDOW_BASE, MEM_WINDOW_SIZE); + if (remapped_fbuf == NULL) + goto out; info=framebuffer_alloc(sizeof(struct w100fb_par), dev); if (!info) { - iounmap(remapped_base); - iounmap(remapped_regs); - iounmap(remapped_fbuf); - return -ENOMEM; + err = -ENOMEM; + goto out; } - info->device=dev; par = info->par; - current_par=info->par; dev_set_drvdata(dev, info); inf = dev->platform_data; - par->phadadj = inf->phadadj; - par->comadj = inf->comadj; - par->fastsysclk_mode = 75; - par->lcdMode = LCD_MODE_INIT; - par->rotation_flag=0; - par->blanking_flag=0; - w100fb_ssp_send = inf->w100fb_ssp_send; - - w100_hw_init(); - w100_pwm_setup(); + par->chip_id = chip_id; + par->mach = inf; + par->fastpll_mode = 0; + par->blanked = 0; + + par->pll_table=w100_get_xtal_table(inf->xtal_freq); + if (!par->pll_table) { + printk(KERN_ERR "No matching Xtal definition found\n"); + err = -EINVAL; + goto out; + } info->pseudo_palette = kmalloc(sizeof (u32) * MAX_PALETTES, GFP_KERNEL); if (!info->pseudo_palette) { - iounmap(remapped_base); - iounmap(remapped_regs); - iounmap(remapped_fbuf); - return -ENOMEM; + err = -ENOMEM; + goto out; } info->fbops = &w100fb_ops; info->flags = FBINFO_DEFAULT; info->node = -1; - info->screen_base = remapped_fbuf; + info->screen_base = remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE); info->screen_size = REMAPPED_FB_LEN; - info->var.xres = 640; + strcpy(info->fix.id, "w100fb"); + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.type_aux = 0; + info->fix.accel = FB_ACCEL_NONE; + info->fix.smem_start = mem->start+W100_FB_BASE; + info->fix.mmio_start = mem->start+W100_REG_BASE; + info->fix.mmio_len = W100_REG_LEN; + + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { + err = -ENOMEM; + goto out; + } + + par->mode = &inf->modelist[0]; + if(inf->init_mode & INIT_MODE_ROTATED) { + info->var.xres = par->mode->yres; + info->var.yres = par->mode->xres; + } + else { + info->var.xres = par->mode->xres; + info->var.yres = par->mode->yres; + } + + if(inf->init_mode &= INIT_MODE_FLIPPED) + par->flip = 1; + else + par->flip = 0; + info->var.xres_virtual = info->var.xres; - info->var.yres = 480; info->var.yres_virtual = info->var.yres; - info->var.pixclock = 0x04; /* 171521; */ + info->var.pixclock = 0x04; /* 171521; */ info->var.sync = 0; info->var.grayscale = 0; info->var.xoffset = info->var.yoffset = 0; info->var.accel_flags = 0; info->var.activate = FB_ACTIVATE_NOW; - strcpy(info->fix.id, "w100fb"); - info->fix.type = FB_TYPE_PACKED_PIXELS; - info->fix.type_aux = 0; - info->fix.accel = FB_ACCEL_NONE; - info->fix.smem_start = mem->start+MEM_EXT_BASE_VALUE; - info->fix.mmio_start = mem->start+W100_REG_BASE; - info->fix.mmio_len = W100_REG_LEN; + w100_hw_init(par); + + if (w100fb_check_var(&info->var, info) < 0) { + err = -EINVAL; + goto out; + } - w100fb_check_var(&info->var, info); w100fb_set_par(info); if (register_framebuffer(info) < 0) { - kfree(info->pseudo_palette); - iounmap(remapped_base); - iounmap(remapped_regs); - iounmap(remapped_fbuf); - return -EINVAL; + err = -EINVAL; + goto out; } - device_create_file(dev, &dev_attr_fastsysclk); + device_create_file(dev, &dev_attr_fastpllclk); device_create_file(dev, &dev_attr_reg_read); device_create_file(dev, &dev_attr_reg_write); - device_create_file(dev, &dev_attr_rotation); + device_create_file(dev, &dev_attr_flip); printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); return 0; +out: + fb_dealloc_cmap(&info->cmap); + kfree(info->pseudo_palette); + if (remapped_fbuf != NULL) + iounmap(remapped_fbuf); + if (remapped_regs != NULL) + iounmap(remapped_regs); + if (remapped_base != NULL) + iounmap(remapped_base); + if (info) + framebuffer_release(info); + return err; } static int w100fb_remove(struct device *dev) { struct fb_info *info = dev_get_drvdata(dev); + struct w100fb_par *par=info->par; - device_remove_file(dev, &dev_attr_fastsysclk); + device_remove_file(dev, &dev_attr_fastpllclk); device_remove_file(dev, &dev_attr_reg_read); device_remove_file(dev, &dev_attr_reg_write); - device_remove_file(dev, &dev_attr_rotation); + device_remove_file(dev, &dev_attr_flip); unregister_framebuffer(info); - w100fb_clear_buffer(); + vfree(par->saved_intmem); + vfree(par->saved_extmem); kfree(info->pseudo_palette); + fb_dealloc_cmap(&info->cmap); iounmap(remapped_base); iounmap(remapped_regs); @@ -721,10 +664,54 @@ static void w100_soft_reset(void) udelay(100); } +static void w100_update_disable(void) +{ + union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl; + + /* Prevent display updates */ + disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e; + disp_db_buf_wr_cntl.f.update_db_buf = 0; + disp_db_buf_wr_cntl.f.en_db_buf = 0; + writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL); +} + +static void w100_update_enable(void) +{ + union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl; + + /* Enable display updates */ + disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e; + disp_db_buf_wr_cntl.f.update_db_buf = 1; + disp_db_buf_wr_cntl.f.en_db_buf = 1; + writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL); +} + +unsigned long w100fb_gpio_read(int port) +{ + unsigned long value; + + if (port==W100_GPIO_PORT_A) + value = readl(remapped_regs + mmGPIO_DATA); + else + value = readl(remapped_regs + mmGPIO_DATA2); + + return value; +} + +void w100fb_gpio_write(int port, unsigned long value) +{ + if (port==W100_GPIO_PORT_A) + value = writel(value, remapped_regs + mmGPIO_DATA); + else + value = writel(value, remapped_regs + mmGPIO_DATA2); +} +EXPORT_SYMBOL(w100fb_gpio_read); +EXPORT_SYMBOL(w100fb_gpio_write); + /* * Initialization of critical w100 hardware */ -static void w100_hw_init(void) +static void w100_hw_init(struct w100fb_par *par) { u32 temp32; union cif_cntl_u cif_cntl; @@ -735,8 +722,8 @@ static void w100_hw_init(void) union cpu_defaults_u cpu_default; union cif_write_dbg_u cif_write_dbg; union wrap_start_dir_u wrap_start_dir; - union mc_ext_mem_location_u mc_ext_mem_loc; union cif_io_u cif_io; + struct w100_gpio_regs *gpio = par->mach->gpio; w100_soft_reset(); @@ -791,19 +778,6 @@ static void w100_hw_init(void) cfgreg_base.f.cfgreg_base = W100_CFG_BASE; writel((u32) (cfgreg_base.val), remapped_regs + mmCFGREG_BASE); - /* This location is relative to internal w100 addresses */ - writel(0x15FF1000, remapped_regs + mmMC_FB_LOCATION); - - mc_ext_mem_loc.val = defMC_EXT_MEM_LOCATION; - mc_ext_mem_loc.f.mc_ext_mem_start = MEM_EXT_BASE_VALUE >> 8; - mc_ext_mem_loc.f.mc_ext_mem_top = MEM_EXT_TOP_VALUE >> 8; - writel((u32) (mc_ext_mem_loc.val), remapped_regs + mmMC_EXT_MEM_LOCATION); - - if ((current_par->lcdMode == LCD_MODE_240) || (current_par->lcdMode == LCD_MODE_320)) - w100_InitExtMem(LCD_SHARP_QVGA); - else - w100_InitExtMem(LCD_SHARP_VGA); - wrap_start_dir.val = defWRAP_START_DIR; wrap_start_dir.f.start_addr = WRAP_BUF_BASE_VALUE >> 1; writel((u32) (wrap_start_dir.val), remapped_regs + mmWRAP_START_DIR); @@ -813,21 +787,24 @@ static void w100_hw_init(void) writel((u32) (wrap_top_dir.val), remapped_regs + mmWRAP_TOP_DIR); writel((u32) 0x2440, remapped_regs + mmRBBM_CNTL); -} + /* Set the hardware to 565 colour */ + temp32 = readl(remapped_regs + mmDISP_DEBUG2); + temp32 &= 0xff7fffff; + temp32 |= 0x00800000; + writel(temp32, remapped_regs + mmDISP_DEBUG2); -/* - * Types - */ + /* Initialise the GPIO lines */ + if (gpio) { + writel(gpio->init_data1, remapped_regs + mmGPIO_DATA); + writel(gpio->init_data2, remapped_regs + mmGPIO_DATA2); + writel(gpio->gpio_dir1, remapped_regs + mmGPIO_CNTL1); + writel(gpio->gpio_oe1, remapped_regs + mmGPIO_CNTL2); + writel(gpio->gpio_dir2, remapped_regs + mmGPIO_CNTL3); + writel(gpio->gpio_oe2, remapped_regs + mmGPIO_CNTL4); + } +} -struct pll_parm { - u16 freq; /* desired Fout for PLL */ - u8 M; - u8 N_int; - u8 N_fac; - u8 tfgoal; - u8 lock_time; -}; struct power_state { union clk_pin_cntl_u clk_pin_cntl; @@ -835,317 +812,275 @@ struct power_state { union pll_cntl_u pll_cntl; union sclk_cntl_u sclk_cntl; union pclk_cntl_u pclk_cntl; - union clk_test_cntl_u clk_test_cntl; union pwrmgt_cntl_u pwrmgt_cntl; - u32 freq; /* Fout for PLL calibration */ - u8 tf100; /* for pll calibration */ - u8 tf80; /* for pll calibration */ - u8 tf20; /* for pll calibration */ - u8 M; /* for pll calibration */ - u8 N_int; /* for pll calibration */ - u8 N_fac; /* for pll calibration */ - u8 lock_time; /* for pll calibration */ - u8 tfgoal; /* for pll calibration */ - u8 auto_mode; /* hardware auto switch? */ - u8 pwm_mode; /* 0 fast, 1 normal/slow */ - u16 fast_sclk; /* fast clk freq */ - u16 norm_sclk; /* slow clk freq */ |