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