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