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 __iomem *remapped_base;
  65static void __iomem *remapped_regs;
  66static void __iomem *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 const 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                par->saved_extmem = NULL;
 592        }
 593        if (par->saved_intmem) {
 594                memsize=MEM_INT_SIZE;
 595                if (par->extmem_active)
 596                        memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_INT_BASE_VALUE), par->saved_intmem, memsize);
 597                else
 598                        memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_intmem, memsize);
 599                vfree(par->saved_intmem);
 600                par->saved_intmem = NULL;
 601        }
 602}
 603
 604static int w100fb_suspend(struct platform_device *dev, pm_message_t state)
 605{
 606        struct fb_info *info = platform_get_drvdata(dev);
 607        struct w100fb_par *par=info->par;
 608        struct w100_tg_info *tg = par->mach->tg;
 609
 610        w100fb_save_vidmem(par);
 611        if(tg && tg->suspend)
 612                tg->suspend(par);
 613        w100_suspend(W100_SUSPEND_ALL);
 614        par->blanked = 1;
 615
 616        return 0;
 617}
 618
 619static int w100fb_resume(struct platform_device *dev)
 620{
 621        struct fb_info *info = platform_get_drvdata(dev);
 622        struct w100fb_par *par=info->par;
 623        struct w100_tg_info *tg = par->mach->tg;
 624
 625        w100_hw_init(par);
 626        w100fb_activate_var(par);
 627        w100fb_restore_vidmem(par);
 628        if(tg && tg->resume)
 629                tg->resume(par);
 630        par->blanked = 0;
 631
 632        return 0;
 633}
 634#else
 635#define w100fb_suspend  NULL
 636#define w100fb_resume   NULL
 637#endif
 638
 639
 640static int w100fb_probe(struct platform_device *pdev)
 641{
 642        int err = -EIO;
 643        struct w100fb_mach_info *inf;
 644        struct fb_info *info = NULL;
 645        struct w100fb_par *par;
 646        struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 647        unsigned int chip_id;
 648
 649        if (!mem)
 650                return -EINVAL;
 651
 652        /* Remap the chip base address */
 653        remapped_base = ioremap(mem->start+W100_CFG_BASE, W100_CFG_LEN);
 654        if (remapped_base == NULL)
 655                goto out;
 656
 657        /* Map the register space */
 658        remapped_regs = ioremap(mem->start+W100_REG_BASE, W100_REG_LEN);
 659        if (remapped_regs == NULL)
 660                goto out;
 661
 662        /* Identify the chip */
 663        printk("Found ");
 664        chip_id = readl(remapped_regs + mmCHIP_ID);
 665        switch(chip_id) {
 666                case CHIP_ID_W100:  printk("w100");  break;
 667                case CHIP_ID_W3200: printk("w3200"); break;
 668                case CHIP_ID_W3220: printk("w3220"); break;
 669                default:
 670                        printk("Unknown imageon chip ID\n");
 671                        err = -ENODEV;
 672                        goto out;
 673        }
 674        printk(" at 0x%08lx.\n", (unsigned long) mem->start+W100_CFG_BASE);
 675
 676        /* Remap the framebuffer */
 677        remapped_fbuf = ioremap(mem->start+MEM_WINDOW_BASE, MEM_WINDOW_SIZE);
 678        if (remapped_fbuf == NULL)
 679                goto out;
 680
 681        info=framebuffer_alloc(sizeof(struct w100fb_par), &pdev->dev);
 682        if (!info) {
 683                err = -ENOMEM;
 684                goto out;
 685        }
 686
 687        par = info->par;
 688        platform_set_drvdata(pdev, info);
 689
 690        inf = dev_get_platdata(&pdev->dev);
 691        par->chip_id = chip_id;
 692        par->mach = inf;
 693        par->fastpll_mode = 0;
 694        par->blanked = 0;
 695
 696        par->pll_table=w100_get_xtal_table(inf->xtal_freq);
 697        if (!par->pll_table) {
 698                printk(KERN_ERR "No matching Xtal definition found\n");
 699                err = -EINVAL;
 700                goto out;
 701        }
 702
 703        info->pseudo_palette = kmalloc_array(MAX_PALETTES, sizeof(u32),
 704                                             GFP_KERNEL);
 705        if (!info->pseudo_palette) {
 706                err = -ENOMEM;
 707                goto out;
 708        }
 709
 710        info->fbops = &w100fb_ops;
 711        info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA |
 712                FBINFO_HWACCEL_FILLRECT;
 713        info->node = -1;
 714        info->screen_base = remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE);
 715        info->screen_size = REMAPPED_FB_LEN;
 716
 717        strcpy(info->fix.id, "w100fb");
 718        info->fix.type = FB_TYPE_PACKED_PIXELS;
 719        info->fix.type_aux = 0;
 720        info->fix.accel = FB_ACCEL_NONE;
 721        info->fix.smem_start = mem->start+W100_FB_BASE;
 722        info->fix.mmio_start = mem->start+W100_REG_BASE;
 723        info->fix.mmio_len = W100_REG_LEN;
 724
 725        if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
 726                err = -ENOMEM;
 727                goto out;
 728        }
 729
 730        par->mode = &inf->modelist[0];
 731        if(inf->init_mode & INIT_MODE_ROTATED) {
 732                info->var.xres = par->mode->yres;
 733                info->var.yres = par->mode->xres;
 734        }
 735        else {
 736                info->var.xres = par->mode->xres;
 737                info->var.yres = par->mode->yres;
 738        }
 739
 740        if(inf->init_mode &= INIT_MODE_FLIPPED)
 741                par->flip = 1;
 742        else
 743                par->flip = 0;
 744
 745        info->var.xres_virtual = info->var.xres;
 746        info->var.yres_virtual = info->var.yres;
 747        info->var.pixclock = 0x04;  /* 171521; */
 748        info->var.sync = 0;
 749        info->var.grayscale = 0;
 750        info->var.xoffset = info->var.yoffset = 0;
 751        info->var.accel_flags = 0;
 752        info->var.activate = FB_ACTIVATE_NOW;
 753
 754        w100_hw_init(par);
 755
 756        if (w100fb_check_var(&info->var, info) < 0) {
 757                err = -EINVAL;
 758                goto out;
 759        }
 760
 761        if (register_framebuffer(info) < 0) {
 762                err = -EINVAL;
 763                goto out;
 764        }
 765
 766        fb_info(info, "%s frame buffer device\n", 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 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        unregister_framebuffer(info);
 791
 792        vfree(par->saved_intmem);
 793        vfree(par->saved_extmem);
 794        kfree(info->pseudo_palette);
 795        fb_dealloc_cmap(&info->cmap);
 796
 797        iounmap(remapped_base);
 798        iounmap(remapped_regs);
 799        iounmap(remapped_fbuf);
 800
 801        framebuffer_release(info);
 802
 803        return 0;
 804}
 805
 806
 807/* ------------------- chipset specific functions -------------------------- */
 808
 809
 810static void w100_soft_reset(void)
 811{
 812        u16 val = readw((u16 __iomem *)remapped_base + cfgSTATUS);
 813
 814        writew(val | 0x08, (u16 __iomem *)remapped_base + cfgSTATUS);
 815        udelay(100);
 816        writew(0x00, (u16 __iomem *)remapped_base + cfgSTATUS);
 817        udelay(100);
 818}
 819
 820static void w100_update_disable(void)
 821{
 822        union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl;
 823
 824        /* Prevent display updates */
 825        disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
 826        disp_db_buf_wr_cntl.f.update_db_buf = 0;
 827        disp_db_buf_wr_cntl.f.en_db_buf = 0;
 828        writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
 829}
 830
 831static void w100_update_enable(void)
 832{
 833        union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl;
 834
 835        /* Enable display updates */
 836        disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
 837        disp_db_buf_wr_cntl.f.update_db_buf = 1;
 838        disp_db_buf_wr_cntl.f.en_db_buf = 1;
 839        writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
 840}
 841
 842unsigned long w100fb_gpio_read(int port)
 843{
 844        unsigned long value;
 845
 846        if (port==W100_GPIO_PORT_A)
 847                value = readl(remapped_regs + mmGPIO_DATA);
 848        else
 849                value = readl(remapped_regs + mmGPIO_DATA2);
 850
 851        return value;
 852}
 853
 854void w100fb_gpio_write(int port, unsigned long value)
 855{
 856        if (port==W100_GPIO_PORT_A)
 857                writel(value, remapped_regs + mmGPIO_DATA);
 858        else
 859                writel(value, remapped_regs + mmGPIO_DATA2);
 860}
 861EXPORT_SYMBOL(w100fb_gpio_read);
 862EXPORT_SYMBOL(w100fb_gpio_write);
 863
 864/*
 865 * Initialization of critical w100 hardware
 866 */
 867static void w100_hw_init(struct w100fb_par *par)
 868{
 869        u32 temp32;
 870        union cif_cntl_u cif_cntl;
 871        union intf_cntl_u intf_cntl;
 872        union cfgreg_base_u cfgreg_base;
 873        union wrap_top_dir_u wrap_top_dir;
 874        union cif_read_dbg_u cif_read_dbg;
 875        union cpu_defaults_u cpu_default;
 876        union cif_write_dbg_u cif_write_dbg;
 877        union wrap_start_dir_u wrap_start_dir;
 878        union cif_io_u cif_io;
 879        struct w100_gpio_regs *gpio = par->mach->gpio;
 880
 881        w100_soft_reset();
 882
 883        /* This is what the fpga_init code does on reset. May be wrong
 884           but there is little info available */
 885        writel(0x31, remapped_regs + mmSCRATCH_UMSK);
 886        for (temp32 = 0; temp32 < 10000; temp32++)
 887                readl(remapped_regs + mmSCRATCH_UMSK);
 888        writel(0x30, remapped_regs + mmSCRATCH_UMSK);
 889
 890        /* Set up CIF */
 891        cif_io.val = defCIF_IO;
 892        writel((u32)(cif_io.val), remapped_regs + mmCIF_IO);
 893
 894        cif_write_dbg.val = readl(remapped_regs + mmCIF_WRITE_DBG);
 895        cif_write_dbg.f.dis_packer_ful_during_rbbm_timeout = 0;
 896        cif_write_dbg.f.en_dword_split_to_rbbm = 1;
 897        cif_write_dbg.f.dis_timeout_during_rbbm = 1;
 898        writel((u32) (cif_write_dbg.val), remapped_regs + mmCIF_WRITE_DBG);
 899
 900        cif_read_dbg.val = readl(remapped_regs + mmCIF_READ_DBG);
 901        cif_read_dbg.f.dis_rd_same_byte_to_trig_fetch = 1;
 902        writel((u32) (cif_read_dbg.val), remapped_regs + mmCIF_READ_DBG);
 903
 904        cif_cntl.val = readl(remapped_regs + mmCIF_CNTL);
 905        cif_cntl.f.dis_system_bits = 1;
 906        cif_cntl.f.dis_mr = 1;
 907        cif_cntl.f.en_wait_to_compensate_dq_prop_dly = 0;
 908        cif_cntl.f.intb_oe = 1;
 909        cif_cntl.f.interrupt_active_high = 1;
 910        writel((u32) (cif_cntl.val), remapped_regs + mmCIF_CNTL);
 911
 912        /* Setup cfgINTF_CNTL and cfgCPU defaults */
 913        intf_cntl.val = defINTF_CNTL;
 914        intf_cntl.f.ad_inc_a = 1;
 915        intf_cntl.f.ad_inc_b = 1;
 916        intf_cntl.f.rd_data_rdy_a = 0;
 917        intf_cntl.f.rd_data_rdy_b = 0;
 918        writeb((u8) (intf_cntl.val), remapped_base + cfgINTF_CNTL);
 919
 920        cpu_default.val = defCPU_DEFAULTS;
 921        cpu_default.f.access_ind_addr_a = 1;
 922        cpu_default.f.access_ind_addr_b = 1;
 923        cpu_default.f.access_scratch_reg = 1;
 924        cpu_default.f.transition_size = 0;
 925        writeb((u8) (cpu_default.val), remapped_base + cfgCPU_DEFAULTS);
 926
 927        /* set up the apertures */
 928        writeb((u8) (W100_REG_BASE >> 16), remapped_base + cfgREG_BASE);
 929
 930        cfgreg_base.val = defCFGREG_BASE;
 931        cfgreg_base.f.cfgreg_base = W100_CFG_BASE;
 932        writel((u32) (cfgreg_base.val), remapped_regs + mmCFGREG_BASE);
 933
 934        wrap_start_dir.val = defWRAP_START_DIR;
 935        wrap_start_dir.f.start_addr = WRAP_BUF_BASE_VALUE >> 1;
 936        writel((u32) (wrap_start_dir.val), remapped_regs + mmWRAP_START_DIR);
 937
 938        wrap_top_dir.val = defWRAP_TOP_DIR;
 939        wrap_top_dir.f.top_addr = WRAP_BUF_TOP_VALUE >> 1;
 940        writel((u32) (wrap_top_dir.val), remapped_regs + mmWRAP_TOP_DIR);
 941
 942        writel((u32) 0x2440, remapped_regs + mmRBBM_CNTL);
 943
 944        /* Set the hardware to 565 colour */
 945        temp32 = readl(remapped_regs + mmDISP_DEBUG2);
 946        temp32 &= 0xff7fffff;
 947        temp32 |= 0x00800000;
 948        writel(temp32, remapped_regs + mmDISP_DEBUG2);
 949
 950        /* Initialise the GPIO lines */
 951        if (gpio) {
 952                writel(gpio->init_data1, remapped_regs + mmGPIO_DATA);
 953                writel(gpio->init_data2, remapped_regs + mmGPIO_DATA2);
 954                writel(gpio->gpio_dir1,  remapped_regs + mmGPIO_CNTL1);
 955                writel(gpio->gpio_oe1,   remapped_regs + mmGPIO_CNTL2);
 956                writel(gpio->gpio_dir2,  remapped_regs + mmGPIO_CNTL3);
 957                writel(gpio->gpio_oe2,   remapped_regs + mmGPIO_CNTL4);
 958        }
 959}
 960
 961
 962struct power_state {
 963        union clk_pin_cntl_u clk_pin_cntl;
 964        union pll_ref_fb_div_u pll_ref_fb_div;
 965        union pll_cntl_u pll_cntl;
 966        union sclk_cntl_u sclk_cntl;
 967        union pclk_cntl_u pclk_cntl;
 968        union pwrmgt_cntl_u pwrmgt_cntl;
 969        int auto_mode;  /* system clock auto changing? */
 970};
 971
 972
 973static struct power_state w100_pwr_state;
 974
 975/* The PLL Fout is determined by (XtalFreq/(M+1)) * ((N_int+1) + (N_fac/8)) */
 976
 977/* 12.5MHz Crystal PLL Table */
 978static struct w100_pll_info xtal_12500000[] = {
 979        /*freq     M   N_int    N_fac  tfgoal  lock_time */
 980        { 50,      0,   1,       0,     0xe0,        56},  /*  50.00 MHz */
 981        { 75,      0,   5,       0,     0xde,        37},  /*  75.00 MHz */
 982        {100,      0,   7,       0,     0xe0,        28},  /* 100.00 MHz */
 983        {125,      0,   9,       0,     0xe0,        22},  /* 125.00 MHz */
 984        {150,      0,   11,      0,     0xe0,        17},  /* 150.00 MHz */
 985        {  0,      0,   0,       0,        0,         0},  /* Terminator */
 986};
 987
 988/* 14.318MHz Crystal PLL Table */
 989static struct w100_pll_info xtal_14318000[] = {
 990        /*freq     M   N_int    N_fac  tfgoal  lock_time */
 991        { 40,      4,   13,      0,     0xe0,        80}, /* tfgoal guessed */
 992        { 50,      1,   6,       0,     0xe0,        64}, /*  50.05 MHz */
 993        { 57,      2,   11,      0,     0xe0,        53}, /* tfgoal guessed */
 994        { 75,      0,   4,       3,     0xe0,        43}, /*  75.08 MHz */
 995        {100,      0,   6,       0,     0xe0,        32}, /* 100.10 MHz */
 996        {  0,      0,   0,       0,        0,         0},
 997};
 998
 999/* 16MHz Crystal PLL Table */
1000static struct w100_pll_info xtal_16000000[] = {
1001        /*freq     M   N_int    N_fac  tfgoal  lock_time */
1002        { 72,      1,   8,       0,     0xe0,        48}, /* tfgoal guessed */
1003        { 80,      1,   9,       0,     0xe0,        13}, /* tfgoal guessed */
1004        { 95,      1,   10,      7,     0xe0,        38}, /* tfgoal guessed */
1005        { 96,      1,   11,      0,     0xe0,        36}, /* tfgoal guessed */
1006        {  0,      0,   0,       0,        0,         0},
1007};
1008
1009static struct pll_entries {
1010        int xtal_freq;
1011        struct w100_pll_info *pll_table;
1012} w100_pll_tables[] = {
1013        { 12500000, &xtal_12500000[0] },
1014        { 14318000, &xtal_14318000[0] },
1015        { 16000000, &xtal_16000000[0] },
1016        { 0 },
1017};
1018
1019struct w100_pll_info *w100_get_xtal_table(unsigned int freq)
1020{
1021        struct pll_entries *pll_entry = w100_pll_tables;
1022
1023        do {
1024                if (freq == pll_entry->xtal_freq)
1025                        return pll_entry->pll_table;
1026                pll_entry++;
1027        } while (pll_entry->xtal_freq);
1028
1029        return NULL;
1030}
1031
1032
1033static unsigned int w100_get_testcount(unsigned int testclk_sel)
1034{
1035        union clk_test_cntl_u clk_test_cntl;
1036
1037        udelay(5);
1038
1039        /* Select the test clock source and reset */
1040        clk_test_cntl.f.start_check_freq = 0x0;
1041        clk_test_cntl.f.testclk_sel = testclk_sel;
1042        clk_test_cntl.f.tstcount_rst = 0x1; /* set reset */
1043        writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
1044
1045        clk_test_cntl.f.tstcount_rst = 0x0; /* clear reset */
1046        writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
1047
1048        /* Run clock test */
1049        clk_test_cntl.f.start_check_freq = 0x1;
1050        writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
1051
1052        /* Give the test time to complete */
1053        udelay(20);
1054
1055        /* Return the result */
1056        clk_test_cntl.val = readl(remapped_regs + mmCLK_TEST_CNTL);
1057        clk_test_cntl.f.start_check_freq = 0x0;
1058        writel((u32) (clk_test_cntl.val), remapped_regs + mmCLK_TEST_CNTL);
1059
1060        return clk_test_cntl.f.test_count;
1061}
1062
1063
1064static int w100_pll_adjust(struct w100_pll_info *pll)
1065{
1066        unsigned int tf80;
1067        unsigned int tf20;
1068
1069        /* Initial Settings */
1070        w100_pwr_state.pll_cntl.f.pll_pwdn = 0x0;     /* power down */
1071        w100_pwr_state.pll_cntl.f.pll_reset = 0x0;    /* not reset */
1072        w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x1;   /* Hi-Z */
1073        w100_pwr_state.pll_cntl.f.pll_pvg = 0x0;      /* VCO gain = 0 */
1074        w100_pwr_state.pll_cntl.f.pll_vcofr = 0x0;    /* VCO frequency range control = off */
1075        w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;  /* current offset inside VCO = 0 */
1076        w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0;
1077
1078        /* Wai Ming 80 percent of VDD 1.3V gives 1.04V, minimum operating voltage is 1.08V
1079         * therefore, commented out the following lines
1080         * tf80 meant tf100
1081         */
1082        do {
1083                /* set VCO input = 0.8 * VDD */
1084                w100_pwr_state.pll_cntl.f.pll_dactal = 0xd;
1085                writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
1086
1087                tf80 = w100_get_testcount(TESTCLK_SRC_PLL);
1088                if (tf80 >= (pll->tfgoal)) {
1089                        /* set VCO input = 0.2 * VDD */
1090                        w100_pwr_state.pll_cntl.f.pll_dactal = 0x7;
1091                        writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
1092
1093                        tf20 = w100_get_testcount(TESTCLK_SRC_PLL);
1094                        if (tf20 <= (pll->tfgoal))
1095                                return 1;  /* Success */
1096
1097                        if ((w100_pwr_state.pll_cntl.f.pll_vcofr == 0x0) &&
1098                                ((w100_pwr_state.pll_cntl.f.pll_pvg == 0x7) ||
1099                                (w100_pwr_state.pll_cntl.f.pll_ioffset == 0x0))) {
1100                                /* slow VCO config */
1101                                w100_pwr_state.pll_cntl.f.pll_vcofr = 0x1;
1102                                w100_pwr_state.pll_cntl.f.pll_pvg = 0x0;
1103                                w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
1104                                continue;
1105                        }
1106                }
1107                if ((w100_pwr_state.pll_cntl.f.pll_ioffset) < 0x3) {
1108                        w100_pwr_state.pll_cntl.f.pll_ioffset += 0x1;
1109                } else if ((w100_pwr_state.pll_cntl.f.pll_pvg) < 0x7) {
1110                        w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
1111                        w100_pwr_state.pll_cntl.f.pll_pvg += 0x1;
1112                } else {
1113                        return 0;  /* Error */
1114                }
1115        } while(1);
1116}
1117
1118
1119/*
1120 * w100_pll_calibration
1121 */
1122static int w100_pll_calibration(struct w100_pll_info *pll)
1123{
1124        int status;
1125
1126        status = w100_pll_adjust(pll);
1127
1128        /* PLL Reset And Lock */
1129        /* set VCO input = 0.5 * VDD */
1130        w100_pwr_state.pll_cntl.f.pll_dactal = 0xa;
1131        writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
1132
1133        udelay(1);  /* reset time */
1134
1135        /* enable charge pump */
1136        w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0;  /* normal */
1137        writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
1138
1139        /* set VCO input = Hi-Z, disable DAC */
1140        w100_pwr_state.pll_cntl.f.pll_dactal = 0x0;
1141        writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
1142
1143        udelay(400);  /* lock time */
1144
1145        /* PLL locked */
1146
1147        return status;
1148}
1149
1150
1151static int w100_pll_set_clk(struct w100_pll_info *pll)
1152{
1153        int status;
1154
1155        if (w100_pwr_state.auto_mode == 1)  /* auto mode */
1156        {
1157                w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0;  /* disable fast to normal */
1158                w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0;  /* disable normal to fast */
1159                writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
1160        }
1161
1162        /* Set system clock source to XTAL whilst adjusting the PLL! */
1163        w100_pwr_state.sclk_cntl.f.sclk_src_sel = CLK_SRC_XTAL;
1164        writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
1165
1166        w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = pll->M;
1167        w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = pll->N_int;
1168        w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = pll->N_fac;
1169        w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = pll->lock_time;
1170        writel((u32) (w100_pwr_state.pll_ref_fb_div.val), remapped_regs + mmPLL_REF_FB_DIV);
1171
1172        w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0;
1173        writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
1174
1175        status = w100_pll_calibration(pll);
1176
1177        if (w100_pwr_state.auto_mode == 1)  /* auto mode */
1178        {
1179                w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x1;  /* reenable fast to normal */
1180                w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x1;  /* reenable normal to fast  */
1181                writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
1182        }
1183        return status;
1184}
1185
1186/* freq = target frequency of the PLL */
1187static int w100_set_pll_freq(struct w100fb_par *par, unsigned int freq)
1188{
1189        struct w100_pll_info *pll = par->pll_table;
1190
1191        do {
1192                if (freq == pll->freq) {
1193                        return w100_pll_set_clk(pll);
1194                }
1195                pll++;
1196        } while(pll->freq);
1197        return 0;
1198}
1199
1200/* Set up an initial state.  Some values/fields set
1201   here will be overwritten. */
1202static void w100_pwm_setup(struct w100fb_par *par)
1203{
1204        w100_pwr_state.clk_pin_cntl.f.osc_en = 0x1;
1205        w100_pwr_state.clk_pin_cntl.f.osc_gain = 0x1f;
1206        w100_pwr_state.clk_pin_cntl.f.dont_use_xtalin = 0x0;
1207        w100_pwr_state.clk_pin_cntl.f.xtalin_pm_en = 0x0;
1208        w100_pwr_state.clk_pin_cntl.f.xtalin_dbl_en = par->mach->xtal_dbl ? 1 : 0;
1209        w100_pwr_state.clk_pin_cntl.f.cg_debug = 0x0;
1210        writel((u32) (w100_pwr_state.clk_pin_cntl.val), remapped_regs + mmCLK_PIN_CNTL);
1211
1212        w100_pwr_state.sclk_cntl.f.sclk_src_sel = CLK_SRC_XTAL;
1213        w100_pwr_state.sclk_cntl.f.sclk_post_div_fast = 0x0;  /* Pfast = 1 */
1214        w100_pwr_state.sclk_cntl.f.sclk_clkon_hys = 0x3;
1215        w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = 0x0;  /* Pslow = 1 */
1216        w100_pwr_state.sclk_cntl.f.disp_cg_ok2switch_en = 0x0;
1217        w100_pwr_state.sclk_cntl.f.sclk_force_reg = 0x0;    /* Dynamic */
1218        w100_pwr_state.sclk_cntl.f.sclk_force_disp = 0x0;   /* Dynamic */
1219        w100_pwr_state.sclk_cntl.f.sclk_force_mc = 0x0;     /* Dynamic */
1220        w100_pwr_state.sclk_cntl.f.sclk_force_extmc = 0x0;  /* Dynamic */
1221        w100_pwr_state.sclk_cntl.f.sclk_force_cp = 0x0;     /* Dynamic */
1222        w100_pwr_state.sclk_cntl.f.sclk_force_e2 = 0x0;     /* Dynamic */
1223        w100_pwr_state.sclk_cntl.f.sclk_force_e3 = 0x0;     /* Dynamic */
1224        w100_pwr_state.sclk_cntl.f.sclk_force_idct = 0x0;   /* Dynamic */
1225        w100_pwr_state.sclk_cntl.f.sclk_force_bist = 0x0;   /* Dynamic */
1226        w100_pwr_state.sclk_cntl.f.busy_extend_cp = 0x0;
1227        w100_pwr_state.sclk_cntl.f.busy_extend_e2 = 0x0;
1228        w100_pwr_state.sclk_cntl.f.busy_extend_e3 = 0x0;
1229        w100_pwr_state.sclk_cntl.f.busy_extend_idct = 0x0;
1230        writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
1231
1232        w100_pwr_state.pclk_cntl.f.pclk_src_sel = CLK_SRC_XTAL;
1233        w100_pwr_state.pclk_cntl.f.pclk_post_div = 0x1;    /* P = 2 */
1234        w100_pwr_state.pclk_cntl.f.pclk_force_disp = 0x0;  /* Dynamic */
1235        writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
1236
1237        w100_pwr_state.pll_ref_fb_div.f.pll_ref_div = 0x0;     /* M = 1 */
1238        w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_int = 0x0;  /* N = 1.0 */
1239        w100_pwr_state.pll_ref_fb_div.f.pll_fb_div_frac = 0x0;
1240        w100_pwr_state.pll_ref_fb_div.f.pll_reset_time = 0x5;
1241        w100_pwr_state.pll_ref_fb_div.f.pll_lock_time = 0xff;
1242        writel((u32) (w100_pwr_state.pll_ref_fb_div.val), remapped_regs + mmPLL_REF_FB_DIV);
1243
1244        w100_pwr_state.pll_cntl.f.pll_pwdn = 0x1;
1245        w100_pwr_state.pll_cntl.f.pll_reset = 0x1;
1246        w100_pwr_state.pll_cntl.f.pll_pm_en = 0x0;
1247        w100_pwr_state.pll_cntl.f.pll_mode = 0x0;  /* uses VCO clock */
1248        w100_pwr_state.pll_cntl.f.pll_refclk_sel = 0x0;
1249        w100_pwr_state.pll_cntl.f.pll_fbclk_sel = 0x0;
1250        w100_pwr_state.pll_cntl.f.pll_tcpoff = 0x0;
1251        w100_pwr_state.pll_cntl.f.pll_pcp = 0x4;
1252        w100_pwr_state.pll_cntl.f.pll_pvg = 0x0;
1253        w100_pwr_state.pll_cntl.f.pll_vcofr = 0x0;
1254        w100_pwr_state.pll_cntl.f.pll_ioffset = 0x0;
1255        w100_pwr_state.pll_cntl.f.pll_pecc_mode = 0x0;
1256        w100_pwr_state.pll_cntl.f.pll_pecc_scon = 0x0;
1257        w100_pwr_state.pll_cntl.f.pll_dactal = 0x0;  /* Hi-Z */
1258        w100_pwr_state.pll_cntl.f.pll_cp_clip = 0x3;
1259        w100_pwr_state.pll_cntl.f.pll_conf = 0x2;
1260        w100_pwr_state.pll_cntl.f.pll_mbctrl = 0x2;
1261        w100_pwr_state.pll_cntl.f.pll_ring_off = 0x0;
1262        writel((u32) (w100_pwr_state.pll_cntl.val), remapped_regs + mmPLL_CNTL);
1263
1264        w100_pwr_state.pwrmgt_cntl.f.pwm_enable = 0x0;
1265        w100_pwr_state.pwrmgt_cntl.f.pwm_mode_req = 0x1;  /* normal mode (0, 1, 3) */
1266        w100_pwr_state.pwrmgt_cntl.f.pwm_wakeup_cond = 0x0;
1267        w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_hw_en = 0x0;
1268        w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_hw_en = 0x0;
1269        w100_pwr_state.pwrmgt_cntl.f.pwm_fast_noml_cond = 0x1;  /* PM4,ENG */
1270        w100_pwr_state.pwrmgt_cntl.f.pwm_noml_fast_cond = 0x1;  /* PM4,ENG */
1271        w100_pwr_state.pwrmgt_cntl.f.pwm_idle_timer = 0xFF;
1272        w100_pwr_state.pwrmgt_cntl.f.pwm_busy_timer = 0xFF;
1273        writel((u32) (w100_pwr_state.pwrmgt_cntl.val), remapped_regs + mmPWRMGT_CNTL);
1274
1275        w100_pwr_state.auto_mode = 0;  /* manual mode */
1276}
1277
1278
1279/*
1280 * Setup the w100 clocks for the specified mode
1281 */
1282static void w100_init_clocks(struct w100fb_par *par)
1283{
1284        struct w100_mode *mode = par->mode;
1285
1286        if (mode->pixclk_src == CLK_SRC_PLL || mode->sysclk_src == CLK_SRC_PLL)
1287                w100_set_pll_freq(par, (par->fastpll_mode && mode->fast_pll_freq) ? mode->fast_pll_freq : mode->pll_freq);
1288
1289        w100_pwr_state.sclk_cntl.f.sclk_src_sel = mode->sysclk_src;
1290        w100_pwr_state.sclk_cntl.f.sclk_post_div_fast = mode->sysclk_divider;
1291        w100_pwr_state.sclk_cntl.f.sclk_post_div_slow = mode->sysclk_divider;
1292        writel((u32) (w100_pwr_state.sclk_cntl.val), remapped_regs + mmSCLK_CNTL);
1293}
1294
1295static void w100_init_lcd(struct w100fb_par *par)
1296{
1297        u32 temp32;
1298        struct w100_mode *mode = par->mode;
1299        struct w100_gen_regs *regs = par->mach->regs;
1300        union active_h_disp_u active_h_disp;
1301        union active_v_disp_u active_v_disp;
1302        union graphic_h_disp_u graphic_h_disp;
1303        union graphic_v_disp_u graphic_v_disp;
1304        union crtc_total_u crtc_total;
1305
1306        /* w3200 doesn't like undefined bits being set so zero register values first */
1307
1308        active_h_disp.val = 0;
1309        active_h_disp.f.active_h_start=mode->left_margin;
1310        active_h_disp.f.active_h_end=mode->left_margin + mode->xres;
1311        writel(active_h_disp.val, remapped_regs + mmACTIVE_H_DISP);
1312
1313        active_v_disp.val = 0;
1314        active_v_disp.f.active_v_start=mode->upper_margin;
1315        active_v_disp.f.active_v_end=mode->upper_margin + mode->yres;
1316        writel(active_v_disp.val, remapped_regs + mmACTIVE_V_DISP);
1317
1318        graphic_h_disp.val = 0;
1319        graphic_h_disp.f.graphic_h_start=mode->left_margin;
1320        graphic_h_disp.f.graphic_h_end=mode->left_margin + mode->xres;
1321        writel(graphic_h_disp.val, remapped_regs + mmGRAPHIC_H_DISP);
1322
1323        graphic_v_disp.val = 0;
1324        graphic_v_disp.f.graphic_v_start=mode->upper_margin;
1325        graphic_v_disp.f.graphic_v_end=mode->upper_margin + mode->yres;
1326        writel(graphic_v_disp.val, remapped_regs + mmGRAPHIC_V_DISP);
1327
1328        crtc_total.val = 0;
1329        crtc_total.f.crtc_h_total=mode->left_margin  + mode->xres + mode->right_margin;
1330        crtc_total.f.crtc_v_total=mode->upper_margin + mode->yres + mode->lower_margin;
1331        writel(crtc_total.val, remapped_regs + mmCRTC_TOTAL);
1332
1333        writel(mode->crtc_ss, remapped_regs + mmCRTC_SS);
1334        writel(mode->crtc_ls, remapped_regs + mmCRTC_LS);
1335        writel(mode->crtc_gs, remapped_regs + mmCRTC_GS);
1336        writel(mode->crtc_vpos_gs, remapped_regs + mmCRTC_VPOS_GS);
1337        writel(mode->crtc_rev, remapped_regs + mmCRTC_REV);
1338        writel(mode->crtc_dclk, remapped_regs + mmCRTC_DCLK);
1339        writel(mode->crtc_gclk, remapped_regs + mmCRTC_GCLK);
1340        writel(mode->crtc_goe, remapped_regs + mmCRTC_GOE);
1341        writel(mode->crtc_ps1_active, remapped_regs + mmCRTC_PS1_ACTIVE);
1342
1343        writel(regs->lcd_format, remapped_regs + mmLCD_FORMAT);
1344        writel(regs->lcdd_cntl1, remapped_regs + mmLCDD_CNTL1);
1345        writel(regs->lcdd_cntl2, remapped_regs + mmLCDD_CNTL2);
1346        writel(regs->genlcd_cntl1, remapped_regs + mmGENLCD_CNTL1);
1347        writel(regs->genlcd_cntl2, remapped_regs + mmGENLCD_CNTL2);
1348        writel(regs->genlcd_cntl3, remapped_regs + mmGENLCD_CNTL3);
1349
1350        writel(0x00000000, remapped_regs + mmCRTC_FRAME);
1351        writel(0x00000000, remapped_regs + mmCRTC_FRAME_VPOS);
1352        writel(0x00000000, remapped_regs + mmCRTC_DEFAULT_COUNT);
1353        writel(0x0000FF00, remapped_regs + mmLCD_BACKGROUND_COLOR);
1354
1355        /* Hack for overlay in ext memory */
1356        temp32 = readl(remapped_regs + mmDISP_DEBUG2);
1357        temp32 |= 0xc0000000;
1358        writel(temp32, remapped_regs + mmDISP_DEBUG2);
1359}
1360
1361
1362static void w100_setup_memory(struct w100fb_par *par)
1363{
1364        union mc_ext_mem_location_u extmem_location;
1365        union mc_fb_location_u intmem_location;
1366        struct w100_mem_info *mem = par->mach->mem;
1367        struct w100_bm_mem_info *bm_mem = par->mach->bm_mem;
1368
1369        if (!par->extmem_active) {
1370                w100_suspend(W100_SUSPEND_EXTMEM);
1371
1372                /* Map Internal Memory at FB Base */
1373                intmem_location.f.mc_fb_start = W100_FB_BASE >> 8;
1374                intmem_location.f.mc_fb_top = (W100_FB_BASE+MEM_INT_SIZE) >> 8;
1375                writel((u32) (intmem_location.val), remapped_regs + mmMC_FB_LOCATION);
1376
1377                /* Unmap External Memory - value is *probably* irrelevant but may have meaning
1378                   to acceleration libraries */
1379                extmem_location.f.mc_ext_mem_start = MEM_EXT_BASE_VALUE >> 8;
1380                extmem_location.f.mc_ext_mem_top = (MEM_EXT_BASE_VALUE-1) >> 8;
1381                writel((u32) (extmem_location.val), remapped_regs + mmMC_EXT_MEM_LOCATION);
1382        } else {
1383                /* Map Internal Memory to its default location */
1384                intmem_location.f.mc_fb_start = MEM_INT_BASE_VALUE >> 8;
1385                intmem_location.f.mc_fb_top = (MEM_INT_BASE_VALUE+MEM_INT_SIZE) >> 8;
1386                writel((u32) (intmem_location.val), remapped_regs + mmMC_FB_LOCATION);
1387
1388                /* Map External Memory at FB Base */
1389                extmem_location.f.mc_ext_mem_start = W100_FB_BASE >> 8;
1390                extmem_location.f.mc_ext_mem_top = (W100_FB_BASE+par->mach->mem->size) >> 8;
1391                writel((u32) (extmem_location.val), remapped_regs + mmMC_EXT_MEM_LOCATION);
1392
1393                writel(0x00007800, remapped_regs + mmMC_BIST_CTRL);
1394                writel(mem->ext_cntl, remapped_regs + mmMEM_EXT_CNTL);
1395                writel(0x00200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
1396                udelay(100);
1397                writel(0x80200021, remapped_regs + mmMEM_SDRAM_MODE_REG);
1398                udelay(100);
1399                writel(mem->sdram_mode_reg, remapped_regs + mmMEM_SDRAM_MODE_REG);
1400                udelay(100);
1401                writel(mem->ext_timing_cntl, remapped_regs + mmMEM_EXT_TIMING_CNTL);
1402                writel(mem->io_cntl, remapped_regs + mmMEM_IO_CNTL);
1403                if (bm_mem) {
1404                        writel(bm_mem->ext_mem_bw, remapped_regs + mmBM_EXT_MEM_BANDWIDTH);
1405                        writel(bm_mem->offset, remapped_regs + mmBM_OFFSET);
1406                        writel(bm_mem->ext_timing_ctl, remapped_regs + mmBM_MEM_EXT_TIMING_CNTL);
1407                        writel(bm_mem->ext_cntl, remapped_regs + mmBM_MEM_EXT_CNTL);
1408                        writel(bm_mem->mode_reg, remapped_regs + mmBM_MEM_MODE_REG);
1409                        writel(bm_mem->io_cntl, remapped_regs + mmBM_MEM_IO_CNTL);
1410                        writel(bm_mem->config, remapped_regs + mmBM_CONFIG);
1411                }
1412        }
1413}
1414
1415static void w100_set_dispregs(struct w100fb_par *par)
1416{
1417        unsigned long rot=0, divider, offset=0;
1418        union graphic_ctrl_u graphic_ctrl;
1419
1420        /* See if the mode has been rotated */
1421        if (par->xres == par->mode->xres) {
1422                if (par->flip) {
1423                        rot=3; /* 180 degree */
1424                        offset=(par->xres * par->yres) - 1;
1425                } /* else 0 degree */
1426                divider = par->mode->pixclk_divider;
1427        } else {
1428                if (par->flip) {
1429                        rot=2; /* 270 degree */
1430                        offset=par->xres - 1;
1431                } else {
1432                        rot=1; /* 90 degree */
1433                        offset=par->xres * (par->yres - 1);
1434                }
1435                divider = par->mode->pixclk_divider_rotated;
1436        }
1437
1438        graphic_ctrl.val = 0; /* w32xx doesn't like undefined bits */
1439        switch (par->chip_id) {
1440                case CHIP_ID_W100:
1441                        graphic_ctrl.f_w100.color_depth=6;
1442                        graphic_ctrl.f_w100.en_crtc=1;
1443                        graphic_ctrl.f_w100.en_graphic_req=1;
1444                        graphic_ctrl.f_w100.en_graphic_crtc=1;
1445                        graphic_ctrl.f_w100.lcd_pclk_on=1;
1446                        graphic_ctrl.f_w100.lcd_sclk_on=1;
1447                        graphic_ctrl.f_w100.low_power_on=0;
1448                        graphic_ctrl.f_w100.req_freq=0;
1449                        graphic_ctrl.f_w100.portrait_mode=rot;
1450
1451                        /* Zaurus needs this */
1452                        switch(par->xres) {
1453                                case 240:
1454                                case 320:
1455                                default:
1456                                        graphic_ctrl.f_w100.total_req_graphic=0xa0;
1457                                        break;
1458                                case 480:
1459                                case 640:
1460                                        switch(rot) {
1461                                                case 0:  /* 0 */
1462                                                case 3:  /* 180 */
1463                                                        graphic_ctrl.f_w100.low_power_on=1;
1464                                                        graphic_ctrl.f_w100.req_freq=5;
1465                                                break;
1466                                                case 1:  /* 90 */
1467                                                case 2:  /* 270 */
1468                                                        graphic_ctrl.f_w100.req_freq=4;
1469                                                        break;
1470                                                default:
1471                                                        break;
1472                                        }
1473                                        graphic_ctrl.f_w100.total_req_graphic=0xf0;
1474                                        break;
1475                        }
1476                        break;
1477                case CHIP_ID_W3200:
1478                case CHIP_ID_W3220:
1479                        graphic_ctrl.f_w32xx.color_depth=6;
1480                        graphic_ctrl.f_w32xx.en_crtc=1;
1481                        graphic_ctrl.f_w32xx.en_graphic_req=1;
1482                        graphic_ctrl.f_w32xx.en_graphic_crtc=1;
1483                        graphic_ctrl.f_w32xx.lcd_pclk_on=1;
1484                        graphic_ctrl.f_w32xx.lcd_sclk_on=1;
1485                        graphic_ctrl.f_w32xx.low_power_on=0;
1486                        graphic_ctrl.f_w32xx.req_freq=0;
1487                        graphic_ctrl.f_w32xx.total_req_graphic=par->mode->xres >> 1; /* panel xres, not mode */
1488                        graphic_ctrl.f_w32xx.portrait_mode=rot;
1489                        break;
1490        }
1491
1492        /* Set the pixel clock source and divider */
1493        w100_pwr_state.pclk_cntl.f.pclk_src_sel = par->mode->pixclk_src;
1494        w100_pwr_state.pclk_cntl.f.pclk_post_div = divider;
1495        writel((u32) (w100_pwr_state.pclk_cntl.val), remapped_regs + mmPCLK_CNTL);
1496
1497        writel(graphic_ctrl.val, remapped_regs + mmGRAPHIC_CTRL);
1498        writel(W100_FB_BASE + ((offset * BITS_PER_PIXEL/8)&~0x03UL), remapped_regs + mmGRAPHIC_OFFSET);
1499        writel((par->xres*BITS_PER_PIXEL/8), remapped_regs + mmGRAPHIC_PITCH);
1500}
1501
1502
1503/*
1504 * Work out how long the sync pulse lasts
1505 * Value is 1/(time in seconds)
1506 */
1507static void calc_hsync(struct w100fb_par *par)
1508{
1509        unsigned long hsync;
1510        struct w100_mode *mode = par->mode;
1511        union crtc_ss_u crtc_ss;
1512
1513        if (mode->pixclk_src == CLK_SRC_XTAL)
1514                hsync=par->mach->xtal_freq;
1515        else
1516                hsync=((par->fastpll_mode && mode->fast_pll_freq) ? mode->fast_pll_freq : mode->pll_freq)*100000;
1517
1518        hsync /= (w100_pwr_state.pclk_cntl.f.pclk_post_div + 1);
1519
1520        crtc_ss.val = readl(remapped_regs + mmCRTC_SS);
1521        if (crtc_ss.val)
1522                par->hsync_len = hsync / (crtc_ss.f.ss_end-crtc_ss.f.ss_start);
1523        else
1524                par->hsync_len = 0;
1525}
1526
1527static void w100_suspend(u32 mode)
1528{
1529        u32 val;
1530
1531        writel(0x7FFF8000, remapped_regs + mmMC_EXT_MEM_LOCATION);
1532        writel(0x00FF0000, remapped_regs + mmMC_PERF_MON_CNTL);
1533
1534        val = readl(remapped_regs + mmMEM_EXT_TIMING_CNTL);
1535        val &= ~(0x00100000);  /* bit20=0 */
1536        val |= 0xFF000000;     /* bit31:24=0xff */
1537        writel(val, remapped_regs + mmMEM_EXT_TIMING_CNTL);
1538
1539        val = readl(remapped_regs + mmMEM_EXT_CNTL);
1540        val &= ~(0x00040000);  /* bit18=0 */
1541        val |= 0x00080000;     /* bit19=1 */
1542        writel(val, remapped_regs + mmMEM_EXT_CNTL);
1543
1544        udelay(1);  /* wait 1us */
1545
1546        if (mode == W100_SUSPEND_EXTMEM) {
1547                /* CKE: Tri-State */
1548                val = readl(remapped_regs + mmMEM_EXT_CNTL);
1549                val |= 0x40000000;  /* bit30=1 */
1550                writel(val, remapped_regs + mmMEM_EXT_CNTL);
1551
1552                /* CLK: Stop */
1553                val = readl(remapped_regs + mmMEM_EXT_CNTL);
1554                val &= ~(0x00000001);  /* bit0=0 */
1555                writel(val, remapped_regs + mmMEM_EXT_CNTL);
1556        } else {
1557                writel(0x00000000, remapped_regs + mmSCLK_CNTL);
1558                writel(0x000000BF, remapped_regs + mmCLK_PIN_CNTL);
1559                writel(0x00000015, remapped_regs + mmPWRMGT_CNTL);
1560
1561                udelay(5);
1562
1563                val = readl(remapped_regs + mmPLL_CNTL);
1564                val |= 0x00000004;  /* bit2=1 */
1565                writel(val, remapped_regs + mmPLL_CNTL);
1566
1567                writel(0x00000000, remapped_regs + mmLCDD_CNTL1);
1568                writel(0x00000000, remapped_regs + mmLCDD_CNTL2);
1569                writel(0x00000000, remapped_regs + mmGENLCD_CNTL1);
1570                writel(0x00000000, remapped_regs + mmGENLCD_CNTL2);
1571                writel(0x00000000, remapped_regs + mmGENLCD_CNTL3);
1572
1573                val = readl(remapped_regs + mmMEM_EXT_CNTL);
1574                val |= 0xF0000000;
1575                val &= ~(0x00000001);
1576                writel(val, remapped_regs + mmMEM_EXT_CNTL);
1577
1578                writel(0x0000001d, remapped_regs + mmPWRMGT_CNTL);
1579        }
1580}
1581
1582static void w100_vsync(void)
1583{
1584        u32 tmp;
1585        int timeout = 30000;  /* VSync timeout = 30[ms] > 16.8[ms] */
1586
1587        tmp = readl(remapped_regs + mmACTIVE_V_DISP);
1588
1589        /* set vline pos  */
1590        writel((tmp >> 16) & 0x3ff, remapped_regs + mmDISP_INT_CNTL);
1591
1592        /* disable vline irq */
1593        tmp = readl(remapped_regs + mmGEN_INT_CNTL);
1594
1595        tmp &= ~0x00000002;
1596        writel(tmp, remapped_regs + mmGEN_INT_CNTL);
1597
1598        /* clear vline irq status */
1599        writel(0x00000002, remapped_regs + mmGEN_INT_STATUS);
1600
1601        /* enable vline irq */
1602        writel((tmp | 0x00000002), remapped_regs + mmGEN_INT_CNTL);
1603
1604        /* clear vline irq status */
1605        writel(0x00000002, remapped_regs + mmGEN_INT_STATUS);
1606
1607        while(timeout > 0) {
1608                if (readl(remapped_regs + mmGEN_INT_STATUS) & 0x00000002)
1609                        break;
1610                udelay(1);
1611                timeout--;
1612        }
1613
1614        /* disable vline irq */
1615        writel(tmp, remapped_regs + mmGEN_INT_CNTL);
1616
1617        /* clear vline irq status */
1618        writel(0x00000002, remapped_regs + mmGEN_INT_STATUS);
1619}
1620
1621static struct platform_driver w100fb_driver = {
1622        .probe          = w100fb_probe,
1623        .remove         = w100fb_remove,
1624        .suspend        = w100fb_suspend,
1625        .resume         = w100fb_resume,
1626        .driver         = {
1627                .name   = "w100fb",
1628                .dev_groups     = w100fb_groups,
1629        },
1630};
1631
1632module_platform_driver(w100fb_driver);
1633
1634MODULE_DESCRIPTION("ATI Imageon w100 framebuffer driver");
1635MODULE_LICENSE("GPL");
1636