GNU Linux-libre 5.10.153-gnu1
[releases.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 __iomem *remapped_base;
65 static void __iomem *remapped_regs;
66 static void __iomem *remapped_fbuf;
67
68 #define REMAPPED_FB_LEN   0x15ffff
69
70 /* This is the offset in the w100's address space we map the current
71    framebuffer memory to. We use the position of external memory as
72    we can remap internal memory to there if external isn't present. */
73 #define W100_FB_BASE MEM_EXT_BASE_VALUE
74
75
76 /*
77  * Sysfs functions
78  */
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                 par->saved_extmem = NULL;
592         }
593         if (par->saved_intmem) {
594                 memsize=MEM_INT_SIZE;
595                 if (par->extmem_active)
596                         memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_INT_BASE_VALUE), par->saved_intmem, memsize);
597                 else
598                         memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_intmem, memsize);
599                 vfree(par->saved_intmem);
600                 par->saved_intmem = NULL;
601         }
602 }
603
604 static int w100fb_suspend(struct platform_device *dev, pm_message_t state)
605 {
606         struct fb_info *info = platform_get_drvdata(dev);
607         struct w100fb_par *par=info->par;
608         struct w100_tg_info *tg = par->mach->tg;
609
610         w100fb_save_vidmem(par);
611         if(tg && tg->suspend)
612                 tg->suspend(par);
613         w100_suspend(W100_SUSPEND_ALL);
614         par->blanked = 1;
615
616         return 0;
617 }
618
619 static int w100fb_resume(struct platform_device *dev)
620 {
621         struct fb_info *info = platform_get_drvdata(dev);
622         struct w100fb_par *par=info->par;
623         struct w100_tg_info *tg = par->mach->tg;
624
625         w100_hw_init(par);
626         w100fb_activate_var(par);
627         w100fb_restore_vidmem(par);
628         if(tg && tg->resume)
629                 tg->resume(par);
630         par->blanked = 0;
631
632         return 0;
633 }
634 #else
635 #define w100fb_suspend  NULL
636 #define w100fb_resume   NULL
637 #endif
638
639
640 static int w100fb_probe(struct platform_device *pdev)
641 {
642         int err = -EIO;
643         struct w100fb_mach_info *inf;
644         struct fb_info *info = NULL;
645         struct w100fb_par *par;
646         struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
647         unsigned int chip_id;
648
649         if (!mem)
650                 return -EINVAL;
651
652         /* Remap the chip base address */
653         remapped_base = ioremap(mem->start+W100_CFG_BASE, W100_CFG_LEN);
654         if (remapped_base == NULL)
655                 goto out;
656
657         /* Map the register space */
658         remapped_regs = ioremap(mem->start+W100_REG_BASE, W100_REG_LEN);
659         if (remapped_regs == NULL)
660                 goto out;
661
662         /* Identify the chip */
663         printk("Found ");
664         chip_id = readl(remapped_regs + mmCHIP_ID);
665         switch(chip_id) {
666                 case CHIP_ID_W100:  printk("w100");  break;
667                 case CHIP_ID_W3200: printk("w3200"); break;
668                 case CHIP_ID_W3220: printk("w3220"); break;
669                 default:
670                         printk("Unknown imageon chip ID\n");
671                         err = -ENODEV;
672                         goto out;
673         }
674         printk(" at 0x%08lx.\n", (unsigned long) mem->start+W100_CFG_BASE);
675
676         /* Remap the framebuffer */
677         remapped_fbuf = ioremap(mem->start+MEM_WINDOW_BASE, MEM_WINDOW_SIZE);
678         if (remapped_fbuf == NULL)
679                 goto out;
680
681         info=framebuffer_alloc(sizeof(struct w100fb_par), &pdev->dev);
682         if (!info) {
683                 err = -ENOMEM;
684                 goto out;
685         }
686
687         par = info->par;
688         platform_set_drvdata(pdev, info);
689
690         inf = dev_get_platdata(&pdev->dev);
691         par->chip_id = chip_id;
692         par->mach = inf;
693         par->fastpll_mode = 0;
694         par->blanked = 0;
695
696         par->pll_table=w100_get_xtal_table(inf->xtal_freq);
697         if (!par->pll_table) {
698                 printk(KERN_ERR "No matching Xtal definition found\n");
699                 err = -EINVAL;
700                 goto out;
701         }
702
703         info->pseudo_palette = kmalloc_array(MAX_PALETTES, sizeof(u32),
704                                              GFP_KERNEL);
705         if (!info->pseudo_palette) {
706                 err = -ENOMEM;
707                 goto out;
708         }
709
710         info->fbops = &w100fb_ops;
711         info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA |
712                 FBINFO_HWACCEL_FILLRECT;
713         info->node = -1;
714         info->screen_base = remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE);
715         info->screen_size = REMAPPED_FB_LEN;
716
717         strcpy(info->fix.id, "w100fb");
718         info->fix.type = FB_TYPE_PACKED_PIXELS;
719         info->fix.type_aux = 0;
720         info->fix.accel = FB_ACCEL_NONE;
721         info->fix.smem_start = mem->start+W100_FB_BASE;
722         info->fix.mmio_start = mem->start+W100_REG_BASE;
723         info->fix.mmio_len = W100_REG_LEN;
724
725         if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
726                 err = -ENOMEM;
727                 goto out;
728         }
729
730         par->mode = &inf->modelist[0];
731         if(inf->init_mode & INIT_MODE_ROTATED) {
732                 info->var.xres = par->mode->yres;
733                 info->var.yres = par->mode->xres;
734         }
735         else {
736                 info->var.xres = par->mode->xres;
737                 info->var.yres = par->mode->yres;
738         }
739
740         if(inf->init_mode &= INIT_MODE_FLIPPED)
741                 par->flip = 1;
742         else
743                 par->flip = 0;
744
745         info->var.xres_virtual = info->var.xres;
746         info->var.yres_virtual = info->var.yres;
747         info->var.pixclock = 0x04;  /* 171521; */
748         info->var.sync = 0;
749         info->var.grayscale = 0;
750         info->var.xoffset = info->var.yoffset = 0;
751         info->var.accel_flags = 0;
752         info->var.activate = FB_ACTIVATE_NOW;
753
754         w100_hw_init(par);
755
756         if (w100fb_check_var(&info->var, info) < 0) {
757                 err = -EINVAL;
758                 goto out;
759         }
760
761         if (register_framebuffer(info) < 0) {
762                 err = -EINVAL;
763                 goto out;
764         }
765
766         fb_info(info, "%s frame buffer device\n", info->fix.id);
767         return 0;
768 out:
769         if (info) {
770                 fb_dealloc_cmap(&info->cmap);
771                 kfree(info->pseudo_palette);
772         }
773         if (remapped_fbuf != NULL) {
774                 iounmap(remapped_fbuf);
775                 remapped_fbuf = NULL;
776         }
777         if (remapped_regs != NULL) {
778                 iounmap(remapped_regs);
779                 remapped_regs = NULL;
780         }
781         if (remapped_base != NULL) {
782                 iounmap(remapped_base);
783                 remapped_base = NULL;
784         }
785         if (info)
786                 framebuffer_release(info);
787         return err;
788 }
789
790
791 static int w100fb_remove(struct platform_device *pdev)
792 {
793         struct fb_info *info = platform_get_drvdata(pdev);
794         struct w100fb_par *par=info->par;
795
796         unregister_framebuffer(info);
797
798         vfree(par->saved_intmem);
799         vfree(par->saved_extmem);
800         kfree(info->pseudo_palette);
801         fb_dealloc_cmap(&info->cmap);
802
803         iounmap(remapped_base);
804         remapped_base = NULL;
805         iounmap(remapped_regs);
806         remapped_regs = NULL;
807         iounmap(remapped_fbuf);
808         remapped_fbuf = NULL;
809
810         framebuffer_release(info);
811
812         return 0;
813 }
814
815
816 /* ------------------- chipset specific functions -------------------------- */
817
818
819 static void w100_soft_reset(void)
820 {
821         u16 val = readw((u16 __iomem *)remapped_base + cfgSTATUS);
822
823         writew(val | 0x08, (u16 __iomem *)remapped_base + cfgSTATUS);
824         udelay(100);
825         writew(0x00, (u16 __iomem *)remapped_base + cfgSTATUS);
826         udelay(100);
827 }
828
829 static void w100_update_disable(void)
830 {
831         union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl;
832
833         /* Prevent display updates */
834         disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
835         disp_db_buf_wr_cntl.f.update_db_buf = 0;
836         disp_db_buf_wr_cntl.f.en_db_buf = 0;
837         writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
838 }
839
840 static void w100_update_enable(void)
841 {
842         union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl;
843
844         /* Enable display updates */
845         disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
846         disp_db_buf_wr_cntl.f.update_db_buf = 1;
847         disp_db_buf_wr_cntl.f.en_db_buf = 1;
848         writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
849 }
850
851 unsigned long w100fb_gpio_read(int port)
852 {
853         unsigned long value;
854
855         if (port==W100_GPIO_PORT_A)
856                 value = readl(remapped_regs + mmGPIO_DATA);
857         else
858                 value = readl(remapped_regs + mmGPIO_DATA2);
859
860         return value;
861 }
862
863 void w100fb_gpio_write(int port, unsigned long value)
864 {
865         if (port==W100_GPIO_PORT_A)
866                 writel(value, remapped_regs + mmGPIO_DATA);
867         else
868                 writel(value, remapped_regs + mmGPIO_DATA2);
869 }
870 EXPORT_SYMBOL(w100fb_gpio_read);
871 EXPORT_SYMBOL(w100fb_gpio_write);
872
873 /*
874  * Initialization of critical w100 hardware
875  */
876 static void w100_hw_init(struct w100fb_par *par)
877 {
878         u32 temp32;
879         union cif_cntl_u cif_cntl;
880         union intf_cntl_u intf_cntl;
881         union cfgreg_base_u cfgreg_base;
882         union wrap_top_dir_u wrap_top_dir;
883         union cif_read_dbg_u cif_read_dbg;
884         union cpu_defaults_u cpu_default;
885         union cif_write_dbg_u cif_write_dbg;
886         union wrap_start_dir_u wrap_start_dir;
887         union cif_io_u cif_io;
888         struct w100_gpio_regs *gpio = par->mach->gpio;
889
890         w100_soft_reset();
891
892         /* This is what the fpga_init code does on reset. May be wrong
893            but there is little info available */
894         writel(0x31, remapped_regs + mmSCRATCH_UMSK);
895         for (temp32 = 0; temp32 < 10000; temp32++)
896                 readl(remapped_regs + mmSCRATCH_UMSK);
897         writel(0x30, remapped_regs + mmSCRATCH_UMSK);
898
899         /* Set up CIF */
900         cif_io.val = defCIF_IO;
901         writel((u32)(cif_io.val), remapped_regs + mmCIF_IO);
902
903         cif_write_dbg.val = readl(remapped_regs + mmCIF_WRITE_DBG);
904         cif_write_dbg.f.dis_packer_ful_during_rbbm_timeout = 0;
905         cif_write_dbg.f.en_dword_split_to_rbbm = 1;
906         cif_write_dbg.f.dis_timeout_during_rbbm = 1;
907         writel((u32) (cif_write_dbg.val), remapped_regs + mmCIF_WRITE_DBG);
908
909         cif_read_dbg.val = readl(remapped_regs + mmCIF_READ_DBG);
910         cif_read_dbg.f.dis_rd_same_byte_to_trig_fetch = 1;
911         writel((u32) (cif_read_dbg.val), remapped_regs + mmCIF_READ_DBG);
912
913         cif_cntl.val = readl(remapped_regs + mmCIF_CNTL);
914         cif_cntl.f.dis_system_bits = 1;
915         cif_cntl.f.dis_mr = 1;
916         cif_cntl.f.en_wait_to_compensate_dq_prop_dly = 0;
917         cif_cntl.f.intb_oe = 1;
918         cif_cntl.f.interrupt_active_high = 1;
919         writel((u32) (cif_cntl.val), remapped_regs + mmCIF_CNTL);
920
921         /* Setup cfgINTF_CNTL and cfgCPU defaults */
922         intf_cntl.val = defINTF_CNTL;
923         intf_cntl.f.ad_inc_a = 1;
924         intf_cntl.f.ad_inc_b = 1;
925         intf_cntl.f.rd_data_rdy_a = 0;
926         intf_cntl.f.rd_data_rdy_b = 0;
927         writeb((u8) (intf_cntl.val), remapped_base + cfgINTF_CNTL);
928
929         cpu_default.val = defCPU_DEFAULTS;
930         cpu_default.f.access_ind_addr_a = 1;
931         cpu_default.f.access_ind_addr_b = 1;
932         cpu_default.f.access_scratch_reg = 1;
933         cpu_default.f.transition_size = 0;
934         writeb((u8) (cpu_default.val), remapped_base + cfgCPU_DEFAULTS);
935
936         /* set up the apertures */
937         writeb((u8) (W100_REG_BASE >> 16), remapped_base + cfgREG_BASE);
938
939         cfgreg_base.val = defCFGREG_BASE;
940         cfgreg_base.f.cfgreg_base = W100_CFG_BASE;
941         writel((u32) (cfgreg_base.val), remapped_regs + mmCFGREG_BASE);
942
943         wrap_start_dir.val = defWRAP_START_DIR;
944         wrap_start_dir.f.start_addr = WRAP_BUF_BASE_VALUE >> 1;
945         writel((u32) (wrap_start_dir.val), remapped_regs + mmWRAP_START_DIR);
946
947         wrap_top_dir.val = defWRAP_TOP_DIR;
948         wrap_top_dir.f.top_addr = WRAP_BUF_TOP_VALUE >> 1;
949         writel((u32) (wrap_top_dir.val), remapped_regs + mmWRAP_TOP_DIR);
950
951         writel((u32) 0x2440, remapped_regs + mmRBBM_CNTL);
952
953         /* Set the hardware to 565 colour */
954         temp32 = readl(remapped_regs + mmDISP_DEBUG2);
955         temp32 &= 0xff7fffff;
956         temp32 |= 0x00800000;
957         writel(temp32, remapped_regs + mmDISP_DEBUG2);
958
959         /* Initialise the GPIO lines */
960         if (gpio) {
961                 writel(gpio->init_data1, remapped_regs + mmGPIO_DATA);
962                 writel(gpio->init_data2, remapped_regs + mmGPIO_DATA2);
963                 writel(gpio->gpio_dir1,  remapped_regs + mmGPIO_CNTL1);
964                 writel(gpio->gpio_oe1,   remapped_regs + mmGPIO_CNTL2);
965                 writel(gpio->gpio_dir2,  remapped_regs + mmGPIO_CNTL3);
966                 writel(gpio->gpio_oe2,   remapped_regs + mmGPIO_CNTL4);
967         }
968 }
969
970
971 struct power_state {
972         union clk_pin_cntl_u clk_pin_cntl;
973         union pll_ref_fb_div_u pll_ref_fb_div;
974         union pll_cntl_u pll_cntl;
975         union sclk_cntl_u sclk_cntl;
976         union pclk_cntl_u pclk_cntl;
977         union pwrmgt_cntl_u pwrmgt_cntl;
978         int auto_mode;  /* system clock auto changing? */
979 };
980
981
982 static struct power_state w100_pwr_state;
983
984 /* The PLL Fout is determined by (XtalFreq/(M+1)) * ((N_int+1) + (N_fac/8)) */
985
986 /* 12.5MHz Crystal PLL Table */
987 static struct w100_pll_info xtal_12500000[] = {
988         /*freq     M   N_int    N_fac  tfgoal  lock_time */
989         { 50,      0,   1,       0,     0xe0,        56},  /*  50.00 MHz */
990         { 75,      0,   5,       0,     0xde,        37},  /*  75.00 MHz */
991         {100,      0,   7,       0,     0xe0,        28},  /* 100.00 MHz */
992         {125,      0,   9,       0,     0xe0,        22},  /* 125.00 MHz */
993         {150,      0,   11,      0,     0xe0,        17},  /* 150.00 MHz */
994         {  0,      0,   0,       0,        0,         0},  /* Terminator */
995 };
996
997 /* 14.318MHz Crystal PLL Table */
998 static struct w100_pll_info xtal_14318000[] = {
999         /*freq     M   N_int    N_fac  tfgoal  lock_time */
1000         { 40,      4,   13,      0,     0xe0,        80}, /* tfgoal guessed */
1001         { 50,      1,   6,       0,     0xe0,        64}, /*  50.05 MHz */
1002         { 57,      2,   11,      0,     0xe0,        53}, /* tfgoal guessed */
1003         { 75,      0,   4,       3,     0xe0,        43}, /*  75.08 MHz */
1004         {100,      0,   6,       0,     0xe0,        32}, /* 100.10 MHz */
1005         {  0,      0,   0,       0,        0,         0},
1006 };
1007
1008 /* 16MHz Crystal PLL Table */
1009 static struct w100_pll_info xtal_16000000[] = {
1010         /*freq     M   N_int    N_fac  tfgoal  lock_time */
1011         { 72,      1,   8,       0,     0xe0,        48}, /* tfgoal guessed */
1012         { 80,      1,   9,       0,     0xe0,        13}, /* tfgoal guessed */
1013         { 95,      1,   10,      7,     0xe0,        38}, /* tfgoal guessed */
1014         { 96,      1,   11,      0,     0xe0,        36}, /* tfgoal guessed */
1015         {  0,      0,   0,       0,        0,         0},
1016 };
1017
1018 static struct pll_entries {
1019         int xtal_freq;
1020         struct w100_pll_info *pll_table;
1021 } w100_pll_tables[] = {
1022         { 12500000, &xtal_12500000[0] },
1023         { 14318000, &xtal_14318000[0] },
1024         { 16000000, &xtal_16000000[0] },
1025         { 0 },
1026 };
1027
1028 struct w100_pll_info *w100_get_xtal_table(unsigned int freq)
1029 {
1030         struct pll_entries *pll_entry = w100_pll_tables;
1031
1032         do {
1033                 if (freq == pll_entry->xtal_freq)
1034                         return pll_entry->pll_table;
1035                 pll_entry++;
1036         } while (pll_entry->xtal_freq);
1037
1038         return NULL;
1039 }
1040
1041
1042 static unsigned int w100_get_testcount(unsigned int testclk_sel)
1043 {
1044         union clk_test_cntl_u clk_test_cntl;
1045
1046         udelay(5);
1047
1048         /* Select the test clock source and reset */
1049         clk_test_cntl.f.start_check_freq = 0x0;
1050         clk_test_cntl.f.testclk_sel = testclk_sel;
1051         clk_test_cntl.f.tstcount_rst = 0x1; /* set reset */
1052         writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
1053
1054         clk_test_cntl.f.tstcount_rst = 0x0; /* clear reset */
1055         writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
1056
1057         /* Run clock test */
1058         clk_test_cntl.f.start_check_freq = 0x1;
1059         writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
1060
1061         /* Give the test time to complete */
1062         udelay(20);
1063
1064         /* Return the result */
1065         clk_test_cntl.val = readl(remapped_regs + mmCLK_TEST_CNTL);
1066         clk_test_cntl.f.start_check_freq = 0x0;
1067         writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
1068
1069         return clk_test_cntl.f.test_count;
1070 }
1071
1072
1073 static int w100_pll_adjust(struct w100_pll_info *pll)
1074 {
1075         unsigned int tf80;
1076         unsigned int tf20;
1077
1078         /* Initial Settings */
1079         w100_pwr_state.pll_cntl.f.pll_pwdn = 0x0;     /* power down */
1080         w100_pwr_state.pll_cntl.f.pll_reset = 0x0;    /* not reset */
1081         w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x1;   /* Hi-Z */
1082         w100_pwr_state.pll_cntl.f.pll_pvg = 0x0;      /* VCO gain = 0 */
1083         w100_pwr_state.pll_cntl.f.pll_vcofr = 0x0;    /* VCO frequency range control = off */
1084         w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;  /* current offset inside VCO = 0 */
1085         w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0;
1086
1087         /* Wai Ming 80 percent of VDD 1.3V gives 1.04V, minimum operating voltage is 1.08V
1088          * therefore, commented out the following lines
1089          * tf80 meant tf100
1090          */
1091         do {
1092                 /* set VCO input = 0.8 * VDD */
1093                 w100_pwr_state.pll_cntl.f.pll_dactal = 0xd;
1094                 writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
1095
1096                 tf80 = w100_get_testcount(TESTCLK_SRC_PLL);
1097                 if (tf80 >= (pll->tfgoal)) {
1098                         /* set VCO input = 0.2 * VDD */
1099                         w100_pwr_state.pll_cntl.f.pll_dactal = 0x7;
1100                         writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
1101
1102                         tf20 = w100_get_testcount(TESTCLK_SRC_PLL);
1103                         if (tf20 <= (pll->tfgoal))
1104                                 return 1;  /* Success */
1105
1106                         if ((w100_pwr_state.pll_cntl.f.pll_vcofr == 0x0) &&
1107                                 ((w100_pwr_state.pll_cntl.f.pll_pvg == 0x7) ||
1108                                 (w100_pwr_state.pll_cntl.f.pll_ioffset == 0x0))) {
1109                                 /* slow VCO config */
1110                                 w100_pwr_state.pll_cntl.f.pll_vcofr = 0x1;
1111                                 w100_pwr_state.pll_cntl.f.pll_pvg = 0x0;
1112                                 w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
1113                                 continue;
1114                         }
1115                 }
1116                 if ((w100_pwr_state.pll_cntl.f.pll_ioffset) < 0x3) {
1117                         w100_pwr_state.pll_cntl.f.pll_ioffset += 0x1;
1118                 } else if ((w100_pwr_state.pll_cntl.f.pll_pvg) < 0x7) {
1119                         w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
1120                         w100_pwr_state.pll_cntl.f.pll_pvg += 0x1;
1121                 } else {
1122                         return 0;  /* Error */
1123                 }
1124         } while(1);
1125 }
1126
1127
1128 /*
1129  * w100_pll_calibration
1130  */
1131 static int w100_pll_calibration(struct w100_pll_info *pll)
1132 {
1133         int status;
1134
1135         status = w100_pll_adjust(pll);
1136
1137         /* PLL Reset And Lock */
1138         /* set VCO input = 0.5 * VDD */
1139         w100_pwr_state.pll_cntl.f.pll_dactal = 0xa;
1140         writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
1141
1142         udelay(1);  /* reset time */
1143
1144         /* enable charge pump */
1145         w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0;  /* normal */
1146         writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
1147
1148         /* set VCO input = Hi-Z, disable DAC */
1149         w100_pwr_state.pll_cntl.f.pll_dactal = 0x0;
1150         writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
1151
1152         udelay(400);  /* lock time */
1153
1154         /* PLL locked */
1155
1156         return status;
1157 }
1158
1159
1160 static int w100_pll_set_clk(struct w100_pll_info *pll)
1161 {
1162         int status;
1163
1164         if (w100_pwr_state.auto_mode == 1)  /* auto mode */
1165         {
1166                 w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0;  /* disable fast to normal */
1167                 w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0;  /* disable normal to fast */
1168                 writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
1169         }
1170
1171         /* Set system clock source to XTAL whilst adjusting the PLL! */
1172         w100_pwr_state.sclk_cntl.f.sclk_src_sel = CLK_SRC_XTAL;
1173         writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
1174
1175         w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = pll->M;
1176         w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = pll->N_int;
1177         w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = pll->N_fac;
1178         w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = pll->lock_time;
1179         writel((u32) (w100_pwr_state.pll_ref_fb_div.val), remapped_regs + mmPLL_REF_FB_DIV);
1180
1181         w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0;
1182         writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
1183
1184         status = w100_pll_calibration(pll);
1185
1186         if (w100_pwr_state.auto_mode == 1)  /* auto mode */
1187         {
1188                 w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x1;  /* reenable fast to normal */
1189                 w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x1;  /* reenable normal to fast  */
1190                 writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
1191         }
1192         return status;
1193 }
1194
1195 /* freq = target frequency of the PLL */
1196 static int w100_set_pll_freq(struct w100fb_par *par, unsigned int freq)
1197 {
1198         struct w100_pll_info *pll = par->pll_table;
1199
1200         do {
1201                 if (freq == pll->freq) {
1202                         return w100_pll_set_clk(pll);
1203                 }
1204                 pll++;
1205         } while(pll->freq);
1206         return 0;
1207 }
1208
1209 /* Set up an initial state.  Some values/fields set
1210    here will be overwritten. */
1211 static void w100_pwm_setup(struct w100fb_par *par)
1212 {
1213         w100_pwr_state.clk_pin_cntl.f.osc_en = 0x1;
1214         w100_pwr_state.clk_pin_cntl.f.osc_gain = 0x1f;
1215         w100_pwr_state.clk_pin_cntl.f.dont_use_xtalin = 0x0;
1216         w100_pwr_state.clk_pin_cntl.f.xtalin_pm_en = 0x0;
1217         w100_pwr_state.clk_pin_cntl.f.xtalin_dbl_en = par->mach->xtal_dbl ? 1 : 0;
1218         w100_pwr_state.clk_pin_cntl.f.cg_debug = 0x0;
1219         writel((u32) (w100_pwr_state.clk_pin_cntl.val), remapped_regs + mmCLK_PIN_CNTL);
1220
1221         w100_pwr_state.sclk_cntl.f.sclk_src_sel = CLK_SRC_XTAL;
1222         w100_pwr_state.sclk_cntl.f.sclk_post_div_fast = 0x0;  /* Pfast = 1 */
1223         w100_pwr_state.sclk_cntl.f.sclk_clkon_hys = 0x3;
1224         w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = 0x0;  /* Pslow = 1 */
1225         w100_pwr_state.sclk_cntl.f.disp_cg_ok2switch_en = 0x0;
1226         w100_pwr_state.sclk_cntl.f.sclk_force_reg = 0x0;    /* Dynamic */
1227         w100_pwr_state.sclk_cntl.f.sclk_force_disp = 0x0;   /* Dynamic */
1228         w100_pwr_state.sclk_cntl.f.sclk_force_mc = 0x0;     /* Dynamic */
1229         w100_pwr_state.sclk_cntl.f.sclk_force_extmc = 0x0;  /* Dynamic */
1230         w100_pwr_state.sclk_cntl.f.sclk_force_cp = 0x0;     /* Dynamic */
1231         w100_pwr_state.sclk_cntl.f.sclk_force_e2 = 0x0;     /* Dynamic */
1232         w100_pwr_state.sclk_cntl.f.sclk_force_e3 = 0x0;     /* Dynamic */
1233         w100_pwr_state.sclk_cntl.f.sclk_force_idct = 0x0;   /* Dynamic */
1234         w100_pwr_state.sclk_cntl.f.sclk_force_bist = 0x0;   /* Dynamic */
1235         w100_pwr_state.sclk_cntl.f.busy_extend_cp = 0x0;
1236         w100_pwr_state.sclk_cntl.f.busy_extend_e2 = 0x0;
1237         w100_pwr_state.sclk_cntl.f.busy_extend_e3 = 0x0;
1238         w100_pwr_state.sclk_cntl.f.busy_extend_idct = 0x0;
1239         writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
1240
1241         w100_pwr_state.pclk_cntl.f.pclk_src_sel = CLK_SRC_XTAL;
1242         w100_pwr_state.pclk_cntl.f.pclk_post_div = 0x1;    /* P = 2 */
1243         w100_pwr_state.pclk_cntl.f.pclk_force_disp = 0x0;  /* Dynamic */
1244         writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
1245
1246         w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = 0x0;     /* M = 1 */
1247         w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = 0x0;  /* N = 1.0 */
1248         w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = 0x0;
1249         w100_pwr_state.pll_ref_fb_div.f.pll_reset_time = 0x5;
1250         w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = 0xff;
1251         writel((u32) (w100_pwr_state.pll_ref_fb_div.val), remapped_regs + mmPLL_REF_FB_DIV);
1252
1253         w100_pwr_state.pll_cntl.f.pll_pwdn = 0x1;
1254         w100_pwr_state.pll_cntl.f.pll_reset = 0x1;
1255         w100_pwr_state.pll_cntl.f.pll_pm_en = 0x0;
1256         w100_pwr_state.pll_cntl.f.pll_mode = 0x0;  /* uses VCO clock */
1257         w100_pwr_state.pll_cntl.f.pll_refclk_sel = 0x0;
1258         w100_pwr_state.pll_cntl.f.pll_fbclk_sel = 0x0;
1259         w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0;
1260         w100_pwr_state.pll_cntl.f.pll_pcp = 0x4;
1261         w100_pwr_state.pll_cntl.f.pll_pvg = 0x0;
1262         w100_pwr_state.pll_cntl.f.pll_vcofr = 0x0;
1263         w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
1264         w100_pwr_state.pll_cntl.f.pll_pecc_mode = 0x0;
1265         w100_pwr_state.pll_cntl.f.pll_pecc_scon = 0x0;
1266         w100_pwr_state.pll_cntl.f.pll_dactal = 0x0;  /* Hi-Z */
1267         w100_pwr_state.pll_cntl.f.pll_cp_clip = 0x3;
1268         w100_pwr_state.pll_cntl.f.pll_conf = 0x2;
1269         w100_pwr_state.pll_cntl.f.pll_mbctrl = 0x2;
1270         w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0;
1271         writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
1272
1273         w100_pwr_state.pwrmgt_cntl.f.pwm_enable = 0x0;
1274         w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0x1;  /* normal mode (0, 1, 3) */
1275         w100_pwr_state.pwrmgt_cntl.f.pwm_wakeup_cond = 0x0;
1276         w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0;
1277         w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0;
1278         w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_cond = 0x1;  /* PM4,ENG */
1279         w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_cond = 0x1;  /* PM4,ENG */
1280         w100_pwr_state.pwrmgt_cntl.f.pwm_idle_timer = 0xFF;
1281         w100_pwr_state.pwrmgt_cntl.f.pwm_busy_timer = 0xFF;
1282         writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
1283
1284         w100_pwr_state.auto_mode = 0;  /* manual mode */
1285 }
1286
1287
1288 /*
1289  * Setup the w100 clocks for the specified mode
1290  */
1291 static void w100_init_clocks(struct w100fb_par *par)
1292 {
1293         struct w100_mode *mode = par->mode;
1294
1295         if (mode->pixclk_src == CLK_SRC_PLL || mode->sysclk_src == CLK_SRC_PLL)
1296                 w100_set_pll_freq(par, (par->fastpll_mode && mode->fast_pll_freq) ? mode->fast_pll_freq : mode->pll_freq);
1297
1298         w100_pwr_state.sclk_cntl.f.sclk_src_sel = mode->sysclk_src;
1299         w100_pwr_state.sclk_cntl.f.sclk_post_div_fast = mode->sysclk_divider;
1300         w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = mode->sysclk_divider;
1301         writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
1302 }
1303
1304 static void w100_init_lcd(struct w100fb_par *par)
1305 {
1306         u32 temp32;
1307         struct w100_mode *mode = par->mode;
1308         struct w100_gen_regs *regs = par->mach->regs;
1309         union active_h_disp_u active_h_disp;
1310         union active_v_disp_u active_v_disp;
1311         union graphic_h_disp_u graphic_h_disp;
1312         union graphic_v_disp_u graphic_v_disp;
1313         union crtc_total_u crtc_total;
1314
1315         /* w3200 doesn't like undefined bits being set so zero register values first */
1316
1317         active_h_disp.val = 0;
1318         active_h_disp.f.active_h_start=mode->left_margin;
1319         active_h_disp.f.active_h_end=mode->left_margin + mode->xres;
1320         writel(active_h_disp.val, remapped_regs + mmACTIVE_H_DISP);
1321
1322         active_v_disp.val = 0;
1323         active_v_disp.f.active_v_start=mode->upper_margin;
1324         active_v_disp.f.active_v_end=mode->upper_margin + mode->yres;
1325         writel(active_v_disp.val, remapped_regs + mmACTIVE_V_DISP);
1326
1327         graphic_h_disp.val = 0;
1328         graphic_h_disp.f.graphic_h_start=mode->left_margin;
1329         graphic_h_disp.f.graphic_h_end=mode->left_margin + mode->xres;
1330         writel(graphic_h_disp.val, remapped_regs + mmGRAPHIC_H_DISP);
1331
1332         graphic_v_disp.val = 0;
1333         graphic_v_disp.f.graphic_v_start=mode->upper_margin;
1334         graphic_v_disp.f.graphic_v_end=mode->upper_margin + mode->yres;
1335         writel(graphic_v_disp.val, remapped_regs + mmGRAPHIC_V_DISP);
1336
1337         crtc_total.val = 0;
1338         crtc_total.f.crtc_h_total=mode->left_margin  + mode->xres + mode->right_margin;
1339         crtc_total.f.crtc_v_total=mode->upper_margin + mode->yres + mode->lower_margin;
1340         writel(crtc_total.val, remapped_regs + mmCRTC_TOTAL);
1341
1342         writel(mode->crtc_ss, remapped_regs + mmCRTC_SS);
1343         writel(mode->crtc_ls, remapped_regs + mmCRTC_LS);
1344         writel(mode->crtc_gs, remapped_regs + mmCRTC_GS);
1345         writel(mode->crtc_vpos_gs, remapped_regs + mmCRTC_VPOS_GS);
1346         writel(mode->crtc_rev, remapped_regs + mmCRTC_REV);
1347         writel(mode->crtc_dclk, remapped_regs + mmCRTC_DCLK);
1348         writel(mode->crtc_gclk, remapped_regs + mmCRTC_GCLK);
1349         writel(mode->crtc_goe, remapped_regs + mmCRTC_GOE);
1350         writel(mode->crtc_ps1_active, remapped_regs + mmCRTC_PS1_ACTIVE);
1351
1352         writel(regs->lcd_format, remapped_regs + mmLCD_FORMAT);
1353         writel(regs->lcdd_cntl1, remapped_regs + mmLCDD_CNTL1);
1354         writel(regs->lcdd_cntl2, remapped_regs + mmLCDD_CNTL2);
1355         writel(regs->genlcd_cntl1, remapped_regs + mmGENLCD_CNTL1);
1356         writel(regs->genlcd_cntl2, remapped_regs + mmGENLCD_CNTL2);
1357         writel(regs->genlcd_cntl3, remapped_regs + mmGENLCD_CNTL3);
1358
1359         writel(0x00000000, remapped_regs + mmCRTC_FRAME);
1360         writel(0x00000000, remapped_regs + mmCRTC_FRAME_VPOS);
1361         writel(0x00000000, remapped_regs + mmCRTC_DEFAULT_COUNT);
1362         writel(0x0000FF00, remapped_regs + mmLCD_BACKGROUND_COLOR);
1363
1364         /* Hack for overlay in ext memory */
1365         temp32 = readl(remapped_regs + mmDISP_DEBUG2);
1366         temp32 |= 0xc0000000;
1367         writel(temp32, remapped_regs + mmDISP_DEBUG2);
1368 }
1369
1370
1371 static void w100_setup_memory(struct w100fb_par *par)
1372 {
1373         union mc_ext_mem_location_u extmem_location;
1374         union mc_fb_location_u intmem_location;
1375         struct w100_mem_info *mem = par->mach->mem;
1376         struct w100_bm_mem_info *bm_mem = par->mach->bm_mem;
1377
1378         if (!par->extmem_active) {
1379                 w100_suspend(W100_SUSPEND_EXTMEM);
1380
1381                 /* Map Internal Memory at FB Base */
1382                 intmem_location.f.mc_fb_start = W100_FB_BASE >> 8;
1383                 intmem_location.f.mc_fb_top = (W100_FB_BASE+MEM_INT_SIZE) >> 8;
1384                 writel((u32) (intmem_location.val), remapped_regs + mmMC_FB_LOCATION);
1385
1386                 /* Unmap External Memory - value is *probably* irrelevant but may have meaning
1387                    to acceleration libraries */
1388                 extmem_location.f.mc_ext_mem_start = MEM_EXT_BASE_VALUE >> 8;
1389                 extmem_location.f.mc_ext_mem_top = (MEM_EXT_BASE_VALUE-1) >> 8;
1390                 writel((u32) (extmem_location.val), remapped_regs + mmMC_EXT_MEM_LOCATION);
1391         } else {
1392                 /* Map Internal Memory to its default location */
1393                 intmem_location.f.mc_fb_start = MEM_INT_BASE_VALUE >> 8;
1394                 intmem_location.f.mc_fb_top = (MEM_INT_BASE_VALUE+MEM_INT_SIZE) >> 8;
1395                 writel((u32) (intmem_location.val), remapped_regs + mmMC_FB_LOCATION);
1396
1397                 /* Map External Memory at FB Base */
1398                 extmem_location.f.mc_ext_mem_start = W100_FB_BASE >> 8;
1399                 extmem_location.f.mc_ext_mem_top = (W100_FB_BASE+par->mach->mem->size) >> 8;
1400                 writel((u32) (extmem_location.val), remapped_regs + mmMC_EXT_MEM_LOCATION);
1401
1402                 writel(0x00007800, remapped_regs + mmMC_BIST_CTRL);
1403                 writel(mem->ext_cntl, remapped_regs + mmMEM_EXT_CNTL);
1404                 writel(0x00200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
1405                 udelay(100);
1406                 writel(0x80200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
1407                 udelay(100);
1408                 writel(mem->sdram_mode_reg, remapped_regs + mmMEM_SDRAM_MODE_REG);
1409                 udelay(100);
1410                 writel(mem->ext_timing_cntl, remapped_regs + mmMEM_EXT_TIMING_CNTL);
1411                 writel(mem->io_cntl, remapped_regs + mmMEM_IO_CNTL);
1412                 if (bm_mem) {
1413                         writel(bm_mem->ext_mem_bw, remapped_regs + mmBM_EXT_MEM_BANDWIDTH);
1414                         writel(bm_mem->offset, remapped_regs + mmBM_OFFSET);
1415                         writel(bm_mem->ext_timing_ctl, remapped_regs + mmBM_MEM_EXT_TIMING_CNTL);
1416                         writel(bm_mem->ext_cntl, remapped_regs + mmBM_MEM_EXT_CNTL);
1417                         writel(bm_mem->mode_reg, remapped_regs + mmBM_MEM_MODE_REG);
1418                         writel(bm_mem->io_cntl, remapped_regs + mmBM_MEM_IO_CNTL);
1419                         writel(bm_mem->config, remapped_regs + mmBM_CONFIG);
1420                 }
1421         }
1422 }
1423
1424 static void w100_set_dispregs(struct w100fb_par *par)
1425 {
1426         unsigned long rot=0, divider, offset=0;
1427         union graphic_ctrl_u graphic_ctrl;
1428
1429         /* See if the mode has been rotated */
1430         if (par->xres == par->mode->xres) {
1431                 if (par->flip) {
1432                         rot=3; /* 180 degree */
1433                         offset=(par->xres * par->yres) - 1;
1434                 } /* else 0 degree */
1435                 divider = par->mode->pixclk_divider;
1436         } else {
1437                 if (par->flip) {
1438                         rot=2; /* 270 degree */
1439                         offset=par->xres - 1;
1440                 } else {
1441                         rot=1; /* 90 degree */
1442                         offset=par->xres * (par->yres - 1);
1443                 }
1444                 divider = par->mode->pixclk_divider_rotated;
1445         }
1446
1447         graphic_ctrl.val = 0; /* w32xx doesn't like undefined bits */
1448         switch (par->chip_id) {
1449                 case CHIP_ID_W100:
1450                         graphic_ctrl.f_w100.color_depth=6;
1451                         graphic_ctrl.f_w100.en_crtc=1;
1452                         graphic_ctrl.f_w100.en_graphic_req=1;
1453                         graphic_ctrl.f_w100.en_graphic_crtc=1;
1454                         graphic_ctrl.f_w100.lcd_pclk_on=1;
1455                         graphic_ctrl.f_w100.lcd_sclk_on=1;
1456                         graphic_ctrl.f_w100.low_power_on=0;
1457                         graphic_ctrl.f_w100.req_freq=0;
1458                         graphic_ctrl.f_w100.portrait_mode=rot;
1459
1460                         /* Zaurus needs this */
1461                         switch(par->xres) {
1462                                 case 240:
1463                                 case 320:
1464                                 default:
1465                                         graphic_ctrl.f_w100.total_req_graphic=0xa0;
1466                                         break;
1467                                 case 480:
1468                                 case 640:
1469                                         switch(rot) {
1470                                                 case 0:  /* 0 */
1471                                                 case 3:  /* 180 */
1472                                                         graphic_ctrl.f_w100.low_power_on=1;
1473                                                         graphic_ctrl.f_w100.req_freq=5;
1474                                                 break;
1475                                                 case 1:  /* 90 */
1476                                                 case 2:  /* 270 */
1477                                                         graphic_ctrl.f_w100.req_freq=4;
1478                                                         break;
1479                                                 default:
1480                                                         break;
1481                                         }
1482                                         graphic_ctrl.f_w100.total_req_graphic=0xf0;
1483                                         break;
1484                         }
1485                         break;
1486                 case CHIP_ID_W3200:
1487                 case CHIP_ID_W3220:
1488                         graphic_ctrl.f_w32xx.color_depth=6;
1489                         graphic_ctrl.f_w32xx.en_crtc=1;
1490                         graphic_ctrl.f_w32xx.en_graphic_req=1;
1491                         graphic_ctrl.f_w32xx.en_graphic_crtc=1;
1492                         graphic_ctrl.f_w32xx.lcd_pclk_on=1;
1493                         graphic_ctrl.f_w32xx.lcd_sclk_on=1;
1494                         graphic_ctrl.f_w32xx.low_power_on=0;
1495                         graphic_ctrl.f_w32xx.req_freq=0;
1496                         graphic_ctrl.f_w32xx.total_req_graphic=par->mode->xres >> 1; /* panel xres, not mode */
1497                         graphic_ctrl.f_w32xx.portrait_mode=rot;
1498                         break;
1499         }
1500
1501         /* Set the pixel clock source and divider */
1502         w100_pwr_state.pclk_cntl.f.pclk_src_sel = par->mode->pixclk_src;
1503         w100_pwr_state.pclk_cntl.f.pclk_post_div = divider;
1504         writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
1505
1506         writel(graphic_ctrl.val, remapped_regs + mmGRAPHIC_CTRL);
1507         writel(W100_FB_BASE + ((offset * BITS_PER_PIXEL/8)&~0x03UL), remapped_regs + mmGRAPHIC_OFFSET);
1508         writel((par->xres*BITS_PER_PIXEL/8), remapped_regs + mmGRAPHIC_PITCH);
1509 }
1510
1511
1512 /*
1513  * Work out how long the sync pulse lasts
1514  * Value is 1/(time in seconds)
1515  */
1516 static void calc_hsync(struct w100fb_par *par)
1517 {
1518         unsigned long hsync;
1519         struct w100_mode *mode = par->mode;
1520         union crtc_ss_u crtc_ss;
1521
1522         if (mode->pixclk_src == CLK_SRC_XTAL)
1523                 hsync=par->mach->xtal_freq;
1524         else
1525                 hsync=((par->fastpll_mode && mode->fast_pll_freq) ? mode->fast_pll_freq : mode->pll_freq)*100000;
1526
1527         hsync /= (w100_pwr_state.pclk_cntl.f.pclk_post_div + 1);
1528
1529         crtc_ss.val = readl(remapped_regs + mmCRTC_SS);
1530         if (crtc_ss.val)
1531                 par->hsync_len = hsync / (crtc_ss.f.ss_end-crtc_ss.f.ss_start);
1532         else
1533                 par->hsync_len = 0;
1534 }
1535
1536 static void w100_suspend(u32 mode)
1537 {
1538         u32 val;
1539
1540         writel(0x7FFF8000, remapped_regs + mmMC_EXT_MEM_LOCATION);
1541         writel(0x00FF0000, remapped_regs + mmMC_PERF_MON_CNTL);
1542
1543         val = readl(remapped_regs + mmMEM_EXT_TIMING_CNTL);
1544         val &= ~(0x00100000);  /* bit20=0 */
1545         val |= 0xFF000000;     /* bit31:24=0xff */
1546         writel(val, remapped_regs + mmMEM_EXT_TIMING_CNTL);
1547
1548         val = readl(remapped_regs + mmMEM_EXT_CNTL);
1549         val &= ~(0x00040000);  /* bit18=0 */
1550         val |= 0x00080000;     /* bit19=1 */
1551         writel(val, remapped_regs + mmMEM_EXT_CNTL);
1552
1553         udelay(1);  /* wait 1us */
1554
1555         if (mode == W100_SUSPEND_EXTMEM) {
1556                 /* CKE: Tri-State */
1557                 val = readl(remapped_regs + mmMEM_EXT_CNTL);
1558                 val |= 0x40000000;  /* bit30=1 */
1559                 writel(val, remapped_regs + mmMEM_EXT_CNTL);
1560
1561                 /* CLK: Stop */
1562                 val = readl(remapped_regs + mmMEM_EXT_CNTL);
1563                 val &= ~(0x00000001);  /* bit0=0 */
1564                 writel(val, remapped_regs + mmMEM_EXT_CNTL);
1565         } else {
1566                 writel(0x00000000, remapped_regs + mmSCLK_CNTL);
1567                 writel(0x000000BF, remapped_regs + mmCLK_PIN_CNTL);
1568                 writel(0x00000015, remapped_regs + mmPWRMGT_CNTL);
1569
1570                 udelay(5);
1571
1572                 val = readl(remapped_regs + mmPLL_CNTL);
1573                 val |= 0x00000004;  /* bit2=1 */
1574                 writel(val, remapped_regs + mmPLL_CNTL);
1575
1576                 writel(0x00000000, remapped_regs + mmLCDD_CNTL1);
1577                 writel(0x00000000, remapped_regs + mmLCDD_CNTL2);
1578                 writel(0x00000000, remapped_regs + mmGENLCD_CNTL1);
1579                 writel(0x00000000, remapped_regs + mmGENLCD_CNTL2);
1580                 writel(0x00000000, remapped_regs + mmGENLCD_CNTL3);
1581
1582                 val = readl(remapped_regs + mmMEM_EXT_CNTL);
1583                 val |= 0xF0000000;
1584                 val &= ~(0x00000001);
1585                 writel(val, remapped_regs + mmMEM_EXT_CNTL);
1586
1587                 writel(0x0000001d, remapped_regs + mmPWRMGT_CNTL);
1588         }
1589 }
1590
1591 static void w100_vsync(void)
1592 {
1593         u32 tmp;
1594         int timeout = 30000;  /* VSync timeout = 30[ms] > 16.8[ms] */
1595
1596         tmp = readl(remapped_regs + mmACTIVE_V_DISP);
1597
1598         /* set vline pos  */
1599         writel((tmp >> 16) & 0x3ff, remapped_regs + mmDISP_INT_CNTL);
1600
1601         /* disable vline irq */
1602         tmp = readl(remapped_regs + mmGEN_INT_CNTL);
1603
1604         tmp &= ~0x00000002;
1605         writel(tmp, remapped_regs + mmGEN_INT_CNTL);
1606
1607         /* clear vline irq status */
1608         writel(0x00000002, remapped_regs + mmGEN_INT_STATUS);
1609
1610         /* enable vline irq */
1611         writel((tmp | 0x00000002), remapped_regs + mmGEN_INT_CNTL);
1612
1613         /* clear vline irq status */
1614         writel(0x00000002, remapped_regs + mmGEN_INT_STATUS);
1615
1616         while(timeout > 0) {
1617                 if (readl(remapped_regs + mmGEN_INT_STATUS) & 0x00000002)
1618                         break;
1619                 udelay(1);
1620                 timeout--;
1621         }
1622
1623         /* disable vline irq */
1624         writel(tmp, remapped_regs + mmGEN_INT_CNTL);
1625
1626         /* clear vline irq status */
1627         writel(0x00000002, remapped_regs + mmGEN_INT_STATUS);
1628 }
1629
1630 static struct platform_driver w100fb_driver = {
1631         .probe          = w100fb_probe,
1632         .remove         = w100fb_remove,
1633         .suspend        = w100fb_suspend,
1634         .resume         = w100fb_resume,
1635         .driver         = {
1636                 .name   = "w100fb",
1637                 .dev_groups     = w100fb_groups,
1638         },
1639 };
1640
1641 module_platform_driver(w100fb_driver);
1642
1643 MODULE_DESCRIPTION("ATI Imageon w100 framebuffer driver");
1644 MODULE_LICENSE("GPL");