2 * linux/drivers/video/w100fb.c
4 * Frame Buffer Device for ATI Imageon w100 (Wallaby)
6 * Copyright (C) 2002, ATI Corp.
7 * Copyright (C) 2004-2006 Richard Purdie
8 * Copyright (c) 2005 Ian Molton
9 * Copyright (c) 2006 Alberto Mardegan
11 * Rewritten for 2.6 by Richard Purdie <rpurdie@rpsys.net>
13 * Generic platform support by Ian Molton <spyro@f2s.com>
14 * and Richard Purdie <rpurdie@rpsys.net>
16 * w32xx support by Ian Molton
18 * Hardware acceleration support by Alberto Mardegan
19 * <mardy@users.sourceforge.net>
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License version 2 as
23 * published by the Free Software Foundation.
27 #include <linux/delay.h>
29 #include <linux/init.h>
30 #include <linux/kernel.h>
32 #include <linux/platform_device.h>
33 #include <linux/string.h>
34 #include <linux/vmalloc.h>
36 #include <asm/uaccess.h>
37 #include <video/w100fb.h>
43 static void w100_suspend(u32 mode);
44 static void w100_vsync(void);
45 static void w100_hw_init(struct w100fb_par*);
46 static void w100_pwm_setup(struct w100fb_par*);
47 static void w100_init_clocks(struct w100fb_par*);
48 static void w100_setup_memory(struct w100fb_par*);
49 static void w100_init_lcd(struct w100fb_par*);
50 static void w100_set_dispregs(struct w100fb_par*);
51 static void w100_update_enable(void);
52 static void w100_update_disable(void);
53 static void calc_hsync(struct w100fb_par *par);
54 static void w100_init_graphic_engine(struct w100fb_par *par);
55 struct w100_pll_info *w100_get_xtal_table(unsigned int freq);
57 /* Pseudo palette size */
58 #define MAX_PALETTES 16
60 #define W100_SUSPEND_EXTMEM 0
61 #define W100_SUSPEND_ALL 1
63 #define BITS_PER_PIXEL 16
65 /* Remapped addresses for base cfg, memmapped regs and the frame buffer itself */
66 static void *remapped_base;
67 static void *remapped_regs;
68 static void *remapped_fbuf;
70 #define REMAPPED_FB_LEN 0x15ffff
72 /* This is the offset in the w100's address space we map the current
73 framebuffer memory to. We use the position of external memory as
74 we can remap internal memory to there if external isn't present. */
75 #define W100_FB_BASE MEM_EXT_BASE_VALUE
81 static ssize_t flip_show(struct device *dev, struct device_attribute *attr, char *buf)
83 struct fb_info *info = dev_get_drvdata(dev);
84 struct w100fb_par *par=info->par;
86 return sprintf(buf, "%d\n",par->flip);
89 static ssize_t flip_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
92 struct fb_info *info = dev_get_drvdata(dev);
93 struct w100fb_par *par=info->par;
95 flip = simple_strtoul(buf, NULL, 10);
102 w100_update_disable();
103 w100_set_dispregs(par);
104 w100_update_enable();
111 static DEVICE_ATTR(flip, 0644, flip_show, flip_store);
113 static ssize_t w100fb_reg_read(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
115 unsigned long regs, param;
116 regs = simple_strtoul(buf, NULL, 16);
117 param = readl(remapped_regs + regs);
118 printk("Read Register 0x%08lX: 0x%08lX\n", regs, param);
122 static DEVICE_ATTR(reg_read, 0200, NULL, w100fb_reg_read);
124 static ssize_t w100fb_reg_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
126 unsigned long regs, param;
127 sscanf(buf, "%lx %lx", ®s, ¶m);
129 if (regs <= 0x2000) {
130 printk("Write Register 0x%08lX: 0x%08lX\n", regs, param);
131 writel(param, remapped_regs + regs);
137 static DEVICE_ATTR(reg_write, 0200, NULL, w100fb_reg_write);
140 static ssize_t fastpllclk_show(struct device *dev, struct device_attribute *attr, char *buf)
142 struct fb_info *info = dev_get_drvdata(dev);
143 struct w100fb_par *par=info->par;
145 return sprintf(buf, "%d\n",par->fastpll_mode);
148 static ssize_t fastpllclk_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
150 struct fb_info *info = dev_get_drvdata(dev);
151 struct w100fb_par *par=info->par;
153 if (simple_strtoul(buf, NULL, 10) > 0) {
155 printk("w100fb: Using fast system clock (if possible)\n");
158 printk("w100fb: Using normal system clock\n");
161 w100_init_clocks(par);
167 static DEVICE_ATTR(fastpllclk, 0644, fastpllclk_show, fastpllclk_store);
170 * Some touchscreens need hsync information from the video driver to
171 * function correctly. We export it here.
173 unsigned long w100fb_get_hsynclen(struct device *dev)
175 struct fb_info *info = dev_get_drvdata(dev);
176 struct w100fb_par *par=info->par;
178 /* If display is blanked/suspended, hsync isn't active */
182 return par->hsync_len;
184 EXPORT_SYMBOL(w100fb_get_hsynclen);
186 static void w100fb_clear_screen(struct w100fb_par *par)
188 memset_io(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), 0, (par->xres * par->yres * BITS_PER_PIXEL/8));
193 * Set a palette value from rgb components
195 static int w100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
196 u_int trans, struct fb_info *info)
202 * If greyscale is true, then we convert the RGB value
203 * to greyscale no matter what visual we are using.
205 if (info->var.grayscale)
206 red = green = blue = (19595 * red + 38470 * green + 7471 * blue) >> 16;
209 * 16-bit True Colour. We encode the RGB value
210 * according to the RGB bitfield information.
212 if (regno < MAX_PALETTES) {
213 u32 *pal = info->pseudo_palette;
215 val = (red & 0xf800) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
224 * Blank the display based on value in blank_mode
226 static int w100fb_blank(int blank_mode, struct fb_info *info)
228 struct w100fb_par *par = info->par;
229 struct w100_tg_info *tg = par->mach->tg;
233 case FB_BLANK_NORMAL: /* Normal blanking */
234 case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
235 case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
236 case FB_BLANK_POWERDOWN: /* Poweroff */
237 if (par->blanked == 0) {
238 if(tg && tg->suspend)
244 case FB_BLANK_UNBLANK: /* Unblanking */
245 if (par->blanked != 0) {
256 static void w100_fifo_wait(int entries)
258 union rbbm_status_u status;
261 for (i = 0; i < 2000000; i++) {
262 status.val = readl(remapped_regs + mmRBBM_STATUS);
263 if (status.f.cmdfifo_avail >= entries)
267 printk(KERN_ERR "w100fb: FIFO Timeout!\n");
271 static int w100fb_sync(struct fb_info *info)
273 union rbbm_status_u status;
276 for (i = 0; i < 2000000; i++) {
277 status.val = readl(remapped_regs + mmRBBM_STATUS);
278 if (!status.f.gui_active)
282 printk(KERN_ERR "w100fb: Graphic engine timeout!\n");
287 static void w100_init_graphic_engine(struct w100fb_par *par)
289 union dp_gui_master_cntl_u gmc;
290 union dp_mix_u dp_mix;
291 union dp_datatype_u dp_datatype;
292 union dp_cntl_u dp_cntl;
295 writel(W100_FB_BASE, remapped_regs + mmDST_OFFSET);
296 writel(par->xres, remapped_regs + mmDST_PITCH);
297 writel(W100_FB_BASE, remapped_regs + mmSRC_OFFSET);
298 writel(par->xres, remapped_regs + mmSRC_PITCH);
301 writel(0, remapped_regs + mmSC_TOP_LEFT);
302 writel((par->yres << 16) | par->xres, remapped_regs + mmSC_BOTTOM_RIGHT);
303 writel(0x1fff1fff, remapped_regs + mmSRC_SC_BOTTOM_RIGHT);
307 dp_cntl.f.dst_x_dir = 1;
308 dp_cntl.f.dst_y_dir = 1;
309 dp_cntl.f.src_x_dir = 1;
310 dp_cntl.f.src_y_dir = 1;
311 dp_cntl.f.dst_major_x = 1;
312 dp_cntl.f.src_major_x = 1;
313 writel(dp_cntl.val, remapped_regs + mmDP_CNTL);
316 gmc.f.gmc_src_pitch_offset_cntl = 1;
317 gmc.f.gmc_dst_pitch_offset_cntl = 1;
318 gmc.f.gmc_src_clipping = 1;
319 gmc.f.gmc_dst_clipping = 1;
320 gmc.f.gmc_brush_datatype = GMC_BRUSH_NONE;
321 gmc.f.gmc_dst_datatype = 3; /* from DstType_16Bpp_444 */
322 gmc.f.gmc_src_datatype = SRC_DATATYPE_EQU_DST;
323 gmc.f.gmc_byte_pix_order = 1;
324 gmc.f.gmc_default_sel = 0;
325 gmc.f.gmc_rop3 = ROP3_SRCCOPY;
326 gmc.f.gmc_dp_src_source = DP_SRC_MEM_RECTANGULAR;
327 gmc.f.gmc_clr_cmp_fcn_dis = 1;
328 gmc.f.gmc_wr_msk_dis = 1;
329 gmc.f.gmc_dp_op = DP_OP_ROP;
330 writel(gmc.val, remapped_regs + mmDP_GUI_MASTER_CNTL);
332 dp_datatype.val = dp_mix.val = 0;
333 dp_datatype.f.dp_dst_datatype = gmc.f.gmc_dst_datatype;
334 dp_datatype.f.dp_brush_datatype = gmc.f.gmc_brush_datatype;
335 dp_datatype.f.dp_src2_type = 0;
336 dp_datatype.f.dp_src2_datatype = gmc.f.gmc_src_datatype;
337 dp_datatype.f.dp_src_datatype = gmc.f.gmc_src_datatype;
338 dp_datatype.f.dp_byte_pix_order = gmc.f.gmc_byte_pix_order;
339 writel(dp_datatype.val, remapped_regs + mmDP_DATATYPE);
341 dp_mix.f.dp_src_source = gmc.f.gmc_dp_src_source;
342 dp_mix.f.dp_src2_source = 1;
343 dp_mix.f.dp_rop3 = gmc.f.gmc_rop3;
344 dp_mix.f.dp_op = gmc.f.gmc_dp_op;
345 writel(dp_mix.val, remapped_regs + mmDP_MIX);
349 static void w100fb_fillrect(struct fb_info *info,
350 const struct fb_fillrect *rect)
352 union dp_gui_master_cntl_u gmc;
354 if (info->state != FBINFO_STATE_RUNNING)
356 if (info->flags & FBINFO_HWACCEL_DISABLED) {
357 cfb_fillrect(info, rect);
361 gmc.val = readl(remapped_regs + mmDP_GUI_MASTER_CNTL);
362 gmc.f.gmc_rop3 = ROP3_PATCOPY;
363 gmc.f.gmc_brush_datatype = GMC_BRUSH_SOLID_COLOR;
365 writel(gmc.val, remapped_regs + mmDP_GUI_MASTER_CNTL);
366 writel(rect->color, remapped_regs + mmDP_BRUSH_FRGD_CLR);
369 writel((rect->dy << 16) | (rect->dx & 0xffff), remapped_regs + mmDST_Y_X);
370 writel((rect->width << 16) | (rect->height & 0xffff),
371 remapped_regs + mmDST_WIDTH_HEIGHT);
375 static void w100fb_copyarea(struct fb_info *info,
376 const struct fb_copyarea *area)
378 u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
379 u32 h = area->height, w = area->width;
380 union dp_gui_master_cntl_u gmc;
382 if (info->state != FBINFO_STATE_RUNNING)
384 if (info->flags & FBINFO_HWACCEL_DISABLED) {
385 cfb_copyarea(info, area);
389 gmc.val = readl(remapped_regs + mmDP_GUI_MASTER_CNTL);
390 gmc.f.gmc_rop3 = ROP3_SRCCOPY;
391 gmc.f.gmc_brush_datatype = GMC_BRUSH_NONE;
393 writel(gmc.val, remapped_regs + mmDP_GUI_MASTER_CNTL);
396 writel((sy << 16) | (sx & 0xffff), remapped_regs + mmSRC_Y_X);
397 writel((dy << 16) | (dx & 0xffff), remapped_regs + mmDST_Y_X);
398 writel((w << 16) | (h & 0xffff), remapped_regs + mmDST_WIDTH_HEIGHT);
403 * Change the resolution by calling the appropriate hardware functions
405 static void w100fb_activate_var(struct w100fb_par *par)
407 struct w100_tg_info *tg = par->mach->tg;
410 w100_setup_memory(par);
411 w100_init_clocks(par);
412 w100fb_clear_screen(par);
415 w100_update_disable();
417 w100_set_dispregs(par);
418 w100_update_enable();
419 w100_init_graphic_engine(par);
423 if (!par->blanked && tg && tg->change)
428 /* Select the smallest mode that allows the desired resolution to be
429 * displayed. If desired, the x and y parameters can be rounded up to
430 * match the selected mode.
432 static struct w100_mode *w100fb_get_mode(struct w100fb_par *par, unsigned int *x, unsigned int *y, int saveval)
434 struct w100_mode *mode = NULL;
435 struct w100_mode *modelist = par->mach->modelist;
436 unsigned int best_x = 0xffffffff, best_y = 0xffffffff;
439 for (i = 0 ; i < par->mach->num_modes ; i++) {
440 if (modelist[i].xres >= *x && modelist[i].yres >= *y &&
441 modelist[i].xres < best_x && modelist[i].yres < best_y) {
442 best_x = modelist[i].xres;
443 best_y = modelist[i].yres;
445 } else if(modelist[i].xres >= *y && modelist[i].yres >= *x &&
446 modelist[i].xres < best_y && modelist[i].yres < best_x) {
447 best_x = modelist[i].yres;
448 best_y = modelist[i].xres;
453 if (mode && saveval) {
463 * w100fb_check_var():
464 * Get the video params out of 'var'. If a value doesn't fit, round it up,
465 * if it's too big, return -EINVAL.
467 static int w100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
469 struct w100fb_par *par=info->par;
471 if(!w100fb_get_mode(par, &var->xres, &var->yres, 1))
474 if (par->mach->mem && ((var->xres*var->yres*BITS_PER_PIXEL/8) > (par->mach->mem->size+1)))
477 if (!par->mach->mem && ((var->xres*var->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1)))
480 var->xres_virtual = max(var->xres_virtual, var->xres);
481 var->yres_virtual = max(var->yres_virtual, var->yres);
483 if (var->bits_per_pixel > BITS_PER_PIXEL)
486 var->bits_per_pixel = BITS_PER_PIXEL;
488 var->red.offset = 11;
490 var->green.offset = 5;
491 var->green.length = 6;
492 var->blue.offset = 0;
493 var->blue.length = 5;
494 var->transp.offset = var->transp.length = 0;
499 var->vmode = FB_VMODE_NONINTERLACED;
501 var->pixclock = 0x04; /* 171521; */
509 * Set the user defined part of the display for the specified console
510 * by looking at the values in info.var
512 static int w100fb_set_par(struct fb_info *info)
514 struct w100fb_par *par=info->par;
516 if (par->xres != info->var.xres || par->yres != info->var.yres) {
517 par->xres = info->var.xres;
518 par->yres = info->var.yres;
519 par->mode = w100fb_get_mode(par, &par->xres, &par->yres, 0);
521 info->fix.visual = FB_VISUAL_TRUECOLOR;
522 info->fix.ypanstep = 0;
523 info->fix.ywrapstep = 0;
524 info->fix.line_length = par->xres * BITS_PER_PIXEL / 8;
526 mutex_lock(&info->mm_lock);
527 if ((par->xres*par->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1)) {
528 par->extmem_active = 1;
529 info->fix.smem_len = par->mach->mem->size+1;
531 par->extmem_active = 0;
532 info->fix.smem_len = MEM_INT_SIZE+1;
534 mutex_unlock(&info->mm_lock);
536 w100fb_activate_var(par);
543 * Frame buffer operations
545 static struct fb_ops w100fb_ops = {
546 .owner = THIS_MODULE,
547 .fb_check_var = w100fb_check_var,
548 .fb_set_par = w100fb_set_par,
549 .fb_setcolreg = w100fb_setcolreg,
550 .fb_blank = w100fb_blank,
551 .fb_fillrect = w100fb_fillrect,
552 .fb_copyarea = w100fb_copyarea,
553 .fb_imageblit = cfb_imageblit,
554 .fb_sync = w100fb_sync,
558 static void w100fb_save_vidmem(struct w100fb_par *par)
562 if (par->extmem_active) {
563 memsize=par->mach->mem->size;
564 par->saved_extmem = vmalloc(memsize);
565 if (par->saved_extmem)
566 memcpy_fromio(par->saved_extmem, remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), memsize);
568 memsize=MEM_INT_SIZE;
569 par->saved_intmem = vmalloc(memsize);
570 if (par->saved_intmem && par->extmem_active)
571 memcpy_fromio(par->saved_intmem, remapped_fbuf + (W100_FB_BASE-MEM_INT_BASE_VALUE), memsize);
572 else if (par->saved_intmem)
573 memcpy_fromio(par->saved_intmem, remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), memsize);
576 static void w100fb_restore_vidmem(struct w100fb_par *par)
580 if (par->extmem_active && par->saved_extmem) {
581 memsize=par->mach->mem->size;
582 memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_extmem, memsize);
583 vfree(par->saved_extmem);
585 if (par->saved_intmem) {
586 memsize=MEM_INT_SIZE;
587 if (par->extmem_active)
588 memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_INT_BASE_VALUE), par->saved_intmem, memsize);
590 memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_intmem, memsize);
591 vfree(par->saved_intmem);
595 static int w100fb_suspend(struct platform_device *dev, pm_message_t state)
597 struct fb_info *info = platform_get_drvdata(dev);
598 struct w100fb_par *par=info->par;
599 struct w100_tg_info *tg = par->mach->tg;
601 w100fb_save_vidmem(par);
602 if(tg && tg->suspend)
604 w100_suspend(W100_SUSPEND_ALL);
610 static int w100fb_resume(struct platform_device *dev)
612 struct fb_info *info = platform_get_drvdata(dev);
613 struct w100fb_par *par=info->par;
614 struct w100_tg_info *tg = par->mach->tg;
617 w100fb_activate_var(par);
618 w100fb_restore_vidmem(par);
626 #define w100fb_suspend NULL
627 #define w100fb_resume NULL
631 int __init w100fb_probe(struct platform_device *pdev)
634 struct w100fb_mach_info *inf;
635 struct fb_info *info = NULL;
636 struct w100fb_par *par;
637 struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
638 unsigned int chip_id;
643 /* Remap the chip base address */
644 remapped_base = ioremap_nocache(mem->start+W100_CFG_BASE, W100_CFG_LEN);
645 if (remapped_base == NULL)
648 /* Map the register space */
649 remapped_regs = ioremap_nocache(mem->start+W100_REG_BASE, W100_REG_LEN);
650 if (remapped_regs == NULL)
653 /* Identify the chip */
655 chip_id = readl(remapped_regs + mmCHIP_ID);
657 case CHIP_ID_W100: printk("w100"); break;
658 case CHIP_ID_W3200: printk("w3200"); break;
659 case CHIP_ID_W3220: printk("w3220"); break;
661 printk("Unknown imageon chip ID\n");
665 printk(" at 0x%08lx.\n", (unsigned long) mem->start+W100_CFG_BASE);
667 /* Remap the framebuffer */
668 remapped_fbuf = ioremap_nocache(mem->start+MEM_WINDOW_BASE, MEM_WINDOW_SIZE);
669 if (remapped_fbuf == NULL)
672 info=framebuffer_alloc(sizeof(struct w100fb_par), &pdev->dev);
679 platform_set_drvdata(pdev, info);
681 inf = pdev->dev.platform_data;
682 par->chip_id = chip_id;
684 par->fastpll_mode = 0;
687 par->pll_table=w100_get_xtal_table(inf->xtal_freq);
688 if (!par->pll_table) {
689 printk(KERN_ERR "No matching Xtal definition found\n");
694 info->pseudo_palette = kmalloc(sizeof (u32) * MAX_PALETTES, GFP_KERNEL);
695 if (!info->pseudo_palette) {
700 info->fbops = &w100fb_ops;
701 info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA |
702 FBINFO_HWACCEL_FILLRECT;
704 info->screen_base = remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE);
705 info->screen_size = REMAPPED_FB_LEN;
707 strcpy(info->fix.id, "w100fb");
708 info->fix.type = FB_TYPE_PACKED_PIXELS;
709 info->fix.type_aux = 0;
710 info->fix.accel = FB_ACCEL_NONE;
711 info->fix.smem_start = mem->start+W100_FB_BASE;
712 info->fix.mmio_start = mem->start+W100_REG_BASE;
713 info->fix.mmio_len = W100_REG_LEN;
715 if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
720 par->mode = &inf->modelist[0];
721 if(inf->init_mode & INIT_MODE_ROTATED) {
722 info->var.xres = par->mode->yres;
723 info->var.yres = par->mode->xres;
726 info->var.xres = par->mode->xres;
727 info->var.yres = par->mode->yres;
730 if(inf->init_mode &= INIT_MODE_FLIPPED)
735 info->var.xres_virtual = info->var.xres;
736 info->var.yres_virtual = info->var.yres;
737 info->var.pixclock = 0x04; /* 171521; */
739 info->var.grayscale = 0;
740 info->var.xoffset = info->var.yoffset = 0;
741 info->var.accel_flags = 0;
742 info->var.activate = FB_ACTIVATE_NOW;
746 if (w100fb_check_var(&info->var, info) < 0) {
751 w100fb_set_par(info);
753 if (register_framebuffer(info) < 0) {
758 err = device_create_file(&pdev->dev, &dev_attr_fastpllclk);
759 err |= device_create_file(&pdev->dev, &dev_attr_reg_read);
760 err |= device_create_file(&pdev->dev, &dev_attr_reg_write);
761 err |= device_create_file(&pdev->dev, &dev_attr_flip);
764 printk(KERN_WARNING "fb%d: failed to register attributes (%d)\n",
767 printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id);
771 fb_dealloc_cmap(&info->cmap);
772 kfree(info->pseudo_palette);
774 if (remapped_fbuf != NULL)
775 iounmap(remapped_fbuf);
776 if (remapped_regs != NULL)
777 iounmap(remapped_regs);
778 if (remapped_base != NULL)
779 iounmap(remapped_base);
781 framebuffer_release(info);
786 static int w100fb_remove(struct platform_device *pdev)
788 struct fb_info *info = platform_get_drvdata(pdev);
789 struct w100fb_par *par=info->par;
791 device_remove_file(&pdev->dev, &dev_attr_fastpllclk);
792 device_remove_file(&pdev->dev, &dev_attr_reg_read);
793 device_remove_file(&pdev->dev, &dev_attr_reg_write);
794 device_remove_file(&pdev->dev, &dev_attr_flip);
796 unregister_framebuffer(info);
798 vfree(par->saved_intmem);
799 vfree(par->saved_extmem);
800 kfree(info->pseudo_palette);
801 fb_dealloc_cmap(&info->cmap);
803 iounmap(remapped_base);
804 iounmap(remapped_regs);
805 iounmap(remapped_fbuf);
807 framebuffer_release(info);
813 /* ------------------- chipset specific functions -------------------------- */
816 static void w100_soft_reset(void)
818 u16 val = readw((u16 *) remapped_base + cfgSTATUS);
819 writew(val | 0x08, (u16 *) remapped_base + cfgSTATUS);
821 writew(0x00, (u16 *) remapped_base + cfgSTATUS);
825 static void w100_update_disable(void)
827 union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl;
829 /* Prevent display updates */
830 disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
831 disp_db_buf_wr_cntl.f.update_db_buf = 0;
832 disp_db_buf_wr_cntl.f.en_db_buf = 0;
833 writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
836 static void w100_update_enable(void)
838 union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl;
840 /* Enable display updates */
841 disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
842 disp_db_buf_wr_cntl.f.update_db_buf = 1;
843 disp_db_buf_wr_cntl.f.en_db_buf = 1;
844 writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
847 unsigned long w100fb_gpio_read(int port)
851 if (port==W100_GPIO_PORT_A)
852 value = readl(remapped_regs + mmGPIO_DATA);
854 value = readl(remapped_regs + mmGPIO_DATA2);
859 void w100fb_gpio_write(int port, unsigned long value)
861 if (port==W100_GPIO_PORT_A)
862 value = writel(value, remapped_regs + mmGPIO_DATA);
864 value = writel(value, remapped_regs + mmGPIO_DATA2);
866 EXPORT_SYMBOL(w100fb_gpio_read);
867 EXPORT_SYMBOL(w100fb_gpio_write);
870 * Initialization of critical w100 hardware
872 static void w100_hw_init(struct w100fb_par *par)
875 union cif_cntl_u cif_cntl;
876 union intf_cntl_u intf_cntl;
877 union cfgreg_base_u cfgreg_base;
878 union wrap_top_dir_u wrap_top_dir;
879 union cif_read_dbg_u cif_read_dbg;
880 union cpu_defaults_u cpu_default;
881 union cif_write_dbg_u cif_write_dbg;
882 union wrap_start_dir_u wrap_start_dir;
883 union cif_io_u cif_io;
884 struct w100_gpio_regs *gpio = par->mach->gpio;
888 /* This is what the fpga_init code does on reset. May be wrong
889 but there is little info available */
890 writel(0x31, remapped_regs + mmSCRATCH_UMSK);
891 for (temp32 = 0; temp32 < 10000; temp32++)
892 readl(remapped_regs + mmSCRATCH_UMSK);
893 writel(0x30, remapped_regs + mmSCRATCH_UMSK);
896 cif_io.val = defCIF_IO;
897 writel((u32)(cif_io.val), remapped_regs + mmCIF_IO);
899 cif_write_dbg.val = readl(remapped_regs + mmCIF_WRITE_DBG);
900 cif_write_dbg.f.dis_packer_ful_during_rbbm_timeout = 0;
901 cif_write_dbg.f.en_dword_split_to_rbbm = 1;
902 cif_write_dbg.f.dis_timeout_during_rbbm = 1;
903 writel((u32) (cif_write_dbg.val), remapped_regs + mmCIF_WRITE_DBG);
905 cif_read_dbg.val = readl(remapped_regs + mmCIF_READ_DBG);
906 cif_read_dbg.f.dis_rd_same_byte_to_trig_fetch = 1;
907 writel((u32) (cif_read_dbg.val), remapped_regs + mmCIF_READ_DBG);
909 cif_cntl.val = readl(remapped_regs + mmCIF_CNTL);
910 cif_cntl.f.dis_system_bits = 1;
911 cif_cntl.f.dis_mr = 1;
912 cif_cntl.f.en_wait_to_compensate_dq_prop_dly = 0;
913 cif_cntl.f.intb_oe = 1;
914 cif_cntl.f.interrupt_active_high = 1;
915 writel((u32) (cif_cntl.val), remapped_regs + mmCIF_CNTL);
917 /* Setup cfgINTF_CNTL and cfgCPU defaults */
918 intf_cntl.val = defINTF_CNTL;
919 intf_cntl.f.ad_inc_a = 1;
920 intf_cntl.f.ad_inc_b = 1;
921 intf_cntl.f.rd_data_rdy_a = 0;
922 intf_cntl.f.rd_data_rdy_b = 0;
923 writeb((u8) (intf_cntl.val), remapped_base + cfgINTF_CNTL);
925 cpu_default.val = defCPU_DEFAULTS;
926 cpu_default.f.access_ind_addr_a = 1;
927 cpu_default.f.access_ind_addr_b = 1;
928 cpu_default.f.access_scratch_reg = 1;
929 cpu_default.f.transition_size = 0;
930 writeb((u8) (cpu_default.val), remapped_base + cfgCPU_DEFAULTS);
932 /* set up the apertures */
933 writeb((u8) (W100_REG_BASE >> 16), remapped_base + cfgREG_BASE);
935 cfgreg_base.val = defCFGREG_BASE;
936 cfgreg_base.f.cfgreg_base = W100_CFG_BASE;
937 writel((u32) (cfgreg_base.val), remapped_regs + mmCFGREG_BASE);
939 wrap_start_dir.val = defWRAP_START_DIR;
940 wrap_start_dir.f.start_addr = WRAP_BUF_BASE_VALUE >> 1;
941 writel((u32) (wrap_start_dir.val), remapped_regs + mmWRAP_START_DIR);
943 wrap_top_dir.val = defWRAP_TOP_DIR;
944 wrap_top_dir.f.top_addr = WRAP_BUF_TOP_VALUE >> 1;
945 writel((u32) (wrap_top_dir.val), remapped_regs + mmWRAP_TOP_DIR);
947 writel((u32) 0x2440, remapped_regs + mmRBBM_CNTL);
949 /* Set the hardware to 565 colour */
950 temp32 = readl(remapped_regs + mmDISP_DEBUG2);
951 temp32 &= 0xff7fffff;
952 temp32 |= 0x00800000;
953 writel(temp32, remapped_regs + mmDISP_DEBUG2);
955 /* Initialise the GPIO lines */
957 writel(gpio->init_data1, remapped_regs + mmGPIO_DATA);
958 writel(gpio->init_data2, remapped_regs + mmGPIO_DATA2);
959 writel(gpio->gpio_dir1, remapped_regs + mmGPIO_CNTL1);
960 writel(gpio->gpio_oe1, remapped_regs + mmGPIO_CNTL2);
961 writel(gpio->gpio_dir2, remapped_regs + mmGPIO_CNTL3);
962 writel(gpio->gpio_oe2, remapped_regs + mmGPIO_CNTL4);
968 union clk_pin_cntl_u clk_pin_cntl;
969 union pll_ref_fb_div_u pll_ref_fb_div;
970 union pll_cntl_u pll_cntl;
971 union sclk_cntl_u sclk_cntl;
972 union pclk_cntl_u pclk_cntl;
973 union pwrmgt_cntl_u pwrmgt_cntl;
974 int auto_mode; /* system clock auto changing? */
978 static struct power_state w100_pwr_state;
980 /* The PLL Fout is determined by (XtalFreq/(M+1)) * ((N_int+1) + (N_fac/8)) */
982 /* 12.5MHz Crystal PLL Table */
983 static struct w100_pll_info xtal_12500000[] = {
984 /*freq M N_int N_fac tfgoal lock_time */
985 { 50, 0, 1, 0, 0xe0, 56}, /* 50.00 MHz */
986 { 75, 0, 5, 0, 0xde, 37}, /* 75.00 MHz */
987 {100, 0, 7, 0, 0xe0, 28}, /* 100.00 MHz */
988 {125, 0, 9, 0, 0xe0, 22}, /* 125.00 MHz */
989 {150, 0, 11, 0, 0xe0, 17}, /* 150.00 MHz */
990 { 0, 0, 0, 0, 0, 0}, /* Terminator */
993 /* 14.318MHz Crystal PLL Table */
994 static struct w100_pll_info xtal_14318000[] = {
995 /*freq M N_int N_fac tfgoal lock_time */
996 { 40, 4, 13, 0, 0xe0, 80}, /* tfgoal guessed */
997 { 50, 1, 6, 0, 0xe0, 64}, /* 50.05 MHz */
998 { 57, 2, 11, 0, 0xe0, 53}, /* tfgoal guessed */
999 { 75, 0, 4, 3, 0xe0, 43}, /* 75.08 MHz */
1000 {100, 0, 6, 0, 0xe0, 32}, /* 100.10 MHz */
1001 { 0, 0, 0, 0, 0, 0},
1004 /* 16MHz Crystal PLL Table */
1005 static struct w100_pll_info xtal_16000000[] = {
1006 /*freq M N_int N_fac tfgoal lock_time */
1007 { 72, 1, 8, 0, 0xe0, 48}, /* tfgoal guessed */
1008 { 80, 1, 9, 0, 0xe0, 13}, /* tfgoal guessed */
1009 { 95, 1, 10, 7, 0xe0, 38}, /* tfgoal guessed */
1010 { 96, 1, 11, 0, 0xe0, 36}, /* tfgoal guessed */
1011 { 0, 0, 0, 0, 0, 0},
1014 static struct pll_entries {
1016 struct w100_pll_info *pll_table;
1017 } w100_pll_tables[] = {
1018 { 12500000, &xtal_12500000[0] },
1019 { 14318000, &xtal_14318000[0] },
1020 { 16000000, &xtal_16000000[0] },
1024 struct w100_pll_info *w100_get_xtal_table(unsigned int freq)
1026 struct pll_entries *pll_entry = w100_pll_tables;
1029 if (freq == pll_entry->xtal_freq)
1030 return pll_entry->pll_table;
1032 } while (pll_entry->xtal_freq);
1037 static unsigned int w100_get_testcount(unsigned int testclk_sel)
1039 union clk_test_cntl_u clk_test_cntl;
1043 /* Select the test clock source and reset */
1044 clk_test_cntl.f.start_check_freq = 0x0;
1045 clk_test_cntl.f.testclk_sel = testclk_sel;
1046 clk_test_cntl.f.tstcount_rst = 0x1; /* set reset */
1047 writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
1049 clk_test_cntl.f.tstcount_rst = 0x0; /* clear reset */
1050 writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
1052 /* Run clock test */
1053 clk_test_cntl.f.start_check_freq = 0x1;
1054 writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
1056 /* Give the test time to complete */
1059 /* Return the result */
1060 clk_test_cntl.val = readl(remapped_regs + mmCLK_TEST_CNTL);
1061 clk_test_cntl.f.start_check_freq = 0x0;
1062 writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
1064 return clk_test_cntl.f.test_count;
1068 static int w100_pll_adjust(struct w100_pll_info *pll)
1073 /* Initial Settings */
1074 w100_pwr_state.pll_cntl.f.pll_pwdn = 0x0; /* power down */
1075 w100_pwr_state.pll_cntl.f.pll_reset = 0x0; /* not reset */
1076 w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x1; /* Hi-Z */
1077 w100_pwr_state.pll_cntl.f.pll_pvg = 0x0; /* VCO gain = 0 */
1078 w100_pwr_state.pll_cntl.f.pll_vcofr = 0x0; /* VCO frequency range control = off */
1079 w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0; /* current offset inside VCO = 0 */
1080 w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0;
1082 /* Wai Ming 80 percent of VDD 1.3V gives 1.04V, minimum operating voltage is 1.08V
1083 * therefore, commented out the following lines
1087 /* set VCO input = 0.8 * VDD */
1088 w100_pwr_state.pll_cntl.f.pll_dactal = 0xd;
1089 writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
1091 tf80 = w100_get_testcount(TESTCLK_SRC_PLL);
1092 if (tf80 >= (pll->tfgoal)) {
1093 /* set VCO input = 0.2 * VDD */
1094 w100_pwr_state.pll_cntl.f.pll_dactal = 0x7;
1095 writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
1097 tf20 = w100_get_testcount(TESTCLK_SRC_PLL);
1098 if (tf20 <= (pll->tfgoal))
1099 return 1; /* Success */
1101 if ((w100_pwr_state.pll_cntl.f.pll_vcofr == 0x0) &&
1102 ((w100_pwr_state.pll_cntl.f.pll_pvg == 0x7) ||
1103 (w100_pwr_state.pll_cntl.f.pll_ioffset == 0x0))) {
1104 /* slow VCO config */
1105 w100_pwr_state.pll_cntl.f.pll_vcofr = 0x1;
1106 w100_pwr_state.pll_cntl.f.pll_pvg = 0x0;
1107 w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
1111 if ((w100_pwr_state.pll_cntl.f.pll_ioffset) < 0x3) {
1112 w100_pwr_state.pll_cntl.f.pll_ioffset += 0x1;
1113 } else if ((w100_pwr_state.pll_cntl.f.pll_pvg) < 0x7) {
1114 w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
1115 w100_pwr_state.pll_cntl.f.pll_pvg += 0x1;
1117 return 0; /* Error */
1124 * w100_pll_calibration
1126 static int w100_pll_calibration(struct w100_pll_info *pll)
1130 status = w100_pll_adjust(pll);
1132 /* PLL Reset And Lock */
1133 /* set VCO input = 0.5 * VDD */
1134 w100_pwr_state.pll_cntl.f.pll_dactal = 0xa;
1135 writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
1137 udelay(1); /* reset time */
1139 /* enable charge pump */
1140 w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0; /* normal */
1141 writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
1143 /* set VCO input = Hi-Z, disable DAC */
1144 w100_pwr_state.pll_cntl.f.pll_dactal = 0x0;
1145 writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
1147 udelay(400); /* lock time */
1155 static int w100_pll_set_clk(struct w100_pll_info *pll)
1159 if (w100_pwr_state.auto_mode == 1) /* auto mode */
1161 w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0; /* disable fast to normal */
1162 w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0; /* disable normal to fast */
1163 writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
1166 /* Set system clock source to XTAL whilst adjusting the PLL! */
1167 w100_pwr_state.sclk_cntl.f.sclk_src_sel = CLK_SRC_XTAL;
1168 writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
1170 w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = pll->M;
1171 w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = pll->N_int;
1172 w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = pll->N_fac;
1173 w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = pll->lock_time;
1174 writel((u32) (w100_pwr_state.pll_ref_fb_div.val), remapped_regs + mmPLL_REF_FB_DIV);
1176 w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0;
1177 writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
1179 status = w100_pll_calibration(pll);
1181 if (w100_pwr_state.auto_mode == 1) /* auto mode */
1183 w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x1; /* reenable fast to normal */
1184 w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x1; /* reenable normal to fast */
1185 writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
1190 /* freq = target frequency of the PLL */
1191 static int w100_set_pll_freq(struct w100fb_par *par, unsigned int freq)
1193 struct w100_pll_info *pll = par->pll_table;
1196 if (freq == pll->freq) {
1197 return w100_pll_set_clk(pll);
1204 /* Set up an initial state. Some values/fields set
1205 here will be overwritten. */
1206 static void w100_pwm_setup(struct w100fb_par *par)
1208 w100_pwr_state.clk_pin_cntl.f.osc_en = 0x1;
1209 w100_pwr_state.clk_pin_cntl.f.osc_gain = 0x1f;
1210 w100_pwr_state.clk_pin_cntl.f.dont_use_xtalin = 0x0;
1211 w100_pwr_state.clk_pin_cntl.f.xtalin_pm_en = 0x0;
1212 w100_pwr_state.clk_pin_cntl.f.xtalin_dbl_en = par->mach->xtal_dbl ? 1 : 0;
1213 w100_pwr_state.clk_pin_cntl.f.cg_debug = 0x0;
1214 writel((u32) (w100_pwr_state.clk_pin_cntl.val), remapped_regs + mmCLK_PIN_CNTL);
1216 w100_pwr_state.sclk_cntl.f.sclk_src_sel = CLK_SRC_XTAL;
1217 w100_pwr_state.sclk_cntl.f.sclk_post_div_fast = 0x0; /* Pfast = 1 */
1218 w100_pwr_state.sclk_cntl.f.sclk_clkon_hys = 0x3;
1219 w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = 0x0; /* Pslow = 1 */
1220 w100_pwr_state.sclk_cntl.f.disp_cg_ok2switch_en = 0x0;
1221 w100_pwr_state.sclk_cntl.f.sclk_force_reg = 0x0; /* Dynamic */
1222 w100_pwr_state.sclk_cntl.f.sclk_force_disp = 0x0; /* Dynamic */
1223 w100_pwr_state.sclk_cntl.f.sclk_force_mc = 0x0; /* Dynamic */
1224 w100_pwr_state.sclk_cntl.f.sclk_force_extmc = 0x0; /* Dynamic */
1225 w100_pwr_state.sclk_cntl.f.sclk_force_cp = 0x0; /* Dynamic */
1226 w100_pwr_state.sclk_cntl.f.sclk_force_e2 = 0x0; /* Dynamic */
1227 w100_pwr_state.sclk_cntl.f.sclk_force_e3 = 0x0; /* Dynamic */
1228 w100_pwr_state.sclk_cntl.f.sclk_force_idct = 0x0; /* Dynamic */
1229 w100_pwr_state.sclk_cntl.f.sclk_force_bist = 0x0; /* Dynamic */
1230 w100_pwr_state.sclk_cntl.f.busy_extend_cp = 0x0;
1231 w100_pwr_state.sclk_cntl.f.busy_extend_e2 = 0x0;
1232 w100_pwr_state.sclk_cntl.f.busy_extend_e3 = 0x0;
1233 w100_pwr_state.sclk_cntl.f.busy_extend_idct = 0x0;
1234 writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
1236 w100_pwr_state.pclk_cntl.f.pclk_src_sel = CLK_SRC_XTAL;
1237 w100_pwr_state.pclk_cntl.f.pclk_post_div = 0x1; /* P = 2 */
1238 w100_pwr_state.pclk_cntl.f.pclk_force_disp = 0x0; /* Dynamic */
1239 writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
1241 w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = 0x0; /* M = 1 */
1242 w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = 0x0; /* N = 1.0 */
1243 w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = 0x0;
1244 w100_pwr_state.pll_ref_fb_div.f.pll_reset_time = 0x5;
1245 w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = 0xff;
1246 writel((u32) (w100_pwr_state.pll_ref_fb_div.val), remapped_regs + mmPLL_REF_FB_DIV);
1248 w100_pwr_state.pll_cntl.f.pll_pwdn = 0x1;
1249 w100_pwr_state.pll_cntl.f.pll_reset = 0x1;
1250 w100_pwr_state.pll_cntl.f.pll_pm_en = 0x0;
1251 w100_pwr_state.pll_cntl.f.pll_mode = 0x0; /* uses VCO clock */
1252 w100_pwr_state.pll_cntl.f.pll_refclk_sel = 0x0;
1253 w100_pwr_state.pll_cntl.f.pll_fbclk_sel = 0x0;
1254 w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0;
1255 w100_pwr_state.pll_cntl.f.pll_pcp = 0x4;
1256 w100_pwr_state.pll_cntl.f.pll_pvg = 0x0;
1257 w100_pwr_state.pll_cntl.f.pll_vcofr = 0x0;
1258 w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
1259 w100_pwr_state.pll_cntl.f.pll_pecc_mode = 0x0;
1260 w100_pwr_state.pll_cntl.f.pll_pecc_scon = 0x0;
1261 w100_pwr_state.pll_cntl.f.pll_dactal = 0x0; /* Hi-Z */
1262 w100_pwr_state.pll_cntl.f.pll_cp_clip = 0x3;
1263 w100_pwr_state.pll_cntl.f.pll_conf = 0x2;
1264 w100_pwr_state.pll_cntl.f.pll_mbctrl = 0x2;
1265 w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0;
1266 writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
1268 w100_pwr_state.pwrmgt_cntl.f.pwm_enable = 0x0;
1269 w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0x1; /* normal mode (0, 1, 3) */
1270 w100_pwr_state.pwrmgt_cntl.f.pwm_wakeup_cond = 0x0;
1271 w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0;
1272 w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0;
1273 w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_cond = 0x1; /* PM4,ENG */
1274 w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_cond = 0x1; /* PM4,ENG */
1275 w100_pwr_state.pwrmgt_cntl.f.pwm_idle_timer = 0xFF;
1276 w100_pwr_state.pwrmgt_cntl.f.pwm_busy_timer = 0xFF;
1277 writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
1279 w100_pwr_state.auto_mode = 0; /* manual mode */
1284 * Setup the w100 clocks for the specified mode
1286 static void w100_init_clocks(struct w100fb_par *par)
1288 struct w100_mode *mode = par->mode;
1290 if (mode->pixclk_src == CLK_SRC_PLL || mode->sysclk_src == CLK_SRC_PLL)
1291 w100_set_pll_freq(par, (par->fastpll_mode && mode->fast_pll_freq) ? mode->fast_pll_freq : mode->pll_freq);
1293 w100_pwr_state.sclk_cntl.f.sclk_src_sel = mode->sysclk_src;
1294 w100_pwr_state.sclk_cntl.f.sclk_post_div_fast = mode->sysclk_divider;
1295 w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = mode->sysclk_divider;
1296 writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
1299 static void w100_init_lcd(struct w100fb_par *par)
1302 struct w100_mode *mode = par->mode;
1303 struct w100_gen_regs *regs = par->mach->regs;
1304 union active_h_disp_u active_h_disp;
1305 union active_v_disp_u active_v_disp;
1306 union graphic_h_disp_u graphic_h_disp;
1307 union graphic_v_disp_u graphic_v_disp;
1308 union crtc_total_u crtc_total;
1310 /* w3200 doesnt like undefined bits being set so zero register values first */
1312 active_h_disp.val = 0;
1313 active_h_disp.f.active_h_start=mode->left_margin;
1314 active_h_disp.f.active_h_end=mode->left_margin + mode->xres;
1315 writel(active_h_disp.val, remapped_regs + mmACTIVE_H_DISP);
1317 active_v_disp.val = 0;
1318 active_v_disp.f.active_v_start=mode->upper_margin;
1319 active_v_disp.f.active_v_end=mode->upper_margin + mode->yres;
1320 writel(active_v_disp.val, remapped_regs + mmACTIVE_V_DISP);
1322 graphic_h_disp.val = 0;
1323 graphic_h_disp.f.graphic_h_start=mode->left_margin;
1324 graphic_h_disp.f.graphic_h_end=mode->left_margin + mode->xres;
1325 writel(graphic_h_disp.val, remapped_regs + mmGRAPHIC_H_DISP);
1327 graphic_v_disp.val = 0;
1328 graphic_v_disp.f.graphic_v_start=mode->upper_margin;
1329 graphic_v_disp.f.graphic_v_end=mode->upper_margin + mode->yres;
1330 writel(graphic_v_disp.val, remapped_regs + mmGRAPHIC_V_DISP);
1333 crtc_total.f.crtc_h_total=mode->left_margin + mode->xres + mode->right_margin;
1334 crtc_total.f.crtc_v_total=mode->upper_margin + mode->yres + mode->lower_margin;
1335 writel(crtc_total.val, remapped_regs + mmCRTC_TOTAL);
1337 writel(mode->crtc_ss, remapped_regs + mmCRTC_SS);
1338 writel(mode->crtc_ls, remapped_regs + mmCRTC_LS);
1339 writel(mode->crtc_gs, remapped_regs + mmCRTC_GS);
1340 writel(mode->crtc_vpos_gs, remapped_regs + mmCRTC_VPOS_GS);
1341 writel(mode->crtc_rev, remapped_regs + mmCRTC_REV);
1342 writel(mode->crtc_dclk, remapped_regs + mmCRTC_DCLK);
1343 writel(mode->crtc_gclk, remapped_regs + mmCRTC_GCLK);
1344 writel(mode->crtc_goe, remapped_regs + mmCRTC_GOE);
1345 writel(mode->crtc_ps1_active, remapped_regs + mmCRTC_PS1_ACTIVE);
1347 writel(regs->lcd_format, remapped_regs + mmLCD_FORMAT);
1348 writel(regs->lcdd_cntl1, remapped_regs + mmLCDD_CNTL1);
1349 writel(regs->lcdd_cntl2, remapped_regs + mmLCDD_CNTL2);
1350 writel(regs->genlcd_cntl1, remapped_regs + mmGENLCD_CNTL1);
1351 writel(regs->genlcd_cntl2, remapped_regs + mmGENLCD_CNTL2);
1352 writel(regs->genlcd_cntl3, remapped_regs + mmGENLCD_CNTL3);
1354 writel(0x00000000, remapped_regs + mmCRTC_FRAME);
1355 writel(0x00000000, remapped_regs + mmCRTC_FRAME_VPOS);
1356 writel(0x00000000, remapped_regs + mmCRTC_DEFAULT_COUNT);
1357 writel(0x0000FF00, remapped_regs + mmLCD_BACKGROUND_COLOR);
1359 /* Hack for overlay in ext memory */
1360 temp32 = readl(remapped_regs + mmDISP_DEBUG2);
1361 temp32 |= 0xc0000000;
1362 writel(temp32, remapped_regs + mmDISP_DEBUG2);
1366 static void w100_setup_memory(struct w100fb_par *par)
1368 union mc_ext_mem_location_u extmem_location;
1369 union mc_fb_location_u intmem_location;
1370 struct w100_mem_info *mem = par->mach->mem;
1371 struct w100_bm_mem_info *bm_mem = par->mach->bm_mem;
1373 if (!par->extmem_active) {
1374 w100_suspend(W100_SUSPEND_EXTMEM);
1376 /* Map Internal Memory at FB Base */
1377 intmem_location.f.mc_fb_start = W100_FB_BASE >> 8;
1378 intmem_location.f.mc_fb_top = (W100_FB_BASE+MEM_INT_SIZE) >> 8;
1379 writel((u32) (intmem_location.val), remapped_regs + mmMC_FB_LOCATION);
1381 /* Unmap External Memory - value is *probably* irrelevant but may have meaning
1382 to acceleration libraries */
1383 extmem_location.f.mc_ext_mem_start = MEM_EXT_BASE_VALUE >> 8;
1384 extmem_location.f.mc_ext_mem_top = (MEM_EXT_BASE_VALUE-1) >> 8;
1385 writel((u32) (extmem_location.val), remapped_regs + mmMC_EXT_MEM_LOCATION);
1387 /* Map Internal Memory to its default location */
1388 intmem_location.f.mc_fb_start = MEM_INT_BASE_VALUE >> 8;
1389 intmem_location.f.mc_fb_top = (MEM_INT_BASE_VALUE+MEM_INT_SIZE) >> 8;
1390 writel((u32) (intmem_location.val), remapped_regs + mmMC_FB_LOCATION);
1392 /* Map External Memory at FB Base */
1393 extmem_location.f.mc_ext_mem_start = W100_FB_BASE >> 8;
1394 extmem_location.f.mc_ext_mem_top = (W100_FB_BASE+par->mach->mem->size) >> 8;
1395 writel((u32) (extmem_location.val), remapped_regs + mmMC_EXT_MEM_LOCATION);
1397 writel(0x00007800, remapped_regs + mmMC_BIST_CTRL);
1398 writel(mem->ext_cntl, remapped_regs + mmMEM_EXT_CNTL);
1399 writel(0x00200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
1401 writel(0x80200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
1403 writel(mem->sdram_mode_reg, remapped_regs + mmMEM_SDRAM_MODE_REG);
1405 writel(mem->ext_timing_cntl, remapped_regs + mmMEM_EXT_TIMING_CNTL);
1406 writel(mem->io_cntl, remapped_regs + mmMEM_IO_CNTL);
1408 writel(bm_mem->ext_mem_bw, remapped_regs + mmBM_EXT_MEM_BANDWIDTH);
1409 writel(bm_mem->offset, remapped_regs + mmBM_OFFSET);
1410 writel(bm_mem->ext_timing_ctl, remapped_regs + mmBM_MEM_EXT_TIMING_CNTL);
1411 writel(bm_mem->ext_cntl, remapped_regs + mmBM_MEM_EXT_CNTL);
1412 writel(bm_mem->mode_reg, remapped_regs + mmBM_MEM_MODE_REG);
1413 writel(bm_mem->io_cntl, remapped_regs + mmBM_MEM_IO_CNTL);
1414 writel(bm_mem->config, remapped_regs + mmBM_CONFIG);
1419 static void w100_set_dispregs(struct w100fb_par *par)
1421 unsigned long rot=0, divider, offset=0;
1422 union graphic_ctrl_u graphic_ctrl;
1424 /* See if the mode has been rotated */
1425 if (par->xres == par->mode->xres) {
1427 rot=3; /* 180 degree */
1428 offset=(par->xres * par->yres) - 1;
1429 } /* else 0 degree */
1430 divider = par->mode->pixclk_divider;
1433 rot=2; /* 270 degree */
1434 offset=par->xres - 1;
1436 rot=1; /* 90 degree */
1437 offset=par->xres * (par->yres - 1);
1439 divider = par->mode->pixclk_divider_rotated;
1442 graphic_ctrl.val = 0; /* w32xx doesn't like undefined bits */
1443 switch (par->chip_id) {
1445 graphic_ctrl.f_w100.color_depth=6;
1446 graphic_ctrl.f_w100.en_crtc=1;
1447 graphic_ctrl.f_w100.en_graphic_req=1;
1448 graphic_ctrl.f_w100.en_graphic_crtc=1;
1449 graphic_ctrl.f_w100.lcd_pclk_on=1;
1450 graphic_ctrl.f_w100.lcd_sclk_on=1;
1451 graphic_ctrl.f_w100.low_power_on=0;
1452 graphic_ctrl.f_w100.req_freq=0;
1453 graphic_ctrl.f_w100.portrait_mode=rot;
1455 /* Zaurus needs this */
1460 graphic_ctrl.f_w100.total_req_graphic=0xa0;
1467 graphic_ctrl.f_w100.low_power_on=1;
1468 graphic_ctrl.f_w100.req_freq=5;
1472 graphic_ctrl.f_w100.req_freq=4;
1477 graphic_ctrl.f_w100.total_req_graphic=0xf0;
1483 graphic_ctrl.f_w32xx.color_depth=6;
1484 graphic_ctrl.f_w32xx.en_crtc=1;
1485 graphic_ctrl.f_w32xx.en_graphic_req=1;
1486 graphic_ctrl.f_w32xx.en_graphic_crtc=1;
1487 graphic_ctrl.f_w32xx.lcd_pclk_on=1;
1488 graphic_ctrl.f_w32xx.lcd_sclk_on=1;
1489 graphic_ctrl.f_w32xx.low_power_on=0;
1490 graphic_ctrl.f_w32xx.req_freq=0;
1491 graphic_ctrl.f_w32xx.total_req_graphic=par->mode->xres >> 1; /* panel xres, not mode */
1492 graphic_ctrl.f_w32xx.portrait_mode=rot;
1496 /* Set the pixel clock source and divider */
1497 w100_pwr_state.pclk_cntl.f.pclk_src_sel = par->mode->pixclk_src;
1498 w100_pwr_state.pclk_cntl.f.pclk_post_div = divider;
1499 writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
1501 writel(graphic_ctrl.val, remapped_regs + mmGRAPHIC_CTRL);
1502 writel(W100_FB_BASE + ((offset * BITS_PER_PIXEL/8)&~0x03UL), remapped_regs + mmGRAPHIC_OFFSET);
1503 writel((par->xres*BITS_PER_PIXEL/8), remapped_regs + mmGRAPHIC_PITCH);
1508 * Work out how long the sync pulse lasts
1509 * Value is 1/(time in seconds)
1511 static void calc_hsync(struct w100fb_par *par)
1513 unsigned long hsync;
1514 struct w100_mode *mode = par->mode;
1515 union crtc_ss_u crtc_ss;
1517 if (mode->pixclk_src == CLK_SRC_XTAL)
1518 hsync=par->mach->xtal_freq;
1520 hsync=((par->fastpll_mode && mode->fast_pll_freq) ? mode->fast_pll_freq : mode->pll_freq)*100000;
1522 hsync /= (w100_pwr_state.pclk_cntl.f.pclk_post_div + 1);
1524 crtc_ss.val = readl(remapped_regs + mmCRTC_SS);
1526 par->hsync_len = hsync / (crtc_ss.f.ss_end-crtc_ss.f.ss_start);
1531 static void w100_suspend(u32 mode)
1535 writel(0x7FFF8000, remapped_regs + mmMC_EXT_MEM_LOCATION);
1536 writel(0x00FF0000, remapped_regs + mmMC_PERF_MON_CNTL);
1538 val = readl(remapped_regs + mmMEM_EXT_TIMING_CNTL);
1539 val &= ~(0x00100000); /* bit20=0 */
1540 val |= 0xFF000000; /* bit31:24=0xff */
1541 writel(val, remapped_regs + mmMEM_EXT_TIMING_CNTL);
1543 val = readl(remapped_regs + mmMEM_EXT_CNTL);
1544 val &= ~(0x00040000); /* bit18=0 */
1545 val |= 0x00080000; /* bit19=1 */
1546 writel(val, remapped_regs + mmMEM_EXT_CNTL);
1548 udelay(1); /* wait 1us */
1550 if (mode == W100_SUSPEND_EXTMEM) {
1551 /* CKE: Tri-State */
1552 val = readl(remapped_regs + mmMEM_EXT_CNTL);
1553 val |= 0x40000000; /* bit30=1 */
1554 writel(val, remapped_regs + mmMEM_EXT_CNTL);
1557 val = readl(remapped_regs + mmMEM_EXT_CNTL);
1558 val &= ~(0x00000001); /* bit0=0 */
1559 writel(val, remapped_regs + mmMEM_EXT_CNTL);
1561 writel(0x00000000, remapped_regs + mmSCLK_CNTL);
1562 writel(0x000000BF, remapped_regs + mmCLK_PIN_CNTL);
1563 writel(0x00000015, remapped_regs + mmPWRMGT_CNTL);
1567 val = readl(remapped_regs + mmPLL_CNTL);
1568 val |= 0x00000004; /* bit2=1 */
1569 writel(val, remapped_regs + mmPLL_CNTL);
1570 writel(0x0000001d, remapped_regs + mmPWRMGT_CNTL);
1574 static void w100_vsync(void)
1577 int timeout = 30000; /* VSync timeout = 30[ms] > 16.8[ms] */
1579 tmp = readl(remapped_regs + mmACTIVE_V_DISP);
1582 writel((tmp >> 16) & 0x3ff, remapped_regs + mmDISP_INT_CNTL);
1584 /* disable vline irq */
1585 tmp = readl(remapped_regs + mmGEN_INT_CNTL);
1588 writel(tmp, remapped_regs + mmGEN_INT_CNTL);
1590 /* clear vline irq status */
1591 writel(0x00000002, remapped_regs + mmGEN_INT_STATUS);
1593 /* enable vline irq */
1594 writel((tmp | 0x00000002), remapped_regs + mmGEN_INT_CNTL);
1596 /* clear vline irq status */
1597 writel(0x00000002, remapped_regs + mmGEN_INT_STATUS);
1599 while(timeout > 0) {
1600 if (readl(remapped_regs + mmGEN_INT_STATUS) & 0x00000002)
1606 /* disable vline irq */
1607 writel(tmp, remapped_regs + mmGEN_INT_CNTL);
1609 /* clear vline irq status */
1610 writel(0x00000002, remapped_regs + mmGEN_INT_STATUS);
1613 static struct platform_driver w100fb_driver = {
1614 .probe = w100fb_probe,
1615 .remove = w100fb_remove,
1616 .suspend = w100fb_suspend,
1617 .resume = w100fb_resume,
1623 int __devinit w100fb_init(void)
1625 return platform_driver_register(&w100fb_driver);
1628 void __exit w100fb_cleanup(void)
1630 platform_driver_unregister(&w100fb_driver);
1633 module_init(w100fb_init);
1634 module_exit(w100fb_cleanup);
1636 MODULE_DESCRIPTION("ATI Imageon w100 framebuffer driver");
1637 MODULE_LICENSE("GPL");