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