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