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