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