summaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/w100fb.c1912
-rw-r--r--drivers/video/w100fb.h777
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", &regs, &param);
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 */
+ int auto_mode; /* system clock auto changing? */
};
-/*
- * Global state variables
- */
-
static struct power_state w100_pwr_state;
-/* This table is specific for 12.5MHz ref crystal. */
-static struct pll_parm gPLLTable[] = {
- /*freq M N_int N_fac tfgoal lock_time */
- { 50, 0, 1, 0, 0xE0, 56}, /* 50.00 MHz */
- { 75, 0, 5, 0, 0xDE, 37}, /* 75.00 MHz */
- {100, 0, 7, 0, 0xE0, 28}, /* 100.00 MHz */
- {125, 0, 9, 0, 0xE0, 22}, /* 125.00 MHz */
- {150, 0, 11, 0, 0xE0, 17}, /* 150.00 MHz */
- { 0, 0, 0, 0, 0, 0} /* Terminator */
+/* The PLL Fout is determined by (XtalFreq/(M+1)) * ((N_int+1) + (N_fac/8)) */
+
+/* 12.5MHz Crystal PLL Table */
+static struct w100_pll_info xtal_12500000[] = {
+ /*freq M N_int N_fac tfgoal lock_time */
+ { 50, 0, 1, 0, 0xe0, 56}, /* 50.00 MHz */
+ { 75, 0, 5, 0, 0xde, 37}, /* 75.00 MHz */
+ {100, 0, 7, 0, 0xe0, 28}, /* 100.00 MHz */
+ {125, 0, 9, 0, 0xe0, 22}, /* 125.00 MHz */
+ {150, 0, 11, 0, 0xe0, 17}, /* 150.00 MHz */
+ { 0, 0, 0, 0, 0, 0}, /* Terminator */
};
+/* 14.318MHz Crystal PLL Table */
+static struct w100_pll_info xtal_14318000[] = {
+ /*