1/* 2 * linux/drivers/video/mbx/mbxfb.c 3 * 4 * Copyright (C) 2006-2007 8D Technologies inc 5 * Raphael Assenat <raph@8d.com> 6 * - Added video overlay support 7 * - Various improvements 8 * 9 * Copyright (C) 2006 Compulab, Ltd. 10 * Mike Rapoport <mike@compulab.co.il> 11 * - Creation of driver 12 * 13 * Based on pxafb.c 14 * 15 * This file is subject to the terms and conditions of the GNU General Public 16 * License. See the file COPYING in the main directory of this archive for 17 * more details. 18 * 19 * Intel 2700G (Marathon) Graphics Accelerator Frame Buffer Driver 20 * 21 */ 22 23#include <linux/delay.h> 24#include <linux/fb.h> 25#include <linux/init.h> 26#include <linux/module.h> 27#include <linux/platform_device.h> 28#include <linux/uaccess.h> 29 30#include <asm/io.h> 31 32#include <video/mbxfb.h> 33 34#include "regs.h" 35#include "reg_bits.h" 36 37static unsigned long virt_base_2700; 38 39#define write_reg(val, reg) do { writel((val), (reg)); } while(0) 40 41/* Without this delay, the graphics appears somehow scaled and 42 * there is a lot of jitter in scanlines. This delay is probably 43 * needed only after setting some specific register(s) somewhere, 44 * not all over the place... */ 45#define write_reg_dly(val, reg) do { writel((val), reg); udelay(1000); } while(0) 46 47#define MIN_XRES 16 48#define MIN_YRES 16 49#define MAX_XRES 2048 50#define MAX_YRES 2048 51 52#define MAX_PALETTES 16 53 54#define MEMORY_OFFSET 0x60000 55 56struct mbxfb_info { 57 struct device *dev; 58 59 struct resource *fb_res; 60 struct resource *fb_req; 61 62 struct resource *reg_res; 63 struct resource *reg_req; 64 65 void __iomem *fb_virt_addr; 66 unsigned long fb_phys_addr; 67 68 void __iomem *reg_virt_addr; 69 unsigned long reg_phys_addr; 70 71 int (*platform_probe) (struct fb_info * fb); 72 int (*platform_remove) (struct fb_info * fb); 73 74 u32 pseudo_palette[MAX_PALETTES]; 75#ifdef CONFIG_FB_MBX_DEBUG 76 void *debugfs_data; 77#endif 78 79}; 80 81static struct fb_var_screeninfo mbxfb_default __devinitdata = { 82 .xres = 640, 83 .yres = 480, 84 .xres_virtual = 640, 85 .yres_virtual = 480, 86 .bits_per_pixel = 16, 87 .red = {11, 5, 0}, 88 .green = {5, 6, 0}, 89 .blue = {0, 5, 0}, 90 .activate = FB_ACTIVATE_TEST, 91 .height = -1, 92 .width = -1, 93 .pixclock = 40000, 94 .left_margin = 48, 95 .right_margin = 16, 96 .upper_margin = 33, 97 .lower_margin = 10, 98 .hsync_len = 96, 99 .vsync_len = 2, 100 .vmode = FB_VMODE_NONINTERLACED, 101 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 102}; 103 104static struct fb_fix_screeninfo mbxfb_fix __devinitdata = { 105 .id = "MBX", 106 .type = FB_TYPE_PACKED_PIXELS, 107 .visual = FB_VISUAL_TRUECOLOR, 108 .xpanstep = 0, 109 .ypanstep = 0, 110 .ywrapstep = 0, 111 .accel = FB_ACCEL_NONE, 112}; 113 114struct pixclock_div { 115 u8 m; 116 u8 n; 117 u8 p; 118}; 119 120static unsigned int mbxfb_get_pixclock(unsigned int pixclock_ps, 121 struct pixclock_div *div) 122{ 123 u8 m, n, p; 124 unsigned int err = 0; 125 unsigned int min_err = ~0x0; 126 unsigned int clk; 127 unsigned int best_clk = 0; 128 unsigned int ref_clk = 13000; 129 unsigned int pixclock; 130 131 /* convert pixclock to KHz */ 132 pixclock = PICOS2KHZ(pixclock_ps); 133 134 /* PLL output freq = (ref_clk * M) / (N * 2^P) 135 * 136 * M: 1 to 63 137 * N: 1 to 7 138 * P: 0 to 7 139 */ 140 141 /* RAPH: When N==1, the resulting pixel clock appears to 142 * get divided by 2. Preventing N=1 by starting the following 143 * loop at 2 prevents this. Is this a bug with my chip 144 * revision or something I dont understand? */ 145 for (m = 1; m < 64; m++) { 146 for (n = 2; n < 8; n++) { 147 for (p = 0; p < 8; p++) { 148 clk = (ref_clk * m) / (n * (1 << p)); 149 err = (clk > pixclock) ? (clk - pixclock) : 150 (pixclock - clk); 151 if (err < min_err) { 152 min_err = err; 153 best_clk = clk; 154 div->m = m; 155 div->n = n; 156 div->p = p; 157 } 158 } 159 } 160 } 161 return KHZ2PICOS(best_clk); 162} 163 164static int mbxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 165 u_int trans, struct fb_info *info) 166{ 167 u32 val, ret = 1; 168 169 if (regno < MAX_PALETTES) { 170 u32 *pal = info->pseudo_palette; 171 172 val = (red & 0xf800) | ((green & 0xfc00) >> 5) | 173 ((blue & 0xf800) >> 11); 174 pal[regno] = val; 175 ret = 0; 176 } 177 178 return ret; 179} 180 181static int mbxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 182{ 183 struct pixclock_div div; 184 185 var->pixclock = mbxfb_get_pixclock(var->pixclock, &div); 186 187 if (var->xres < MIN_XRES) 188 var->xres = MIN_XRES; 189 if (var->yres < MIN_YRES) 190 var->yres = MIN_YRES; 191 if (var->xres > MAX_XRES) 192 return -EINVAL; 193 if (var->yres > MAX_YRES) 194 return -EINVAL; 195 var->xres_virtual = max(var->xres_virtual, var->xres); 196 var->yres_virtual = max(var->yres_virtual, var->yres); 197 198 switch (var->bits_per_pixel) { 199 /* 8 bits-per-pixel is not supported yet */ 200 case 8: 201 return -EINVAL; 202 case 16: 203 var->green.length = (var->green.length == 5) ? 5 : 6; 204 var->red.length = 5; 205 var->blue.length = 5; 206 var->transp.length = 6 - var->green.length; 207 var->blue.offset = 0; 208 var->green.offset = 5; 209 var->red.offset = 5 + var->green.length; 210 var->transp.offset = (5 + var->red.offset) & 15; 211 break; 212 case 24: /* RGB 888 */ 213 case 32: /* RGBA 8888 */ 214 var->red.offset = 16; 215 var->red.length = 8; 216 var->green.offset = 8; 217 var->green.length = 8; 218 var->blue.offset = 0; 219 var->blue.length = 8; 220 var->transp.length = var->bits_per_pixel - 24; 221 var->transp.offset = (var->transp.length) ? 24 : 0; 222 break; 223 } 224 var->red.msb_right = 0; 225 var->green.msb_right = 0; 226 var->blue.msb_right = 0; 227 var->transp.msb_right = 0; 228 229 return 0; 230} 231 232static int mbxfb_set_par(struct fb_info *info) 233{ 234 struct fb_var_screeninfo *var = &info->var; 235 struct pixclock_div div; 236 ushort hbps, ht, hfps, has; 237 ushort vbps, vt, vfps, vas; 238 u32 gsctrl = readl(GSCTRL); 239 u32 gsadr = readl(GSADR); 240 241 info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8; 242 243 /* setup color mode */ 244 gsctrl &= ~(FMsk(GSCTRL_GPIXFMT)); 245 if (info->var.bits_per_pixel == 8) { 246 return -EINVAL; 247 } else { 248 fb_dealloc_cmap(&info->cmap); 249 gsctrl &= ~GSCTRL_LUT_EN; 250 251 info->fix.visual = FB_VISUAL_TRUECOLOR; 252 switch (info->var.bits_per_pixel) { 253 case 16: 254 if (info->var.green.length == 5) 255 gsctrl |= GSCTRL_GPIXFMT_ARGB1555; 256 else 257 gsctrl |= GSCTRL_GPIXFMT_RGB565; 258 break; 259 case 24: 260 gsctrl |= GSCTRL_GPIXFMT_RGB888; 261 break; 262 case 32: 263 gsctrl |= GSCTRL_GPIXFMT_ARGB8888; 264 break; 265 } 266 } 267 268 /* setup resolution */ 269 gsctrl &= ~(FMsk(GSCTRL_GSWIDTH) | FMsk(GSCTRL_GSHEIGHT)); 270 gsctrl |= Gsctrl_Width(info->var.xres) | 271 Gsctrl_Height(info->var.yres); 272 write_reg_dly(gsctrl, GSCTRL); 273 274 gsadr &= ~(FMsk(GSADR_SRCSTRIDE)); 275 gsadr |= Gsadr_Srcstride(info->var.xres * info->var.bits_per_pixel / 276 (8 * 16) - 1); 277 write_reg_dly(gsadr, GSADR); 278 279 /* setup timings */ 280 var->pixclock = mbxfb_get_pixclock(info->var.pixclock, &div); 281 282 write_reg_dly((Disp_Pll_M(div.m) | Disp_Pll_N(div.n) | 283 Disp_Pll_P(div.p) | DISP_PLL_EN), DISPPLL); 284 285 hbps = var->hsync_len; 286 has = hbps + var->left_margin; 287 hfps = has + var->xres; 288 ht = hfps + var->right_margin; 289 290 vbps = var->vsync_len; 291 vas = vbps + var->upper_margin; 292 vfps = vas + var->yres; 293 vt = vfps + var->lower_margin; 294 295 write_reg_dly((Dht01_Hbps(hbps) | Dht01_Ht(ht)), DHT01); 296 write_reg_dly((Dht02_Hlbs(has) | Dht02_Has(has)), DHT02); 297 write_reg_dly((Dht03_Hfps(hfps) | Dht03_Hrbs(hfps)), DHT03); 298 write_reg_dly((Dhdet_Hdes(has) | Dhdet_Hdef(hfps)), DHDET); 299 300 write_reg_dly((Dvt01_Vbps(vbps) | Dvt01_Vt(vt)), DVT01); 301 write_reg_dly((Dvt02_Vtbs(vas) | Dvt02_Vas(vas)), DVT02); 302 write_reg_dly((Dvt03_Vfps(vfps) | Dvt03_Vbbs(vfps)), DVT03); 303 write_reg_dly((Dvdet_Vdes(vas) | Dvdet_Vdef(vfps)), DVDET); 304 write_reg_dly((Dvectrl_Vevent(vfps) | Dvectrl_Vfetch(vbps)), DVECTRL); 305 306 write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL); 307 308 write_reg_dly(DINTRE_VEVENT0_EN, DINTRE); 309 310 return 0; 311} 312 313static int mbxfb_blank(int blank, struct fb_info *info) 314{ 315 switch (blank) { 316 case FB_BLANK_POWERDOWN: 317 case FB_BLANK_VSYNC_SUSPEND: 318 case FB_BLANK_HSYNC_SUSPEND: 319 case FB_BLANK_NORMAL: 320 write_reg_dly((readl(DSCTRL) & ~DSCTRL_SYNCGEN_EN), DSCTRL); 321 write_reg_dly((readl(PIXCLK) & ~PIXCLK_EN), PIXCLK); 322 write_reg_dly((readl(VOVRCLK) & ~VOVRCLK_EN), VOVRCLK); 323 break; 324 case FB_BLANK_UNBLANK: 325 write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL); 326 write_reg_dly((readl(PIXCLK) | PIXCLK_EN), PIXCLK); 327 break; 328 } 329 return 0; 330} 331 332static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set) 333{ 334 u32 vsctrl, vscadr, vsadr; 335 u32 sssize, spoctrl, shctrl; 336 u32 vubase, vvbase; 337 u32 vovrclk; 338 339 if (set->scaled_width==0 || set->scaled_height==0) 340 return -EINVAL; 341 342 /* read registers which have reserved bits 343 * so we can write them back as-is. */ 344 vovrclk = readl(VOVRCLK); 345 vsctrl = readl(VSCTRL); 346 vscadr = readl(VSCADR); 347 vubase = readl(VUBASE); 348 vvbase = readl(VVBASE); 349 shctrl = readl(SHCTRL); 350 351 spoctrl = readl(SPOCTRL); 352 sssize = readl(SSSIZE); 353 354 vsctrl &= ~( FMsk(VSCTRL_VSWIDTH) | 355 FMsk(VSCTRL_VSHEIGHT) | 356 FMsk(VSCTRL_VPIXFMT) | 357 VSCTRL_GAMMA_EN | VSCTRL_CSC_EN | 358 VSCTRL_COSITED ); 359 vsctrl |= Vsctrl_Width(set->width) | Vsctrl_Height(set->height) | 360 VSCTRL_CSC_EN; 361 362 vscadr &= ~(VSCADR_STR_EN | FMsk(VSCADR_VBASE_ADR) ); 363 vubase &= ~(VUBASE_UVHALFSTR | FMsk(VUBASE_UBASE_ADR)); 364 vvbase &= ~(FMsk(VVBASE_VBASE_ADR)); 365 366 switch (set->fmt) { 367 case MBXFB_FMT_YUV16: 368 vsctrl |= VSCTRL_VPIXFMT_YUV12; 369 370 set->Y_stride = ((set->width) + 0xf ) & ~0xf; 371 break; 372 case MBXFB_FMT_YUV12: 373 vsctrl |= VSCTRL_VPIXFMT_YUV12; 374 375 set->Y_stride = ((set->width) + 0xf ) & ~0xf; 376 vubase |= VUBASE_UVHALFSTR; 377 378 break; 379 case MBXFB_FMT_UY0VY1: 380 vsctrl |= VSCTRL_VPIXFMT_UY0VY1; 381 set->Y_stride = (set->width*2 + 0xf ) & ~0xf; 382 break; 383 case MBXFB_FMT_VY0UY1: 384 vsctrl |= VSCTRL_VPIXFMT_VY0UY1; 385 set->Y_stride = (set->width*2 + 0xf ) & ~0xf; 386 break; 387 case MBXFB_FMT_Y0UY1V: 388 vsctrl |= VSCTRL_VPIXFMT_Y0UY1V; 389 set->Y_stride = (set->width*2 + 0xf ) & ~0xf; 390 break; 391 case MBXFB_FMT_Y0VY1U: 392 vsctrl |= VSCTRL_VPIXFMT_Y0VY1U; 393 set->Y_stride = (set->width*2 + 0xf ) & ~0xf; 394 break; 395 default: 396 return -EINVAL; 397 } 398 399 /* VSCTRL has the bits which sets the Video Pixel Format. 400 * When passing from a packed to planar format, 401 * if we write VSCTRL first, VVBASE and VUBASE would 402 * be zero if we would not set them here. (And then, 403 * the chips hangs and only a reset seems to fix it). 404 * 405 * If course, the values calculated here have no meaning 406 * for packed formats. 407 */ 408 set->UV_stride = ((set->width/2) + 0x7 ) & ~0x7; 409 set->U_offset = set->height * set->Y_stride; 410 set->V_offset = set->U_offset + 411 set->height * set->UV_stride; 412 vubase |= Vubase_Ubase_Adr( 413 (0x60000 + set->mem_offset + set->U_offset)>>3); 414 vvbase |= Vvbase_Vbase_Adr( 415 (0x60000 + set->mem_offset + set->V_offset)>>3); 416 417 418 vscadr |= Vscadr_Vbase_Adr((0x60000 + set->mem_offset)>>4); 419 420 if (set->enable) 421 vscadr |= VSCADR_STR_EN; 422 423 424 vsadr = Vsadr_Srcstride((set->Y_stride)/16-1) | 425 Vsadr_Xstart(set->x) | Vsadr_Ystart(set->y); 426 427 sssize &= ~(FMsk(SSSIZE_SC_WIDTH) | FMsk(SSSIZE_SC_HEIGHT)); 428 sssize = Sssize_Sc_Width(set->scaled_width-1) | 429 Sssize_Sc_Height(set->scaled_height-1); 430 431 spoctrl &= ~(SPOCTRL_H_SC_BP | SPOCTRL_V_SC_BP | 432 SPOCTRL_HV_SC_OR | SPOCTRL_VS_UR_C | 433 FMsk(SPOCTRL_VPITCH)); 434 spoctrl |= Spoctrl_Vpitch((set->height<<11)/set->scaled_height); 435 436 /* Bypass horiz/vert scaler when same size */ 437 if (set->scaled_width == set->width) 438 spoctrl |= SPOCTRL_H_SC_BP; 439 if (set->scaled_height == set->height) 440 spoctrl |= SPOCTRL_V_SC_BP; 441 442 shctrl &= ~(FMsk(SHCTRL_HPITCH) | SHCTRL_HDECIM); 443 shctrl |= Shctrl_Hpitch((set->width<<11)/set->scaled_width); 444 445 /* Video plane registers */ 446 write_reg(vsctrl, VSCTRL); 447 write_reg(vscadr, VSCADR); 448 write_reg(vubase, VUBASE); 449 write_reg(vvbase, VVBASE); 450 write_reg(vsadr, VSADR); 451 452 /* Video scaler registers */ 453 write_reg(sssize, SSSIZE); 454 write_reg(spoctrl, SPOCTRL); 455 write_reg(shctrl, SHCTRL); 456 457 /* Clock */ 458 if (set->enable) 459 vovrclk |= 1; 460 else 461 vovrclk &= ~1; 462 463 write_reg(vovrclk, VOVRCLK); 464 465 return 0; 466} 467 468static int mbxfb_ioctl_planeorder(struct mbxfb_planeorder *porder) 469{ 470 unsigned long gscadr, vscadr; 471 472 if (porder->bottom == porder->top) 473 return -EINVAL; 474 475 gscadr = readl(GSCADR); 476 vscadr = readl(VSCADR); 477 478 gscadr &= ~(FMsk(GSCADR_BLEND_POS)); 479 vscadr &= ~(FMsk(VSCADR_BLEND_POS)); 480 481 switch (porder->bottom) { 482 case MBXFB_PLANE_GRAPHICS: 483 gscadr |= GSCADR_BLEND_GFX; 484 break; 485 case MBXFB_PLANE_VIDEO: 486 vscadr |= VSCADR_BLEND_GFX; 487 break; 488 default: 489 return -EINVAL; 490 } 491 492 switch (porder->top) { 493 case MBXFB_PLANE_GRAPHICS: 494 gscadr |= GSCADR_BLEND_VID; 495 break; 496 case MBXFB_PLANE_VIDEO: 497 vscadr |= GSCADR_BLEND_VID; 498 break; 499 default: 500 return -EINVAL; 501 } 502 503 write_reg_dly(vscadr, VSCADR); 504 write_reg_dly(gscadr, GSCADR); 505 506 return 0; 507 508} 509 510static int mbxfb_ioctl_alphactl(struct mbxfb_alphaCtl *alpha) 511{ 512 unsigned long vscadr, vbbase, vcmsk; 513 unsigned long gscadr, gbbase, gdrctrl; 514 515 vbbase = Vbbase_Glalpha(alpha->overlay_global_alpha) | 516 Vbbase_Colkey(alpha->overlay_colorkey); 517 518 gbbase = Gbbase_Glalpha(alpha->graphics_global_alpha) | 519 Gbbase_Colkey(alpha->graphics_colorkey); 520 521 vcmsk = readl(VCMSK); 522 vcmsk &= ~(FMsk(VCMSK_COLKEY_M)); 523 vcmsk |= Vcmsk_colkey_m(alpha->overlay_colorkey_mask); 524 525 gdrctrl = readl(GDRCTRL); 526 gdrctrl &= ~(FMsk(GDRCTRL_COLKEYM)); 527 gdrctrl |= Gdrctrl_Colkeym(alpha->graphics_colorkey_mask); 528 529 vscadr = readl(VSCADR); 530 vscadr &= ~(FMsk(VSCADR_BLEND_M) | VSCADR_COLKEYSRC | VSCADR_COLKEY_EN); 531 532 gscadr = readl(GSCADR); 533 gscadr &= ~(FMsk(GSCADR_BLEND_M) | GSCADR_COLKEY_EN | GSCADR_COLKEYSRC); 534 535 switch (alpha->overlay_colorkey_mode) { 536 case MBXFB_COLORKEY_DISABLED: 537 break; 538 case MBXFB_COLORKEY_PREVIOUS: 539 vscadr |= VSCADR_COLKEY_EN; 540 break; 541 case MBXFB_COLORKEY_CURRENT: 542 vscadr |= VSCADR_COLKEY_EN | VSCADR_COLKEYSRC; 543 break; 544 default: 545 return -EINVAL; 546 } 547 548 switch (alpha->overlay_blend_mode) { 549 case MBXFB_ALPHABLEND_NONE: 550 vscadr |= VSCADR_BLEND_NONE; 551 break; 552 case MBXFB_ALPHABLEND_GLOBAL: 553 vscadr |= VSCADR_BLEND_GLOB; 554 break; 555 case MBXFB_ALPHABLEND_PIXEL: 556 vscadr |= VSCADR_BLEND_PIX; 557 break; 558 default: 559 return -EINVAL; 560 } 561 562 switch (alpha->graphics_colorkey_mode) { 563 case MBXFB_COLORKEY_DISABLED: 564 break; 565 case MBXFB_COLORKEY_PREVIOUS: 566 gscadr |= GSCADR_COLKEY_EN; 567 break; 568 case MBXFB_COLORKEY_CURRENT: 569 gscadr |= GSCADR_COLKEY_EN | GSCADR_COLKEYSRC; 570 break; 571 default: 572 return -EINVAL; 573 } 574 575 switch (alpha->graphics_blend_mode) { 576 case MBXFB_ALPHABLEND_NONE: 577 gscadr |= GSCADR_BLEND_NONE; 578 break; 579 case MBXFB_ALPHABLEND_GLOBAL: 580 gscadr |= GSCADR_BLEND_GLOB; 581 break; 582 case MBXFB_ALPHABLEND_PIXEL: 583 gscadr |= GSCADR_BLEND_PIX; 584 break; 585 default: 586 return -EINVAL; 587 } 588 589 write_reg_dly(vbbase, VBBASE); 590 write_reg_dly(gbbase, GBBASE); 591 write_reg_dly(vcmsk, VCMSK); 592 write_reg_dly(gdrctrl, GDRCTRL); 593 write_reg_dly(gscadr, GSCADR); 594 write_reg_dly(vscadr, VSCADR); 595 596 return 0; 597} 598 599static int mbxfb_ioctl(struct fb_info *info, unsigned int cmd, 600 unsigned long arg) 601{ 602 struct mbxfb_overlaySetup setup; 603 struct mbxfb_planeorder porder; 604 struct mbxfb_alphaCtl alpha; 605 struct mbxfb_reg reg; 606 int res; 607 __u32 tmp; 608 609 switch (cmd) 610 { 611 case MBXFB_IOCX_OVERLAY: 612 if (copy_from_user(&setup, (void __user*)arg, 613 sizeof(struct mbxfb_overlaySetup))) 614 return -EFAULT; 615 616 res = mbxfb_setupOverlay(&setup); 617 if (res) 618 return res; 619 620 if (copy_to_user((void __user*)arg, &setup, 621 sizeof(struct mbxfb_overlaySetup))) 622 return -EFAULT; 623 624 return 0; 625 626 case MBXFB_IOCS_PLANEORDER: 627 if (copy_from_user(&porder, (void __user*)arg, 628 sizeof(struct mbxfb_planeorder))) 629 return -EFAULT; 630 631 return mbxfb_ioctl_planeorder(&porder); 632 633 case MBXFB_IOCS_ALPHA: 634 if (copy_from_user(&alpha, (void __user*)arg, 635 sizeof(struct mbxfb_alphaCtl))) 636 return -EFAULT; 637 638 return mbxfb_ioctl_alphactl(&alpha); 639 640 case MBXFB_IOCS_REG: 641 if (copy_from_user(®, (void __user*)arg, 642 sizeof(struct mbxfb_reg))) 643 return -EFAULT; 644 645 if (reg.addr >= 0x10000) /* regs are from 0x3fe0000 to 0x3feffff */ 646 return -EINVAL; 647 648 tmp = readl(virt_base_2700 + reg.addr); 649 tmp &= ~reg.mask; 650 tmp |= reg.val & reg.mask; 651 writel(tmp, virt_base_2700 + reg.addr); 652 653 return 0; 654 case MBXFB_IOCX_REG: 655 if (copy_from_user(®, (void __user*)arg, 656 sizeof(struct mbxfb_reg))) 657 return -EFAULT; 658 659 if (reg.addr >= 0x10000) /* regs are from 0x3fe0000 to 0x3feffff */ 660 return -EINVAL; 661 reg.val = readl(virt_base_2700 + reg.addr); 662 663 if (copy_to_user((void __user*)arg, ®, 664 sizeof(struct mbxfb_reg))) 665 return -EFAULT; 666 667 return 0; 668 } 669 return -EINVAL; 670} 671 672static struct fb_ops mbxfb_ops = { 673 .owner = THIS_MODULE, 674 .fb_check_var = mbxfb_check_var, 675 .fb_set_par = mbxfb_set_par, 676 .fb_setcolreg = mbxfb_setcolreg, 677 .fb_fillrect = cfb_fillrect, 678 .fb_copyarea = cfb_copyarea, 679 .fb_imageblit = cfb_imageblit, 680 .fb_blank = mbxfb_blank, 681 .fb_ioctl = mbxfb_ioctl, 682}; 683 684/* 685 Enable external SDRAM controller. Assume that all clocks are active 686 by now. 687*/ 688static void __devinit setup_memc(struct fb_info *fbi) 689{ 690 unsigned long tmp; 691 int i; 692 693 /* setup SDRAM controller */ 694 write_reg_dly((LMCFG_LMC_DS | LMCFG_LMC_TS | LMCFG_LMD_TS | 695 LMCFG_LMA_TS), 696 LMCFG); 697 698 write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR); 699 700 /* setup SDRAM timings */ 701 write_reg_dly((Lmtim_Tras(7) | Lmtim_Trp(3) | Lmtim_Trcd(3) | 702 Lmtim_Trc(9) | Lmtim_Tdpl(2)), 703 LMTIM); 704 /* setup SDRAM refresh rate */ 705 write_reg_dly(0xc2b, LMREFRESH); 706 /* setup SDRAM type parameters */ 707 write_reg_dly((LMTYPE_CASLAT_3 | LMTYPE_BKSZ_2 | LMTYPE_ROWSZ_11 | 708 LMTYPE_COLSZ_8), 709 LMTYPE); 710 /* enable memory controller */ 711 write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR); 712 /* perform dummy reads */ 713 for ( i = 0; i < 16; i++ ) { 714 tmp = readl(fbi->screen_base); 715 } 716} 717 718static void enable_clocks(struct fb_info *fbi) 719{ 720 /* enable clocks */ 721 write_reg_dly(SYSCLKSRC_PLL_2, SYSCLKSRC); 722 write_reg_dly(PIXCLKSRC_PLL_1, PIXCLKSRC); 723 write_reg_dly(0x00000000, CLKSLEEP); 724 725 /* PLL output = (Frefclk * M) / (N * 2^P ) 726 * 727 * M: 0x17, N: 0x3, P: 0x0 == 100 Mhz! 728 * M: 0xb, N: 0x1, P: 0x1 == 71 Mhz 729 * */ 730 write_reg_dly((Core_Pll_M(0xb) | Core_Pll_N(0x1) | Core_Pll_P(0x1) | 731 CORE_PLL_EN), 732 COREPLL); 733 734 write_reg_dly((Disp_Pll_M(0x1b) | Disp_Pll_N(0x7) | Disp_Pll_P(0x1) | 735 DISP_PLL_EN), 736 DISPPLL); 737 738 write_reg_dly(0x00000000, VOVRCLK); 739 write_reg_dly(PIXCLK_EN, PIXCLK); 740 write_reg_dly(MEMCLK_EN, MEMCLK); 741 write_reg_dly(0x00000001, M24CLK); 742 write_reg_dly(0x00000001, MBXCLK); 743 write_reg_dly(SDCLK_EN, SDCLK); 744 write_reg_dly(0x00000001, PIXCLKDIV); 745} 746 747static void __devinit setup_graphics(struct fb_info *fbi) 748{ 749 unsigned long gsctrl; 750 unsigned long vscadr; 751 752 gsctrl = GSCTRL_GAMMA_EN | Gsctrl_Width(fbi->var.xres) | 753 Gsctrl_Height(fbi->var.yres); 754 switch (fbi->var.bits_per_pixel) { 755 case 16: 756 if (fbi->var.green.length == 5) 757 gsctrl |= GSCTRL_GPIXFMT_ARGB1555; 758 else 759 gsctrl |= GSCTRL_GPIXFMT_RGB565; 760 break; 761 case 24: 762 gsctrl |= GSCTRL_GPIXFMT_RGB888; 763 break; 764 case 32: 765 gsctrl |= GSCTRL_GPIXFMT_ARGB8888; 766 break; 767 } 768 769 write_reg_dly(gsctrl, GSCTRL); 770 write_reg_dly(0x00000000, GBBASE); 771 write_reg_dly(0x00ffffff, GDRCTRL); 772 write_reg_dly((GSCADR_STR_EN | Gscadr_Gbase_Adr(0x6000)), GSCADR); 773 write_reg_dly(0x00000000, GPLUT); 774 775 vscadr = readl(VSCADR); 776 vscadr &= ~(FMsk(VSCADR_BLEND_POS) | FMsk(VSCADR_BLEND_M)); 777 vscadr |= VSCADR_BLEND_VID | VSCADR_BLEND_NONE; 778 write_reg_dly(vscadr, VSCADR); 779} 780 781static void __devinit setup_display(struct fb_info *fbi) 782{ 783 unsigned long dsctrl = 0; 784 785 dsctrl = DSCTRL_BLNK_POL; 786 if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT) 787 dsctrl |= DSCTRL_HS_POL; 788 if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT) 789 dsctrl |= DSCTRL_VS_POL; 790 write_reg_dly(dsctrl, DSCTRL); 791 write_reg_dly(0xd0303010, DMCTRL); 792 write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL); 793} 794 795static void __devinit enable_controller(struct fb_info *fbi) 796{ 797 u32 svctrl, shctrl; 798 799 write_reg_dly(SYSRST_RST, SYSRST); 800 801 /* setup a timeout, raise drive strength */ 802 write_reg_dly(0xffffff0c, SYSCFG); 803 804 enable_clocks(fbi); 805 setup_memc(fbi); 806 setup_graphics(fbi); 807 setup_display(fbi); 808 809 shctrl = readl(SHCTRL); 810 shctrl &= ~(FMsk(SHCTRL_HINITIAL)); 811 shctrl |= Shctrl_Hinitial(4<<11); 812 writel(shctrl, SHCTRL); 813 814 svctrl = Svctrl_Initial1(1<<10) | Svctrl_Initial2(1<<10); 815 writel(svctrl, SVCTRL); 816 817 writel(SPOCTRL_H_SC_BP | SPOCTRL_V_SC_BP | SPOCTRL_VORDER_4TAP 818 , SPOCTRL); 819 820 /* Those coefficients are good for scaling up. For scaling 821 * down, the application has to calculate them. */ 822 write_reg(0xff000100, VSCOEFF0); 823 write_reg(0xfdfcfdfe, VSCOEFF1); 824 write_reg(0x170d0500, VSCOEFF2); 825 write_reg(0x3d372d22, VSCOEFF3); 826 write_reg(0x00000040, VSCOEFF4); 827 828 write_reg(0xff010100, HSCOEFF0); 829 write_reg(0x00000000, HSCOEFF1); 830 write_reg(0x02010000, HSCOEFF2); 831 write_reg(0x01020302, HSCOEFF3); 832 write_reg(0xf9fbfe00, HSCOEFF4); 833 write_reg(0xfbf7f6f7, HSCOEFF5); 834 write_reg(0x1c110700, HSCOEFF6); 835 write_reg(0x3e393127, HSCOEFF7); 836 write_reg(0x00000040, HSCOEFF8); 837 838} 839 840#ifdef CONFIG_PM 841/* 842 * Power management hooks. Note that we won't be called from IRQ context, 843 * unlike the blank functions above, so we may sleep. 844 */ 845static int mbxfb_suspend(struct platform_device *dev, pm_message_t state) 846{ 847 /* make frame buffer memory enter self-refresh mode */ 848 write_reg_dly(LMPWR_MC_PWR_SRM, LMPWR); 849 while (LMPWRSTAT != LMPWRSTAT_MC_PWR_SRM) 850 ; /* empty statement */ 851 852 /* reset the device, since it's initial state is 'mostly sleeping' */ 853 write_reg_dly(SYSRST_RST, SYSRST); 854 return 0; 855} 856 857static int mbxfb_resume(struct platform_device *dev) 858{ 859 struct fb_info *fbi = platform_get_drvdata(dev); 860 861 enable_clocks(fbi); 862/* setup_graphics(fbi); */ 863/* setup_display(fbi); */ 864 865 write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL); 866 return 0; 867} 868#else 869#define mbxfb_suspend NULL 870#define mbxfb_resume NULL 871#endif 872 873/* debugfs entries */ 874#ifndef CONFIG_FB_MBX_DEBUG 875#define mbxfb_debugfs_init(x) do {} while(0) 876#define mbxfb_debugfs_remove(x) do {} while(0) 877#endif 878 879#define res_size(_r) (((_r)->end - (_r)->start) + 1) 880 881static int __devinit mbxfb_probe(struct platform_device *dev) 882{ 883 int ret; 884 struct fb_info *fbi; 885 struct mbxfb_info *mfbi; 886 struct mbxfb_platform_data *pdata; 887 888 dev_dbg(&dev->dev, "mbxfb_probe\n"); 889 890 pdata = dev->dev.platform_data; 891 if (!pdata) { 892 dev_err(&dev->dev, "platform data is required\n"); 893 return -EINVAL; 894 } 895 896 fbi = framebuffer_alloc(sizeof(struct mbxfb_info), &dev->dev); 897 if (fbi == NULL) { 898 dev_err(&dev->dev, "framebuffer_alloc failed\n"); 899 return -ENOMEM; 900 } 901 902 mfbi = fbi->par; 903 fbi->pseudo_palette = mfbi->pseudo_palette; 904 905 906 if (pdata->probe) 907 mfbi->platform_probe = pdata->probe; 908 if (pdata->remove) 909 mfbi->platform_remove = pdata->remove; 910 911 mfbi->fb_res = platform_get_resource(dev, IORESOURCE_MEM, 0); 912 mfbi->reg_res = platform_get_resource(dev, IORESOURCE_MEM, 1); 913 914 if (!mfbi->fb_res || !mfbi->reg_res) { 915 dev_err(&dev->dev, "no resources found\n"); 916 ret = -ENODEV; 917 goto err1; 918 } 919 920 mfbi->fb_req = request_mem_region(mfbi->fb_res->start, 921 res_size(mfbi->fb_res), dev->name); 922 if (mfbi->fb_req == NULL) { 923 dev_err(&dev->dev, "failed to claim framebuffer memory\n"); 924 ret = -EINVAL; 925 goto err1; 926 } 927 mfbi->fb_phys_addr = mfbi->fb_res->start; 928 929 mfbi->reg_req = request_mem_region(mfbi->reg_res->start, 930 res_size(mfbi->reg_res), dev->name); 931 if (mfbi->reg_req == NULL) { 932 dev_err(&dev->dev, "failed to claim Marathon registers\n"); 933 ret = -EINVAL; 934 goto err2; 935 } 936 mfbi->reg_phys_addr = mfbi->reg_res->start; 937 938 mfbi->reg_virt_addr = ioremap_nocache(mfbi->reg_phys_addr, 939 res_size(mfbi->reg_req)); 940 if (!mfbi->reg_virt_addr) { 941 dev_err(&dev->dev, "failed to ioremap Marathon registers\n"); 942 ret = -EINVAL; 943 goto err3; 944 } 945 virt_base_2700 = (unsigned long)mfbi->reg_virt_addr; 946 947 mfbi->fb_virt_addr = ioremap_nocache(mfbi->fb_phys_addr, 948 res_size(mfbi->fb_req)); 949 if (!mfbi->reg_virt_addr) { 950 dev_err(&dev->dev, "failed to ioremap frame buffer\n"); 951 ret = -EINVAL; 952 goto err4; 953 } 954 955 fbi->screen_base = (char __iomem *)(mfbi->fb_virt_addr + 0x60000); 956 fbi->screen_size = pdata->memsize; 957 fbi->fbops = &mbxfb_ops; 958 959 fbi->var = mbxfb_default; 960 fbi->fix = mbxfb_fix; 961 fbi->fix.smem_start = mfbi->fb_phys_addr + 0x60000; 962 fbi->fix.smem_len = pdata->memsize; 963 fbi->fix.line_length = mbxfb_default.xres_virtual * 964 mbxfb_default.bits_per_pixel / 8; 965 966 ret = fb_alloc_cmap(&fbi->cmap, 256, 0); 967 if (ret < 0) { 968 dev_err(&dev->dev, "fb_alloc_cmap failed\n"); 969 ret = -EINVAL; 970 goto err5; 971 } 972 973 platform_set_drvdata(dev, fbi); 974 975 printk(KERN_INFO "fb%d: mbx frame buffer device\n", fbi->node); 976 977 if (mfbi->platform_probe) 978 mfbi->platform_probe(fbi); 979 980 enable_controller(fbi); 981 982 mbxfb_debugfs_init(fbi); 983 984 ret = register_framebuffer(fbi); 985 if (ret < 0) { 986 dev_err(&dev->dev, "register_framebuffer failed\n"); 987 ret = -EINVAL; 988 goto err6; 989 } 990 991 return 0; 992 993err6: 994 fb_dealloc_cmap(&fbi->cmap); 995err5: 996 iounmap(mfbi->fb_virt_addr); 997err4: 998 iounmap(mfbi->reg_virt_addr); 999err3: 1000 release_mem_region(mfbi->reg_res->start, res_size(mfbi->reg_res)); 1001err2: 1002 release_mem_region(mfbi->fb_res->start, res_size(mfbi->fb_res)); 1003err1: 1004 framebuffer_release(fbi); 1005 1006 return ret; 1007} 1008 1009static int __devexit mbxfb_remove(struct platform_device *dev) 1010{ 1011 struct fb_info *fbi = platform_get_drvdata(dev); 1012 1013 write_reg_dly(SYSRST_RST, SYSRST); 1014 1015 mbxfb_debugfs_remove(fbi); 1016 1017 if (fbi) { 1018 struct mbxfb_info *mfbi = fbi->par; 1019 1020 unregister_framebuffer(fbi); 1021 if (mfbi) { 1022 if (mfbi->platform_remove) 1023 mfbi->platform_remove(fbi); 1024 1025 if (mfbi->fb_virt_addr) 1026 iounmap(mfbi->fb_virt_addr); 1027 if (mfbi->reg_virt_addr) 1028 iounmap(mfbi->reg_virt_addr); 1029 if (mfbi->reg_req) 1030 release_mem_region(mfbi->reg_req->start, 1031 res_size(mfbi->reg_req)); 1032 if (mfbi->fb_req) 1033 release_mem_region(mfbi->fb_req->start, 1034 res_size(mfbi->fb_req)); 1035 } 1036 framebuffer_release(fbi); 1037 } 1038 1039 return 0; 1040} 1041 1042static struct platform_driver mbxfb_driver = { 1043 .probe = mbxfb_probe, 1044 .remove = mbxfb_remove, 1045 .suspend = mbxfb_suspend, 1046 .resume = mbxfb_resume, 1047 .driver = { 1048 .name = "mbx-fb", 1049 }, 1050}; 1051 1052int __devinit mbxfb_init(void) 1053{ 1054 return platform_driver_register(&mbxfb_driver); 1055} 1056 1057static void __devexit mbxfb_exit(void) 1058{ 1059 platform_driver_unregister(&mbxfb_driver); 1060} 1061 1062module_init(mbxfb_init); 1063module_exit(mbxfb_exit); 1064 1065MODULE_DESCRIPTION("loadable framebuffer driver for Marathon device"); 1066MODULE_AUTHOR("Mike Rapoport, Compulab"); 1067MODULE_LICENSE("GPL"); 1068