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 */
flip_show(struct device * dev,struct device_attribute * attr,char * buf)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
flip_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)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
w100fb_reg_read(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)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
w100fb_reg_write(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)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", ®s, ¶m);
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
fastpllclk_show(struct device * dev,struct device_attribute * attr,char * buf)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
fastpllclk_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)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 */
w100fb_get_hsynclen(struct device * dev)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
w100fb_clear_screen(struct w100fb_par * par)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 */
w100fb_setcolreg(u_int regno,u_int red,u_int green,u_int blue,u_int trans,struct fb_info * info)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 */
w100fb_blank(int blank_mode,struct fb_info * info)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
w100_fifo_wait(int entries)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
w100fb_sync(struct fb_info * info)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
w100_init_graphic_engine(struct w100fb_par * par)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
w100fb_fillrect(struct fb_info * info,const struct fb_fillrect * rect)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
w100fb_copyarea(struct fb_info * info,const struct fb_copyarea * area)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 */
w100fb_activate_var(struct w100fb_par * par)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 */
w100fb_get_mode(struct w100fb_par * par,unsigned int * x,unsigned int * y,int saveval)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 */
w100fb_check_var(struct fb_var_screeninfo * var,struct fb_info * info)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 */
w100fb_set_par(struct fb_info * info)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
w100fb_save_vidmem(struct w100fb_par * par)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
w100fb_restore_vidmem(struct w100fb_par * par)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
w100fb_suspend(struct platform_device * dev,pm_message_t state)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
w100fb_resume(struct platform_device * dev)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
w100fb_probe(struct platform_device * pdev)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
w100fb_remove(struct platform_device * pdev)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
w100_soft_reset(void)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
w100_update_disable(void)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
w100_update_enable(void)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
w100fb_gpio_read(int port)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
w100fb_gpio_write(int port,unsigned long value)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 */
w100_hw_init(struct w100fb_par * par)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
w100_get_xtal_table(unsigned int freq)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
w100_get_testcount(unsigned int testclk_sel)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
w100_pll_adjust(struct w100_pll_info * pll)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 */
w100_pll_calibration(struct w100_pll_info * pll)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
w100_pll_set_clk(struct w100_pll_info * pll)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 */
w100_set_pll_freq(struct w100fb_par * par,unsigned int freq)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. */
w100_pwm_setup(struct w100fb_par * par)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 */
w100_init_clocks(struct w100fb_par * par)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
w100_init_lcd(struct w100fb_par * par)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
w100_setup_memory(struct w100fb_par * par)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
w100_set_dispregs(struct w100fb_par * par)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 */
calc_hsync(struct w100fb_par * par)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
w100_suspend(u32 mode)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
w100_vsync(void)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");
1645