diff options
author | Raphael Assenat <raph@8d.com> | 2006-12-08 05:40:36 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-08 11:29:06 -0500 |
commit | ea465250d41c99b4ee7dac1e6eb87b7106f7b11e (patch) | |
tree | c9c4d883562b14121390f6736f9ee3e6616d7f57 /drivers | |
parent | 128806c3b3e263c579af12c061a9b04db3950016 (diff) |
[PATCH] mbxfb: Add YUV video overlay support
This patch adds a way to create and use the video plane (YUV overlay) and
scaling video scaling features of the chip.
The overlay is configured, resized and modified using a device specific
ioctl.
Also included in this patch:
- If no platform data was passed, print an error and exit instead of crashing.
- Added a write_reg(_dly) macro. This improves readability when
manipulating chip registers. (no more udelay() after each write).
- Comments about some issues.
Signed-off-by: Raphael Assenat <raph@8d.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Acked-by: James Simmons <jsimmons@infradead.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/mbx/mbxfb.c | 359 |
1 files changed, 271 insertions, 88 deletions
diff --git a/drivers/video/mbx/mbxfb.c b/drivers/video/mbx/mbxfb.c index a32d1af79e07..980d5f623902 100644 --- a/drivers/video/mbx/mbxfb.c +++ b/drivers/video/mbx/mbxfb.c | |||
@@ -1,8 +1,14 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/video/mbx/mbxfb.c | 2 | * linux/drivers/video/mbx/mbxfb.c |
3 | * | 3 | * |
4 | * Copyright (C) 2006 8D Technologies inc | ||
5 | * Raphael Assenat <raph@8d.com> | ||
6 | * - Added video overlay support | ||
7 | * - Various improvements | ||
8 | * | ||
4 | * Copyright (C) 2006 Compulab, Ltd. | 9 | * Copyright (C) 2006 Compulab, Ltd. |
5 | * Mike Rapoport <mike@compulab.co.il> | 10 | * Mike Rapoport <mike@compulab.co.il> |
11 | * - Creation of driver | ||
6 | * | 12 | * |
7 | * Based on pxafb.c | 13 | * Based on pxafb.c |
8 | * | 14 | * |
@@ -19,6 +25,7 @@ | |||
19 | #include <linux/init.h> | 25 | #include <linux/init.h> |
20 | #include <linux/module.h> | 26 | #include <linux/module.h> |
21 | #include <linux/platform_device.h> | 27 | #include <linux/platform_device.h> |
28 | #include <linux/uaccess.h> | ||
22 | 29 | ||
23 | #include <asm/io.h> | 30 | #include <asm/io.h> |
24 | 31 | ||
@@ -29,6 +36,14 @@ | |||
29 | 36 | ||
30 | static unsigned long virt_base_2700; | 37 | static unsigned long virt_base_2700; |
31 | 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 | |||
32 | #define MIN_XRES 16 | 47 | #define MIN_XRES 16 |
33 | #define MIN_YRES 16 | 48 | #define MIN_YRES 16 |
34 | #define MAX_XRES 2048 | 49 | #define MAX_XRES 2048 |
@@ -257,19 +272,17 @@ static int mbxfb_set_par(struct fb_info *info) | |||
257 | gsctrl &= ~(FMsk(GSCTRL_GSWIDTH) | FMsk(GSCTRL_GSHEIGHT)); | 272 | gsctrl &= ~(FMsk(GSCTRL_GSWIDTH) | FMsk(GSCTRL_GSHEIGHT)); |
258 | gsctrl |= Gsctrl_Width(info->var.xres) | | 273 | gsctrl |= Gsctrl_Width(info->var.xres) | |
259 | Gsctrl_Height(info->var.yres); | 274 | Gsctrl_Height(info->var.yres); |
260 | writel(gsctrl, GSCTRL); | 275 | write_reg_dly(gsctrl, GSCTRL); |
261 | udelay(1000); | ||
262 | 276 | ||
263 | gsadr &= ~(FMsk(GSADR_SRCSTRIDE)); | 277 | gsadr &= ~(FMsk(GSADR_SRCSTRIDE)); |
264 | gsadr |= Gsadr_Srcstride(info->var.xres * info->var.bits_per_pixel / | 278 | gsadr |= Gsadr_Srcstride(info->var.xres * info->var.bits_per_pixel / |
265 | (8 * 16) - 1); | 279 | (8 * 16) - 1); |
266 | writel(gsadr, GSADR); | 280 | write_reg_dly(gsadr, GSADR); |
267 | udelay(1000); | ||
268 | 281 | ||
269 | /* setup timings */ | 282 | /* setup timings */ |
270 | var->pixclock = mbxfb_get_pixclock(info->var.pixclock, &div); | 283 | var->pixclock = mbxfb_get_pixclock(info->var.pixclock, &div); |
271 | 284 | ||
272 | writel((Disp_Pll_M(div.m) | Disp_Pll_N(div.n) | | 285 | write_reg_dly((Disp_Pll_M(div.m) | Disp_Pll_N(div.n) | |
273 | Disp_Pll_P(div.p) | DISP_PLL_EN), DISPPLL); | 286 | Disp_Pll_P(div.p) | DISP_PLL_EN), DISPPLL); |
274 | 287 | ||
275 | hbps = var->hsync_len; | 288 | hbps = var->hsync_len; |
@@ -282,18 +295,20 @@ static int mbxfb_set_par(struct fb_info *info) | |||
282 | vfps = vas + var->yres; | 295 | vfps = vas + var->yres; |
283 | vt = vfps + var->lower_margin; | 296 | vt = vfps + var->lower_margin; |
284 | 297 | ||
285 | writel((Dht01_Hbps(hbps) | Dht01_Ht(ht)), DHT01); | 298 | write_reg_dly((Dht01_Hbps(hbps) | Dht01_Ht(ht)), DHT01); |
286 | writel((Dht02_Hlbs(has) | Dht02_Has(has)), DHT02); | 299 | write_reg_dly((Dht02_Hlbs(has) | Dht02_Has(has)), DHT02); |
287 | writel((Dht03_Hfps(hfps) | Dht03_Hrbs(hfps)), DHT03); | 300 | write_reg_dly((Dht03_Hfps(hfps) | Dht03_Hrbs(hfps)), DHT03); |
288 | writel((Dhdet_Hdes(has) | Dhdet_Hdef(hfps)), DHDET); | 301 | write_reg_dly((Dhdet_Hdes(has) | Dhdet_Hdef(hfps)), DHDET); |
289 | 302 | ||
290 | writel((Dvt01_Vbps(vbps) | Dvt01_Vt(vt)), DVT01); | 303 | write_reg_dly((Dvt01_Vbps(vbps) | Dvt01_Vt(vt)), DVT01); |
291 | writel((Dvt02_Vtbs(vas) | Dvt02_Vas(vas)), DVT02); | 304 | write_reg_dly((Dvt02_Vtbs(vas) | Dvt02_Vas(vas)), DVT02); |
292 | writel((Dvt03_Vfps(vfps) | Dvt03_Vbbs(vfps)), DVT03); | 305 | write_reg_dly((Dvt03_Vfps(vfps) | Dvt03_Vbbs(vfps)), DVT03); |
293 | writel((Dvdet_Vdes(vas) | Dvdet_Vdef(vfps)), DVDET); | 306 | write_reg_dly((Dvdet_Vdes(vas) | Dvdet_Vdef(vfps)), DVDET); |
294 | writel((Dvectrl_Vevent(vfps) | Dvectrl_Vfetch(vbps)), DVECTRL); | 307 | write_reg_dly((Dvectrl_Vevent(vfps) | Dvectrl_Vfetch(vbps)), DVECTRL); |
295 | 308 | ||
296 | writel((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL); | 309 | write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL); |
310 | |||
311 | write_reg_dly(DINTRE_VEVENT0_EN, DINTRE); | ||
297 | 312 | ||
298 | return 0; | 313 | return 0; |
299 | } | 314 | } |
@@ -305,23 +320,203 @@ static int mbxfb_blank(int blank, struct fb_info *info) | |||
305 | case FB_BLANK_VSYNC_SUSPEND: | 320 | case FB_BLANK_VSYNC_SUSPEND: |
306 | case FB_BLANK_HSYNC_SUSPEND: | 321 | case FB_BLANK_HSYNC_SUSPEND: |
307 | case FB_BLANK_NORMAL: | 322 | case FB_BLANK_NORMAL: |
308 | writel((readl(DSCTRL) & ~DSCTRL_SYNCGEN_EN), DSCTRL); | 323 | write_reg_dly((readl(DSCTRL) & ~DSCTRL_SYNCGEN_EN), DSCTRL); |
309 | udelay(1000); | 324 | write_reg_dly((readl(PIXCLK) & ~PIXCLK_EN), PIXCLK); |
310 | writel((readl(PIXCLK) & ~PIXCLK_EN), PIXCLK); | 325 | write_reg_dly((readl(VOVRCLK) & ~VOVRCLK_EN), VOVRCLK); |
311 | udelay(1000); | ||
312 | writel((readl(VOVRCLK) & ~VOVRCLK_EN), VOVRCLK); | ||
313 | udelay(1000); | ||
314 | break; | 326 | break; |
315 | case FB_BLANK_UNBLANK: | 327 | case FB_BLANK_UNBLANK: |
316 | writel((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL); | 328 | write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL); |
317 | udelay(1000); | 329 | write_reg_dly((readl(PIXCLK) | PIXCLK_EN), PIXCLK); |
318 | writel((readl(PIXCLK) | PIXCLK_EN), PIXCLK); | ||
319 | udelay(1000); | ||
320 | break; | 330 | break; |
321 | } | 331 | } |
322 | return 0; | 332 | return 0; |
323 | } | 333 | } |
324 | 334 | ||
335 | static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set) | ||
336 | { | ||
337 | u32 vsctrl, vbbase, vscadr, vsadr; | ||
338 | u32 sssize, spoctrl, svctrl, shctrl; | ||
339 | u32 vubase, vvbase; | ||
340 | u32 vovrclk; | ||
341 | |||
342 | if (set->scaled_width==0 || set->scaled_height==0) | ||
343 | return -EINVAL; | ||
344 | |||
345 | /* read registers which have reserved bits | ||
346 | * so we can write them back as-is. */ | ||
347 | vovrclk = readl(VOVRCLK); | ||
348 | vsctrl = readl(VSCTRL); | ||
349 | vscadr = readl(VSCADR); | ||
350 | vubase = readl(VUBASE); | ||
351 | vvbase = readl(VVBASE); | ||
352 | |||
353 | spoctrl = readl(SPOCTRL); | ||
354 | sssize = readl(SSSIZE); | ||
355 | |||
356 | |||
357 | vbbase = Vbbase_Glalpha(set->alpha); | ||
358 | |||
359 | vsctrl &= ~( FMsk(VSCTRL_VSWIDTH) | | ||
360 | FMsk(VSCTRL_VSHEIGHT) | | ||
361 | FMsk(VSCTRL_VPIXFMT) | | ||
362 | VSCTRL_GAMMA_EN | VSCTRL_CSC_EN | | ||
363 | VSCTRL_COSITED ); | ||
364 | vsctrl |= Vsctrl_Width(set->width) | Vsctrl_Height(set->height) | | ||
365 | VSCTRL_CSC_EN; | ||
366 | |||
367 | vscadr &= ~(VSCADR_STR_EN | VSCADR_COLKEY_EN | VSCADR_COLKEYSRC | | ||
368 | FMsk(VSCADR_BLEND_M) | FMsk(VSCADR_BLEND_POS) | | ||
369 | FMsk(VSCADR_VBASE_ADR) ); | ||
370 | vubase &= ~(VUBASE_UVHALFSTR | FMsk(VUBASE_UBASE_ADR)); | ||
371 | vvbase &= ~(FMsk(VVBASE_VBASE_ADR)); | ||
372 | |||
373 | switch (set->fmt) | ||
374 | { | ||
375 | case MBXFB_FMT_YUV12: | ||
376 | vsctrl |= VSCTRL_VPIXFMT_YUV12; | ||
377 | |||
378 | set->Y_stride = ((set->width) + 0xf ) & ~0xf; | ||
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_BLEND_VID | VSCADR_BLEND_GLOB | | ||
421 | Vscadr_Vbase_Adr((0x60000 + set->mem_offset)>>4); | ||
422 | |||
423 | if (set->enable) | ||
424 | vscadr |= VSCADR_STR_EN; | ||
425 | |||
426 | |||
427 | vsadr = Vsadr_Srcstride((set->Y_stride)/16-1) | | ||
428 | Vsadr_Xstart(set->x) | Vsadr_Ystart(set->y); | ||
429 | |||
430 | sssize &= ~(FMsk(SSSIZE_SC_WIDTH) | FMsk(SSSIZE_SC_HEIGHT)); | ||
431 | sssize = Sssize_Sc_Width(set->scaled_width-1) | | ||
432 | Sssize_Sc_Height(set->scaled_height-1); | ||
433 | |||
434 | spoctrl &= ~(SPOCTRL_H_SC_BP | SPOCTRL_V_SC_BP | | ||
435 | SPOCTRL_HV_SC_OR | SPOCTRL_VS_UR_C | | ||
436 | FMsk(SPOCTRL_VORDER) | FMsk(SPOCTRL_VPITCH)); | ||
437 | spoctrl = Spoctrl_Vpitch((set->height<<11)/set->scaled_height) | ||
438 | | SPOCTRL_VORDER_2TAP; | ||
439 | |||
440 | /* Bypass horiz/vert scaler when same size */ | ||
441 | if (set->scaled_width == set->width) | ||
442 | spoctrl |= SPOCTRL_H_SC_BP; | ||
443 | if (set->scaled_height == set->height) | ||
444 | spoctrl |= SPOCTRL_V_SC_BP; | ||
445 | |||
446 | svctrl = Svctrl_Initial1(1<<10) | Svctrl_Initial2(1<<10); | ||
447 | |||
448 | shctrl = Shctrl_Hinitial(4<<11) | ||
449 | | Shctrl_Hpitch((set->width<<11)/set->scaled_width); | ||
450 | |||
451 | /* Video plane registers */ | ||
452 | write_reg(vsctrl, VSCTRL); | ||
453 | write_reg(vbbase, VBBASE); | ||
454 | write_reg(vscadr, VSCADR); | ||
455 | write_reg(vubase, VUBASE); | ||
456 | write_reg(vvbase, VVBASE); | ||
457 | write_reg(vsadr, VSADR); | ||
458 | |||
459 | /* Video scaler registers */ | ||
460 | write_reg(sssize, SSSIZE); | ||
461 | write_reg(spoctrl, SPOCTRL); | ||
462 | write_reg(svctrl, SVCTRL); | ||
463 | write_reg(shctrl, SHCTRL); | ||
464 | |||
465 | /* RAPH: Using those coefficients, the scaled | ||
466 | * image is quite blurry. I dont know how | ||
467 | * to improve them ; The chip documentation | ||
468 | * was not helpful.. */ | ||
469 | write_reg(0x21212121, VSCOEFF0); | ||
470 | write_reg(0x21212121, VSCOEFF1); | ||
471 | write_reg(0x21212121, VSCOEFF2); | ||
472 | write_reg(0x21212121, VSCOEFF3); | ||
473 | write_reg(0x21212121, VSCOEFF4); | ||
474 | write_reg(0x00000000, HSCOEFF0); | ||
475 | write_reg(0x00000000, HSCOEFF1); | ||
476 | write_reg(0x00000000, HSCOEFF2); | ||
477 | write_reg(0x03020201, HSCOEFF3); | ||
478 | write_reg(0x09070604, HSCOEFF4); | ||
479 | write_reg(0x0f0e0c0a, HSCOEFF5); | ||
480 | write_reg(0x15141211, HSCOEFF6); | ||
481 | write_reg(0x19181716, HSCOEFF7); | ||
482 | write_reg(0x00000019, HSCOEFF8); | ||
483 | |||
484 | /* Clock */ | ||
485 | if (set->enable) | ||
486 | vovrclk |= 1; | ||
487 | else | ||
488 | vovrclk &= ~1; | ||
489 | |||
490 | write_reg(vovrclk, VOVRCLK); | ||
491 | |||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | static int mbxfb_ioctl(struct fb_info *info, unsigned int cmd, | ||
496 | unsigned long arg) | ||
497 | { | ||
498 | struct mbxfb_overlaySetup setup; | ||
499 | int res; | ||
500 | |||
501 | if (cmd == MBXFB_IOCX_OVERLAY) | ||
502 | { | ||
503 | if (copy_from_user(&setup, (void __user*)arg, | ||
504 | sizeof(struct mbxfb_overlaySetup))) | ||
505 | return -EFAULT; | ||
506 | |||
507 | res = mbxfb_setupOverlay(&setup); | ||
508 | if (res) | ||
509 | return res; | ||
510 | |||
511 | if (copy_to_user((void __user*)arg, &setup, | ||
512 | sizeof(struct mbxfb_overlaySetup))) | ||
513 | return -EFAULT; | ||
514 | |||
515 | return 0; | ||
516 | } | ||
517 | return -EINVAL; | ||
518 | } | ||
519 | |||
325 | static struct fb_ops mbxfb_ops = { | 520 | static struct fb_ops mbxfb_ops = { |
326 | .owner = THIS_MODULE, | 521 | .owner = THIS_MODULE, |
327 | .fb_check_var = mbxfb_check_var, | 522 | .fb_check_var = mbxfb_check_var, |
@@ -331,6 +526,7 @@ static struct fb_ops mbxfb_ops = { | |||
331 | .fb_copyarea = cfb_copyarea, | 526 | .fb_copyarea = cfb_copyarea, |
332 | .fb_imageblit = cfb_imageblit, | 527 | .fb_imageblit = cfb_imageblit, |
333 | .fb_blank = mbxfb_blank, | 528 | .fb_blank = mbxfb_blank, |
529 | .fb_ioctl = mbxfb_ioctl, | ||
334 | }; | 530 | }; |
335 | 531 | ||
336 | /* | 532 | /* |
@@ -339,36 +535,29 @@ static struct fb_ops mbxfb_ops = { | |||
339 | */ | 535 | */ |
340 | static void __devinit setup_memc(struct fb_info *fbi) | 536 | static void __devinit setup_memc(struct fb_info *fbi) |
341 | { | 537 | { |
342 | struct mbxfb_info *mfbi = fbi->par; | ||
343 | unsigned long tmp; | 538 | unsigned long tmp; |
344 | int i; | 539 | int i; |
345 | 540 | ||
346 | /* FIXME: use platfrom specific parameters */ | 541 | /* FIXME: use platfrom specific parameters */ |
347 | /* setup SDRAM controller */ | 542 | /* setup SDRAM controller */ |
348 | writel((LMCFG_LMC_DS | LMCFG_LMC_TS | LMCFG_LMD_TS | | 543 | write_reg_dly((LMCFG_LMC_DS | LMCFG_LMC_TS | LMCFG_LMD_TS | |
349 | LMCFG_LMA_TS), | 544 | LMCFG_LMA_TS), |
350 | LMCFG); | 545 | LMCFG); |
351 | udelay(1000); | ||
352 | 546 | ||
353 | writel(LMPWR_MC_PWR_ACT, LMPWR); | 547 | write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR); |
354 | udelay(1000); | ||
355 | 548 | ||
356 | /* setup SDRAM timings */ | 549 | /* setup SDRAM timings */ |
357 | writel((Lmtim_Tras(7) | Lmtim_Trp(3) | Lmtim_Trcd(3) | | 550 | write_reg_dly((Lmtim_Tras(7) | Lmtim_Trp(3) | Lmtim_Trcd(3) | |
358 | Lmtim_Trc(9) | Lmtim_Tdpl(2)), | 551 | Lmtim_Trc(9) | Lmtim_Tdpl(2)), |
359 | LMTIM); | 552 | LMTIM); |
360 | udelay(1000); | ||
361 | /* setup SDRAM refresh rate */ | 553 | /* setup SDRAM refresh rate */ |
362 | writel(0xc2b, LMREFRESH); | 554 | write_reg_dly(0xc2b, LMREFRESH); |
363 | udelay(1000); | ||
364 | /* setup SDRAM type parameters */ | 555 | /* setup SDRAM type parameters */ |
365 | writel((LMTYPE_CASLAT_3 | LMTYPE_BKSZ_2 | LMTYPE_ROWSZ_11 | | 556 | write_reg_dly((LMTYPE_CASLAT_3 | LMTYPE_BKSZ_2 | LMTYPE_ROWSZ_11 | |
366 | LMTYPE_COLSZ_8), | 557 | LMTYPE_COLSZ_8), |
367 | LMTYPE); | 558 | LMTYPE); |
368 | udelay(1000); | ||
369 | /* enable memory controller */ | 559 | /* enable memory controller */ |
370 | writel(LMPWR_MC_PWR_ACT, LMPWR); | 560 | write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR); |
371 | udelay(1000); | ||
372 | 561 | ||
373 | /* perform dummy reads */ | 562 | /* perform dummy reads */ |
374 | for ( i = 0; i < 16; i++ ) { | 563 | for ( i = 0; i < 16; i++ ) { |
@@ -379,34 +568,30 @@ static void __devinit setup_memc(struct fb_info *fbi) | |||
379 | static void enable_clocks(struct fb_info *fbi) | 568 | static void enable_clocks(struct fb_info *fbi) |
380 | { | 569 | { |
381 | /* enable clocks */ | 570 | /* enable clocks */ |
382 | writel(SYSCLKSRC_PLL_2, SYSCLKSRC); | 571 | write_reg_dly(SYSCLKSRC_PLL_2, SYSCLKSRC); |
383 | udelay(1000); | 572 | write_reg_dly(PIXCLKSRC_PLL_1, PIXCLKSRC); |
384 | writel(PIXCLKSRC_PLL_1, PIXCLKSRC); | 573 | write_reg_dly(0x00000000, CLKSLEEP); |
385 | udelay(1000); | 574 | |
386 | writel(0x00000000, CLKSLEEP); | 575 | /* PLL output = (Frefclk * M) / (N * 2^P ) |
387 | udelay(1000); | 576 | * |
388 | writel((Core_Pll_M(0x17) | Core_Pll_N(0x3) | Core_Pll_P(0x0) | | 577 | * M: 0x17, N: 0x3, P: 0x0 == 100 Mhz! |
578 | * M: 0xb, N: 0x1, P: 0x1 == 71 Mhz | ||
579 | * */ | ||
580 | write_reg_dly((Core_Pll_M(0xb) | Core_Pll_N(0x1) | Core_Pll_P(0x1) | | ||
389 | CORE_PLL_EN), | 581 | CORE_PLL_EN), |
390 | COREPLL); | 582 | COREPLL); |
391 | udelay(1000); | 583 | |
392 | writel((Disp_Pll_M(0x1b) | Disp_Pll_N(0x7) | Disp_Pll_P(0x1) | | 584 | write_reg_dly((Disp_Pll_M(0x1b) | Disp_Pll_N(0x7) | Disp_Pll_P(0x1) | |
393 | DISP_PLL_EN), | 585 | DISP_PLL_EN), |
394 | DISPPLL); | 586 | DISPPLL); |
395 | 587 | ||
396 | writel(0x00000000, VOVRCLK); | 588 | write_reg_dly(0x00000000, VOVRCLK); |
397 | udelay(1000); | 589 | write_reg_dly(PIXCLK_EN, PIXCLK); |
398 | writel(PIXCLK_EN, PIXCLK); | 590 | write_reg_dly(MEMCLK_EN, MEMCLK); |
399 | udelay(1000); | 591 | write_reg_dly(0x00000006, M24CLK); |
400 | writel(MEMCLK_EN, MEMCLK); | 592 | write_reg_dly(0x00000006, MBXCLK); |
401 | udelay(1000); | 593 | write_reg_dly(SDCLK_EN, SDCLK); |
402 | writel(0x00000006, M24CLK); | 594 | write_reg_dly(0x00000001, PIXCLKDIV); |
403 | udelay(1000); | ||
404 | writel(0x00000006, MBXCLK); | ||
405 | udelay(1000); | ||
406 | writel(SDCLK_EN, SDCLK); | ||
407 | udelay(1000); | ||
408 | writel(0x00000001, PIXCLKDIV); | ||
409 | udelay(1000); | ||
410 | } | 595 | } |
411 | 596 | ||
412 | static void __devinit setup_graphics(struct fb_info *fbi) | 597 | static void __devinit setup_graphics(struct fb_info *fbi) |
@@ -430,16 +615,11 @@ static void __devinit setup_graphics(struct fb_info *fbi) | |||
430 | break; | 615 | break; |
431 | } | 616 | } |
432 | 617 | ||
433 | writel(gsctrl, GSCTRL); | 618 | write_reg_dly(gsctrl, GSCTRL); |
434 | udelay(1000); | 619 | write_reg_dly(0x00000000, GBBASE); |
435 | writel(0x00000000, GBBASE); | 620 | write_reg_dly(0x00ffffff, GDRCTRL); |
436 | udelay(1000); | 621 | write_reg_dly((GSCADR_STR_EN | Gscadr_Gbase_Adr(0x6000)), GSCADR); |
437 | writel(0x00ffffff, GDRCTRL); | 622 | write_reg_dly(0x00000000, GPLUT); |
438 | udelay(1000); | ||
439 | writel((GSCADR_STR_EN | Gscadr_Gbase_Adr(0x6000)), GSCADR); | ||
440 | udelay(1000); | ||
441 | writel(0x00000000, GPLUT); | ||
442 | udelay(1000); | ||
443 | } | 623 | } |
444 | 624 | ||
445 | static void __devinit setup_display(struct fb_info *fbi) | 625 | static void __devinit setup_display(struct fb_info *fbi) |
@@ -451,17 +631,14 @@ static void __devinit setup_display(struct fb_info *fbi) | |||
451 | dsctrl |= DSCTRL_HS_POL; | 631 | dsctrl |= DSCTRL_HS_POL; |
452 | if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT) | 632 | if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT) |
453 | dsctrl |= DSCTRL_VS_POL; | 633 | dsctrl |= DSCTRL_VS_POL; |
454 | writel(dsctrl, DSCTRL); | 634 | write_reg_dly(dsctrl, DSCTRL); |
455 | udelay(1000); | 635 | write_reg_dly(0xd0303010, DMCTRL); |
456 | writel(0xd0303010, DMCTRL); | 636 | write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL); |
457 | udelay(1000); | ||
458 | writel((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL); | ||
459 | } | 637 | } |
460 | 638 | ||
461 | static void __devinit enable_controller(struct fb_info *fbi) | 639 | static void __devinit enable_controller(struct fb_info *fbi) |
462 | { | 640 | { |
463 | writel(SYSRST_RST, SYSRST); | 641 | write_reg_dly(SYSRST_RST, SYSRST); |
464 | udelay(1000); | ||
465 | 642 | ||
466 | 643 | ||
467 | enable_clocks(fbi); | 644 | enable_clocks(fbi); |
@@ -478,12 +655,12 @@ static void __devinit enable_controller(struct fb_info *fbi) | |||
478 | static int mbxfb_suspend(struct platform_device *dev, pm_message_t state) | 655 | static int mbxfb_suspend(struct platform_device *dev, pm_message_t state) |
479 | { | 656 | { |
480 | /* make frame buffer memory enter self-refresh mode */ | 657 | /* make frame buffer memory enter self-refresh mode */ |
481 | writel(LMPWR_MC_PWR_SRM, LMPWR); | 658 | write_reg_dly(LMPWR_MC_PWR_SRM, LMPWR); |
482 | while (LMPWRSTAT != LMPWRSTAT_MC_PWR_SRM) | 659 | while (LMPWRSTAT != LMPWRSTAT_MC_PWR_SRM) |
483 | ; /* empty statement */ | 660 | ; /* empty statement */ |
484 | 661 | ||
485 | /* reset the device, since it's initial state is 'mostly sleeping' */ | 662 | /* reset the device, since it's initial state is 'mostly sleeping' */ |
486 | writel(SYSRST_RST, SYSRST); | 663 | write_reg_dly(SYSRST_RST, SYSRST); |
487 | return 0; | 664 | return 0; |
488 | } | 665 | } |
489 | 666 | ||
@@ -495,7 +672,7 @@ static int mbxfb_resume(struct platform_device *dev) | |||
495 | /* setup_graphics(fbi); */ | 672 | /* setup_graphics(fbi); */ |
496 | /* setup_display(fbi); */ | 673 | /* setup_display(fbi); */ |
497 | 674 | ||
498 | writel((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL); | 675 | write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL); |
499 | return 0; | 676 | return 0; |
500 | } | 677 | } |
501 | #else | 678 | #else |
@@ -520,6 +697,12 @@ static int __devinit mbxfb_probe(struct platform_device *dev) | |||
520 | 697 | ||
521 | dev_dbg(dev, "mbxfb_probe\n"); | 698 | dev_dbg(dev, "mbxfb_probe\n"); |
522 | 699 | ||
700 | pdata = dev->dev.platform_data; | ||
701 | if (!pdata) { | ||
702 | dev_err(&dev->dev, "platform data is required\n"); | ||
703 | return -EINVAL; | ||
704 | } | ||
705 | |||
523 | fbi = framebuffer_alloc(sizeof(struct mbxfb_info), &dev->dev); | 706 | fbi = framebuffer_alloc(sizeof(struct mbxfb_info), &dev->dev); |
524 | if (fbi == NULL) { | 707 | if (fbi == NULL) { |
525 | dev_err(&dev->dev, "framebuffer_alloc failed\n"); | 708 | dev_err(&dev->dev, "framebuffer_alloc failed\n"); |
@@ -528,7 +711,8 @@ static int __devinit mbxfb_probe(struct platform_device *dev) | |||
528 | 711 | ||
529 | mfbi = fbi->par; | 712 | mfbi = fbi->par; |
530 | fbi->pseudo_palette = mfbi->pseudo_palette; | 713 | fbi->pseudo_palette = mfbi->pseudo_palette; |
531 | pdata = dev->dev.platform_data; | 714 | |
715 | |||
532 | if (pdata->probe) | 716 | if (pdata->probe) |
533 | mfbi->platform_probe = pdata->probe; | 717 | mfbi->platform_probe = pdata->probe; |
534 | if (pdata->remove) | 718 | if (pdata->remove) |
@@ -578,16 +762,16 @@ static int __devinit mbxfb_probe(struct platform_device *dev) | |||
578 | goto err4; | 762 | goto err4; |
579 | } | 763 | } |
580 | 764 | ||
581 | /* FIXME: get from platform */ | ||
582 | fbi->screen_base = (char __iomem *)(mfbi->fb_virt_addr + 0x60000); | 765 | fbi->screen_base = (char __iomem *)(mfbi->fb_virt_addr + 0x60000); |
583 | fbi->screen_size = 8 * 1024 * 1024; /* 8 Megs */ | 766 | fbi->screen_size = pdata->memsize; |
584 | fbi->fbops = &mbxfb_ops; | 767 | fbi->fbops = &mbxfb_ops; |
585 | 768 | ||
586 | fbi->var = mbxfb_default; | 769 | fbi->var = mbxfb_default; |
587 | fbi->fix = mbxfb_fix; | 770 | fbi->fix = mbxfb_fix; |
588 | fbi->fix.smem_start = mfbi->fb_phys_addr + 0x60000; | 771 | fbi->fix.smem_start = mfbi->fb_phys_addr + 0x60000; |
589 | fbi->fix.smem_len = 8 * 1024 * 1024; | 772 | fbi->fix.smem_len = pdata->memsize; |
590 | fbi->fix.line_length = 640 * 2; | 773 | fbi->fix.line_length = mbxfb_default.xres_virtual * |
774 | mbxfb_default.bits_per_pixel / 8; | ||
591 | 775 | ||
592 | ret = fb_alloc_cmap(&fbi->cmap, 256, 0); | 776 | ret = fb_alloc_cmap(&fbi->cmap, 256, 0); |
593 | if (ret < 0) { | 777 | if (ret < 0) { |
@@ -636,8 +820,7 @@ static int __devexit mbxfb_remove(struct platform_device *dev) | |||
636 | { | 820 | { |
637 | struct fb_info *fbi = platform_get_drvdata(dev); | 821 | struct fb_info *fbi = platform_get_drvdata(dev); |
638 | 822 | ||
639 | writel(SYSRST_RST, SYSRST); | 823 | write_reg_dly(SYSRST_RST, SYSRST); |
640 | udelay(1000); | ||
641 | 824 | ||
642 | mbxfb_debugfs_remove(fbi); | 825 | mbxfb_debugfs_remove(fbi); |
643 | 826 | ||