cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

w100fb.c (48975B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * linux/drivers/video/w100fb.c
      4 *
      5 * Frame Buffer Device for ATI Imageon w100 (Wallaby)
      6 *
      7 * Copyright (C) 2002, ATI Corp.
      8 * Copyright (C) 2004-2006 Richard Purdie
      9 * Copyright (c) 2005 Ian Molton
     10 * Copyright (c) 2006 Alberto Mardegan
     11 *
     12 * Rewritten for 2.6 by Richard Purdie <rpurdie@rpsys.net>
     13 *
     14 * Generic platform support by Ian Molton <spyro@f2s.com>
     15 * and Richard Purdie <rpurdie@rpsys.net>
     16 *
     17 * w32xx support by Ian Molton
     18 *
     19 * Hardware acceleration support by Alberto Mardegan
     20 * <mardy@users.sourceforge.net>
     21 */
     22
     23#include <linux/delay.h>
     24#include <linux/fb.h>
     25#include <linux/init.h>
     26#include <linux/kernel.h>
     27#include <linux/mm.h>
     28#include <linux/platform_device.h>
     29#include <linux/slab.h>
     30#include <linux/string.h>
     31#include <linux/vmalloc.h>
     32#include <linux/module.h>
     33#include <asm/io.h>
     34#include <linux/uaccess.h>
     35#include <video/w100fb.h>
     36#include "w100fb.h"
     37
     38/*
     39 * Prototypes
     40 */
     41static void w100_suspend(u32 mode);
     42static void w100_vsync(void);
     43static void w100_hw_init(struct w100fb_par*);
     44static void w100_pwm_setup(struct w100fb_par*);
     45static void w100_init_clocks(struct w100fb_par*);
     46static void w100_setup_memory(struct w100fb_par*);
     47static void w100_init_lcd(struct w100fb_par*);
     48static void w100_set_dispregs(struct w100fb_par*);
     49static void w100_update_enable(void);
     50static void w100_update_disable(void);
     51static void calc_hsync(struct w100fb_par *par);
     52static void w100_init_graphic_engine(struct w100fb_par *par);
     53struct w100_pll_info *w100_get_xtal_table(unsigned int freq);
     54
     55/* Pseudo palette size */
     56#define MAX_PALETTES      16
     57
     58#define W100_SUSPEND_EXTMEM 0
     59#define W100_SUSPEND_ALL    1
     60
     61#define BITS_PER_PIXEL    16
     62
     63/* Remapped addresses for base cfg, memmapped regs and the frame buffer itself */
     64static void __iomem *remapped_base;
     65static void __iomem *remapped_regs;
     66static void __iomem *remapped_fbuf;
     67
     68#define REMAPPED_FB_LEN   0x15ffff
     69
     70/* This is the offset in the w100's address space we map the current
     71   framebuffer memory to. We use the position of external memory as
     72   we can remap internal memory to there if external isn't present. */
     73#define W100_FB_BASE MEM_EXT_BASE_VALUE
     74
     75
     76/*
     77 * Sysfs functions
     78 */
     79static ssize_t flip_show(struct device *dev, struct device_attribute *attr, char *buf)
     80{
     81	struct fb_info *info = dev_get_drvdata(dev);
     82	struct w100fb_par *par=info->par;
     83
     84	return sprintf(buf, "%d\n",par->flip);
     85}
     86
     87static ssize_t flip_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
     88{
     89	unsigned int flip;
     90	struct fb_info *info = dev_get_drvdata(dev);
     91	struct w100fb_par *par=info->par;
     92
     93	flip = simple_strtoul(buf, NULL, 10);
     94
     95	if (flip > 0)
     96		par->flip = 1;
     97	else
     98		par->flip = 0;
     99
    100	w100_update_disable();
    101	w100_set_dispregs(par);
    102	w100_update_enable();
    103
    104	calc_hsync(par);
    105
    106	return count;
    107}
    108
    109static DEVICE_ATTR_RW(flip);
    110
    111static ssize_t w100fb_reg_read(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
    112{
    113	unsigned long regs, param;
    114	regs = simple_strtoul(buf, NULL, 16);
    115	param = readl(remapped_regs + regs);
    116	printk("Read Register 0x%08lX: 0x%08lX\n", regs, param);
    117	return count;
    118}
    119
    120static DEVICE_ATTR(reg_read, 0200, NULL, w100fb_reg_read);
    121
    122static ssize_t w100fb_reg_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
    123{
    124	unsigned long regs, param;
    125	sscanf(buf, "%lx %lx", &regs, &param);
    126
    127	if (regs <= 0x2000) {
    128		printk("Write Register 0x%08lX: 0x%08lX\n", regs, param);
    129		writel(param, remapped_regs + regs);
    130	}
    131
    132	return count;
    133}
    134
    135static DEVICE_ATTR(reg_write, 0200, NULL, w100fb_reg_write);
    136
    137
    138static ssize_t fastpllclk_show(struct device *dev, struct device_attribute *attr, char *buf)
    139{
    140	struct fb_info *info = dev_get_drvdata(dev);
    141	struct w100fb_par *par=info->par;
    142
    143	return sprintf(buf, "%d\n",par->fastpll_mode);
    144}
    145
    146static ssize_t fastpllclk_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
    147{
    148	struct fb_info *info = dev_get_drvdata(dev);
    149	struct w100fb_par *par=info->par;
    150
    151	if (simple_strtoul(buf, NULL, 10) > 0) {
    152		par->fastpll_mode=1;
    153		printk("w100fb: Using fast system clock (if possible)\n");
    154	} else {
    155		par->fastpll_mode=0;
    156		printk("w100fb: Using normal system clock\n");
    157	}
    158
    159	w100_init_clocks(par);
    160	calc_hsync(par);
    161
    162	return count;
    163}
    164
    165static DEVICE_ATTR_RW(fastpllclk);
    166
    167static struct attribute *w100fb_attrs[] = {
    168	&dev_attr_fastpllclk.attr,
    169	&dev_attr_reg_read.attr,
    170	&dev_attr_reg_write.attr,
    171	&dev_attr_flip.attr,
    172	NULL,
    173};
    174ATTRIBUTE_GROUPS(w100fb);
    175
    176/*
    177 * Some touchscreens need hsync information from the video driver to
    178 * function correctly. We export it here.
    179 */
    180unsigned long w100fb_get_hsynclen(struct device *dev)
    181{
    182	struct fb_info *info = dev_get_drvdata(dev);
    183	struct w100fb_par *par=info->par;
    184
    185	/* If display is blanked/suspended, hsync isn't active */
    186	if (par->blanked)
    187		return 0;
    188	else
    189		return par->hsync_len;
    190}
    191EXPORT_SYMBOL(w100fb_get_hsynclen);
    192
    193static void w100fb_clear_screen(struct w100fb_par *par)
    194{
    195	memset_io(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), 0, (par->xres * par->yres * BITS_PER_PIXEL/8));
    196}
    197
    198
    199/*
    200 * Set a palette value from rgb components
    201 */
    202static int w100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
    203			     u_int trans, struct fb_info *info)
    204{
    205	unsigned int val;
    206	int ret = 1;
    207
    208	/*
    209	 * If greyscale is true, then we convert the RGB value
    210	 * to greyscale no matter what visual we are using.
    211	 */
    212	if (info->var.grayscale)
    213		red = green = blue = (19595 * red + 38470 * green + 7471 * blue) >> 16;
    214
    215	/*
    216	 * 16-bit True Colour.  We encode the RGB value
    217	 * according to the RGB bitfield information.
    218	 */
    219	if (regno < MAX_PALETTES) {
    220		u32 *pal = info->pseudo_palette;
    221
    222		val = (red & 0xf800) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
    223		pal[regno] = val;
    224		ret = 0;
    225	}
    226	return ret;
    227}
    228
    229
    230/*
    231 * Blank the display based on value in blank_mode
    232 */
    233static int w100fb_blank(int blank_mode, struct fb_info *info)
    234{
    235	struct w100fb_par *par = info->par;
    236	struct w100_tg_info *tg = par->mach->tg;
    237
    238	switch(blank_mode) {
    239
    240 	case FB_BLANK_NORMAL:         /* Normal blanking */
    241	case FB_BLANK_VSYNC_SUSPEND:  /* VESA blank (vsync off) */
    242	case FB_BLANK_HSYNC_SUSPEND:  /* VESA blank (hsync off) */
    243 	case FB_BLANK_POWERDOWN:      /* Poweroff */
    244  		if (par->blanked == 0) {
    245			if(tg && tg->suspend)
    246				tg->suspend(par);
    247			par->blanked = 1;
    248  		}
    249  		break;
    250
    251 	case FB_BLANK_UNBLANK: /* Unblanking */
    252  		if (par->blanked != 0) {
    253			if(tg && tg->resume)
    254				tg->resume(par);
    255			par->blanked = 0;
    256  		}
    257  		break;
    258 	}
    259	return 0;
    260}
    261
    262
    263static void w100_fifo_wait(int entries)
    264{
    265	union rbbm_status_u status;
    266	int i;
    267
    268	for (i = 0; i < 2000000; i++) {
    269		status.val = readl(remapped_regs + mmRBBM_STATUS);
    270		if (status.f.cmdfifo_avail >= entries)
    271			return;
    272		udelay(1);
    273	}
    274	printk(KERN_ERR "w100fb: FIFO Timeout!\n");
    275}
    276
    277
    278static int w100fb_sync(struct fb_info *info)
    279{
    280	union rbbm_status_u status;
    281	int i;
    282
    283	for (i = 0; i < 2000000; i++) {
    284		status.val = readl(remapped_regs + mmRBBM_STATUS);
    285		if (!status.f.gui_active)
    286			return 0;
    287		udelay(1);
    288	}
    289	printk(KERN_ERR "w100fb: Graphic engine timeout!\n");
    290	return -EBUSY;
    291}
    292
    293
    294static void w100_init_graphic_engine(struct w100fb_par *par)
    295{
    296	union dp_gui_master_cntl_u gmc;
    297	union dp_mix_u dp_mix;
    298	union dp_datatype_u dp_datatype;
    299	union dp_cntl_u dp_cntl;
    300
    301	w100_fifo_wait(4);
    302	writel(W100_FB_BASE, remapped_regs + mmDST_OFFSET);
    303	writel(par->xres, remapped_regs + mmDST_PITCH);
    304	writel(W100_FB_BASE, remapped_regs + mmSRC_OFFSET);
    305	writel(par->xres, remapped_regs + mmSRC_PITCH);
    306
    307	w100_fifo_wait(3);
    308	writel(0, remapped_regs + mmSC_TOP_LEFT);
    309	writel((par->yres << 16) | par->xres, remapped_regs + mmSC_BOTTOM_RIGHT);
    310	writel(0x1fff1fff, remapped_regs + mmSRC_SC_BOTTOM_RIGHT);
    311
    312	w100_fifo_wait(4);
    313	dp_cntl.val = 0;
    314	dp_cntl.f.dst_x_dir = 1;
    315	dp_cntl.f.dst_y_dir = 1;
    316	dp_cntl.f.src_x_dir = 1;
    317	dp_cntl.f.src_y_dir = 1;
    318	dp_cntl.f.dst_major_x = 1;
    319	dp_cntl.f.src_major_x = 1;
    320	writel(dp_cntl.val, remapped_regs + mmDP_CNTL);
    321
    322	gmc.val = 0;
    323	gmc.f.gmc_src_pitch_offset_cntl = 1;
    324	gmc.f.gmc_dst_pitch_offset_cntl = 1;
    325	gmc.f.gmc_src_clipping = 1;
    326	gmc.f.gmc_dst_clipping = 1;
    327	gmc.f.gmc_brush_datatype = GMC_BRUSH_NONE;
    328	gmc.f.gmc_dst_datatype = 3; /* from DstType_16Bpp_444 */
    329	gmc.f.gmc_src_datatype = SRC_DATATYPE_EQU_DST;
    330	gmc.f.gmc_byte_pix_order = 1;
    331	gmc.f.gmc_default_sel = 0;
    332	gmc.f.gmc_rop3 = ROP3_SRCCOPY;
    333	gmc.f.gmc_dp_src_source = DP_SRC_MEM_RECTANGULAR;
    334	gmc.f.gmc_clr_cmp_fcn_dis = 1;
    335	gmc.f.gmc_wr_msk_dis = 1;
    336	gmc.f.gmc_dp_op = DP_OP_ROP;
    337	writel(gmc.val, remapped_regs + mmDP_GUI_MASTER_CNTL);
    338
    339	dp_datatype.val = dp_mix.val = 0;
    340	dp_datatype.f.dp_dst_datatype = gmc.f.gmc_dst_datatype;
    341	dp_datatype.f.dp_brush_datatype = gmc.f.gmc_brush_datatype;
    342	dp_datatype.f.dp_src2_type = 0;
    343	dp_datatype.f.dp_src2_datatype = gmc.f.gmc_src_datatype;
    344	dp_datatype.f.dp_src_datatype = gmc.f.gmc_src_datatype;
    345	dp_datatype.f.dp_byte_pix_order = gmc.f.gmc_byte_pix_order;
    346	writel(dp_datatype.val, remapped_regs + mmDP_DATATYPE);
    347
    348	dp_mix.f.dp_src_source = gmc.f.gmc_dp_src_source;
    349	dp_mix.f.dp_src2_source = 1;
    350	dp_mix.f.dp_rop3 = gmc.f.gmc_rop3;
    351	dp_mix.f.dp_op = gmc.f.gmc_dp_op;
    352	writel(dp_mix.val, remapped_regs + mmDP_MIX);
    353}
    354
    355
    356static void w100fb_fillrect(struct fb_info *info,
    357                            const struct fb_fillrect *rect)
    358{
    359	union dp_gui_master_cntl_u gmc;
    360
    361	if (info->state != FBINFO_STATE_RUNNING)
    362		return;
    363	if (info->flags & FBINFO_HWACCEL_DISABLED) {
    364		cfb_fillrect(info, rect);
    365		return;
    366	}
    367
    368	gmc.val = readl(remapped_regs + mmDP_GUI_MASTER_CNTL);
    369	gmc.f.gmc_rop3 = ROP3_PATCOPY;
    370	gmc.f.gmc_brush_datatype = GMC_BRUSH_SOLID_COLOR;
    371	w100_fifo_wait(2);
    372	writel(gmc.val, remapped_regs + mmDP_GUI_MASTER_CNTL);
    373	writel(rect->color, remapped_regs + mmDP_BRUSH_FRGD_CLR);
    374
    375	w100_fifo_wait(2);
    376	writel((rect->dy << 16) | (rect->dx & 0xffff), remapped_regs + mmDST_Y_X);
    377	writel((rect->width << 16) | (rect->height & 0xffff),
    378	       remapped_regs + mmDST_WIDTH_HEIGHT);
    379}
    380
    381
    382static void w100fb_copyarea(struct fb_info *info,
    383                            const struct fb_copyarea *area)
    384{
    385	u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
    386	u32 h = area->height, w = area->width;
    387	union dp_gui_master_cntl_u gmc;
    388
    389	if (info->state != FBINFO_STATE_RUNNING)
    390		return;
    391	if (info->flags & FBINFO_HWACCEL_DISABLED) {
    392		cfb_copyarea(info, area);
    393		return;
    394	}
    395
    396	gmc.val = readl(remapped_regs + mmDP_GUI_MASTER_CNTL);
    397	gmc.f.gmc_rop3 = ROP3_SRCCOPY;
    398	gmc.f.gmc_brush_datatype = GMC_BRUSH_NONE;
    399	w100_fifo_wait(1);
    400	writel(gmc.val, remapped_regs + mmDP_GUI_MASTER_CNTL);
    401
    402	w100_fifo_wait(3);
    403	writel((sy << 16) | (sx & 0xffff), remapped_regs + mmSRC_Y_X);
    404	writel((dy << 16) | (dx & 0xffff), remapped_regs + mmDST_Y_X);
    405	writel((w << 16) | (h & 0xffff), remapped_regs + mmDST_WIDTH_HEIGHT);
    406}
    407
    408
    409/*
    410 *  Change the resolution by calling the appropriate hardware functions
    411 */
    412static void w100fb_activate_var(struct w100fb_par *par)
    413{
    414	struct w100_tg_info *tg = par->mach->tg;
    415
    416	w100_pwm_setup(par);
    417	w100_setup_memory(par);
    418	w100_init_clocks(par);
    419	w100fb_clear_screen(par);
    420	w100_vsync();
    421
    422	w100_update_disable();
    423	w100_init_lcd(par);
    424	w100_set_dispregs(par);
    425	w100_update_enable();
    426	w100_init_graphic_engine(par);
    427
    428	calc_hsync(par);
    429
    430	if (!par->blanked && tg && tg->change)
    431		tg->change(par);
    432}
    433
    434
    435/* Select the smallest mode that allows the desired resolution to be
    436 * displayed. If desired, the x and y parameters can be rounded up to
    437 * match the selected mode.
    438 */
    439static struct w100_mode *w100fb_get_mode(struct w100fb_par *par, unsigned int *x, unsigned int *y, int saveval)
    440{
    441	struct w100_mode *mode = NULL;
    442	struct w100_mode *modelist = par->mach->modelist;
    443	unsigned int best_x = 0xffffffff, best_y = 0xffffffff;
    444	unsigned int i;
    445
    446	for (i = 0 ; i < par->mach->num_modes ; i++) {
    447		if (modelist[i].xres >= *x && modelist[i].yres >= *y &&
    448				modelist[i].xres < best_x && modelist[i].yres < best_y) {
    449			best_x = modelist[i].xres;
    450			best_y = modelist[i].yres;
    451			mode = &modelist[i];
    452		} else if(modelist[i].xres >= *y && modelist[i].yres >= *x &&
    453		        modelist[i].xres < best_y && modelist[i].yres < best_x) {
    454			best_x = modelist[i].yres;
    455			best_y = modelist[i].xres;
    456			mode = &modelist[i];
    457		}
    458	}
    459
    460	if (mode && saveval) {
    461		*x = best_x;
    462		*y = best_y;
    463	}
    464
    465	return mode;
    466}
    467
    468
    469/*
    470 *  w100fb_check_var():
    471 *  Get the video params out of 'var'. If a value doesn't fit, round it up,
    472 *  if it's too big, return -EINVAL.
    473 */
    474static int w100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
    475{
    476	struct w100fb_par *par=info->par;
    477
    478	if(!w100fb_get_mode(par, &var->xres, &var->yres, 1))
    479		return -EINVAL;
    480
    481	if (par->mach->mem && ((var->xres*var->yres*BITS_PER_PIXEL/8) > (par->mach->mem->size+1)))
    482		return -EINVAL;
    483
    484	if (!par->mach->mem && ((var->xres*var->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1)))
    485		return -EINVAL;
    486
    487	var->xres_virtual = max(var->xres_virtual, var->xres);
    488	var->yres_virtual = max(var->yres_virtual, var->yres);
    489
    490	if (var->bits_per_pixel > BITS_PER_PIXEL)
    491		return -EINVAL;
    492	else
    493		var->bits_per_pixel = BITS_PER_PIXEL;
    494
    495	var->red.offset = 11;
    496	var->red.length = 5;
    497	var->green.offset = 5;
    498	var->green.length = 6;
    499	var->blue.offset = 0;
    500	var->blue.length = 5;
    501	var->transp.offset = var->transp.length = 0;
    502
    503	var->nonstd = 0;
    504	var->height = -1;
    505	var->width = -1;
    506	var->vmode = FB_VMODE_NONINTERLACED;
    507	var->sync = 0;
    508	var->pixclock = 0x04;  /* 171521; */
    509
    510	return 0;
    511}
    512
    513
    514/*
    515 * w100fb_set_par():
    516 *	Set the user defined part of the display for the specified console
    517 *  by looking at the values in info.var
    518 */
    519static int w100fb_set_par(struct fb_info *info)
    520{
    521	struct w100fb_par *par=info->par;
    522
    523	if (par->xres != info->var.xres || par->yres != info->var.yres)	{
    524		par->xres = info->var.xres;
    525		par->yres = info->var.yres;
    526		par->mode = w100fb_get_mode(par, &par->xres, &par->yres, 0);
    527
    528		info->fix.visual = FB_VISUAL_TRUECOLOR;
    529		info->fix.ypanstep = 0;
    530		info->fix.ywrapstep = 0;
    531		info->fix.line_length = par->xres * BITS_PER_PIXEL / 8;
    532
    533		mutex_lock(&info->mm_lock);
    534		if ((par->xres*par->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1)) {
    535			par->extmem_active = 1;
    536			info->fix.smem_len = par->mach->mem->size+1;
    537		} else {
    538			par->extmem_active = 0;
    539			info->fix.smem_len = MEM_INT_SIZE+1;
    540		}
    541		mutex_unlock(&info->mm_lock);
    542
    543		w100fb_activate_var(par);
    544	}
    545	return 0;
    546}
    547
    548
    549/*
    550 *  Frame buffer operations
    551 */
    552static const struct fb_ops w100fb_ops = {
    553	.owner        = THIS_MODULE,
    554	.fb_check_var = w100fb_check_var,
    555	.fb_set_par   = w100fb_set_par,
    556	.fb_setcolreg = w100fb_setcolreg,
    557	.fb_blank     = w100fb_blank,
    558	.fb_fillrect  = w100fb_fillrect,
    559	.fb_copyarea  = w100fb_copyarea,
    560	.fb_imageblit = cfb_imageblit,
    561	.fb_sync      = w100fb_sync,
    562};
    563
    564#ifdef CONFIG_PM
    565static void w100fb_save_vidmem(struct w100fb_par *par)
    566{
    567	int memsize;
    568
    569	if (par->extmem_active) {
    570		memsize=par->mach->mem->size;
    571		par->saved_extmem = vmalloc(memsize);
    572		if (par->saved_extmem)
    573			memcpy_fromio(par->saved_extmem, remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), memsize);
    574	}
    575	memsize=MEM_INT_SIZE;
    576	par->saved_intmem = vmalloc(memsize);
    577	if (par->saved_intmem && par->extmem_active)
    578		memcpy_fromio(par->saved_intmem, remapped_fbuf + (W100_FB_BASE-MEM_INT_BASE_VALUE), memsize);
    579	else if (par->saved_intmem)
    580		memcpy_fromio(par->saved_intmem, remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), memsize);
    581}
    582
    583static void w100fb_restore_vidmem(struct w100fb_par *par)
    584{
    585	int memsize;
    586
    587	if (par->extmem_active && par->saved_extmem) {
    588		memsize=par->mach->mem->size;
    589		memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_extmem, memsize);
    590		vfree(par->saved_extmem);
    591		par->saved_extmem = NULL;
    592	}
    593	if (par->saved_intmem) {
    594		memsize=MEM_INT_SIZE;
    595		if (par->extmem_active)
    596			memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_INT_BASE_VALUE), par->saved_intmem, memsize);
    597		else
    598			memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_intmem, memsize);
    599		vfree(par->saved_intmem);
    600		par->saved_intmem = NULL;
    601	}
    602}
    603
    604static int w100fb_suspend(struct platform_device *dev, pm_message_t state)
    605{
    606	struct fb_info *info = platform_get_drvdata(dev);
    607	struct w100fb_par *par=info->par;
    608	struct w100_tg_info *tg = par->mach->tg;
    609
    610	w100fb_save_vidmem(par);
    611	if(tg && tg->suspend)
    612		tg->suspend(par);
    613	w100_suspend(W100_SUSPEND_ALL);
    614	par->blanked = 1;
    615
    616	return 0;
    617}
    618
    619static int w100fb_resume(struct platform_device *dev)
    620{
    621	struct fb_info *info = platform_get_drvdata(dev);
    622	struct w100fb_par *par=info->par;
    623	struct w100_tg_info *tg = par->mach->tg;
    624
    625	w100_hw_init(par);
    626	w100fb_activate_var(par);
    627	w100fb_restore_vidmem(par);
    628	if(tg && tg->resume)
    629		tg->resume(par);
    630	par->blanked = 0;
    631
    632	return 0;
    633}
    634#else
    635#define w100fb_suspend  NULL
    636#define w100fb_resume   NULL
    637#endif
    638
    639
    640static int w100fb_probe(struct platform_device *pdev)
    641{
    642	int err = -EIO;
    643	struct w100fb_mach_info *inf;
    644	struct fb_info *info = NULL;
    645	struct w100fb_par *par;
    646	struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    647	unsigned int chip_id;
    648
    649	if (!mem)
    650		return -EINVAL;
    651
    652	/* Remap the chip base address */
    653	remapped_base = ioremap(mem->start+W100_CFG_BASE, W100_CFG_LEN);
    654	if (remapped_base == NULL)
    655		goto out;
    656
    657	/* Map the register space */
    658	remapped_regs = ioremap(mem->start+W100_REG_BASE, W100_REG_LEN);
    659	if (remapped_regs == NULL)
    660		goto out;
    661
    662	/* Identify the chip */
    663	printk("Found ");
    664	chip_id = readl(remapped_regs + mmCHIP_ID);
    665	switch(chip_id) {
    666		case CHIP_ID_W100:  printk("w100");  break;
    667		case CHIP_ID_W3200: printk("w3200"); break;
    668		case CHIP_ID_W3220: printk("w3220"); break;
    669		default:
    670			printk("Unknown imageon chip ID\n");
    671			err = -ENODEV;
    672			goto out;
    673	}
    674	printk(" at 0x%08lx.\n", (unsigned long) mem->start+W100_CFG_BASE);
    675
    676	/* Remap the framebuffer */
    677	remapped_fbuf = ioremap(mem->start+MEM_WINDOW_BASE, MEM_WINDOW_SIZE);
    678	if (remapped_fbuf == NULL)
    679		goto out;
    680
    681	info=framebuffer_alloc(sizeof(struct w100fb_par), &pdev->dev);
    682	if (!info) {
    683		err = -ENOMEM;
    684		goto out;
    685	}
    686
    687	par = info->par;
    688	platform_set_drvdata(pdev, info);
    689
    690	inf = dev_get_platdata(&pdev->dev);
    691	par->chip_id = chip_id;
    692	par->mach = inf;
    693	par->fastpll_mode = 0;
    694	par->blanked = 0;
    695
    696	par->pll_table=w100_get_xtal_table(inf->xtal_freq);
    697	if (!par->pll_table) {
    698		printk(KERN_ERR "No matching Xtal definition found\n");
    699		err = -EINVAL;
    700		goto out;
    701	}
    702
    703	info->pseudo_palette = kmalloc_array(MAX_PALETTES, sizeof(u32),
    704					     GFP_KERNEL);
    705	if (!info->pseudo_palette) {
    706		err = -ENOMEM;
    707		goto out;
    708	}
    709
    710	info->fbops = &w100fb_ops;
    711	info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA |
    712		FBINFO_HWACCEL_FILLRECT;
    713	info->node = -1;
    714	info->screen_base = remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE);
    715	info->screen_size = REMAPPED_FB_LEN;
    716
    717	strcpy(info->fix.id, "w100fb");
    718	info->fix.type = FB_TYPE_PACKED_PIXELS;
    719	info->fix.type_aux = 0;
    720	info->fix.accel = FB_ACCEL_NONE;
    721	info->fix.smem_start = mem->start+W100_FB_BASE;
    722	info->fix.mmio_start = mem->start+W100_REG_BASE;
    723	info->fix.mmio_len = W100_REG_LEN;
    724
    725	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
    726		err = -ENOMEM;
    727		goto out;
    728	}
    729
    730	par->mode = &inf->modelist[0];
    731	if(inf->init_mode & INIT_MODE_ROTATED) {
    732		info->var.xres = par->mode->yres;
    733		info->var.yres = par->mode->xres;
    734	}
    735	else {
    736		info->var.xres = par->mode->xres;
    737		info->var.yres = par->mode->yres;
    738	}
    739
    740	if(inf->init_mode &= INIT_MODE_FLIPPED)
    741		par->flip = 1;
    742	else
    743		par->flip = 0;
    744
    745	info->var.xres_virtual = info->var.xres;
    746	info->var.yres_virtual = info->var.yres;
    747	info->var.pixclock = 0x04;  /* 171521; */
    748	info->var.sync = 0;
    749	info->var.grayscale = 0;
    750	info->var.xoffset = info->var.yoffset = 0;
    751	info->var.accel_flags = 0;
    752	info->var.activate = FB_ACTIVATE_NOW;
    753
    754	w100_hw_init(par);
    755
    756	if (w100fb_check_var(&info->var, info) < 0) {
    757		err = -EINVAL;
    758		goto out;
    759	}
    760
    761	if (register_framebuffer(info) < 0) {
    762		err = -EINVAL;
    763		goto out;
    764	}
    765
    766	fb_info(info, "%s frame buffer device\n", info->fix.id);
    767	return 0;
    768out:
    769	if (info) {
    770		fb_dealloc_cmap(&info->cmap);
    771		kfree(info->pseudo_palette);
    772	}
    773	if (remapped_fbuf != NULL) {
    774		iounmap(remapped_fbuf);
    775		remapped_fbuf = NULL;
    776	}
    777	if (remapped_regs != NULL) {
    778		iounmap(remapped_regs);
    779		remapped_regs = NULL;
    780	}
    781	if (remapped_base != NULL) {
    782		iounmap(remapped_base);
    783		remapped_base = NULL;
    784	}
    785	if (info)
    786		framebuffer_release(info);
    787	return err;
    788}
    789
    790
    791static int w100fb_remove(struct platform_device *pdev)
    792{
    793	struct fb_info *info = platform_get_drvdata(pdev);
    794	struct w100fb_par *par=info->par;
    795
    796	unregister_framebuffer(info);
    797
    798	vfree(par->saved_intmem);
    799	vfree(par->saved_extmem);
    800	kfree(info->pseudo_palette);
    801	fb_dealloc_cmap(&info->cmap);
    802
    803	iounmap(remapped_base);
    804	remapped_base = NULL;
    805	iounmap(remapped_regs);
    806	remapped_regs = NULL;
    807	iounmap(remapped_fbuf);
    808	remapped_fbuf = NULL;
    809
    810	framebuffer_release(info);
    811
    812	return 0;
    813}
    814
    815
    816/* ------------------- chipset specific functions -------------------------- */
    817
    818
    819static void w100_soft_reset(void)
    820{
    821	u16 val = readw((u16 __iomem *)remapped_base + cfgSTATUS);
    822
    823	writew(val | 0x08, (u16 __iomem *)remapped_base + cfgSTATUS);
    824	udelay(100);
    825	writew(0x00, (u16 __iomem *)remapped_base + cfgSTATUS);
    826	udelay(100);
    827}
    828
    829static void w100_update_disable(void)
    830{
    831	union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl;
    832
    833	/* Prevent display updates */
    834	disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
    835	disp_db_buf_wr_cntl.f.update_db_buf = 0;
    836	disp_db_buf_wr_cntl.f.en_db_buf = 0;
    837	writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
    838}
    839
    840static void w100_update_enable(void)
    841{
    842	union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl;
    843
    844	/* Enable display updates */
    845	disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
    846	disp_db_buf_wr_cntl.f.update_db_buf = 1;
    847	disp_db_buf_wr_cntl.f.en_db_buf = 1;
    848	writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
    849}
    850
    851unsigned long w100fb_gpio_read(int port)
    852{
    853	unsigned long value;
    854
    855	if (port==W100_GPIO_PORT_A)
    856		value = readl(remapped_regs + mmGPIO_DATA);
    857	else
    858		value = readl(remapped_regs + mmGPIO_DATA2);
    859
    860	return value;
    861}
    862
    863void w100fb_gpio_write(int port, unsigned long value)
    864{
    865	if (port==W100_GPIO_PORT_A)
    866		writel(value, remapped_regs + mmGPIO_DATA);
    867	else
    868		writel(value, remapped_regs + mmGPIO_DATA2);
    869}
    870EXPORT_SYMBOL(w100fb_gpio_read);
    871EXPORT_SYMBOL(w100fb_gpio_write);
    872
    873/*
    874 * Initialization of critical w100 hardware
    875 */
    876static void w100_hw_init(struct w100fb_par *par)
    877{
    878	u32 temp32;
    879	union cif_cntl_u cif_cntl;
    880	union intf_cntl_u intf_cntl;
    881	union cfgreg_base_u cfgreg_base;
    882	union wrap_top_dir_u wrap_top_dir;
    883	union cif_read_dbg_u cif_read_dbg;
    884	union cpu_defaults_u cpu_default;
    885	union cif_write_dbg_u cif_write_dbg;
    886	union wrap_start_dir_u wrap_start_dir;
    887	union cif_io_u cif_io;
    888	struct w100_gpio_regs *gpio = par->mach->gpio;
    889
    890	w100_soft_reset();
    891
    892	/* This is what the fpga_init code does on reset. May be wrong
    893	   but there is little info available */
    894	writel(0x31, remapped_regs + mmSCRATCH_UMSK);
    895	for (temp32 = 0; temp32 < 10000; temp32++)
    896		readl(remapped_regs + mmSCRATCH_UMSK);
    897	writel(0x30, remapped_regs + mmSCRATCH_UMSK);
    898
    899	/* Set up CIF */
    900	cif_io.val = defCIF_IO;
    901	writel((u32)(cif_io.val), remapped_regs + mmCIF_IO);
    902
    903	cif_write_dbg.val = readl(remapped_regs + mmCIF_WRITE_DBG);
    904	cif_write_dbg.f.dis_packer_ful_during_rbbm_timeout = 0;
    905	cif_write_dbg.f.en_dword_split_to_rbbm = 1;
    906	cif_write_dbg.f.dis_timeout_during_rbbm = 1;
    907	writel((u32) (cif_write_dbg.val), remapped_regs + mmCIF_WRITE_DBG);
    908
    909	cif_read_dbg.val = readl(remapped_regs + mmCIF_READ_DBG);
    910	cif_read_dbg.f.dis_rd_same_byte_to_trig_fetch = 1;
    911	writel((u32) (cif_read_dbg.val), remapped_regs + mmCIF_READ_DBG);
    912
    913	cif_cntl.val = readl(remapped_regs + mmCIF_CNTL);
    914	cif_cntl.f.dis_system_bits = 1;
    915	cif_cntl.f.dis_mr = 1;
    916	cif_cntl.f.en_wait_to_compensate_dq_prop_dly = 0;
    917	cif_cntl.f.intb_oe = 1;
    918	cif_cntl.f.interrupt_active_high = 1;
    919	writel((u32) (cif_cntl.val), remapped_regs + mmCIF_CNTL);
    920
    921	/* Setup cfgINTF_CNTL and cfgCPU defaults */
    922	intf_cntl.val = defINTF_CNTL;
    923	intf_cntl.f.ad_inc_a = 1;
    924	intf_cntl.f.ad_inc_b = 1;
    925	intf_cntl.f.rd_data_rdy_a = 0;
    926	intf_cntl.f.rd_data_rdy_b = 0;
    927	writeb((u8) (intf_cntl.val), remapped_base + cfgINTF_CNTL);
    928
    929	cpu_default.val = defCPU_DEFAULTS;
    930	cpu_default.f.access_ind_addr_a = 1;
    931	cpu_default.f.access_ind_addr_b = 1;
    932	cpu_default.f.access_scratch_reg = 1;
    933	cpu_default.f.transition_size = 0;
    934	writeb((u8) (cpu_default.val), remapped_base + cfgCPU_DEFAULTS);
    935
    936	/* set up the apertures */
    937	writeb((u8) (W100_REG_BASE >> 16), remapped_base + cfgREG_BASE);
    938
    939	cfgreg_base.val = defCFGREG_BASE;
    940	cfgreg_base.f.cfgreg_base = W100_CFG_BASE;
    941	writel((u32) (cfgreg_base.val), remapped_regs + mmCFGREG_BASE);
    942
    943	wrap_start_dir.val = defWRAP_START_DIR;
    944	wrap_start_dir.f.start_addr = WRAP_BUF_BASE_VALUE >> 1;
    945	writel((u32) (wrap_start_dir.val), remapped_regs + mmWRAP_START_DIR);
    946
    947	wrap_top_dir.val = defWRAP_TOP_DIR;
    948	wrap_top_dir.f.top_addr = WRAP_BUF_TOP_VALUE >> 1;
    949	writel((u32) (wrap_top_dir.val), remapped_regs + mmWRAP_TOP_DIR);
    950
    951	writel((u32) 0x2440, remapped_regs + mmRBBM_CNTL);
    952
    953	/* Set the hardware to 565 colour */
    954	temp32 = readl(remapped_regs + mmDISP_DEBUG2);
    955	temp32 &= 0xff7fffff;
    956	temp32 |= 0x00800000;
    957	writel(temp32, remapped_regs + mmDISP_DEBUG2);
    958
    959	/* Initialise the GPIO lines */
    960	if (gpio) {
    961		writel(gpio->init_data1, remapped_regs + mmGPIO_DATA);
    962		writel(gpio->init_data2, remapped_regs + mmGPIO_DATA2);
    963		writel(gpio->gpio_dir1,  remapped_regs + mmGPIO_CNTL1);
    964		writel(gpio->gpio_oe1,   remapped_regs + mmGPIO_CNTL2);
    965		writel(gpio->gpio_dir2,  remapped_regs + mmGPIO_CNTL3);
    966		writel(gpio->gpio_oe2,   remapped_regs + mmGPIO_CNTL4);
    967	}
    968}
    969
    970
    971struct power_state {
    972	union clk_pin_cntl_u clk_pin_cntl;
    973	union pll_ref_fb_div_u pll_ref_fb_div;
    974	union pll_cntl_u pll_cntl;
    975	union sclk_cntl_u sclk_cntl;
    976	union pclk_cntl_u pclk_cntl;
    977	union pwrmgt_cntl_u pwrmgt_cntl;
    978	int auto_mode;  /* system clock auto changing? */
    979};
    980
    981
    982static struct power_state w100_pwr_state;
    983
    984/* The PLL Fout is determined by (XtalFreq/(M+1)) * ((N_int+1) + (N_fac/8)) */
    985
    986/* 12.5MHz Crystal PLL Table */
    987static struct w100_pll_info xtal_12500000[] = {
    988	/*freq     M   N_int    N_fac  tfgoal  lock_time */
    989	{ 50,      0,   1,       0,     0xe0,        56},  /*  50.00 MHz */
    990	{ 75,      0,   5,       0,     0xde,        37},  /*  75.00 MHz */
    991	{100,      0,   7,       0,     0xe0,        28},  /* 100.00 MHz */
    992	{125,      0,   9,       0,     0xe0,        22},  /* 125.00 MHz */
    993	{150,      0,   11,      0,     0xe0,        17},  /* 150.00 MHz */
    994	{  0,      0,   0,       0,        0,         0},  /* Terminator */
    995};
    996
    997/* 14.318MHz Crystal PLL Table */
    998static struct w100_pll_info xtal_14318000[] = {
    999	/*freq     M   N_int    N_fac  tfgoal  lock_time */
   1000	{ 40,      4,   13,      0,     0xe0,        80}, /* tfgoal guessed */
   1001	{ 50,      1,   6,       0,     0xe0,	     64}, /*  50.05 MHz */
   1002	{ 57,      2,   11,      0,     0xe0,        53}, /* tfgoal guessed */
   1003	{ 75,      0,   4,       3,     0xe0,	     43}, /*  75.08 MHz */
   1004	{100,      0,   6,       0,     0xe0,        32}, /* 100.10 MHz */
   1005	{  0,      0,   0,       0,        0,         0},
   1006};
   1007
   1008/* 16MHz Crystal PLL Table */
   1009static struct w100_pll_info xtal_16000000[] = {
   1010	/*freq     M   N_int    N_fac  tfgoal  lock_time */
   1011	{ 72,      1,   8,       0,     0xe0,        48}, /* tfgoal guessed */
   1012	{ 80,      1,   9,       0,     0xe0,        13}, /* tfgoal guessed */
   1013	{ 95,      1,   10,      7,     0xe0,        38}, /* tfgoal guessed */
   1014	{ 96,      1,   11,      0,     0xe0,        36}, /* tfgoal guessed */
   1015	{  0,      0,   0,       0,        0,         0},
   1016};
   1017
   1018static struct pll_entries {
   1019	int xtal_freq;
   1020	struct w100_pll_info *pll_table;
   1021} w100_pll_tables[] = {
   1022	{ 12500000, &xtal_12500000[0] },
   1023	{ 14318000, &xtal_14318000[0] },
   1024	{ 16000000, &xtal_16000000[0] },
   1025	{ 0 },
   1026};
   1027
   1028struct w100_pll_info *w100_get_xtal_table(unsigned int freq)
   1029{
   1030	struct pll_entries *pll_entry = w100_pll_tables;
   1031
   1032	do {
   1033		if (freq == pll_entry->xtal_freq)
   1034			return pll_entry->pll_table;
   1035		pll_entry++;
   1036	} while (pll_entry->xtal_freq);
   1037
   1038	return NULL;
   1039}
   1040
   1041
   1042static unsigned int w100_get_testcount(unsigned int testclk_sel)
   1043{
   1044	union clk_test_cntl_u clk_test_cntl;
   1045
   1046	udelay(5);
   1047
   1048	/* Select the test clock source and reset */
   1049	clk_test_cntl.f.start_check_freq = 0x0;
   1050	clk_test_cntl.f.testclk_sel = testclk_sel;
   1051	clk_test_cntl.f.tstcount_rst = 0x1; /* set reset */
   1052	writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
   1053
   1054	clk_test_cntl.f.tstcount_rst = 0x0; /* clear reset */
   1055	writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
   1056
   1057	/* Run clock test */
   1058	clk_test_cntl.f.start_check_freq = 0x1;
   1059	writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
   1060
   1061	/* Give the test time to complete */
   1062	udelay(20);
   1063
   1064	/* Return the result */
   1065	clk_test_cntl.val = readl(remapped_regs + mmCLK_TEST_CNTL);
   1066	clk_test_cntl.f.start_check_freq = 0x0;
   1067	writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
   1068
   1069	return clk_test_cntl.f.test_count;
   1070}
   1071
   1072
   1073static int w100_pll_adjust(struct w100_pll_info *pll)
   1074{
   1075	unsigned int tf80;
   1076	unsigned int tf20;
   1077
   1078	/* Initial Settings */
   1079	w100_pwr_state.pll_cntl.f.pll_pwdn = 0x0;     /* power down */
   1080	w100_pwr_state.pll_cntl.f.pll_reset = 0x0;    /* not reset */
   1081	w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x1;   /* Hi-Z */
   1082	w100_pwr_state.pll_cntl.f.pll_pvg = 0x0;      /* VCO gain = 0 */
   1083	w100_pwr_state.pll_cntl.f.pll_vcofr = 0x0;    /* VCO frequency range control = off */
   1084	w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;  /* current offset inside VCO = 0 */
   1085	w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0;
   1086
   1087	/* Wai Ming 80 percent of VDD 1.3V gives 1.04V, minimum operating voltage is 1.08V
   1088	 * therefore, commented out the following lines
   1089	 * tf80 meant tf100
   1090	 */
   1091	do {
   1092		/* set VCO input = 0.8 * VDD */
   1093		w100_pwr_state.pll_cntl.f.pll_dactal = 0xd;
   1094		writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
   1095
   1096		tf80 = w100_get_testcount(TESTCLK_SRC_PLL);
   1097		if (tf80 >= (pll->tfgoal)) {
   1098			/* set VCO input = 0.2 * VDD */
   1099			w100_pwr_state.pll_cntl.f.pll_dactal = 0x7;
   1100			writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
   1101
   1102			tf20 = w100_get_testcount(TESTCLK_SRC_PLL);
   1103			if (tf20 <= (pll->tfgoal))
   1104				return 1;  /* Success */
   1105
   1106			if ((w100_pwr_state.pll_cntl.f.pll_vcofr == 0x0) &&
   1107				((w100_pwr_state.pll_cntl.f.pll_pvg == 0x7) ||
   1108				(w100_pwr_state.pll_cntl.f.pll_ioffset == 0x0))) {
   1109				/* slow VCO config */
   1110				w100_pwr_state.pll_cntl.f.pll_vcofr = 0x1;
   1111				w100_pwr_state.pll_cntl.f.pll_pvg = 0x0;
   1112				w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
   1113				continue;
   1114			}
   1115		}
   1116		if ((w100_pwr_state.pll_cntl.f.pll_ioffset) < 0x3) {
   1117			w100_pwr_state.pll_cntl.f.pll_ioffset += 0x1;
   1118		} else if ((w100_pwr_state.pll_cntl.f.pll_pvg) < 0x7) {
   1119			w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
   1120			w100_pwr_state.pll_cntl.f.pll_pvg += 0x1;
   1121		} else {
   1122			return 0;  /* Error */
   1123		}
   1124	} while(1);
   1125}
   1126
   1127
   1128/*
   1129 * w100_pll_calibration
   1130 */
   1131static int w100_pll_calibration(struct w100_pll_info *pll)
   1132{
   1133	int status;
   1134
   1135	status = w100_pll_adjust(pll);
   1136
   1137	/* PLL Reset And Lock */
   1138	/* set VCO input = 0.5 * VDD */
   1139	w100_pwr_state.pll_cntl.f.pll_dactal = 0xa;
   1140	writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
   1141
   1142	udelay(1);  /* reset time */
   1143
   1144	/* enable charge pump */
   1145	w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0;  /* normal */
   1146	writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
   1147
   1148	/* set VCO input = Hi-Z, disable DAC */
   1149	w100_pwr_state.pll_cntl.f.pll_dactal = 0x0;
   1150	writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
   1151
   1152	udelay(400);  /* lock time */
   1153
   1154	/* PLL locked */
   1155
   1156	return status;
   1157}
   1158
   1159
   1160static int w100_pll_set_clk(struct w100_pll_info *pll)
   1161{
   1162	int status;
   1163
   1164	if (w100_pwr_state.auto_mode == 1)  /* auto mode */
   1165	{
   1166		w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0;  /* disable fast to normal */
   1167		w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0;  /* disable normal to fast */
   1168		writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
   1169	}
   1170
   1171	/* Set system clock source to XTAL whilst adjusting the PLL! */
   1172	w100_pwr_state.sclk_cntl.f.sclk_src_sel = CLK_SRC_XTAL;
   1173	writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
   1174
   1175	w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = pll->M;
   1176	w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = pll->N_int;
   1177	w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = pll->N_fac;
   1178	w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = pll->lock_time;
   1179	writel((u32) (w100_pwr_state.pll_ref_fb_div.val), remapped_regs + mmPLL_REF_FB_DIV);
   1180
   1181	w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0;
   1182	writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
   1183
   1184	status = w100_pll_calibration(pll);
   1185
   1186	if (w100_pwr_state.auto_mode == 1)  /* auto mode */
   1187	{
   1188		w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x1;  /* reenable fast to normal */
   1189		w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x1;  /* reenable normal to fast  */
   1190		writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
   1191	}
   1192	return status;
   1193}
   1194
   1195/* freq = target frequency of the PLL */
   1196static int w100_set_pll_freq(struct w100fb_par *par, unsigned int freq)
   1197{
   1198	struct w100_pll_info *pll = par->pll_table;
   1199
   1200	do {
   1201		if (freq == pll->freq) {
   1202			return w100_pll_set_clk(pll);
   1203		}
   1204		pll++;
   1205	} while(pll->freq);
   1206	return 0;
   1207}
   1208
   1209/* Set up an initial state.  Some values/fields set
   1210   here will be overwritten. */
   1211static void w100_pwm_setup(struct w100fb_par *par)
   1212{
   1213	w100_pwr_state.clk_pin_cntl.f.osc_en = 0x1;
   1214	w100_pwr_state.clk_pin_cntl.f.osc_gain = 0x1f;
   1215	w100_pwr_state.clk_pin_cntl.f.dont_use_xtalin = 0x0;
   1216	w100_pwr_state.clk_pin_cntl.f.xtalin_pm_en = 0x0;
   1217	w100_pwr_state.clk_pin_cntl.f.xtalin_dbl_en = par->mach->xtal_dbl ? 1 : 0;
   1218	w100_pwr_state.clk_pin_cntl.f.cg_debug = 0x0;
   1219	writel((u32) (w100_pwr_state.clk_pin_cntl.val), remapped_regs + mmCLK_PIN_CNTL);
   1220
   1221	w100_pwr_state.sclk_cntl.f.sclk_src_sel = CLK_SRC_XTAL;
   1222	w100_pwr_state.sclk_cntl.f.sclk_post_div_fast = 0x0;  /* Pfast = 1 */
   1223	w100_pwr_state.sclk_cntl.f.sclk_clkon_hys = 0x3;
   1224	w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = 0x0;  /* Pslow = 1 */
   1225	w100_pwr_state.sclk_cntl.f.disp_cg_ok2switch_en = 0x0;
   1226	w100_pwr_state.sclk_cntl.f.sclk_force_reg = 0x0;    /* Dynamic */
   1227	w100_pwr_state.sclk_cntl.f.sclk_force_disp = 0x0;   /* Dynamic */
   1228	w100_pwr_state.sclk_cntl.f.sclk_force_mc = 0x0;     /* Dynamic */
   1229	w100_pwr_state.sclk_cntl.f.sclk_force_extmc = 0x0;  /* Dynamic */
   1230	w100_pwr_state.sclk_cntl.f.sclk_force_cp = 0x0;     /* Dynamic */
   1231	w100_pwr_state.sclk_cntl.f.sclk_force_e2 = 0x0;     /* Dynamic */
   1232	w100_pwr_state.sclk_cntl.f.sclk_force_e3 = 0x0;     /* Dynamic */
   1233	w100_pwr_state.sclk_cntl.f.sclk_force_idct = 0x0;   /* Dynamic */
   1234	w100_pwr_state.sclk_cntl.f.sclk_force_bist = 0x0;   /* Dynamic */
   1235	w100_pwr_state.sclk_cntl.f.busy_extend_cp = 0x0;
   1236	w100_pwr_state.sclk_cntl.f.busy_extend_e2 = 0x0;
   1237	w100_pwr_state.sclk_cntl.f.busy_extend_e3 = 0x0;
   1238	w100_pwr_state.sclk_cntl.f.busy_extend_idct = 0x0;
   1239	writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
   1240
   1241	w100_pwr_state.pclk_cntl.f.pclk_src_sel = CLK_SRC_XTAL;
   1242	w100_pwr_state.pclk_cntl.f.pclk_post_div = 0x1;    /* P = 2 */
   1243	w100_pwr_state.pclk_cntl.f.pclk_force_disp = 0x0;  /* Dynamic */
   1244	writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
   1245
   1246	w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = 0x0;     /* M = 1 */
   1247	w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = 0x0;  /* N = 1.0 */
   1248	w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = 0x0;
   1249	w100_pwr_state.pll_ref_fb_div.f.pll_reset_time = 0x5;
   1250	w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = 0xff;
   1251	writel((u32) (w100_pwr_state.pll_ref_fb_div.val), remapped_regs + mmPLL_REF_FB_DIV);
   1252
   1253	w100_pwr_state.pll_cntl.f.pll_pwdn = 0x1;
   1254	w100_pwr_state.pll_cntl.f.pll_reset = 0x1;
   1255	w100_pwr_state.pll_cntl.f.pll_pm_en = 0x0;
   1256	w100_pwr_state.pll_cntl.f.pll_mode = 0x0;  /* uses VCO clock */
   1257	w100_pwr_state.pll_cntl.f.pll_refclk_sel = 0x0;
   1258	w100_pwr_state.pll_cntl.f.pll_fbclk_sel = 0x0;
   1259	w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0;
   1260	w100_pwr_state.pll_cntl.f.pll_pcp = 0x4;
   1261	w100_pwr_state.pll_cntl.f.pll_pvg = 0x0;
   1262	w100_pwr_state.pll_cntl.f.pll_vcofr = 0x0;
   1263	w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
   1264	w100_pwr_state.pll_cntl.f.pll_pecc_mode = 0x0;
   1265	w100_pwr_state.pll_cntl.f.pll_pecc_scon = 0x0;
   1266	w100_pwr_state.pll_cntl.f.pll_dactal = 0x0;  /* Hi-Z */
   1267	w100_pwr_state.pll_cntl.f.pll_cp_clip = 0x3;
   1268	w100_pwr_state.pll_cntl.f.pll_conf = 0x2;
   1269	w100_pwr_state.pll_cntl.f.pll_mbctrl = 0x2;
   1270	w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0;
   1271	writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
   1272
   1273	w100_pwr_state.pwrmgt_cntl.f.pwm_enable = 0x0;
   1274	w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0x1;  /* normal mode (0, 1, 3) */
   1275	w100_pwr_state.pwrmgt_cntl.f.pwm_wakeup_cond = 0x0;
   1276	w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0;
   1277	w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0;
   1278	w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_cond = 0x1;  /* PM4,ENG */
   1279	w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_cond = 0x1;  /* PM4,ENG */
   1280	w100_pwr_state.pwrmgt_cntl.f.pwm_idle_timer = 0xFF;
   1281	w100_pwr_state.pwrmgt_cntl.f.pwm_busy_timer = 0xFF;
   1282	writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
   1283
   1284	w100_pwr_state.auto_mode = 0;  /* manual mode */
   1285}
   1286
   1287
   1288/*
   1289 * Setup the w100 clocks for the specified mode
   1290 */
   1291static void w100_init_clocks(struct w100fb_par *par)
   1292{
   1293	struct w100_mode *mode = par->mode;
   1294
   1295	if (mode->pixclk_src == CLK_SRC_PLL || mode->sysclk_src == CLK_SRC_PLL)
   1296		w100_set_pll_freq(par, (par->fastpll_mode && mode->fast_pll_freq) ? mode->fast_pll_freq : mode->pll_freq);
   1297
   1298	w100_pwr_state.sclk_cntl.f.sclk_src_sel = mode->sysclk_src;
   1299	w100_pwr_state.sclk_cntl.f.sclk_post_div_fast = mode->sysclk_divider;
   1300	w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = mode->sysclk_divider;
   1301	writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
   1302}
   1303
   1304static void w100_init_lcd(struct w100fb_par *par)
   1305{
   1306	u32 temp32;
   1307	struct w100_mode *mode = par->mode;
   1308	struct w100_gen_regs *regs = par->mach->regs;
   1309	union active_h_disp_u active_h_disp;
   1310	union active_v_disp_u active_v_disp;
   1311	union graphic_h_disp_u graphic_h_disp;
   1312	union graphic_v_disp_u graphic_v_disp;
   1313	union crtc_total_u crtc_total;
   1314
   1315	/* w3200 doesn't like undefined bits being set so zero register values first */
   1316
   1317	active_h_disp.val = 0;
   1318	active_h_disp.f.active_h_start=mode->left_margin;
   1319	active_h_disp.f.active_h_end=mode->left_margin + mode->xres;
   1320	writel(active_h_disp.val, remapped_regs + mmACTIVE_H_DISP);
   1321
   1322	active_v_disp.val = 0;
   1323	active_v_disp.f.active_v_start=mode->upper_margin;
   1324	active_v_disp.f.active_v_end=mode->upper_margin + mode->yres;
   1325	writel(active_v_disp.val, remapped_regs + mmACTIVE_V_DISP);
   1326
   1327	graphic_h_disp.val = 0;
   1328	graphic_h_disp.f.graphic_h_start=mode->left_margin;
   1329	graphic_h_disp.f.graphic_h_end=mode->left_margin + mode->xres;
   1330	writel(graphic_h_disp.val, remapped_regs + mmGRAPHIC_H_DISP);
   1331
   1332	graphic_v_disp.val = 0;
   1333	graphic_v_disp.f.graphic_v_start=mode->upper_margin;
   1334	graphic_v_disp.f.graphic_v_end=mode->upper_margin + mode->yres;
   1335	writel(graphic_v_disp.val, remapped_regs + mmGRAPHIC_V_DISP);
   1336
   1337	crtc_total.val = 0;
   1338	crtc_total.f.crtc_h_total=mode->left_margin  + mode->xres + mode->right_margin;
   1339	crtc_total.f.crtc_v_total=mode->upper_margin + mode->yres + mode->lower_margin;
   1340	writel(crtc_total.val, remapped_regs + mmCRTC_TOTAL);
   1341
   1342	writel(mode->crtc_ss, remapped_regs + mmCRTC_SS);
   1343	writel(mode->crtc_ls, remapped_regs + mmCRTC_LS);
   1344	writel(mode->crtc_gs, remapped_regs + mmCRTC_GS);
   1345	writel(mode->crtc_vpos_gs, remapped_regs + mmCRTC_VPOS_GS);
   1346	writel(mode->crtc_rev, remapped_regs + mmCRTC_REV);
   1347	writel(mode->crtc_dclk, remapped_regs + mmCRTC_DCLK);
   1348	writel(mode->crtc_gclk, remapped_regs + mmCRTC_GCLK);
   1349	writel(mode->crtc_goe, remapped_regs + mmCRTC_GOE);
   1350	writel(mode->crtc_ps1_active, remapped_regs + mmCRTC_PS1_ACTIVE);
   1351
   1352	writel(regs->lcd_format, remapped_regs + mmLCD_FORMAT);
   1353	writel(regs->lcdd_cntl1, remapped_regs + mmLCDD_CNTL1);
   1354	writel(regs->lcdd_cntl2, remapped_regs + mmLCDD_CNTL2);
   1355	writel(regs->genlcd_cntl1, remapped_regs + mmGENLCD_CNTL1);
   1356	writel(regs->genlcd_cntl2, remapped_regs + mmGENLCD_CNTL2);
   1357	writel(regs->genlcd_cntl3, remapped_regs + mmGENLCD_CNTL3);
   1358
   1359	writel(0x00000000, remapped_regs + mmCRTC_FRAME);
   1360	writel(0x00000000, remapped_regs + mmCRTC_FRAME_VPOS);
   1361	writel(0x00000000, remapped_regs + mmCRTC_DEFAULT_COUNT);
   1362	writel(0x0000FF00, remapped_regs + mmLCD_BACKGROUND_COLOR);
   1363
   1364	/* Hack for overlay in ext memory */
   1365	temp32 = readl(remapped_regs + mmDISP_DEBUG2);
   1366	temp32 |= 0xc0000000;
   1367	writel(temp32, remapped_regs + mmDISP_DEBUG2);
   1368}
   1369
   1370
   1371static void w100_setup_memory(struct w100fb_par *par)
   1372{
   1373	union mc_ext_mem_location_u extmem_location;
   1374	union mc_fb_location_u intmem_location;
   1375	struct w100_mem_info *mem = par->mach->mem;
   1376	struct w100_bm_mem_info *bm_mem = par->mach->bm_mem;
   1377
   1378	if (!par->extmem_active) {
   1379		w100_suspend(W100_SUSPEND_EXTMEM);
   1380
   1381		/* Map Internal Memory at FB Base */
   1382		intmem_location.f.mc_fb_start = W100_FB_BASE >> 8;
   1383		intmem_location.f.mc_fb_top = (W100_FB_BASE+MEM_INT_SIZE) >> 8;
   1384		writel((u32) (intmem_location.val), remapped_regs + mmMC_FB_LOCATION);
   1385
   1386		/* Unmap External Memory - value is *probably* irrelevant but may have meaning
   1387		   to acceleration libraries */
   1388		extmem_location.f.mc_ext_mem_start = MEM_EXT_BASE_VALUE >> 8;
   1389		extmem_location.f.mc_ext_mem_top = (MEM_EXT_BASE_VALUE-1) >> 8;
   1390		writel((u32) (extmem_location.val), remapped_regs + mmMC_EXT_MEM_LOCATION);
   1391	} else {
   1392		/* Map Internal Memory to its default location */
   1393		intmem_location.f.mc_fb_start = MEM_INT_BASE_VALUE >> 8;
   1394		intmem_location.f.mc_fb_top = (MEM_INT_BASE_VALUE+MEM_INT_SIZE) >> 8;
   1395		writel((u32) (intmem_location.val), remapped_regs + mmMC_FB_LOCATION);
   1396
   1397		/* Map External Memory at FB Base */
   1398		extmem_location.f.mc_ext_mem_start = W100_FB_BASE >> 8;
   1399		extmem_location.f.mc_ext_mem_top = (W100_FB_BASE+par->mach->mem->size) >> 8;
   1400		writel((u32) (extmem_location.val), remapped_regs + mmMC_EXT_MEM_LOCATION);
   1401
   1402		writel(0x00007800, remapped_regs + mmMC_BIST_CTRL);
   1403		writel(mem->ext_cntl, remapped_regs + mmMEM_EXT_CNTL);
   1404		writel(0x00200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
   1405		udelay(100);
   1406		writel(0x80200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
   1407		udelay(100);
   1408		writel(mem->sdram_mode_reg, remapped_regs + mmMEM_SDRAM_MODE_REG);
   1409		udelay(100);
   1410		writel(mem->ext_timing_cntl, remapped_regs + mmMEM_EXT_TIMING_CNTL);
   1411		writel(mem->io_cntl, remapped_regs + mmMEM_IO_CNTL);
   1412		if (bm_mem) {
   1413			writel(bm_mem->ext_mem_bw, remapped_regs + mmBM_EXT_MEM_BANDWIDTH);
   1414			writel(bm_mem->offset, remapped_regs + mmBM_OFFSET);
   1415			writel(bm_mem->ext_timing_ctl, remapped_regs + mmBM_MEM_EXT_TIMING_CNTL);
   1416			writel(bm_mem->ext_cntl, remapped_regs + mmBM_MEM_EXT_CNTL);
   1417			writel(bm_mem->mode_reg, remapped_regs + mmBM_MEM_MODE_REG);
   1418			writel(bm_mem->io_cntl, remapped_regs + mmBM_MEM_IO_CNTL);
   1419			writel(bm_mem->config, remapped_regs + mmBM_CONFIG);
   1420		}
   1421	}
   1422}
   1423
   1424static void w100_set_dispregs(struct w100fb_par *par)
   1425{
   1426	unsigned long rot=0, divider, offset=0;
   1427	union graphic_ctrl_u graphic_ctrl;
   1428
   1429	/* See if the mode has been rotated */
   1430	if (par->xres == par->mode->xres) {
   1431		if (par->flip) {
   1432			rot=3; /* 180 degree */
   1433			offset=(par->xres * par->yres) - 1;
   1434		} /* else 0 degree */
   1435		divider = par->mode->pixclk_divider;
   1436	} else {
   1437		if (par->flip) {
   1438			rot=2; /* 270 degree */
   1439			offset=par->xres - 1;
   1440		} else {
   1441			rot=1; /* 90 degree */
   1442			offset=par->xres * (par->yres - 1);
   1443		}
   1444		divider = par->mode->pixclk_divider_rotated;
   1445	}
   1446
   1447	graphic_ctrl.val = 0; /* w32xx doesn't like undefined bits */
   1448	switch (par->chip_id) {
   1449		case CHIP_ID_W100:
   1450			graphic_ctrl.f_w100.color_depth=6;
   1451			graphic_ctrl.f_w100.en_crtc=1;
   1452			graphic_ctrl.f_w100.en_graphic_req=1;
   1453			graphic_ctrl.f_w100.en_graphic_crtc=1;
   1454			graphic_ctrl.f_w100.lcd_pclk_on=1;
   1455			graphic_ctrl.f_w100.lcd_sclk_on=1;
   1456			graphic_ctrl.f_w100.low_power_on=0;
   1457			graphic_ctrl.f_w100.req_freq=0;
   1458			graphic_ctrl.f_w100.portrait_mode=rot;
   1459
   1460			/* Zaurus needs this */
   1461			switch(par->xres) {
   1462				case 240:
   1463				case 320:
   1464				default:
   1465					graphic_ctrl.f_w100.total_req_graphic=0xa0;
   1466					break;
   1467				case 480:
   1468				case 640:
   1469					switch(rot) {
   1470						case 0:  /* 0 */
   1471						case 3:  /* 180 */
   1472							graphic_ctrl.f_w100.low_power_on=1;
   1473							graphic_ctrl.f_w100.req_freq=5;
   1474						break;
   1475						case 1:  /* 90 */
   1476						case 2:  /* 270 */
   1477							graphic_ctrl.f_w100.req_freq=4;
   1478							break;
   1479						default:
   1480							break;
   1481					}
   1482					graphic_ctrl.f_w100.total_req_graphic=0xf0;
   1483					break;
   1484			}
   1485			break;
   1486		case CHIP_ID_W3200:
   1487		case CHIP_ID_W3220:
   1488			graphic_ctrl.f_w32xx.color_depth=6;
   1489			graphic_ctrl.f_w32xx.en_crtc=1;
   1490			graphic_ctrl.f_w32xx.en_graphic_req=1;
   1491			graphic_ctrl.f_w32xx.en_graphic_crtc=1;
   1492			graphic_ctrl.f_w32xx.lcd_pclk_on=1;
   1493			graphic_ctrl.f_w32xx.lcd_sclk_on=1;
   1494			graphic_ctrl.f_w32xx.low_power_on=0;
   1495			graphic_ctrl.f_w32xx.req_freq=0;
   1496			graphic_ctrl.f_w32xx.total_req_graphic=par->mode->xres >> 1; /* panel xres, not mode */
   1497			graphic_ctrl.f_w32xx.portrait_mode=rot;
   1498			break;
   1499	}
   1500
   1501	/* Set the pixel clock source and divider */
   1502	w100_pwr_state.pclk_cntl.f.pclk_src_sel = par->mode->pixclk_src;
   1503	w100_pwr_state.pclk_cntl.f.pclk_post_div = divider;
   1504	writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
   1505
   1506	writel(graphic_ctrl.val, remapped_regs + mmGRAPHIC_CTRL);
   1507	writel(W100_FB_BASE + ((offset * BITS_PER_PIXEL/8)&~0x03UL), remapped_regs + mmGRAPHIC_OFFSET);
   1508	writel((par->xres*BITS_PER_PIXEL/8), remapped_regs + mmGRAPHIC_PITCH);
   1509}
   1510
   1511
   1512/*
   1513 * Work out how long the sync pulse lasts
   1514 * Value is 1/(time in seconds)
   1515 */
   1516static void calc_hsync(struct w100fb_par *par)
   1517{
   1518	unsigned long hsync;
   1519	struct w100_mode *mode = par->mode;
   1520	union crtc_ss_u crtc_ss;
   1521
   1522	if (mode->pixclk_src == CLK_SRC_XTAL)
   1523		hsync=par->mach->xtal_freq;
   1524	else
   1525		hsync=((par->fastpll_mode && mode->fast_pll_freq) ? mode->fast_pll_freq : mode->pll_freq)*100000;
   1526
   1527	hsync /= (w100_pwr_state.pclk_cntl.f.pclk_post_div + 1);
   1528
   1529	crtc_ss.val = readl(remapped_regs + mmCRTC_SS);
   1530	if (crtc_ss.val)
   1531		par->hsync_len = hsync / (crtc_ss.f.ss_end-crtc_ss.f.ss_start);
   1532	else
   1533		par->hsync_len = 0;
   1534}
   1535
   1536static void w100_suspend(u32 mode)
   1537{
   1538	u32 val;
   1539
   1540	writel(0x7FFF8000, remapped_regs + mmMC_EXT_MEM_LOCATION);
   1541	writel(0x00FF0000, remapped_regs + mmMC_PERF_MON_CNTL);
   1542
   1543	val = readl(remapped_regs + mmMEM_EXT_TIMING_CNTL);
   1544	val &= ~(0x00100000);  /* bit20=0 */
   1545	val |= 0xFF000000;     /* bit31:24=0xff */
   1546	writel(val, remapped_regs + mmMEM_EXT_TIMING_CNTL);
   1547
   1548	val = readl(remapped_regs + mmMEM_EXT_CNTL);
   1549	val &= ~(0x00040000);  /* bit18=0 */
   1550	val |= 0x00080000;     /* bit19=1 */
   1551	writel(val, remapped_regs + mmMEM_EXT_CNTL);
   1552
   1553	udelay(1);  /* wait 1us */
   1554
   1555	if (mode == W100_SUSPEND_EXTMEM) {
   1556		/* CKE: Tri-State */
   1557		val = readl(remapped_regs + mmMEM_EXT_CNTL);
   1558		val |= 0x40000000;  /* bit30=1 */
   1559		writel(val, remapped_regs + mmMEM_EXT_CNTL);
   1560
   1561		/* CLK: Stop */
   1562		val = readl(remapped_regs + mmMEM_EXT_CNTL);
   1563		val &= ~(0x00000001);  /* bit0=0 */
   1564		writel(val, remapped_regs + mmMEM_EXT_CNTL);
   1565	} else {
   1566		writel(0x00000000, remapped_regs + mmSCLK_CNTL);
   1567		writel(0x000000BF, remapped_regs + mmCLK_PIN_CNTL);
   1568		writel(0x00000015, remapped_regs + mmPWRMGT_CNTL);
   1569
   1570		udelay(5);
   1571
   1572		val = readl(remapped_regs + mmPLL_CNTL);
   1573		val |= 0x00000004;  /* bit2=1 */
   1574		writel(val, remapped_regs + mmPLL_CNTL);
   1575
   1576		writel(0x00000000, remapped_regs + mmLCDD_CNTL1);
   1577		writel(0x00000000, remapped_regs + mmLCDD_CNTL2);
   1578		writel(0x00000000, remapped_regs + mmGENLCD_CNTL1);
   1579		writel(0x00000000, remapped_regs + mmGENLCD_CNTL2);
   1580		writel(0x00000000, remapped_regs + mmGENLCD_CNTL3);
   1581
   1582		val = readl(remapped_regs + mmMEM_EXT_CNTL);
   1583		val |= 0xF0000000;
   1584		val &= ~(0x00000001);
   1585		writel(val, remapped_regs + mmMEM_EXT_CNTL);
   1586
   1587		writel(0x0000001d, remapped_regs + mmPWRMGT_CNTL);
   1588	}
   1589}
   1590
   1591static void w100_vsync(void)
   1592{
   1593	u32 tmp;
   1594	int timeout = 30000;  /* VSync timeout = 30[ms] > 16.8[ms] */
   1595
   1596	tmp = readl(remapped_regs + mmACTIVE_V_DISP);
   1597
   1598	/* set vline pos  */
   1599	writel((tmp >> 16) & 0x3ff, remapped_regs + mmDISP_INT_CNTL);
   1600
   1601	/* disable vline irq */
   1602	tmp = readl(remapped_regs + mmGEN_INT_CNTL);
   1603
   1604	tmp &= ~0x00000002;
   1605	writel(tmp, remapped_regs + mmGEN_INT_CNTL);
   1606
   1607	/* clear vline irq status */
   1608	writel(0x00000002, remapped_regs + mmGEN_INT_STATUS);
   1609
   1610	/* enable vline irq */
   1611	writel((tmp | 0x00000002), remapped_regs + mmGEN_INT_CNTL);
   1612
   1613	/* clear vline irq status */
   1614	writel(0x00000002, remapped_regs + mmGEN_INT_STATUS);
   1615
   1616	while(timeout > 0) {
   1617		if (readl(remapped_regs + mmGEN_INT_STATUS) & 0x00000002)
   1618			break;
   1619		udelay(1);
   1620		timeout--;
   1621	}
   1622
   1623	/* disable vline irq */
   1624	writel(tmp, remapped_regs + mmGEN_INT_CNTL);
   1625
   1626	/* clear vline irq status */
   1627	writel(0x00000002, remapped_regs + mmGEN_INT_STATUS);
   1628}
   1629
   1630static struct platform_driver w100fb_driver = {
   1631	.probe		= w100fb_probe,
   1632	.remove		= w100fb_remove,
   1633	.suspend	= w100fb_suspend,
   1634	.resume		= w100fb_resume,
   1635	.driver		= {
   1636		.name	= "w100fb",
   1637		.dev_groups	= w100fb_groups,
   1638	},
   1639};
   1640
   1641module_platform_driver(w100fb_driver);
   1642
   1643MODULE_DESCRIPTION("ATI Imageon w100 framebuffer driver");
   1644MODULE_LICENSE("GPL");