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