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