1/* 2 * linux/drivers/video/mbx/mbxfb.c 3 * 4 * Copyright (C) 2006 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, vbbase, vscadr, vsadr; 335 u32 sssize, spoctrl, svctrl, 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 350 spoctrl = readl(SPOCTRL); 351 sssize = readl(SSSIZE); 352 353 354 vbbase = Vbbase_Glalpha(set->alpha); 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 | VSCADR_COLKEY_EN | VSCADR_COLKEYSRC | 365 FMsk(VSCADR_BLEND_M) | FMsk(VSCADR_BLEND_POS) | 366 FMsk(VSCADR_VBASE_ADR) ); 367 vubase &= ~(VUBASE_UVHALFSTR | FMsk(VUBASE_UBASE_ADR)); 368 vvbase &= ~(FMsk(VVBASE_VBASE_ADR)); 369 370 switch (set->fmt) 371 { 372 case MBXFB_FMT_YUV12: 373 vsctrl |= VSCTRL_VPIXFMT_YUV12; 374 375 set->Y_stride = ((set->width) + 0xf ) & ~0xf; 376 377 break; 378 case MBXFB_FMT_UY0VY1: 379 vsctrl |= VSCTRL_VPIXFMT_UY0VY1; 380 set->Y_stride = (set->width*2 + 0xf ) & ~0xf; 381 break; 382 case MBXFB_FMT_VY0UY1: 383 vsctrl |= VSCTRL_VPIXFMT_VY0UY1; 384 set->Y_stride = (set->width*2 + 0xf ) & ~0xf; 385 break; 386 case MBXFB_FMT_Y0UY1V: 387 vsctrl |= VSCTRL_VPIXFMT_Y0UY1V; 388 set->Y_stride = (set->width*2 + 0xf ) & ~0xf; 389 break; 390 case MBXFB_FMT_Y0VY1U: 391 vsctrl |= VSCTRL_VPIXFMT_Y0VY1U; 392 set->Y_stride = (set->width*2 + 0xf ) & ~0xf; 393 break; 394 default: 395 return -EINVAL; 396 } 397 398 /* VSCTRL has the bits which sets the Video Pixel Format. 399 * When passing from a packed to planar format, 400 * if we write VSCTRL first, VVBASE and VUBASE would 401 * be zero if we would not set them here. (And then, 402 * the chips hangs and only a reset seems to fix it). 403 * 404 * If course, the values calculated here have no meaning 405 * for packed formats. 406 */ 407 set->UV_stride = ((set->width/2) + 0x7 ) & ~0x7; 408 set->U_offset = set->height * set->Y_stride; 409 set->V_offset = set->U_offset + 410 set->height * set->UV_stride; 411 vubase |= Vubase_Ubase_Adr( 412 (0x60000 + set->mem_offset + set->U_offset)>>3); 413 vvbase |= Vvbase_Vbase_Adr( 414 (0x60000 + set->mem_offset + set->V_offset)>>3); 415 416 417 vscadr |= VSCADR_BLEND_VID | VSCADR_BLEND_GLOB | 418 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_VORDER) | FMsk(SPOCTRL_VPITCH)); 434 spoctrl = Spoctrl_Vpitch((set->height<<11)/set->scaled_height) 435 | SPOCTRL_VORDER_2TAP; 436 437 /* Bypass horiz/vert scaler when same size */ 438 if (set->scaled_width == set->width) 439 spoctrl |= SPOCTRL_H_SC_BP; 440 if (set->scaled_height == set->height) 441 spoctrl |= SPOCTRL_V_SC_BP; 442 443 svctrl = Svctrl_Initial1(1<<10) | Svctrl_Initial2(1<<10); 444 445 shctrl = Shctrl_Hinitial(4<<11) 446 | Shctrl_Hpitch((set->width<<11)/set->scaled_width); 447 448 /* Video plane registers */ 449 write_reg(vsctrl, VSCTRL); 450 write_reg(vbbase, VBBASE); 451 write_reg(vscadr, VSCADR); 452 write_reg(vubase, VUBASE); 453 write_reg(vvbase, VVBASE); 454 write_reg(vsadr, VSADR); 455 456 /* Video scaler registers */ 457 write_reg(sssize, SSSIZE); 458 write_reg(spoctrl, SPOCTRL); 459 write_reg(svctrl, SVCTRL); 460 write_reg(shctrl, SHCTRL); 461 462 /* RAPH: Using those coefficients, the scaled 463 * image is quite blurry. I dont know how 464 * to improve them ; The chip documentation 465 * was not helpful.. */ 466 write_reg(0x21212121, VSCOEFF0); 467 write_reg(0x21212121, VSCOEFF1); 468 write_reg(0x21212121, VSCOEFF2); 469 write_reg(0x21212121, VSCOEFF3); 470 write_reg(0x21212121, VSCOEFF4); 471 write_reg(0x00000000, HSCOEFF0); 472 write_reg(0x00000000, HSCOEFF1); 473 write_reg(0x00000000, HSCOEFF2); 474 write_reg(0x03020201, HSCOEFF3); 475 write_reg(0x09070604, HSCOEFF4); 476 write_reg(0x0f0e0c0a, HSCOEFF5); 477 write_reg(0x15141211, HSCOEFF6); 478 write_reg(0x19181716, HSCOEFF7); 479 write_reg(0x00000019, HSCOEFF8); 480 481 /* Clock */ 482 if (set->enable) 483 vovrclk |= 1; 484 else 485 vovrclk &= ~1; 486 487 write_reg(vovrclk, VOVRCLK); 488 489 return 0; 490} 491 492static int mbxfb_ioctl(struct fb_info *info, unsigned int cmd, 493 unsigned long arg) 494{ 495 struct mbxfb_overlaySetup setup; 496 int res; 497 498 if (cmd == MBXFB_IOCX_OVERLAY) 499 { 500 if (copy_from_user(&setup, (void __user*)arg, 501 sizeof(struct mbxfb_overlaySetup))) 502 return -EFAULT; 503 504 res = mbxfb_setupOverlay(&setup); 505 if (res) 506 return res; 507 508 if (copy_to_user((void __user*)arg, &setup, 509 sizeof(struct mbxfb_overlaySetup))) 510 return -EFAULT; 511 512 return 0; 513 } 514 return -EINVAL; 515} 516 517static struct fb_ops mbxfb_ops = { 518 .owner = THIS_MODULE, 519 .fb_check_var = mbxfb_check_var, 520 .fb_set_par = mbxfb_set_par, 521 .fb_setcolreg = mbxfb_setcolreg, 522 .fb_fillrect = cfb_fillrect, 523 .fb_copyarea = cfb_copyarea, 524 .fb_imageblit = cfb_imageblit, 525 .fb_blank = mbxfb_blank, 526 .fb_ioctl = mbxfb_ioctl, 527}; 528 529/* 530 Enable external SDRAM controller. Assume that all clocks are active 531 by now. 532*/ 533static void __devinit setup_memc(struct fb_info *fbi) 534{ 535 unsigned long tmp; 536 int i; 537 538 /* setup SDRAM controller */ 539 write_reg_dly((LMCFG_LMC_DS | LMCFG_LMC_TS | LMCFG_LMD_TS | 540 LMCFG_LMA_TS), 541 LMCFG); 542 543 write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR); 544 545 /* setup SDRAM timings */ 546 write_reg_dly((Lmtim_Tras(7) | Lmtim_Trp(3) | Lmtim_Trcd(3) | 547 Lmtim_Trc(9) | Lmtim_Tdpl(2)), 548 LMTIM); 549 /* setup SDRAM refresh rate */ 550 write_reg_dly(0xc2b, LMREFRESH); 551 /* setup SDRAM type parameters */ 552 write_reg_dly((LMTYPE_CASLAT_3 | LMTYPE_BKSZ_2 | LMTYPE_ROWSZ_11 | 553 LMTYPE_COLSZ_8), 554 LMTYPE); 555 /* enable memory controller */ 556 write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR); 557 558 /* perform dummy reads */ 559 for ( i = 0; i < 16; i++ ) { 560 tmp = readl(fbi->screen_base); 561 } 562} 563 564static void enable_clocks(struct fb_info *fbi) 565{ 566 /* enable clocks */ 567 write_reg_dly(SYSCLKSRC_PLL_2, SYSCLKSRC); 568 write_reg_dly(PIXCLKSRC_PLL_1, PIXCLKSRC); 569 write_reg_dly(0x00000000, CLKSLEEP); 570 571 /* PLL output = (Frefclk * M) / (N * 2^P ) 572 * 573 * M: 0x17, N: 0x3, P: 0x0 == 100 Mhz! 574 * M: 0xb, N: 0x1, P: 0x1 == 71 Mhz 575 * */ 576 write_reg_dly((Core_Pll_M(0xb) | Core_Pll_N(0x1) | Core_Pll_P(0x1) | 577 CORE_PLL_EN), 578 COREPLL); 579 580 write_reg_dly((Disp_Pll_M(0x1b) | Disp_Pll_N(0x7) | Disp_Pll_P(0x1) | 581 DISP_PLL_EN), 582 DISPPLL); 583 584 write_reg_dly(0x00000000, VOVRCLK); 585 write_reg_dly(PIXCLK_EN, PIXCLK); 586 write_reg_dly(MEMCLK_EN, MEMCLK); 587 write_reg_dly(0x00000006, M24CLK); 588 write_reg_dly(0x00000006, MBXCLK); 589 write_reg_dly(SDCLK_EN, SDCLK); 590 write_reg_dly(0x00000001, PIXCLKDIV); 591} 592 593static void __devinit setup_graphics(struct fb_info *fbi) 594{ 595 unsigned long gsctrl; 596 597 gsctrl = GSCTRL_GAMMA_EN | Gsctrl_Width(fbi->var.xres) | 598 Gsctrl_Height(fbi->var.yres); 599 switch (fbi->var.bits_per_pixel) { 600 case 16: 601 if (fbi->var.green.length == 5) 602 gsctrl |= GSCTRL_GPIXFMT_ARGB1555; 603 else 604 gsctrl |= GSCTRL_GPIXFMT_RGB565; 605 break; 606 case 24: 607 gsctrl |= GSCTRL_GPIXFMT_RGB888; 608 break; 609 case 32: 610 gsctrl |= GSCTRL_GPIXFMT_ARGB8888; 611 break; 612 } 613 614 write_reg_dly(gsctrl, GSCTRL); 615 write_reg_dly(0x00000000, GBBASE); 616 write_reg_dly(0x00ffffff, GDRCTRL); 617 write_reg_dly((GSCADR_STR_EN | Gscadr_Gbase_Adr(0x6000)), GSCADR); 618 write_reg_dly(0x00000000, GPLUT); 619} 620 621static void __devinit setup_display(struct fb_info *fbi) 622{ 623 unsigned long dsctrl = 0; 624 625 dsctrl = DSCTRL_BLNK_POL; 626 if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT) 627 dsctrl |= DSCTRL_HS_POL; 628 if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT) 629 dsctrl |= DSCTRL_VS_POL; 630 write_reg_dly(dsctrl, DSCTRL); 631 write_reg_dly(0xd0303010, DMCTRL); 632 write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL); 633} 634 635static void __devinit enable_controller(struct fb_info *fbi) 636{ 637 write_reg_dly(SYSRST_RST, SYSRST); 638 639 640 enable_clocks(fbi); 641 setup_memc(fbi); 642 setup_graphics(fbi); 643 setup_display(fbi); 644} 645 646#ifdef CONFIG_PM 647/* 648 * Power management hooks. Note that we won't be called from IRQ context, 649 * unlike the blank functions above, so we may sleep. 650 */ 651static int mbxfb_suspend(struct platform_device *dev, pm_message_t state) 652{ 653 /* make frame buffer memory enter self-refresh mode */ 654 write_reg_dly(LMPWR_MC_PWR_SRM, LMPWR); 655 while (LMPWRSTAT != LMPWRSTAT_MC_PWR_SRM) 656 ; /* empty statement */ 657 658 /* reset the device, since it's initial state is 'mostly sleeping' */ 659 write_reg_dly(SYSRST_RST, SYSRST); 660 return 0; 661} 662 663static int mbxfb_resume(struct platform_device *dev) 664{ 665 struct fb_info *fbi = platform_get_drvdata(dev); 666 667 enable_clocks(fbi); 668/* setup_graphics(fbi); */ 669/* setup_display(fbi); */ 670 671 write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL); 672 return 0; 673} 674#else 675#define mbxfb_suspend NULL 676#define mbxfb_resume NULL 677#endif 678 679/* debugfs entries */ 680#ifndef CONFIG_FB_MBX_DEBUG 681#define mbxfb_debugfs_init(x) do {} while(0) 682#define mbxfb_debugfs_remove(x) do {} while(0) 683#endif 684 685#define res_size(_r) (((_r)->end - (_r)->start) + 1) 686 687static int __devinit mbxfb_probe(struct platform_device *dev) 688{ 689 int ret; 690 struct fb_info *fbi; 691 struct mbxfb_info *mfbi; 692 struct mbxfb_platform_data *pdata; 693 694 dev_dbg(dev, "mbxfb_probe\n"); 695 696 pdata = dev->dev.platform_data; 697 if (!pdata) { 698 dev_err(&dev->dev, "platform data is required\n"); 699 return -EINVAL; 700 } 701 702 fbi = framebuffer_alloc(sizeof(struct mbxfb_info), &dev->dev); 703 if (fbi == NULL) { 704 dev_err(&dev->dev, "framebuffer_alloc failed\n"); 705 return -ENOMEM; 706 } 707 708 mfbi = fbi->par; 709 fbi->pseudo_palette = mfbi->pseudo_palette; 710 711 712 if (pdata->probe) 713 mfbi->platform_probe = pdata->probe; 714 if (pdata->remove) 715 mfbi->platform_remove = pdata->remove; 716 717 mfbi->fb_res = platform_get_resource(dev, IORESOURCE_MEM, 0); 718 mfbi->reg_res = platform_get_resource(dev, IORESOURCE_MEM, 1); 719 720 if (!mfbi->fb_res || !mfbi->reg_res) { 721 dev_err(&dev->dev, "no resources found\n"); 722 ret = -ENODEV; 723 goto err1; 724 } 725 726 mfbi->fb_req = request_mem_region(mfbi->fb_res->start, 727 res_size(mfbi->fb_res), dev->name); 728 if (mfbi->fb_req == NULL) { 729 dev_err(&dev->dev, "failed to claim framebuffer memory\n"); 730 ret = -EINVAL; 731 goto err1; 732 } 733 mfbi->fb_phys_addr = mfbi->fb_res->start; 734 735 mfbi->reg_req = request_mem_region(mfbi->reg_res->start, 736 res_size(mfbi->reg_res), dev->name); 737 if (mfbi->reg_req == NULL) { 738 dev_err(&dev->dev, "failed to claim Marathon registers\n"); 739 ret = -EINVAL; 740 goto err2; 741 } 742 mfbi->reg_phys_addr = mfbi->reg_res->start; 743 744 mfbi->reg_virt_addr = ioremap_nocache(mfbi->reg_phys_addr, 745 res_size(mfbi->reg_req)); 746 if (!mfbi->reg_virt_addr) { 747 dev_err(&dev->dev, "failed to ioremap Marathon registers\n"); 748 ret = -EINVAL; 749 goto err3; 750 } 751 virt_base_2700 = (unsigned long)mfbi->reg_virt_addr; 752 753 mfbi->fb_virt_addr = ioremap_nocache(mfbi->fb_phys_addr, 754 res_size(mfbi->fb_req)); 755 if (!mfbi->reg_virt_addr) { 756 dev_err(&dev->dev, "failed to ioremap frame buffer\n"); 757 ret = -EINVAL; 758 goto err4; 759 } 760 761 fbi->screen_base = (char __iomem *)(mfbi->fb_virt_addr + 0x60000); 762 fbi->screen_size = pdata->memsize; 763 fbi->fbops = &mbxfb_ops; 764 765 fbi->var = mbxfb_default; 766 fbi->fix = mbxfb_fix; 767 fbi->fix.smem_start = mfbi->fb_phys_addr + 0x60000; 768 fbi->fix.smem_len = pdata->memsize; 769 fbi->fix.line_length = mbxfb_default.xres_virtual * 770 mbxfb_default.bits_per_pixel / 8; 771 772 ret = fb_alloc_cmap(&fbi->cmap, 256, 0); 773 if (ret < 0) { 774 dev_err(&dev->dev, "fb_alloc_cmap failed\n"); 775 ret = -EINVAL; 776 goto err5; 777 } 778 779 platform_set_drvdata(dev, fbi); 780 781 printk(KERN_INFO "fb%d: mbx frame buffer device\n", fbi->node); 782 783 if (mfbi->platform_probe) 784 mfbi->platform_probe(fbi); 785 786 enable_controller(fbi); 787 788 mbxfb_debugfs_init(fbi); 789 790 ret = register_framebuffer(fbi); 791 if (ret < 0) { 792 dev_err(&dev->dev, "register_framebuffer failed\n"); 793 ret = -EINVAL; 794 goto err6; 795 } 796 797 return 0; 798 799err6: 800 fb_dealloc_cmap(&fbi->cmap); 801err5: 802 iounmap(mfbi->fb_virt_addr); 803err4: 804 iounmap(mfbi->reg_virt_addr); 805err3: 806 release_mem_region(mfbi->reg_res->start, res_size(mfbi->reg_res)); 807err2: 808 release_mem_region(mfbi->fb_res->start, res_size(mfbi->fb_res)); 809err1: 810 framebuffer_release(fbi); 811 812 return ret; 813} 814 815static int __devexit mbxfb_remove(struct platform_device *dev) 816{ 817 struct fb_info *fbi = platform_get_drvdata(dev); 818 819 write_reg_dly(SYSRST_RST, SYSRST); 820 821 mbxfb_debugfs_remove(fbi); 822 823 if (fbi) { 824 struct mbxfb_info *mfbi = fbi->par; 825 826 unregister_framebuffer(fbi); 827 if (mfbi) { 828 if (mfbi->platform_remove) 829 mfbi->platform_remove(fbi); 830 831 if (mfbi->fb_virt_addr) 832 iounmap(mfbi->fb_virt_addr); 833 if (mfbi->reg_virt_addr) 834 iounmap(mfbi->reg_virt_addr); 835 if (mfbi->reg_req) 836 release_mem_region(mfbi->reg_req->start, 837 res_size(mfbi->reg_req)); 838 if (mfbi->fb_req) 839 release_mem_region(mfbi->fb_req->start, 840 res_size(mfbi->fb_req)); 841 } 842 framebuffer_release(fbi); 843 } 844 845 return 0; 846} 847 848static struct platform_driver mbxfb_driver = { 849 .probe = mbxfb_probe, 850 .remove = mbxfb_remove, 851 .suspend = mbxfb_suspend, 852 .resume = mbxfb_resume, 853 .driver = { 854 .name = "mbx-fb", 855 }, 856}; 857 858int __devinit mbxfb_init(void) 859{ 860 return platform_driver_register(&mbxfb_driver); 861} 862 863static void __devexit mbxfb_exit(void) 864{ 865 platform_driver_unregister(&mbxfb_driver); 866} 867 868module_init(mbxfb_init); 869module_exit(mbxfb_exit); 870 871MODULE_DESCRIPTION("loadable framebuffer driver for Marathon device"); 872MODULE_AUTHOR("Mike Rapoport, Compulab"); 873MODULE_LICENSE("GPL"); 874