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