at v5.3-rc2 1634 lines 49 kB view raw
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");