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