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