• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/video/
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 doesnt 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");
1637