linux/drivers/video/fbdev/w100fb.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * linux/drivers/video/w100fb.c
   4 *
   5 * Frame Buffer Device for ATI Imageon w100 (Wallaby)
   6 *
   7 * Copyright (C) 2002, ATI Corp.
   8 * Copyright (C) 2004-2006 Richard Purdie
   9 * Copyright (c) 2005 Ian Molton
  10 * Copyright (c) 2006 Alberto Mardegan
  11 *
  12 * Rewritten for 2.6 by Richard Purdie <rpurdie@rpsys.net>
  13 *
  14 * Generic platform support by Ian Molton <spyro@f2s.com>
  15 * and Richard Purdie <rpurdie@rpsys.net>
  16 *
  17 * w32xx support by Ian Molton
  18 *
  19 * Hardware acceleration support by Alberto Mardegan
  20 * <mardy@users.sourceforge.net>
  21 */
  22
  23#include <linux/delay.h>
  24#include <linux/fb.h>
  25#include <linux/init.h>
  26#include <linux/kernel.h>
  27#include <linux/mm.h>
  28#include <linux/platform_device.h>
  29#include <linux/slab.h>
  30#include <linux/string.h>
  31#include <linux/vmalloc.h>
  32#include <linux/module.h>
  33#include <asm/io.h>
  34#include <linux/uaccess.h>
  35#include <video/w100fb.h>
  36#include "w100fb.h"
  37
  38/*
  39 * Prototypes
  40 */
  41static void w100_suspend(u32 mode);
  42static void w100_vsync(void);
  43static void w100_hw_init(struct w100fb_par*);
  44static void w100_pwm_setup(struct w100fb_par*);
  45static void w100_init_clocks(struct w100fb_par*);
  46static void w100_setup_memory(struct w100fb_par*);
  47static void w100_init_lcd(struct w100fb_par*);
  48static void w100_set_dispregs(struct w100fb_par*);
  49static void w100_update_enable(void);
  50static void w100_update_disable(void);
  51static void calc_hsync(struct w100fb_par *par);
  52static void w100_init_graphic_engine(struct w100fb_par *par);
  53struct w100_pll_info *w100_get_xtal_table(unsigned int freq);
  54
  55/* Pseudo palette size */
  56#define MAX_PALETTES      16
  57
  58#define W100_SUSPEND_EXTMEM 0
  59#define W100_SUSPEND_ALL    1
  60
  61#define BITS_PER_PIXEL    16
  62
  63/* Remapped addresses for base cfg, memmapped regs and the frame buffer itself */
  64static void *remapped_base;
  65static void *remapped_regs;
  66static void *remapped_fbuf;
  67
  68#define REMAPPED_FB_LEN   0x15ffff
  69
  70/* This is the offset in the w100's address space we map the current
  71   framebuffer memory to. We use the position of external memory as
  72   we can remap internal memory to there if external isn't present. */
  73#define W100_FB_BASE MEM_EXT_BASE_VALUE
  74
  75
  76/*
  77 * Sysfs functions
  78 */
  79static ssize_t flip_show(struct device *dev, struct device_attribute *attr, char *buf)
  80{
  81        struct fb_info *info = dev_get_drvdata(dev);
  82        struct w100fb_par *par=info->par;
  83
  84        return sprintf(buf, "%d\n",par->flip);
  85}
  86
  87static ssize_t flip_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
  88{
  89        unsigned int flip;
  90        struct fb_info *info = dev_get_drvdata(dev);
  91        struct w100fb_par *par=info->par;
  92
  93        flip = simple_strtoul(buf, NULL, 10);
  94
  95        if (flip > 0)
  96                par->flip = 1;
  97        else
  98                par->flip = 0;
  99
 100        w100_update_disable();
 101        w100_set_dispregs(par);
 102        w100_update_enable();
 103
 104        calc_hsync(par);
 105
 106        return count;
 107}
 108
 109static DEVICE_ATTR_RW(flip);
 110
 111static ssize_t w100fb_reg_read(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 112{
 113        unsigned long regs, param;
 114        regs = simple_strtoul(buf, NULL, 16);
 115        param = readl(remapped_regs + regs);
 116        printk("Read Register 0x%08lX: 0x%08lX\n", regs, param);
 117        return count;
 118}
 119
 120static DEVICE_ATTR(reg_read, 0200, NULL, w100fb_reg_read);
 121
 122static ssize_t w100fb_reg_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 123{
 124        unsigned long regs, param;
 125        sscanf(buf, "%lx %lx", &regs, &param);
 126
 127        if (regs <= 0x2000) {
 128                printk("Write Register 0x%08lX: 0x%08lX\n", regs, param);
 129                writel(param, remapped_regs + regs);
 130        }
 131
 132        return count;
 133}
 134
 135static DEVICE_ATTR(reg_write, 0200, NULL, w100fb_reg_write);
 136
 137
 138static ssize_t fastpllclk_show(struct device *dev, struct device_attribute *attr, char *buf)
 139{
 140        struct fb_info *info = dev_get_drvdata(dev);
 141        struct w100fb_par *par=info->par;
 142
 143        return sprintf(buf, "%d\n",par->fastpll_mode);
 144}
 145
 146static ssize_t fastpllclk_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 147{
 148        struct fb_info *info = dev_get_drvdata(dev);
 149        struct w100fb_par *par=info->par;
 150
 151        if (simple_strtoul(buf, NULL, 10) > 0) {
 152                par->fastpll_mode=1;
 153                printk("w100fb: Using fast system clock (if possible)\n");
 154        } else {
 155                par->fastpll_mode=0;
 156                printk("w100fb: Using normal system clock\n");
 157        }
 158
 159        w100_init_clocks(par);
 160        calc_hsync(par);
 161
 162        return count;
 163}
 164
 165static DEVICE_ATTR_RW(fastpllclk);
 166
 167/*
 168 * Some touchscreens need hsync information from the video driver to
 169 * function correctly. We export it here.
 170 */
 171unsigned long w100fb_get_hsynclen(struct device *dev)
 172{
 173        struct fb_info *info = dev_get_drvdata(dev);
 174        struct w100fb_par *par=info->par;
 175
 176        /* If display is blanked/suspended, hsync isn't active */
 177        if (par->blanked)
 178                return 0;
 179        else
 180                return par->hsync_len;
 181}
 182EXPORT_SYMBOL(w100fb_get_hsynclen);
 183
 184static void w100fb_clear_screen(struct w100fb_par *par)
 185{
 186        memset_io(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), 0, (par->xres * par->yres * BITS_PER_PIXEL/8));
 187}
 188
 189
 190/*
 191 * Set a palette value from rgb components
 192 */
 193static int w100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 194                             u_int trans, struct fb_info *info)
 195{
 196        unsigned int val;
 197        int ret = 1;
 198
 199        /*
 200         * If greyscale is true, then we convert the RGB value
 201         * to greyscale no matter what visual we are using.
 202         */
 203        if (info->var.grayscale)
 204                red = green = blue = (19595 * red + 38470 * green + 7471 * blue) >> 16;
 205
 206        /*
 207         * 16-bit True Colour.  We encode the RGB value
 208         * according to the RGB bitfield information.
 209         */
 210        if (regno < MAX_PALETTES) {
 211                u32 *pal = info->pseudo_palette;
 212
 213                val = (red & 0xf800) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
 214                pal[regno] = val;
 215                ret = 0;
 216        }
 217        return ret;
 218}
 219
 220
 221/*
 222 * Blank the display based on value in blank_mode
 223 */
 224static int w100fb_blank(int blank_mode, struct fb_info *info)
 225{
 226        struct w100fb_par *par = info->par;
 227        struct w100_tg_info *tg = par->mach->tg;
 228
 229        switch(blank_mode) {
 230
 231        case FB_BLANK_NORMAL:         /* Normal blanking */
 232        case FB_BLANK_VSYNC_SUSPEND:  /* VESA blank (vsync off) */
 233        case FB_BLANK_HSYNC_SUSPEND:  /* VESA blank (hsync off) */
 234        case FB_BLANK_POWERDOWN:      /* Poweroff */
 235                if (par->blanked == 0) {
 236                        if(tg && tg->suspend)
 237                                tg->suspend(par);
 238                        par->blanked = 1;
 239                }
 240                break;
 241
 242        case FB_BLANK_UNBLANK: /* Unblanking */
 243                if (par->blanked != 0) {
 244                        if(tg && tg->resume)
 245                                tg->resume(par);
 246                        par->blanked = 0;
 247                }
 248                break;
 249        }
 250        return 0;
 251}
 252
 253
 254static void w100_fifo_wait(int entries)
 255{
 256        union rbbm_status_u status;
 257        int i;
 258
 259        for (i = 0; i < 2000000; i++) {
 260                status.val = readl(remapped_regs + mmRBBM_STATUS);
 261                if (status.f.cmdfifo_avail >= entries)
 262                        return;
 263                udelay(1);
 264        }
 265        printk(KERN_ERR "w100fb: FIFO Timeout!\n");
 266}
 267
 268
 269static int w100fb_sync(struct fb_info *info)
 270{
 271        union rbbm_status_u status;
 272        int i;
 273
 274        for (i = 0; i < 2000000; i++) {
 275                status.val = readl(remapped_regs + mmRBBM_STATUS);
 276                if (!status.f.gui_active)
 277                        return 0;
 278                udelay(1);
 279        }
 280        printk(KERN_ERR "w100fb: Graphic engine timeout!\n");
 281        return -EBUSY;
 282}
 283
 284
 285static void w100_init_graphic_engine(struct w100fb_par *par)
 286{
 287        union dp_gui_master_cntl_u gmc;
 288        union dp_mix_u dp_mix;
 289        union dp_datatype_u dp_datatype;
 290        union dp_cntl_u dp_cntl;
 291
 292        w100_fifo_wait(4);
 293        writel(W100_FB_BASE, remapped_regs + mmDST_OFFSET);
 294        writel(par->xres, remapped_regs + mmDST_PITCH);
 295        writel(W100_FB_BASE, remapped_regs + mmSRC_OFFSET);
 296        writel(par->xres, remapped_regs + mmSRC_PITCH);
 297
 298        w100_fifo_wait(3);
 299        writel(0, remapped_regs + mmSC_TOP_LEFT);
 300        writel((par->yres << 16) | par->xres, remapped_regs + mmSC_BOTTOM_RIGHT);
 301        writel(0x1fff1fff, remapped_regs + mmSRC_SC_BOTTOM_RIGHT);
 302
 303        w100_fifo_wait(4);
 304        dp_cntl.val = 0;
 305        dp_cntl.f.dst_x_dir = 1;
 306        dp_cntl.f.dst_y_dir = 1;
 307        dp_cntl.f.src_x_dir = 1;
 308        dp_cntl.f.src_y_dir = 1;
 309        dp_cntl.f.dst_major_x = 1;
 310        dp_cntl.f.src_major_x = 1;
 311        writel(dp_cntl.val, remapped_regs + mmDP_CNTL);
 312
 313        gmc.val = 0;
 314        gmc.f.gmc_src_pitch_offset_cntl = 1;
 315        gmc.f.gmc_dst_pitch_offset_cntl = 1;
 316        gmc.f.gmc_src_clipping = 1;
 317        gmc.f.gmc_dst_clipping = 1;
 318        gmc.f.gmc_brush_datatype = GMC_BRUSH_NONE;
 319        gmc.f.gmc_dst_datatype = 3; /* from DstType_16Bpp_444 */
 320        gmc.f.gmc_src_datatype = SRC_DATATYPE_EQU_DST;
 321        gmc.f.gmc_byte_pix_order = 1;
 322        gmc.f.gmc_default_sel = 0;
 323        gmc.f.gmc_rop3 = ROP3_SRCCOPY;
 324        gmc.f.gmc_dp_src_source = DP_SRC_MEM_RECTANGULAR;
 325        gmc.f.gmc_clr_cmp_fcn_dis = 1;
 326        gmc.f.gmc_wr_msk_dis = 1;
 327        gmc.f.gmc_dp_op = DP_OP_ROP;
 328        writel(gmc.val, remapped_regs + mmDP_GUI_MASTER_CNTL);
 329
 330        dp_datatype.val = dp_mix.val = 0;
 331        dp_datatype.f.dp_dst_datatype = gmc.f.gmc_dst_datatype;
 332        dp_datatype.f.dp_brush_datatype = gmc.f.gmc_brush_datatype;
 333        dp_datatype.f.dp_src2_type = 0;
 334        dp_datatype.f.dp_src2_datatype = gmc.f.gmc_src_datatype;
 335        dp_datatype.f.dp_src_datatype = gmc.f.gmc_src_datatype;
 336        dp_datatype.f.dp_byte_pix_order = gmc.f.gmc_byte_pix_order;
 337        writel(dp_datatype.val, remapped_regs + mmDP_DATATYPE);
 338
 339        dp_mix.f.dp_src_source = gmc.f.gmc_dp_src_source;
 340        dp_mix.f.dp_src2_source = 1;
 341        dp_mix.f.dp_rop3 = gmc.f.gmc_rop3;
 342        dp_mix.f.dp_op = gmc.f.gmc_dp_op;
 343        writel(dp_mix.val, remapped_regs + mmDP_MIX);
 344}
 345
 346
 347static void w100fb_fillrect(struct fb_info *info,
 348                            const struct fb_fillrect *rect)
 349{
 350        union dp_gui_master_cntl_u gmc;
 351
 352        if (info->state != FBINFO_STATE_RUNNING)
 353                return;
 354        if (info->flags & FBINFO_HWACCEL_DISABLED) {
 355                cfb_fillrect(info, rect);
 356                return;
 357        }
 358
 359        gmc.val = readl(remapped_regs + mmDP_GUI_MASTER_CNTL);
 360        gmc.f.gmc_rop3 = ROP3_PATCOPY;
 361        gmc.f.gmc_brush_datatype = GMC_BRUSH_SOLID_COLOR;
 362        w100_fifo_wait(2);
 363        writel(gmc.val, remapped_regs + mmDP_GUI_MASTER_CNTL);
 364        writel(rect->color, remapped_regs + mmDP_BRUSH_FRGD_CLR);
 365
 366        w100_fifo_wait(2);
 367        writel((rect->dy << 16) | (rect->dx & 0xffff), remapped_regs + mmDST_Y_X);
 368        writel((rect->width << 16) | (rect->height & 0xffff),
 369               remapped_regs + mmDST_WIDTH_HEIGHT);
 370}
 371
 372
 373static void w100fb_copyarea(struct fb_info *info,
 374                            const struct fb_copyarea *area)
 375{
 376        u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
 377        u32 h = area->height, w = area->width;
 378        union dp_gui_master_cntl_u gmc;
 379
 380        if (info->state != FBINFO_STATE_RUNNING)
 381                return;
 382        if (info->flags & FBINFO_HWACCEL_DISABLED) {
 383                cfb_copyarea(info, area);
 384                return;
 385        }
 386
 387        gmc.val = readl(remapped_regs + mmDP_GUI_MASTER_CNTL);
 388        gmc.f.gmc_rop3 = ROP3_SRCCOPY;
 389        gmc.f.gmc_brush_datatype = GMC_BRUSH_NONE;
 390        w100_fifo_wait(1);
 391        writel(gmc.val, remapped_regs + mmDP_GUI_MASTER_CNTL);
 392
 393        w100_fifo_wait(3);
 394        writel((sy << 16) | (sx & 0xffff), remapped_regs + mmSRC_Y_X);
 395        writel((dy << 16) | (dx & 0xffff), remapped_regs + mmDST_Y_X);
 396        writel((w << 16) | (h & 0xffff), remapped_regs + mmDST_WIDTH_HEIGHT);
 397}
 398
 399
 400/*
 401 *  Change the resolution by calling the appropriate hardware functions
 402 */
 403static void w100fb_activate_var(struct w100fb_par *par)
 404{
 405        struct w100_tg_info *tg = par->mach->tg;
 406
 407        w100_pwm_setup(par);
 408        w100_setup_memory(par);
 409        w100_init_clocks(par);
 410        w100fb_clear_screen(par);
 411        w100_vsync();
 412
 413        w100_update_disable();
 414        w100_init_lcd(par);
 415        w100_set_dispregs(par);
 416        w100_update_enable();
 417        w100_init_graphic_engine(par);
 418
 419        calc_hsync(par);
 420
 421        if (!par->blanked && tg && tg->change)
 422                tg->change(par);
 423}
 424
 425
 426/* Select the smallest mode that allows the desired resolution to be
 427 * displayed. If desired, the x and y parameters can be rounded up to
 428 * match the selected mode.
 429 */
 430static struct w100_mode *w100fb_get_mode(struct w100fb_par *par, unsigned int *x, unsigned int *y, int saveval)
 431{
 432        struct w100_mode *mode = NULL;
 433        struct w100_mode *modelist = par->mach->modelist;
 434        unsigned int best_x = 0xffffffff, best_y = 0xffffffff;
 435        unsigned int i;
 436
 437        for (i = 0 ; i < par->mach->num_modes ; i++) {
 438                if (modelist[i].xres >= *x && modelist[i].yres >= *y &&
 439                                modelist[i].xres < best_x && modelist[i].yres < best_y) {
 440                        best_x = modelist[i].xres;
 441                        best_y = modelist[i].yres;
 442                        mode = &modelist[i];
 443                } else if(modelist[i].xres >= *y && modelist[i].yres >= *x &&
 444                        modelist[i].xres < best_y && modelist[i].yres < best_x) {
 445                        best_x = modelist[i].yres;
 446                        best_y = modelist[i].xres;
 447                        mode = &modelist[i];
 448                }
 449        }
 450
 451        if (mode && saveval) {
 452                *x = best_x;
 453                *y = best_y;
 454        }
 455
 456        return mode;
 457}
 458
 459
 460/*
 461 *  w100fb_check_var():
 462 *  Get the video params out of 'var'. If a value doesn't fit, round it up,
 463 *  if it's too big, return -EINVAL.
 464 */
 465static int w100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 466{
 467        struct w100fb_par *par=info->par;
 468
 469        if(!w100fb_get_mode(par, &var->xres, &var->yres, 1))
 470                return -EINVAL;
 471
 472        if (par->mach->mem && ((var->xres*var->yres*BITS_PER_PIXEL/8) > (par->mach->mem->size+1)))
 473                return -EINVAL;
 474
 475        if (!par->mach->mem && ((var->xres*var->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1)))
 476                return -EINVAL;
 477
 478        var->xres_virtual = max(var->xres_virtual, var->xres);
 479        var->yres_virtual = max(var->yres_virtual, var->yres);
 480
 481        if (var->bits_per_pixel > BITS_PER_PIXEL)
 482                return -EINVAL;
 483        else
 484                var->bits_per_pixel = BITS_PER_PIXEL;
 485
 486        var->red.offset = 11;
 487        var->red.length = 5;
 488        var->green.offset = 5;
 489        var->green.length = 6;
 490        var->blue.offset = 0;
 491        var->blue.length = 5;
 492        var->transp.offset = var->transp.length = 0;
 493
 494        var->nonstd = 0;
 495        var->height = -1;
 496        var->width = -1;
 497        var->vmode = FB_VMODE_NONINTERLACED;
 498        var->sync = 0;
 499        var->pixclock = 0x04;  /* 171521; */
 500
 501        return 0;
 502}
 503
 504
 505/*
 506 * w100fb_set_par():
 507 *      Set the user defined part of the display for the specified console
 508 *  by looking at the values in info.var
 509 */
 510static int w100fb_set_par(struct fb_info *info)
 511{
 512        struct w100fb_par *par=info->par;
 513
 514        if (par->xres != info->var.xres || par->yres != info->var.yres) {
 515                par->xres = info->var.xres;
 516                par->yres = info->var.yres;
 517                par->mode = w100fb_get_mode(par, &par->xres, &par->yres, 0);
 518
 519                info->fix.visual = FB_VISUAL_TRUECOLOR;
 520                info->fix.ypanstep = 0;
 521                info->fix.ywrapstep = 0;
 522                info->fix.line_length = par->xres * BITS_PER_PIXEL / 8;
 523
 524                mutex_lock(&info->mm_lock);
 525                if ((par->xres*par->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1)) {
 526                        par->extmem_active = 1;
 527                        info->fix.smem_len = par->mach->mem->size+1;
 528                } else {
 529                        par->extmem_active = 0;
 530                        info->fix.smem_len = MEM_INT_SIZE+1;
 531                }
 532                mutex_unlock(&info->mm_lock);
 533
 534                w100fb_activate_var(par);
 535        }
 536        return 0;
 537}
 538
 539
 540/*
 541 *  Frame buffer operations
 542 */
 543static struct fb_ops w100fb_ops = {
 544        .owner        = THIS_MODULE,
 545        .fb_check_var = w100fb_check_var,
 546        .fb_set_par   = w100fb_set_par,
 547        .fb_setcolreg = w100fb_setcolreg,
 548        .fb_blank     = w100fb_blank,
 549        .fb_fillrect  = w100fb_fillrect,
 550        .fb_copyarea  = w100fb_copyarea,
 551        .fb_imageblit = cfb_imageblit,
 552        .fb_sync      = w100fb_sync,
 553};
 554
 555#ifdef CONFIG_PM
 556static void w100fb_save_vidmem(struct w100fb_par *par)
 557{
 558        int memsize;
 559
 560        if (par->extmem_active) {
 561                memsize=par->mach->mem->size;
 562                par->saved_extmem = vmalloc(memsize);
 563                if (par->saved_extmem)
 564                        memcpy_fromio(par->saved_extmem, remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), memsize);
 565        }
 566        memsize=MEM_INT_SIZE;
 567        par->saved_intmem = vmalloc(memsize);
 568        if (par->saved_intmem && par->extmem_active)
 569                memcpy_fromio(par->saved_intmem, remapped_fbuf + (W100_FB_BASE-MEM_INT_BASE_VALUE), memsize);
 570        else if (par->saved_intmem)
 571                memcpy_fromio(par->saved_intmem, remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), memsize);
 572}
 573
 574static void w100fb_restore_vidmem(struct w100fb_par *par)
 575{
 576        int memsize;
 577
 578        if (par->extmem_active && par->saved_extmem) {
 579                memsize=par->mach->mem->size;
 580                memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_extmem, memsize);
 581                vfree(par->saved_extmem);
 582        }
 583        if (par->saved_intmem) {
 584                memsize=MEM_INT_SIZE;
 585                if (par->extmem_active)
 586                        memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_INT_BASE_VALUE), par->saved_intmem, memsize);
 587                else
 588                        memcpy_toio(remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE), par->saved_intmem, memsize);
 589                vfree(par->saved_intmem);
 590        }
 591}
 592
 593static int w100fb_suspend(struct platform_device *dev, pm_message_t state)
 594{
 595        struct fb_info *info = platform_get_drvdata(dev);
 596        struct w100fb_par *par=info->par;
 597        struct w100_tg_info *tg = par->mach->tg;
 598
 599        w100fb_save_vidmem(par);
 600        if(tg && tg->suspend)
 601                tg->suspend(par);
 602        w100_suspend(W100_SUSPEND_ALL);
 603        par->blanked = 1;
 604
 605        return 0;
 606}
 607
 608static int w100fb_resume(struct platform_device *dev)
 609{
 610        struct fb_info *info = platform_get_drvdata(dev);
 611        struct w100fb_par *par=info->par;
 612        struct w100_tg_info *tg = par->mach->tg;
 613
 614        w100_hw_init(par);
 615        w100fb_activate_var(par);
 616        w100fb_restore_vidmem(par);
 617        if(tg && tg->resume)
 618                tg->resume(par);
 619        par->blanked = 0;
 620
 621        return 0;
 622}
 623#else
 624#define w100fb_suspend  NULL
 625#define w100fb_resume   NULL
 626#endif
 627
 628
 629int w100fb_probe(struct platform_device *pdev)
 630{
 631        int err = -EIO;
 632        struct w100fb_mach_info *inf;
 633        struct fb_info *info = NULL;
 634        struct w100fb_par *par;
 635        struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 636        unsigned int chip_id;
 637
 638        if (!mem)
 639                return -EINVAL;
 640
 641        /* Remap the chip base address */
 642        remapped_base = ioremap_nocache(mem->start+W100_CFG_BASE, W100_CFG_LEN);
 643        if (remapped_base == NULL)
 644                goto out;
 645
 646        /* Map the register space */
 647        remapped_regs = ioremap_nocache(mem->start+W100_REG_BASE, W100_REG_LEN);
 648        if (remapped_regs == NULL)
 649                goto out;
 650
 651        /* Identify the chip */
 652        printk("Found ");
 653        chip_id = readl(remapped_regs + mmCHIP_ID);
 654        switch(chip_id) {
 655                case CHIP_ID_W100:  printk("w100");  break;
 656                case CHIP_ID_W3200: printk("w3200"); break;
 657                case CHIP_ID_W3220: printk("w3220"); break;
 658                default:
 659                        printk("Unknown imageon chip ID\n");
 660                        err = -ENODEV;
 661                        goto out;
 662        }
 663        printk(" at 0x%08lx.\n", (unsigned long) mem->start+W100_CFG_BASE);
 664
 665        /* Remap the framebuffer */
 666        remapped_fbuf = ioremap_nocache(mem->start+MEM_WINDOW_BASE, MEM_WINDOW_SIZE);
 667        if (remapped_fbuf == NULL)
 668                goto out;
 669
 670        info=framebuffer_alloc(sizeof(struct w100fb_par), &pdev->dev);
 671        if (!info) {
 672                err = -ENOMEM;
 673                goto out;
 674        }
 675
 676        par = info->par;
 677        platform_set_drvdata(pdev, info);
 678
 679        inf = dev_get_platdata(&pdev->dev);
 680        par->chip_id = chip_id;
 681        par->mach = inf;
 682        par->fastpll_mode = 0;
 683        par->blanked = 0;
 684
 685        par->pll_table=w100_get_xtal_table(inf->xtal_freq);
 686        if (!par->pll_table) {
 687                printk(KERN_ERR "No matching Xtal definition found\n");
 688                err = -EINVAL;
 689                goto out;
 690        }
 691
 692        info->pseudo_palette = kmalloc_array(MAX_PALETTES, sizeof(u32),
 693                                             GFP_KERNEL);
 694        if (!info->pseudo_palette) {
 695                err = -ENOMEM;
 696                goto out;
 697        }
 698
 699        info->fbops = &w100fb_ops;
 700        info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA |
 701                FBINFO_HWACCEL_FILLRECT;
 702        info->node = -1;
 703        info->screen_base = remapped_fbuf + (W100_FB_BASE-MEM_WINDOW_BASE);
 704        info->screen_size = REMAPPED_FB_LEN;
 705
 706        strcpy(info->fix.id, "w100fb");
 707        info->fix.type = FB_TYPE_PACKED_PIXELS;
 708        info->fix.type_aux = 0;
 709        info->fix.accel = FB_ACCEL_NONE;
 710        info->fix.smem_start = mem->start+W100_FB_BASE;
 711        info->fix.mmio_start = mem->start+W100_REG_BASE;
 712        info->fix.mmio_len = W100_REG_LEN;
 713
 714        if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
 715                err = -ENOMEM;
 716                goto out;
 717        }
 718
 719        par->mode = &inf->modelist[0];
 720        if(inf->init_mode & INIT_MODE_ROTATED) {
 721                info->var.xres = par->mode->yres;
 722                info->var.yres = par->mode->xres;
 723        }
 724        else {
 725                info->var.xres = par->mode->xres;
 726                info->var.yres = par->mode->yres;
 727        }
 728
 729        if(inf->init_mode &= INIT_MODE_FLIPPED)
 730                par->flip = 1;
 731        else
 732                par->flip = 0;
 733
 734        info->var.xres_virtual = info->var.xres;
 735        info->var.yres_virtual = info->var.yres;
 736        info->var.pixclock = 0x04;  /* 171521; */
 737        info->var.sync = 0;
 738        info->var.grayscale = 0;
 739        info->var.xoffset = info->var.yoffset = 0;
 740        info->var.accel_flags = 0;
 741        info->var.activate = FB_ACTIVATE_NOW;
 742
 743        w100_hw_init(par);
 744
 745        if (w100fb_check_var(&info->var, info) < 0) {
 746                err = -EINVAL;
 747                goto out;
 748        }
 749
 750        if (register_framebuffer(info) < 0) {
 751                err = -EINVAL;
 752                goto out;
 753        }
 754
 755        err = device_create_file(&pdev->dev, &dev_attr_fastpllclk);
 756        err |= device_create_file(&pdev->dev, &dev_attr_reg_read);
 757        err |= device_create_file(&pdev->dev, &dev_attr_reg_write);
 758        err |= device_create_file(&pdev->dev, &dev_attr_flip);
 759
 760        if (err != 0)
 761                fb_warn(info, "failed to register attributes (%d)\n", err);
 762
 763        fb_info(info, "%s frame buffer device\n", info->fix.id);
 764        return 0;
 765out:
 766        if (info) {
 767                fb_dealloc_cmap(&info->cmap);
 768                kfree(info->pseudo_palette);
 769        }
 770        if (remapped_fbuf != NULL)
 771                iounmap(remapped_fbuf);
 772        if (remapped_regs != NULL)
 773                iounmap(remapped_regs);
 774        if (remapped_base != NULL)
 775                iounmap(remapped_base);
 776        if (info)
 777                framebuffer_release(info);
 778        return err;
 779}
 780
 781
 782static int w100fb_remove(struct platform_device *pdev)
 783{
 784        struct fb_info *info = platform_get_drvdata(pdev);
 785        struct w100fb_par *par=info->par;
 786
 787        device_remove_file(&pdev->dev, &dev_attr_fastpllclk);
 788        device_remove_file(&pdev->dev, &dev_attr_reg_read);
 789        device_remove_file(&pdev->dev, &dev_attr_reg_write);
 790        device_remove_file(&pdev->dev, &dev_attr_flip);
 791
 792        unregister_framebuffer(info);
 793
 794        vfree(par->saved_intmem);
 795        vfree(par->saved_extmem);
 796        kfree(info->pseudo_palette);
 797        fb_dealloc_cmap(&info->cmap);
 798
 799        iounmap(remapped_base);
 800        iounmap(remapped_regs);
 801        iounmap(remapped_fbuf);
 802
 803        framebuffer_release(info);
 804
 805        return 0;
 806}
 807
 808
 809/* ------------------- chipset specific functions -------------------------- */
 810
 811
 812static void w100_soft_reset(void)
 813{
 814        u16 val = readw((u16 *) remapped_base + cfgSTATUS);
 815        writew(val | 0x08, (u16 *) remapped_base + cfgSTATUS);
 816        udelay(100);
 817        writew(0x00, (u16 *) remapped_base + cfgSTATUS);
 818        udelay(100);
 819}
 820
 821static void w100_update_disable(void)
 822{
 823        union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl;
 824
 825        /* Prevent display updates */
 826        disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
 827        disp_db_buf_wr_cntl.f.update_db_buf = 0;
 828        disp_db_buf_wr_cntl.f.en_db_buf = 0;
 829        writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
 830}
 831
 832static void w100_update_enable(void)
 833{
 834        union disp_db_buf_cntl_wr_u disp_db_buf_wr_cntl;
 835
 836        /* Enable display updates */
 837        disp_db_buf_wr_cntl.f.db_buf_cntl = 0x1e;
 838        disp_db_buf_wr_cntl.f.update_db_buf = 1;
 839        disp_db_buf_wr_cntl.f.en_db_buf = 1;
 840        writel((u32) (disp_db_buf_wr_cntl.val), remapped_regs + mmDISP_DB_BUF_CNTL);
 841}
 842
 843unsigned long w100fb_gpio_read(int port)
 844{
 845        unsigned long value;
 846
 847        if (port==W100_GPIO_PORT_A)
 848                value = readl(remapped_regs + mmGPIO_DATA);
 849        else
 850                value = readl(remapped_regs + mmGPIO_DATA2);
 851
 852        return value;
 853}
 854
 855void w100fb_gpio_write(int port, unsigned long value)
 856{
 857        if (port==W100_GPIO_PORT_A)
 858                writel(value, remapped_regs + mmGPIO_DATA);
 859        else
 860                writel(value, remapped_regs + mmGPIO_DATA2);
 861}
 862EXPORT_SYMBOL(w100fb_gpio_read);
 863EXPORT_SYMBOL(w100fb_gpio_write);
 864
 865/*
 866 * Initialization of critical w100 hardware
 867 */
 868static void w100_hw_init(struct w100fb_par *par)
 869{
 870        u32 temp32;
 871        union cif_cntl_u cif_cntl;
 872        union intf_cntl_u intf_cntl;
 873        union cfgreg_base_u cfgreg_base;
 874        union wrap_top_dir_u wrap_top_dir;
 875        union cif_read_dbg_u cif_read_dbg;
 876        union cpu_defaults_u cpu_default;
 877        union cif_write_dbg_u cif_write_dbg;
 878        union wrap_start_dir_u wrap_start_dir;
 879        union cif_io_u cif_io;
 880        struct w100_gpio_regs *gpio = par->mach->gpio;
 881
 882        w100_soft_reset();
 883
 884        /* This is what the fpga_init code does on reset. May be wrong
 885           but there is little info available */
 886        writel(0x31, remapped_regs + mmSCRATCH_UMSK);
 887        for (temp32 = 0; temp32 < 10000; temp32++)
 888                readl(remapped_regs + mmSCRATCH_UMSK);
 889        writel(0x30, remapped_regs + mmSCRATCH_UMSK);
 890
 891        /* Set up CIF */
 892        cif_io.val = defCIF_IO;
 893        writel((u32)(cif_io.val), remapped_regs + mmCIF_IO);
 894
 895        cif_write_dbg.val = readl(remapped_regs + mmCIF_WRITE_DBG);
 896        cif_write_dbg.f.dis_packer_ful_during_rbbm_timeout = 0;
 897        cif_write_dbg.f.en_dword_split_to_rbbm = 1;
 898        cif_write_dbg.f.dis_timeout_during_rbbm = 1;
 899        writel((u32) (cif_write_dbg.val), remapped_regs + mmCIF_WRITE_DBG);
 900
 901        cif_read_dbg.val = readl(remapped_regs + mmCIF_READ_DBG);
 902        cif_read_dbg.f.dis_rd_same_byte_to_trig_fetch = 1;
 903        writel((u32) (cif_read_dbg.val), remapped_regs + mmCIF_READ_DBG);
 904
 905        cif_cntl.val = readl(remapped_regs + mmCIF_CNTL);
 906        cif_cntl.f.dis_system_bits = 1;
 907        cif_cntl.f.dis_mr = 1;
 908        cif_cntl.f.en_wait_to_compensate_dq_prop_dly = 0;
 909        cif_cntl.f.intb_oe = 1;
 910        cif_cntl.f.interrupt_active_high = 1;
 911        writel((u32) (cif_cntl.val), remapped_regs + mmCIF_CNTL);
 912
 913        /* Setup cfgINTF_CNTL and cfgCPU defaults */
 914        intf_cntl.val = defINTF_CNTL;
 915        intf_cntl.f.ad_inc_a = 1;
 916        intf_cntl.f.ad_inc_b = 1;
 917        intf_cntl.f.rd_data_rdy_a = 0;
 918        intf_cntl.f.rd_data_rdy_b = 0;
 919        writeb((u8) (intf_cntl.val), remapped_base + cfgINTF_CNTL);
 920
 921        cpu_default.val = defCPU_DEFAULTS;
 922        cpu_default.f.access_ind_addr_a = 1;
 923        cpu_default.f.access_ind_addr_b = 1;
 924        cpu_default.f.access_scratch_reg = 1;
 925        cpu_default.f.transition_size = 0;
 926        writeb((u8) (cpu_default.val), remapped_base + cfgCPU_DEFAULTS);
 927
 928        /* set up the apertures */
 929        writeb((u8) (W100_REG_BASE >> 16), remapped_base + cfgREG_BASE);
 930
 931        cfgreg_base.val = defCFGREG_BASE;
 932        cfgreg_base.f.cfgreg_base = W100_CFG_BASE;
 933        writel((u32) (cfgreg_base.val), remapped_regs + mmCFGREG_BASE);
 934
 935        wrap_start_dir.val = defWRAP_START_DIR;
 936        wrap_start_dir.f.start_addr = WRAP_BUF_BASE_VALUE >> 1;
 937        writel((u32) (wrap_start_dir.val), remapped_regs + mmWRAP_START_DIR);
 938
 939        wrap_top_dir.val = defWRAP_TOP_DIR;
 940        wrap_top_dir.f.top_addr = WRAP_BUF_TOP_VALUE >> 1;
 941        writel((u32) (wrap_top_dir.val), remapped_regs + mmWRAP_TOP_DIR);
 942
 943        writel((u32) 0x2440, remapped_regs + mmRBBM_CNTL);
 944
 945        /* Set the hardware to 565 colour */
 946        temp32 = readl(remapped_regs + mmDISP_DEBUG2);
 947        temp32 &= 0xff7fffff;
 948        temp32 |= 0x00800000;
 949        writel(temp32, remapped_regs + mmDISP_DEBUG2);
 950
 951        /* Initialise the GPIO lines */
 952        if (gpio) {
 953                writel(gpio->init_data1, remapped_regs + mmGPIO_DATA);
 954                writel(gpio->init_data2, remapped_regs + mmGPIO_DATA2);
 955                writel(gpio->gpio_dir1,  remapped_regs + mmGPIO_CNTL1);
 956                writel(gpio->gpio_oe1,   remapped_regs + mmGPIO_CNTL2);
 957                writel(gpio->gpio_dir2,  remapped_regs + mmGPIO_CNTL3);
 958                writel(gpio->gpio_oe2,   remapped_regs + mmGPIO_CNTL4);
 959        }
 960}
 961
 962
 963struct power_state {
 964        union clk_pin_cntl_u clk_pin_cntl;
 965        union pll_ref_fb_div_u pll_ref_fb_div;
 966        union pll_cntl_u pll_cntl;
 967        union sclk_cntl_u sclk_cntl;
 968        union pclk_cntl_u pclk_cntl;
 969        union pwrmgt_cntl_u pwrmgt_cntl;
 970        int auto_mode;  /* system clock auto changing? */
 971};
 972
 973
 974static struct power_state w100_pwr_state;
 975
 976/* The PLL Fout is determined by (XtalFreq/(M+1)) * ((N_int+1) + (N_fac/8)) */
 977
 978/* 12.5MHz Crystal PLL Table */
 979static struct w100_pll_info xtal_12500000[] = {
 980        /*freq     M   N_int    N_fac  tfgoal  lock_time */
 981        { 50,      0,   1,       0,     0xe0,        56},  /*  50.00 MHz */
 982        { 75,      0,   5,       0,     0xde,        37},  /*  75.00 MHz */
 983        {100,      0,   7,       0,     0xe0,        28},  /* 100.00 MHz */
 984        {125,      0,   9,       0,     0xe0,        22},  /* 125.00 MHz */
 985        {150,      0,   11,      0,     0xe0,        17},  /* 150.00 MHz */
 986        {  0,      0,   0,       0,        0,         0},  /* Terminator */
 987};
 988
 989/* 14.318MHz Crystal PLL Table */
 990static struct w100_pll_info xtal_14318000[] = {
 991        /*freq     M   N_int    N_fac  tfgoal  lock_time */
 992        { 40,      4,   13,      0,     0xe0,        80}, /* tfgoal guessed */
 993        { 50,      1,   6,       0,     0xe0,        64}, /*  50.05 MHz */
 994        { 57,      2,   11,      0,     0xe0,        53}, /* tfgoal guessed */
 995        { 75,      0,   4,       3,     0xe0,        43}, /*  75.08 MHz */
 996        {100,      0,   6,       0,     0xe0,        32}, /* 100.10 MHz */
 997        {  0,      0,   0,       0,        0,         0},
 998};
 999
1000/* 16MHz Crystal PLL Table */
1001static struct w100_pll_info xtal_16000000[] = {
1002        /*freq     M   N_int    N_fac  tfgoal  lock_time */
1003        { 72,      1,   8,       0,     0xe0,        48}, /* tfgoal guessed */
1004        { 80,      1,   9,       0,     0xe0,        13}, /* tfgoal guessed */
1005        { 95,      1,   10,      7,     0xe0,        38}, /* tfgoal guessed */
1006        { 96,      1,   11,      0,     0xe0,        36}, /* tfgoal guessed */
1007        {  0,      0,   0,       0,        0,         0},
1008};
1009
1010static struct pll_entries {
1011        int xtal_freq;
1012        struct w100_pll_info *pll_table;
1013} w100_pll_tables[] = {
1014        { 12500000, &xtal_12500000[0] },
1015        { 14318000, &xtal_14318000[0] },
1016        { 16000000, &xtal_16000000[0] },
1017        { 0 },
1018};
1019
1020struct w100_pll_info *w100_get_xtal_table(unsigned int freq)
1021{
1022        struct pll_entries *pll_entry = w100_pll_tables;
1023
1024        do {
1025                if (freq == pll_entry->xtal_freq)
1026                        return pll_entry->pll_table;
1027                pll_entry++;
1028        } while (pll_entry->xtal_freq);
1029        return 0;
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        },
1629};
1630
1631module_platform_driver(w100fb_driver);
1632
1633MODULE_DESCRIPTION("ATI Imageon w100 framebuffer driver");
1634MODULE_LICENSE("GPL");
1635