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