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