PageRenderTime 82ms CodeModel.GetById 16ms app.highlight 54ms RepoModel.GetById 0ms app.codeStats 1ms

/drivers/video/w100fb.c

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