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