diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-22 23:43:40 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-22 23:43:40 -0400 |
commit | 437538267b672f9320833907f1b5acbb2605f4be (patch) | |
tree | d10173b35a5b86bc037bb2ece1b406d5575a2094 /drivers | |
parent | 9586c959bfc917695893bef0102433a7d0675691 (diff) | |
parent | 6bff98b455cf3e666fd0e3d0d908eba874de0eee (diff) |
Merge tag 'fbdev-updates-for-3.4' of git://github.com/schandinat/linux-2.6
Pull fbdev updates for 3.4 from Florian Tobias Schandinat:
- drivers for Samsung Exynos MIPI DSI and display port
- i740fb to support those old Intel chips
- large updates to OMAP, viafb and sh_mobile_lcdcfb
- some updates to s3c-fb and udlfb, few patches to others
Fix up conflicts in drivers/video/udlfb.c due to Key Sievers' fix making
it in twice.
* tag 'fbdev-updates-for-3.4' of git://github.com/schandinat/linux-2.6: (156 commits)
Revert "video:uvesafb: Fix oops that uvesafb try to execute NX-protected page"
OMAPDSS: register dss drivers in module init
video: pxafb: add clk_prepare/clk_unprepare calls
fbdev: bfin_adv7393fb: Drop needless include
fbdev: sh_mipi_dsi: add extra phyctrl for sh_mipi_dsi_info
fbdev: remove dependency of FB_SH_MOBILE_MERAM from FB_SH_MOBILE_LCDC
Revert "MAINTAINERS: add entry for exynos mipi display drivers"
fbdev: da8xx: add support for SP10Q010 display
fbdev: da8xx:: fix reporting of the display timing info
drivers/video/pvr2fb.c: ensure arguments to request_irq and free_irq are compatible
OMAPDSS: APPLY: fix clearing shadow dirty flag with manual update
fbdev: sh_mobile_meram: Implement system suspend/resume
fbdev: sh_mobile_meram: Remove unneeded sanity checks
fbdev: sh_mobile_meram: Don't perform update in register operation
arm: mach-shmobile: Constify sh_mobile_meram_cfg structures
fbdev: sh_mobile_lcdc: Don't store copy of platform data
fbdev: sh_mobile_meram: Remove unused sh_mobile_meram_icb_cfg fields
arm: mach-shmobile: Don't set MERAM ICB numbers in platform data
fbdev: sh_mobile_meram: Allocate ICBs automatically
fbdev: sh_mobile_meram: Use genalloc to manage MERAM allocation
...
Diffstat (limited to 'drivers')
102 files changed, 11424 insertions, 7324 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index eca60c73ef1f..a8a897ac5446 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -1123,6 +1123,18 @@ config FB_RIVA_BACKLIGHT | |||
1123 | help | 1123 | help |
1124 | Say Y here if you want to control the backlight of your display. | 1124 | Say Y here if you want to control the backlight of your display. |
1125 | 1125 | ||
1126 | config FB_I740 | ||
1127 | tristate "Intel740 support (EXPERIMENTAL)" | ||
1128 | depends on EXPERIMENTAL && FB && PCI | ||
1129 | select FB_MODE_HELPERS | ||
1130 | select FB_CFB_FILLRECT | ||
1131 | select FB_CFB_COPYAREA | ||
1132 | select FB_CFB_IMAGEBLIT | ||
1133 | select VGASTATE | ||
1134 | select FB_DDC | ||
1135 | help | ||
1136 | This driver supports graphics cards based on Intel740 chip. | ||
1137 | |||
1126 | config FB_I810 | 1138 | config FB_I810 |
1127 | tristate "Intel 810/815 support (EXPERIMENTAL)" | 1139 | tristate "Intel 810/815 support (EXPERIMENTAL)" |
1128 | depends on EXPERIMENTAL && FB && PCI && X86_32 && AGP_INTEL | 1140 | depends on EXPERIMENTAL && FB && PCI && X86_32 && AGP_INTEL |
@@ -2001,18 +2013,6 @@ config FB_SH_MOBILE_HDMI | |||
2001 | ---help--- | 2013 | ---help--- |
2002 | Driver for the on-chip SH-Mobile HDMI controller. | 2014 | Driver for the on-chip SH-Mobile HDMI controller. |
2003 | 2015 | ||
2004 | config FB_SH_MOBILE_MERAM | ||
2005 | tristate "SuperH Mobile MERAM read ahead support for LCDC" | ||
2006 | depends on FB_SH_MOBILE_LCDC | ||
2007 | default y | ||
2008 | ---help--- | ||
2009 | Enable MERAM support for the SH-Mobile LCD controller. | ||
2010 | |||
2011 | This will allow for caching of the framebuffer to provide more | ||
2012 | reliable access under heavy main memory bus traffic situations. | ||
2013 | Up to 4 memory channels can be configured, allowing 4 RGB or | ||
2014 | 2 YCbCr framebuffers to be configured. | ||
2015 | |||
2016 | config FB_TMIO | 2016 | config FB_TMIO |
2017 | tristate "Toshiba Mobile IO FrameBuffer support" | 2017 | tristate "Toshiba Mobile IO FrameBuffer support" |
2018 | depends on FB && MFD_CORE | 2018 | depends on FB && MFD_CORE |
@@ -2233,6 +2233,7 @@ config FB_DA8XX | |||
2233 | select FB_CFB_FILLRECT | 2233 | select FB_CFB_FILLRECT |
2234 | select FB_CFB_COPYAREA | 2234 | select FB_CFB_COPYAREA |
2235 | select FB_CFB_IMAGEBLIT | 2235 | select FB_CFB_IMAGEBLIT |
2236 | select FB_CFB_REV_PIXELS_IN_BYTE | ||
2236 | ---help--- | 2237 | ---help--- |
2237 | This is the frame buffer device driver for the TI LCD controller | 2238 | This is the frame buffer device driver for the TI LCD controller |
2238 | found on DA8xx/OMAP-L1xx SoCs. | 2239 | found on DA8xx/OMAP-L1xx SoCs. |
@@ -2412,7 +2413,7 @@ config FB_PUV3_UNIGFX | |||
2412 | 2413 | ||
2413 | source "drivers/video/omap/Kconfig" | 2414 | source "drivers/video/omap/Kconfig" |
2414 | source "drivers/video/omap2/Kconfig" | 2415 | source "drivers/video/omap2/Kconfig" |
2415 | 2416 | source "drivers/video/exynos/Kconfig" | |
2416 | source "drivers/video/backlight/Kconfig" | 2417 | source "drivers/video/backlight/Kconfig" |
2417 | 2418 | ||
2418 | if VT | 2419 | if VT |
@@ -2423,4 +2424,16 @@ if FB || SGI_NEWPORT_CONSOLE | |||
2423 | source "drivers/video/logo/Kconfig" | 2424 | source "drivers/video/logo/Kconfig" |
2424 | endif | 2425 | endif |
2425 | 2426 | ||
2427 | config FB_SH_MOBILE_MERAM | ||
2428 | tristate "SuperH Mobile MERAM read ahead support" | ||
2429 | depends on (SUPERH || ARCH_SHMOBILE) | ||
2430 | select GENERIC_ALLOCATOR | ||
2431 | ---help--- | ||
2432 | Enable MERAM support for the SuperH controller. | ||
2433 | |||
2434 | This will allow for caching of the framebuffer to provide more | ||
2435 | reliable access under heavy main memory bus traffic situations. | ||
2436 | Up to 4 memory channels can be configured, allowing 4 RGB or | ||
2437 | 2 YCbCr framebuffers to be configured. | ||
2438 | |||
2426 | endmenu | 2439 | endmenu |
diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 142606814d98..9356add945b3 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile | |||
@@ -15,6 +15,8 @@ obj-$(CONFIG_VT) += console/ | |||
15 | obj-$(CONFIG_LOGO) += logo/ | 15 | obj-$(CONFIG_LOGO) += logo/ |
16 | obj-y += backlight/ | 16 | obj-y += backlight/ |
17 | 17 | ||
18 | obj-$(CONFIG_EXYNOS_VIDEO) += exynos/ | ||
19 | |||
18 | obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o | 20 | obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o |
19 | obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o | 21 | obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o |
20 | obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o | 22 | obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o |
@@ -37,6 +39,7 @@ obj-$(CONFIG_FB_GRVGA) += grvga.o | |||
37 | obj-$(CONFIG_FB_PM2) += pm2fb.o | 39 | obj-$(CONFIG_FB_PM2) += pm2fb.o |
38 | obj-$(CONFIG_FB_PM3) += pm3fb.o | 40 | obj-$(CONFIG_FB_PM3) += pm3fb.o |
39 | 41 | ||
42 | obj-$(CONFIG_FB_I740) += i740fb.o | ||
40 | obj-$(CONFIG_FB_MATROX) += matrox/ | 43 | obj-$(CONFIG_FB_MATROX) += matrox/ |
41 | obj-$(CONFIG_FB_RIVA) += riva/ | 44 | obj-$(CONFIG_FB_RIVA) += riva/ |
42 | obj-$(CONFIG_FB_NVIDIA) += nvidia/ | 45 | obj-$(CONFIG_FB_NVIDIA) += nvidia/ |
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index e40c00f2c2ba..d99505b16374 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c | |||
@@ -421,24 +421,18 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, | |||
421 | var->red.length = var->green.length = var->blue.length | 421 | var->red.length = var->green.length = var->blue.length |
422 | = var->bits_per_pixel; | 422 | = var->bits_per_pixel; |
423 | break; | 423 | break; |
424 | case 15: | ||
425 | case 16: | 424 | case 16: |
426 | if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) { | 425 | if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) { |
427 | /* RGB:565 mode */ | 426 | /* RGB:565 mode */ |
428 | var->red.offset = 11; | 427 | var->red.offset = 11; |
429 | var->blue.offset = 0; | 428 | var->blue.offset = 0; |
430 | var->green.length = 6; | ||
431 | } else if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB555) { | ||
432 | var->red.offset = 10; | ||
433 | var->blue.offset = 0; | ||
434 | var->green.length = 5; | ||
435 | } else { | 429 | } else { |
436 | /* BGR:555 mode */ | 430 | /* BGR:565 mode */ |
437 | var->red.offset = 0; | 431 | var->red.offset = 0; |
438 | var->blue.offset = 10; | 432 | var->blue.offset = 11; |
439 | var->green.length = 5; | ||
440 | } | 433 | } |
441 | var->green.offset = 5; | 434 | var->green.offset = 5; |
435 | var->green.length = 6; | ||
442 | var->red.length = var->blue.length = 5; | 436 | var->red.length = var->blue.length = 5; |
443 | break; | 437 | break; |
444 | case 32: | 438 | case 32: |
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c index de9da6774fd9..befcbd8ef019 100644 --- a/drivers/video/au1100fb.c +++ b/drivers/video/au1100fb.c | |||
@@ -477,7 +477,8 @@ static int __devinit au1100fb_drv_probe(struct platform_device *dev) | |||
477 | u32 sys_clksrc; | 477 | u32 sys_clksrc; |
478 | 478 | ||
479 | /* Allocate new device private */ | 479 | /* Allocate new device private */ |
480 | fbdev = kzalloc(sizeof(struct au1100fb_device), GFP_KERNEL); | 480 | fbdev = devm_kzalloc(&dev->dev, sizeof(struct au1100fb_device), |
481 | GFP_KERNEL); | ||
481 | if (!fbdev) { | 482 | if (!fbdev) { |
482 | print_err("fail to allocate device private record"); | 483 | print_err("fail to allocate device private record"); |
483 | return -ENOMEM; | 484 | return -ENOMEM; |
@@ -498,8 +499,9 @@ static int __devinit au1100fb_drv_probe(struct platform_device *dev) | |||
498 | au1100fb_fix.mmio_start = regs_res->start; | 499 | au1100fb_fix.mmio_start = regs_res->start; |
499 | au1100fb_fix.mmio_len = resource_size(regs_res); | 500 | au1100fb_fix.mmio_len = resource_size(regs_res); |
500 | 501 | ||
501 | if (!request_mem_region(au1100fb_fix.mmio_start, au1100fb_fix.mmio_len, | 502 | if (!devm_request_mem_region(au1100fb_fix.mmio_start, |
502 | DRIVER_NAME)) { | 503 | au1100fb_fix.mmio_len, |
504 | DRIVER_NAME)) { | ||
503 | print_err("fail to lock memory region at 0x%08lx", | 505 | print_err("fail to lock memory region at 0x%08lx", |
504 | au1100fb_fix.mmio_start); | 506 | au1100fb_fix.mmio_start); |
505 | return -EBUSY; | 507 | return -EBUSY; |
@@ -514,8 +516,9 @@ static int __devinit au1100fb_drv_probe(struct platform_device *dev) | |||
514 | fbdev->fb_len = fbdev->panel->xres * fbdev->panel->yres * | 516 | fbdev->fb_len = fbdev->panel->xres * fbdev->panel->yres * |
515 | (fbdev->panel->bpp >> 3) * AU1100FB_NBR_VIDEO_BUFFERS; | 517 | (fbdev->panel->bpp >> 3) * AU1100FB_NBR_VIDEO_BUFFERS; |
516 | 518 | ||
517 | fbdev->fb_mem = dma_alloc_coherent(&dev->dev, PAGE_ALIGN(fbdev->fb_len), | 519 | fbdev->fb_mem = dmam_alloc_coherent(&dev->dev, &dev->dev, |
518 | &fbdev->fb_phys, GFP_KERNEL); | 520 | PAGE_ALIGN(fbdev->fb_len), |
521 | &fbdev->fb_phys, GFP_KERNEL); | ||
519 | if (!fbdev->fb_mem) { | 522 | if (!fbdev->fb_mem) { |
520 | print_err("fail to allocate frambuffer (size: %dK))", | 523 | print_err("fail to allocate frambuffer (size: %dK))", |
521 | fbdev->fb_len / 1024); | 524 | fbdev->fb_len / 1024); |
@@ -557,14 +560,14 @@ static int __devinit au1100fb_drv_probe(struct platform_device *dev) | |||
557 | fbdev->info.fbops = &au1100fb_ops; | 560 | fbdev->info.fbops = &au1100fb_ops; |
558 | fbdev->info.fix = au1100fb_fix; | 561 | fbdev->info.fix = au1100fb_fix; |
559 | 562 | ||
560 | if (!(fbdev->info.pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL))) { | 563 | fbdev->info.pseudo_palette = |
564 | devm_kzalloc(&dev->dev, sizeof(u32) * 16, GFP_KERNEL); | ||
565 | if (!fbdev->info.pseudo_palette) | ||
561 | return -ENOMEM; | 566 | return -ENOMEM; |
562 | } | ||
563 | 567 | ||
564 | if (fb_alloc_cmap(&fbdev->info.cmap, AU1100_LCD_NBR_PALETTE_ENTRIES, 0) < 0) { | 568 | if (fb_alloc_cmap(&fbdev->info.cmap, AU1100_LCD_NBR_PALETTE_ENTRIES, 0) < 0) { |
565 | print_err("Fail to allocate colormap (%d entries)", | 569 | print_err("Fail to allocate colormap (%d entries)", |
566 | AU1100_LCD_NBR_PALETTE_ENTRIES); | 570 | AU1100_LCD_NBR_PALETTE_ENTRIES); |
567 | kfree(fbdev->info.pseudo_palette); | ||
568 | return -EFAULT; | 571 | return -EFAULT; |
569 | } | 572 | } |
570 | 573 | ||
@@ -582,9 +585,6 @@ static int __devinit au1100fb_drv_probe(struct platform_device *dev) | |||
582 | return 0; | 585 | return 0; |
583 | 586 | ||
584 | failed: | 587 | failed: |
585 | if (fbdev->regs) { | ||
586 | release_mem_region(fbdev->regs_phys, fbdev->regs_len); | ||
587 | } | ||
588 | if (fbdev->fb_mem) { | 588 | if (fbdev->fb_mem) { |
589 | dma_free_noncoherent(&dev->dev, fbdev->fb_len, fbdev->fb_mem, | 589 | dma_free_noncoherent(&dev->dev, fbdev->fb_len, fbdev->fb_mem, |
590 | fbdev->fb_phys); | 590 | fbdev->fb_phys); |
@@ -592,10 +592,9 @@ failed: | |||
592 | if (fbdev->info.cmap.len != 0) { | 592 | if (fbdev->info.cmap.len != 0) { |
593 | fb_dealloc_cmap(&fbdev->info.cmap); | 593 | fb_dealloc_cmap(&fbdev->info.cmap); |
594 | } | 594 | } |
595 | kfree(fbdev); | ||
596 | platform_set_drvdata(dev, NULL); | 595 | platform_set_drvdata(dev, NULL); |
597 | 596 | ||
598 | return 0; | 597 | return -ENODEV; |
599 | } | 598 | } |
600 | 599 | ||
601 | int au1100fb_drv_remove(struct platform_device *dev) | 600 | int au1100fb_drv_remove(struct platform_device *dev) |
@@ -615,14 +614,7 @@ int au1100fb_drv_remove(struct platform_device *dev) | |||
615 | /* Clean up all probe data */ | 614 | /* Clean up all probe data */ |
616 | unregister_framebuffer(&fbdev->info); | 615 | unregister_framebuffer(&fbdev->info); |
617 | 616 | ||
618 | release_mem_region(fbdev->regs_phys, fbdev->regs_len); | ||
619 | |||
620 | dma_free_coherent(&dev->dev, PAGE_ALIGN(fbdev->fb_len), fbdev->fb_mem, | ||
621 | fbdev->fb_phys); | ||
622 | |||
623 | fb_dealloc_cmap(&fbdev->info.cmap); | 617 | fb_dealloc_cmap(&fbdev->info.cmap); |
624 | kfree(fbdev->info.pseudo_palette); | ||
625 | kfree((void*)fbdev); | ||
626 | 618 | ||
627 | return 0; | 619 | return 0; |
628 | } | 620 | } |
diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c index 04e4479d5afd..3e9a773db09f 100644 --- a/drivers/video/au1200fb.c +++ b/drivers/video/au1200fb.c | |||
@@ -1724,7 +1724,7 @@ static int __devinit au1200fb_drv_probe(struct platform_device *dev) | |||
1724 | /* Allocate the framebuffer to the maximum screen size */ | 1724 | /* Allocate the framebuffer to the maximum screen size */ |
1725 | fbdev->fb_len = (win->w[plane].xres * win->w[plane].yres * bpp) / 8; | 1725 | fbdev->fb_len = (win->w[plane].xres * win->w[plane].yres * bpp) / 8; |
1726 | 1726 | ||
1727 | fbdev->fb_mem = dma_alloc_noncoherent(&dev->dev, | 1727 | fbdev->fb_mem = dmam_alloc_noncoherent(&dev->dev, &dev->dev, |
1728 | PAGE_ALIGN(fbdev->fb_len), | 1728 | PAGE_ALIGN(fbdev->fb_len), |
1729 | &fbdev->fb_phys, GFP_KERNEL); | 1729 | &fbdev->fb_phys, GFP_KERNEL); |
1730 | if (!fbdev->fb_mem) { | 1730 | if (!fbdev->fb_mem) { |
@@ -1788,9 +1788,6 @@ static int __devinit au1200fb_drv_probe(struct platform_device *dev) | |||
1788 | 1788 | ||
1789 | failed: | 1789 | failed: |
1790 | /* NOTE: This only does the current plane/window that failed; others are still active */ | 1790 | /* NOTE: This only does the current plane/window that failed; others are still active */ |
1791 | if (fbdev->fb_mem) | ||
1792 | dma_free_noncoherent(&dev->dev, PAGE_ALIGN(fbdev->fb_len), | ||
1793 | fbdev->fb_mem, fbdev->fb_phys); | ||
1794 | if (fbi) { | 1791 | if (fbi) { |
1795 | if (fbi->cmap.len != 0) | 1792 | if (fbi->cmap.len != 0) |
1796 | fb_dealloc_cmap(&fbi->cmap); | 1793 | fb_dealloc_cmap(&fbi->cmap); |
@@ -1817,10 +1814,6 @@ static int __devexit au1200fb_drv_remove(struct platform_device *dev) | |||
1817 | 1814 | ||
1818 | /* Clean up all probe data */ | 1815 | /* Clean up all probe data */ |
1819 | unregister_framebuffer(fbi); | 1816 | unregister_framebuffer(fbi); |
1820 | if (fbdev->fb_mem) | ||
1821 | dma_free_noncoherent(&dev->dev, | ||
1822 | PAGE_ALIGN(fbdev->fb_len), | ||
1823 | fbdev->fb_mem, fbdev->fb_phys); | ||
1824 | if (fbi->cmap.len != 0) | 1817 | if (fbi->cmap.len != 0) |
1825 | fb_dealloc_cmap(&fbi->cmap); | 1818 | fb_dealloc_cmap(&fbi->cmap); |
1826 | kfree(fbi->pseudo_palette); | 1819 | kfree(fbi->pseudo_palette); |
diff --git a/drivers/video/bf537-lq035.c b/drivers/video/bf537-lq035.c index bea53c1a4950..befbc80d11fc 100644 --- a/drivers/video/bf537-lq035.c +++ b/drivers/video/bf537-lq035.c | |||
@@ -383,23 +383,19 @@ static int __devinit request_ports(void) | |||
383 | } | 383 | } |
384 | 384 | ||
385 | #if (defined(UD) && defined(LBR)) | 385 | #if (defined(UD) && defined(LBR)) |
386 | if (gpio_request(UD, KBUILD_MODNAME)) { | 386 | if (gpio_request_one(UD, GPIOF_OUT_INIT_LOW, KBUILD_MODNAME)) { |
387 | pr_err("requesting GPIO %d failed\n", UD); | 387 | pr_err("requesting GPIO %d failed\n", UD); |
388 | return -EBUSY; | 388 | return -EBUSY; |
389 | } | 389 | } |
390 | 390 | ||
391 | if (gpio_request(LBR, KBUILD_MODNAME)) { | 391 | if (gpio_request_one(LBR, GPIOF_OUT_INIT_HIGH, KBUILD_MODNAME)) { |
392 | pr_err("requesting GPIO %d failed\n", LBR); | 392 | pr_err("requesting GPIO %d failed\n", LBR); |
393 | gpio_free(UD); | 393 | gpio_free(UD); |
394 | return -EBUSY; | 394 | return -EBUSY; |
395 | } | 395 | } |
396 | |||
397 | gpio_direction_output(UD, 0); | ||
398 | gpio_direction_output(LBR, 1); | ||
399 | |||
400 | #endif | 396 | #endif |
401 | 397 | ||
402 | if (gpio_request(MOD, KBUILD_MODNAME)) { | 398 | if (gpio_request_one(MOD, GPIOF_OUT_INIT_HIGH, KBUILD_MODNAME)) { |
403 | pr_err("requesting GPIO %d failed\n", MOD); | 399 | pr_err("requesting GPIO %d failed\n", MOD); |
404 | #if (defined(UD) && defined(LBR)) | 400 | #if (defined(UD) && defined(LBR)) |
405 | gpio_free(LBR); | 401 | gpio_free(LBR); |
@@ -408,8 +404,6 @@ static int __devinit request_ports(void) | |||
408 | return -EBUSY; | 404 | return -EBUSY; |
409 | } | 405 | } |
410 | 406 | ||
411 | gpio_direction_output(MOD, 1); | ||
412 | |||
413 | SSYNC(); | 407 | SSYNC(); |
414 | return 0; | 408 | return 0; |
415 | } | 409 | } |
diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c index 46b03f53985f..dc2f0047769b 100644 --- a/drivers/video/bf54x-lq043fb.c +++ b/drivers/video/bf54x-lq043fb.c | |||
@@ -240,7 +240,7 @@ static int request_ports(struct bfin_bf54xfb_info *fbi) | |||
240 | u16 eppi_req_18[] = EPPI0_18; | 240 | u16 eppi_req_18[] = EPPI0_18; |
241 | u16 disp = fbi->mach_info->disp; | 241 | u16 disp = fbi->mach_info->disp; |
242 | 242 | ||
243 | if (gpio_request(disp, DRIVER_NAME)) { | 243 | if (gpio_request_one(disp, GPIOF_OUT_INIT_HIGH, DRIVER_NAME)) { |
244 | printk(KERN_ERR "Requesting GPIO %d failed\n", disp); | 244 | printk(KERN_ERR "Requesting GPIO %d failed\n", disp); |
245 | return -EFAULT; | 245 | return -EFAULT; |
246 | } | 246 | } |
@@ -263,8 +263,6 @@ static int request_ports(struct bfin_bf54xfb_info *fbi) | |||
263 | } | 263 | } |
264 | } | 264 | } |
265 | 265 | ||
266 | gpio_direction_output(disp, 1); | ||
267 | |||
268 | return 0; | 266 | return 0; |
269 | } | 267 | } |
270 | 268 | ||
diff --git a/drivers/video/bfin-lq035q1-fb.c b/drivers/video/bfin-lq035q1-fb.c index c633068372c9..86922ac84412 100644 --- a/drivers/video/bfin-lq035q1-fb.c +++ b/drivers/video/bfin-lq035q1-fb.c | |||
@@ -365,10 +365,10 @@ static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev, | |||
365 | * Drive PPI_FS3 Low | 365 | * Drive PPI_FS3 Low |
366 | */ | 366 | */ |
367 | if (ANOMALY_05000400) { | 367 | if (ANOMALY_05000400) { |
368 | int ret = gpio_request(P_IDENT(P_PPI0_FS3), "PPI_FS3"); | 368 | int ret = gpio_request_one(P_IDENT(P_PPI0_FS3), |
369 | GPIOF_OUT_INIT_LOW, "PPI_FS3"); | ||
369 | if (ret) | 370 | if (ret) |
370 | return ret; | 371 | return ret; |
371 | gpio_direction_output(P_IDENT(P_PPI0_FS3), 0); | ||
372 | } | 372 | } |
373 | 373 | ||
374 | if (ppi16) | 374 | if (ppi16) |
@@ -716,14 +716,14 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) | |||
716 | } | 716 | } |
717 | 717 | ||
718 | if (info->disp_info->use_bl) { | 718 | if (info->disp_info->use_bl) { |
719 | ret = gpio_request(info->disp_info->gpio_bl, "LQ035 Backlight"); | 719 | ret = gpio_request_one(info->disp_info->gpio_bl, |
720 | GPIOF_OUT_INIT_LOW, "LQ035 Backlight"); | ||
720 | 721 | ||
721 | if (ret) { | 722 | if (ret) { |
722 | dev_err(&pdev->dev, "failed to request GPIO %d\n", | 723 | dev_err(&pdev->dev, "failed to request GPIO %d\n", |
723 | info->disp_info->gpio_bl); | 724 | info->disp_info->gpio_bl); |
724 | goto out9; | 725 | goto out9; |
725 | } | 726 | } |
726 | gpio_direction_output(info->disp_info->gpio_bl, 0); | ||
727 | } | 727 | } |
728 | 728 | ||
729 | ret = register_framebuffer(fbinfo); | 729 | ret = register_framebuffer(fbinfo); |
diff --git a/drivers/video/bfin_adv7393fb.c b/drivers/video/bfin_adv7393fb.c index 811dd7f6aa41..1a268a294478 100644 --- a/drivers/video/bfin_adv7393fb.c +++ b/drivers/video/bfin_adv7393fb.c | |||
@@ -36,9 +36,7 @@ | |||
36 | #include <linux/dma-mapping.h> | 36 | #include <linux/dma-mapping.h> |
37 | #include <linux/proc_fs.h> | 37 | #include <linux/proc_fs.h> |
38 | #include <linux/platform_device.h> | 38 | #include <linux/platform_device.h> |
39 | |||
40 | #include <linux/i2c.h> | 39 | #include <linux/i2c.h> |
41 | #include <linux/i2c-dev.h> | ||
42 | 40 | ||
43 | #include "bfin_adv7393fb.h" | 41 | #include "bfin_adv7393fb.h" |
44 | 42 | ||
@@ -411,12 +409,13 @@ static int __devinit bfin_adv7393_fb_probe(struct i2c_client *client, | |||
411 | 409 | ||
412 | /* Workaround "PPI Does Not Start Properly In Specific Mode" */ | 410 | /* Workaround "PPI Does Not Start Properly In Specific Mode" */ |
413 | if (ANOMALY_05000400) { | 411 | if (ANOMALY_05000400) { |
414 | if (gpio_request(P_IDENT(P_PPI0_FS3), "PPI0_FS3")) { | 412 | ret = gpio_request_one(P_IDENT(P_PPI0_FS3), GPIOF_OUT_INIT_LOW, |
413 | "PPI0_FS3") | ||
414 | if (ret) { | ||
415 | dev_err(&client->dev, "PPI0_FS3 GPIO request failed\n"); | 415 | dev_err(&client->dev, "PPI0_FS3 GPIO request failed\n"); |
416 | ret = -EBUSY; | 416 | ret = -EBUSY; |
417 | goto out_8; | 417 | goto out_8; |
418 | } | 418 | } |
419 | gpio_direction_output(P_IDENT(P_PPI0_FS3), 0); | ||
420 | } | 419 | } |
421 | 420 | ||
422 | if (peripheral_request_list(ppi_pins, DRIVER_NAME)) { | 421 | if (peripheral_request_list(ppi_pins, DRIVER_NAME)) { |
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index 29577bf1f559..47118c75a4c0 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/console.h> | 32 | #include <linux/console.h> |
33 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
34 | #include <video/da8xx-fb.h> | 34 | #include <video/da8xx-fb.h> |
35 | #include <asm/div64.h> | ||
35 | 36 | ||
36 | #define DRIVER_NAME "da8xx_lcdc" | 37 | #define DRIVER_NAME "da8xx_lcdc" |
37 | 38 | ||
@@ -161,6 +162,7 @@ struct da8xx_fb_par { | |||
161 | int vsync_timeout; | 162 | int vsync_timeout; |
162 | #ifdef CONFIG_CPU_FREQ | 163 | #ifdef CONFIG_CPU_FREQ |
163 | struct notifier_block freq_transition; | 164 | struct notifier_block freq_transition; |
165 | unsigned int lcd_fck_rate; | ||
164 | #endif | 166 | #endif |
165 | void (*panel_power_ctrl)(int); | 167 | void (*panel_power_ctrl)(int); |
166 | }; | 168 | }; |
@@ -174,7 +176,6 @@ static struct fb_var_screeninfo da8xx_fb_var __devinitdata = { | |||
174 | .activate = 0, | 176 | .activate = 0, |
175 | .height = -1, | 177 | .height = -1, |
176 | .width = -1, | 178 | .width = -1, |
177 | .pixclock = 46666, /* 46us - AUO display */ | ||
178 | .accel_flags = 0, | 179 | .accel_flags = 0, |
179 | .left_margin = LEFT_MARGIN, | 180 | .left_margin = LEFT_MARGIN, |
180 | .right_margin = RIGHT_MARGIN, | 181 | .right_margin = RIGHT_MARGIN, |
@@ -238,6 +239,20 @@ static struct da8xx_panel known_lcd_panels[] = { | |||
238 | .pxl_clk = 7833600, | 239 | .pxl_clk = 7833600, |
239 | .invert_pxl_clk = 0, | 240 | .invert_pxl_clk = 0, |
240 | }, | 241 | }, |
242 | [2] = { | ||
243 | /* Hitachi SP10Q010 */ | ||
244 | .name = "SP10Q010", | ||
245 | .width = 320, | ||
246 | .height = 240, | ||
247 | .hfp = 10, | ||
248 | .hbp = 10, | ||
249 | .hsw = 10, | ||
250 | .vfp = 10, | ||
251 | .vbp = 10, | ||
252 | .vsw = 10, | ||
253 | .pxl_clk = 7833600, | ||
254 | .invert_pxl_clk = 0, | ||
255 | }, | ||
241 | }; | 256 | }; |
242 | 257 | ||
243 | /* Enable the Raster Engine of the LCD Controller */ | 258 | /* Enable the Raster Engine of the LCD Controller */ |
@@ -546,7 +561,26 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
546 | if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) | 561 | if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) |
547 | return 1; | 562 | return 1; |
548 | 563 | ||
549 | if (info->var.bits_per_pixel == 8) { | 564 | if (info->var.bits_per_pixel == 4) { |
565 | if (regno > 15) | ||
566 | return 1; | ||
567 | |||
568 | if (info->var.grayscale) { | ||
569 | pal = regno; | ||
570 | } else { | ||
571 | red >>= 4; | ||
572 | green >>= 8; | ||
573 | blue >>= 12; | ||
574 | |||
575 | pal = (red & 0x0f00); | ||
576 | pal |= (green & 0x00f0); | ||
577 | pal |= (blue & 0x000f); | ||
578 | } | ||
579 | if (regno == 0) | ||
580 | pal |= 0x2000; | ||
581 | palette[regno] = pal; | ||
582 | |||
583 | } else if (info->var.bits_per_pixel == 8) { | ||
550 | red >>= 4; | 584 | red >>= 4; |
551 | green >>= 8; | 585 | green >>= 8; |
552 | blue >>= 12; | 586 | blue >>= 12; |
@@ -801,6 +835,7 @@ static int fb_check_var(struct fb_var_screeninfo *var, | |||
801 | var->blue.length = 8; | 835 | var->blue.length = 8; |
802 | var->transp.offset = 0; | 836 | var->transp.offset = 0; |
803 | var->transp.length = 0; | 837 | var->transp.length = 0; |
838 | var->nonstd = 0; | ||
804 | break; | 839 | break; |
805 | case 4: | 840 | case 4: |
806 | var->red.offset = 0; | 841 | var->red.offset = 0; |
@@ -811,6 +846,7 @@ static int fb_check_var(struct fb_var_screeninfo *var, | |||
811 | var->blue.length = 4; | 846 | var->blue.length = 4; |
812 | var->transp.offset = 0; | 847 | var->transp.offset = 0; |
813 | var->transp.length = 0; | 848 | var->transp.length = 0; |
849 | var->nonstd = FB_NONSTD_REV_PIX_IN_B; | ||
814 | break; | 850 | break; |
815 | case 16: /* RGB 565 */ | 851 | case 16: /* RGB 565 */ |
816 | var->red.offset = 11; | 852 | var->red.offset = 11; |
@@ -821,6 +857,7 @@ static int fb_check_var(struct fb_var_screeninfo *var, | |||
821 | var->blue.length = 5; | 857 | var->blue.length = 5; |
822 | var->transp.offset = 0; | 858 | var->transp.offset = 0; |
823 | var->transp.length = 0; | 859 | var->transp.length = 0; |
860 | var->nonstd = 0; | ||
824 | break; | 861 | break; |
825 | default: | 862 | default: |
826 | err = -EINVAL; | 863 | err = -EINVAL; |
@@ -840,11 +877,13 @@ static int lcd_da8xx_cpufreq_transition(struct notifier_block *nb, | |||
840 | struct da8xx_fb_par *par; | 877 | struct da8xx_fb_par *par; |
841 | 878 | ||
842 | par = container_of(nb, struct da8xx_fb_par, freq_transition); | 879 | par = container_of(nb, struct da8xx_fb_par, freq_transition); |
843 | if (val == CPUFREQ_PRECHANGE) { | 880 | if (val == CPUFREQ_POSTCHANGE) { |
844 | lcd_disable_raster(); | 881 | if (par->lcd_fck_rate != clk_get_rate(par->lcdc_clk)) { |
845 | } else if (val == CPUFREQ_POSTCHANGE) { | 882 | par->lcd_fck_rate = clk_get_rate(par->lcdc_clk); |
846 | lcd_calc_clk_divider(par); | 883 | lcd_disable_raster(); |
847 | lcd_enable_raster(); | 884 | lcd_calc_clk_divider(par); |
885 | lcd_enable_raster(); | ||
886 | } | ||
848 | } | 887 | } |
849 | 888 | ||
850 | return 0; | 889 | return 0; |
@@ -1048,6 +1087,22 @@ static struct fb_ops da8xx_fb_ops = { | |||
1048 | .fb_blank = cfb_blank, | 1087 | .fb_blank = cfb_blank, |
1049 | }; | 1088 | }; |
1050 | 1089 | ||
1090 | /* Calculate and return pixel clock period in pico seconds */ | ||
1091 | static unsigned int da8xxfb_pixel_clk_period(struct da8xx_fb_par *par) | ||
1092 | { | ||
1093 | unsigned int lcd_clk, div; | ||
1094 | unsigned int configured_pix_clk; | ||
1095 | unsigned long long pix_clk_period_picosec = 1000000000000ULL; | ||
1096 | |||
1097 | lcd_clk = clk_get_rate(par->lcdc_clk); | ||
1098 | div = lcd_clk / par->pxl_clk; | ||
1099 | configured_pix_clk = (lcd_clk / div); | ||
1100 | |||
1101 | do_div(pix_clk_period_picosec, configured_pix_clk); | ||
1102 | |||
1103 | return pix_clk_period_picosec; | ||
1104 | } | ||
1105 | |||
1051 | static int __devinit fb_probe(struct platform_device *device) | 1106 | static int __devinit fb_probe(struct platform_device *device) |
1052 | { | 1107 | { |
1053 | struct da8xx_lcdc_platform_data *fb_pdata = | 1108 | struct da8xx_lcdc_platform_data *fb_pdata = |
@@ -1137,6 +1192,9 @@ static int __devinit fb_probe(struct platform_device *device) | |||
1137 | 1192 | ||
1138 | par = da8xx_fb_info->par; | 1193 | par = da8xx_fb_info->par; |
1139 | par->lcdc_clk = fb_clk; | 1194 | par->lcdc_clk = fb_clk; |
1195 | #ifdef CONFIG_CPU_FREQ | ||
1196 | par->lcd_fck_rate = clk_get_rate(fb_clk); | ||
1197 | #endif | ||
1140 | par->pxl_clk = lcdc_info->pxl_clk; | 1198 | par->pxl_clk = lcdc_info->pxl_clk; |
1141 | if (fb_pdata->panel_power_ctrl) { | 1199 | if (fb_pdata->panel_power_ctrl) { |
1142 | par->panel_power_ctrl = fb_pdata->panel_power_ctrl; | 1200 | par->panel_power_ctrl = fb_pdata->panel_power_ctrl; |
@@ -1209,6 +1267,11 @@ static int __devinit fb_probe(struct platform_device *device) | |||
1209 | 1267 | ||
1210 | da8xx_fb_var.hsync_len = lcdc_info->hsw; | 1268 | da8xx_fb_var.hsync_len = lcdc_info->hsw; |
1211 | da8xx_fb_var.vsync_len = lcdc_info->vsw; | 1269 | da8xx_fb_var.vsync_len = lcdc_info->vsw; |
1270 | da8xx_fb_var.right_margin = lcdc_info->hfp; | ||
1271 | da8xx_fb_var.left_margin = lcdc_info->hbp; | ||
1272 | da8xx_fb_var.lower_margin = lcdc_info->vfp; | ||
1273 | da8xx_fb_var.upper_margin = lcdc_info->vbp; | ||
1274 | da8xx_fb_var.pixclock = da8xxfb_pixel_clk_period(par); | ||
1212 | 1275 | ||
1213 | /* Initialize fbinfo */ | 1276 | /* Initialize fbinfo */ |
1214 | da8xx_fb_info->flags = FBINFO_FLAG_DEFAULT; | 1277 | da8xx_fb_info->flags = FBINFO_FLAG_DEFAULT; |
@@ -1264,8 +1327,8 @@ static int __devinit fb_probe(struct platform_device *device) | |||
1264 | irq_freq: | 1327 | irq_freq: |
1265 | #ifdef CONFIG_CPU_FREQ | 1328 | #ifdef CONFIG_CPU_FREQ |
1266 | lcd_da8xx_cpufreq_deregister(par); | 1329 | lcd_da8xx_cpufreq_deregister(par); |
1267 | #endif | ||
1268 | err_cpu_freq: | 1330 | err_cpu_freq: |
1331 | #endif | ||
1269 | unregister_framebuffer(da8xx_fb_info); | 1332 | unregister_framebuffer(da8xx_fb_info); |
1270 | 1333 | ||
1271 | err_dealloc_cmap: | 1334 | err_dealloc_cmap: |
diff --git a/drivers/video/exynos/Kconfig b/drivers/video/exynos/Kconfig new file mode 100644 index 000000000000..1b035b2eb6b6 --- /dev/null +++ b/drivers/video/exynos/Kconfig | |||
@@ -0,0 +1,37 @@ | |||
1 | # | ||
2 | # Exynos Video configuration | ||
3 | # | ||
4 | |||
5 | menuconfig EXYNOS_VIDEO | ||
6 | bool "Exynos Video driver support" | ||
7 | help | ||
8 | This enables support for EXYNOS Video device. | ||
9 | |||
10 | if EXYNOS_VIDEO | ||
11 | |||
12 | # | ||
13 | # MIPI DSI driver | ||
14 | # | ||
15 | |||
16 | config EXYNOS_MIPI_DSI | ||
17 | bool "EXYNOS MIPI DSI driver support." | ||
18 | depends on ARCH_S5PV210 || ARCH_EXYNOS | ||
19 | help | ||
20 | This enables support for MIPI-DSI device. | ||
21 | |||
22 | config EXYNOS_LCD_S6E8AX0 | ||
23 | bool "S6E8AX0 MIPI AMOLED LCD Driver" | ||
24 | depends on (EXYNOS_MIPI_DSI && BACKLIGHT_CLASS_DEVICE && LCD_CLASS_DEVICE) | ||
25 | default n | ||
26 | help | ||
27 | If you have an S6E8AX0 MIPI AMOLED LCD Panel, say Y to enable its | ||
28 | LCD control driver. | ||
29 | |||
30 | config EXYNOS_DP | ||
31 | bool "EXYNOS DP driver support" | ||
32 | depends on ARCH_EXYNOS | ||
33 | default n | ||
34 | help | ||
35 | This enables support for DP device. | ||
36 | |||
37 | endif # EXYNOS_VIDEO | ||
diff --git a/drivers/video/exynos/Makefile b/drivers/video/exynos/Makefile new file mode 100644 index 000000000000..ec7772e452a9 --- /dev/null +++ b/drivers/video/exynos/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | # | ||
2 | # Makefile for the exynos video drivers. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_EXYNOS_MIPI_DSI) += exynos_mipi_dsi.o exynos_mipi_dsi_common.o \ | ||
6 | exynos_mipi_dsi_lowlevel.o | ||
7 | obj-$(CONFIG_EXYNOS_LCD_S6E8AX0) += s6e8ax0.o | ||
8 | obj-$(CONFIG_EXYNOS_DP) += exynos_dp_core.o exynos_dp_reg.o | ||
diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c new file mode 100644 index 000000000000..2a4481cf260c --- /dev/null +++ b/drivers/video/exynos/exynos_dp_core.c | |||
@@ -0,0 +1,1058 @@ | |||
1 | /* | ||
2 | * Samsung SoC DP (Display Port) interface driver. | ||
3 | * | ||
4 | * Copyright (C) 2012 Samsung Electronics Co., Ltd. | ||
5 | * Author: Jingoo Han <jg1.han@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/clk.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/delay.h> | ||
21 | |||
22 | #include <video/exynos_dp.h> | ||
23 | |||
24 | #include <plat/cpu.h> | ||
25 | |||
26 | #include "exynos_dp_core.h" | ||
27 | |||
28 | static int exynos_dp_init_dp(struct exynos_dp_device *dp) | ||
29 | { | ||
30 | exynos_dp_reset(dp); | ||
31 | |||
32 | /* SW defined function Normal operation */ | ||
33 | exynos_dp_enable_sw_function(dp); | ||
34 | |||
35 | exynos_dp_config_interrupt(dp); | ||
36 | exynos_dp_init_analog_func(dp); | ||
37 | |||
38 | exynos_dp_init_hpd(dp); | ||
39 | exynos_dp_init_aux(dp); | ||
40 | |||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | static int exynos_dp_detect_hpd(struct exynos_dp_device *dp) | ||
45 | { | ||
46 | int timeout_loop = 0; | ||
47 | |||
48 | exynos_dp_init_hpd(dp); | ||
49 | |||
50 | udelay(200); | ||
51 | |||
52 | while (exynos_dp_get_plug_in_status(dp) != 0) { | ||
53 | timeout_loop++; | ||
54 | if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { | ||
55 | dev_err(dp->dev, "failed to get hpd plug status\n"); | ||
56 | return -ETIMEDOUT; | ||
57 | } | ||
58 | udelay(10); | ||
59 | } | ||
60 | |||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | static unsigned char exynos_dp_calc_edid_check_sum(unsigned char *edid_data) | ||
65 | { | ||
66 | int i; | ||
67 | unsigned char sum = 0; | ||
68 | |||
69 | for (i = 0; i < EDID_BLOCK_LENGTH; i++) | ||
70 | sum = sum + edid_data[i]; | ||
71 | |||
72 | return sum; | ||
73 | } | ||
74 | |||
75 | static int exynos_dp_read_edid(struct exynos_dp_device *dp) | ||
76 | { | ||
77 | unsigned char edid[EDID_BLOCK_LENGTH * 2]; | ||
78 | unsigned int extend_block = 0; | ||
79 | unsigned char sum; | ||
80 | unsigned char test_vector; | ||
81 | int retval; | ||
82 | |||
83 | /* | ||
84 | * EDID device address is 0x50. | ||
85 | * However, if necessary, you must have set upper address | ||
86 | * into E-EDID in I2C device, 0x30. | ||
87 | */ | ||
88 | |||
89 | /* Read Extension Flag, Number of 128-byte EDID extension blocks */ | ||
90 | exynos_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, | ||
91 | EDID_EXTENSION_FLAG, | ||
92 | &extend_block); | ||
93 | |||
94 | if (extend_block > 0) { | ||
95 | dev_dbg(dp->dev, "EDID data includes a single extension!\n"); | ||
96 | |||
97 | /* Read EDID data */ | ||
98 | retval = exynos_dp_read_bytes_from_i2c(dp, I2C_EDID_DEVICE_ADDR, | ||
99 | EDID_HEADER_PATTERN, | ||
100 | EDID_BLOCK_LENGTH, | ||
101 | &edid[EDID_HEADER_PATTERN]); | ||
102 | if (retval != 0) { | ||
103 | dev_err(dp->dev, "EDID Read failed!\n"); | ||
104 | return -EIO; | ||
105 | } | ||
106 | sum = exynos_dp_calc_edid_check_sum(edid); | ||
107 | if (sum != 0) { | ||
108 | dev_err(dp->dev, "EDID bad checksum!\n"); | ||
109 | return -EIO; | ||
110 | } | ||
111 | |||
112 | /* Read additional EDID data */ | ||
113 | retval = exynos_dp_read_bytes_from_i2c(dp, | ||
114 | I2C_EDID_DEVICE_ADDR, | ||
115 | EDID_BLOCK_LENGTH, | ||
116 | EDID_BLOCK_LENGTH, | ||
117 | &edid[EDID_BLOCK_LENGTH]); | ||
118 | if (retval != 0) { | ||
119 | dev_err(dp->dev, "EDID Read failed!\n"); | ||
120 | return -EIO; | ||
121 | } | ||
122 | sum = exynos_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]); | ||
123 | if (sum != 0) { | ||
124 | dev_err(dp->dev, "EDID bad checksum!\n"); | ||
125 | return -EIO; | ||
126 | } | ||
127 | |||
128 | exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_TEST_REQUEST, | ||
129 | &test_vector); | ||
130 | if (test_vector & DPCD_TEST_EDID_READ) { | ||
131 | exynos_dp_write_byte_to_dpcd(dp, | ||
132 | DPCD_ADDR_TEST_EDID_CHECKSUM, | ||
133 | edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); | ||
134 | exynos_dp_write_byte_to_dpcd(dp, | ||
135 | DPCD_ADDR_TEST_RESPONSE, | ||
136 | DPCD_TEST_EDID_CHECKSUM_WRITE); | ||
137 | } | ||
138 | } else { | ||
139 | dev_info(dp->dev, "EDID data does not include any extensions.\n"); | ||
140 | |||
141 | /* Read EDID data */ | ||
142 | retval = exynos_dp_read_bytes_from_i2c(dp, | ||
143 | I2C_EDID_DEVICE_ADDR, | ||
144 | EDID_HEADER_PATTERN, | ||
145 | EDID_BLOCK_LENGTH, | ||
146 | &edid[EDID_HEADER_PATTERN]); | ||
147 | if (retval != 0) { | ||
148 | dev_err(dp->dev, "EDID Read failed!\n"); | ||
149 | return -EIO; | ||
150 | } | ||
151 | sum = exynos_dp_calc_edid_check_sum(edid); | ||
152 | if (sum != 0) { | ||
153 | dev_err(dp->dev, "EDID bad checksum!\n"); | ||
154 | return -EIO; | ||
155 | } | ||
156 | |||
157 | exynos_dp_read_byte_from_dpcd(dp, | ||
158 | DPCD_ADDR_TEST_REQUEST, | ||
159 | &test_vector); | ||
160 | if (test_vector & DPCD_TEST_EDID_READ) { | ||
161 | exynos_dp_write_byte_to_dpcd(dp, | ||
162 | DPCD_ADDR_TEST_EDID_CHECKSUM, | ||
163 | edid[EDID_CHECKSUM]); | ||
164 | exynos_dp_write_byte_to_dpcd(dp, | ||
165 | DPCD_ADDR_TEST_RESPONSE, | ||
166 | DPCD_TEST_EDID_CHECKSUM_WRITE); | ||
167 | } | ||
168 | } | ||
169 | |||
170 | dev_err(dp->dev, "EDID Read success!\n"); | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static int exynos_dp_handle_edid(struct exynos_dp_device *dp) | ||
175 | { | ||
176 | u8 buf[12]; | ||
177 | int i; | ||
178 | int retval; | ||
179 | |||
180 | /* Read DPCD DPCD_ADDR_DPCD_REV~RECEIVE_PORT1_CAP_1 */ | ||
181 | exynos_dp_read_bytes_from_dpcd(dp, | ||
182 | DPCD_ADDR_DPCD_REV, | ||
183 | 12, buf); | ||
184 | |||
185 | /* Read EDID */ | ||
186 | for (i = 0; i < 3; i++) { | ||
187 | retval = exynos_dp_read_edid(dp); | ||
188 | if (retval == 0) | ||
189 | break; | ||
190 | } | ||
191 | |||
192 | return retval; | ||
193 | } | ||
194 | |||
195 | static void exynos_dp_enable_rx_to_enhanced_mode(struct exynos_dp_device *dp, | ||
196 | bool enable) | ||
197 | { | ||
198 | u8 data; | ||
199 | |||
200 | exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, &data); | ||
201 | |||
202 | if (enable) | ||
203 | exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, | ||
204 | DPCD_ENHANCED_FRAME_EN | | ||
205 | DPCD_LANE_COUNT_SET(data)); | ||
206 | else | ||
207 | exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, | ||
208 | DPCD_LANE_COUNT_SET(data)); | ||
209 | } | ||
210 | |||
211 | static int exynos_dp_is_enhanced_mode_available(struct exynos_dp_device *dp) | ||
212 | { | ||
213 | u8 data; | ||
214 | int retval; | ||
215 | |||
216 | exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data); | ||
217 | retval = DPCD_ENHANCED_FRAME_CAP(data); | ||
218 | |||
219 | return retval; | ||
220 | } | ||
221 | |||
222 | static void exynos_dp_set_enhanced_mode(struct exynos_dp_device *dp) | ||
223 | { | ||
224 | u8 data; | ||
225 | |||
226 | data = exynos_dp_is_enhanced_mode_available(dp); | ||
227 | exynos_dp_enable_rx_to_enhanced_mode(dp, data); | ||
228 | exynos_dp_enable_enhanced_mode(dp, data); | ||
229 | } | ||
230 | |||
231 | static void exynos_dp_training_pattern_dis(struct exynos_dp_device *dp) | ||
232 | { | ||
233 | exynos_dp_set_training_pattern(dp, DP_NONE); | ||
234 | |||
235 | exynos_dp_write_byte_to_dpcd(dp, | ||
236 | DPCD_ADDR_TRAINING_PATTERN_SET, | ||
237 | DPCD_TRAINING_PATTERN_DISABLED); | ||
238 | } | ||
239 | |||
240 | static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp, | ||
241 | int pre_emphasis, int lane) | ||
242 | { | ||
243 | switch (lane) { | ||
244 | case 0: | ||
245 | exynos_dp_set_lane0_pre_emphasis(dp, pre_emphasis); | ||
246 | break; | ||
247 | case 1: | ||
248 | exynos_dp_set_lane1_pre_emphasis(dp, pre_emphasis); | ||
249 | break; | ||
250 | |||
251 | case 2: | ||
252 | exynos_dp_set_lane2_pre_emphasis(dp, pre_emphasis); | ||
253 | break; | ||
254 | |||
255 | case 3: | ||
256 | exynos_dp_set_lane3_pre_emphasis(dp, pre_emphasis); | ||
257 | break; | ||
258 | } | ||
259 | } | ||
260 | |||
261 | static void exynos_dp_link_start(struct exynos_dp_device *dp) | ||
262 | { | ||
263 | u8 buf[5]; | ||
264 | int lane; | ||
265 | int lane_count; | ||
266 | |||
267 | lane_count = dp->link_train.lane_count; | ||
268 | |||
269 | dp->link_train.lt_state = CLOCK_RECOVERY; | ||
270 | dp->link_train.eq_loop = 0; | ||
271 | |||
272 | for (lane = 0; lane < lane_count; lane++) | ||
273 | dp->link_train.cr_loop[lane] = 0; | ||
274 | |||
275 | /* Set sink to D0 (Sink Not Ready) mode. */ | ||
276 | exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_SINK_POWER_STATE, | ||
277 | DPCD_SET_POWER_STATE_D0); | ||
278 | |||
279 | /* Set link rate and count as you want to establish*/ | ||
280 | exynos_dp_set_link_bandwidth(dp, dp->link_train.link_rate); | ||
281 | exynos_dp_set_lane_count(dp, dp->link_train.lane_count); | ||
282 | |||
283 | /* Setup RX configuration */ | ||
284 | buf[0] = dp->link_train.link_rate; | ||
285 | buf[1] = dp->link_train.lane_count; | ||
286 | exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_LINK_BW_SET, | ||
287 | 2, buf); | ||
288 | |||
289 | /* Set TX pre-emphasis to minimum */ | ||
290 | for (lane = 0; lane < lane_count; lane++) | ||
291 | exynos_dp_set_lane_lane_pre_emphasis(dp, | ||
292 | PRE_EMPHASIS_LEVEL_0, lane); | ||
293 | |||
294 | /* Set training pattern 1 */ | ||
295 | exynos_dp_set_training_pattern(dp, TRAINING_PTN1); | ||
296 | |||
297 | /* Set RX training pattern */ | ||
298 | buf[0] = DPCD_SCRAMBLING_DISABLED | | ||
299 | DPCD_TRAINING_PATTERN_1; | ||
300 | exynos_dp_write_byte_to_dpcd(dp, | ||
301 | DPCD_ADDR_TRAINING_PATTERN_SET, buf[0]); | ||
302 | |||
303 | for (lane = 0; lane < lane_count; lane++) | ||
304 | buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 | | ||
305 | DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0; | ||
306 | exynos_dp_write_bytes_to_dpcd(dp, | ||
307 | DPCD_ADDR_TRAINING_PATTERN_SET, | ||
308 | lane_count, buf); | ||
309 | } | ||
310 | |||
311 | static unsigned char exynos_dp_get_lane_status(u8 link_status[6], int lane) | ||
312 | { | ||
313 | int shift = (lane & 1) * 4; | ||
314 | u8 link_value = link_status[lane>>1]; | ||
315 | |||
316 | return (link_value >> shift) & 0xf; | ||
317 | } | ||
318 | |||
319 | static int exynos_dp_clock_recovery_ok(u8 link_status[6], int lane_count) | ||
320 | { | ||
321 | int lane; | ||
322 | u8 lane_status; | ||
323 | |||
324 | for (lane = 0; lane < lane_count; lane++) { | ||
325 | lane_status = exynos_dp_get_lane_status(link_status, lane); | ||
326 | if ((lane_status & DPCD_LANE_CR_DONE) == 0) | ||
327 | return -EINVAL; | ||
328 | } | ||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static int exynos_dp_channel_eq_ok(u8 link_status[6], int lane_count) | ||
333 | { | ||
334 | int lane; | ||
335 | u8 lane_align; | ||
336 | u8 lane_status; | ||
337 | |||
338 | lane_align = link_status[2]; | ||
339 | if ((lane_align == DPCD_INTERLANE_ALIGN_DONE) == 0) | ||
340 | return -EINVAL; | ||
341 | |||
342 | for (lane = 0; lane < lane_count; lane++) { | ||
343 | lane_status = exynos_dp_get_lane_status(link_status, lane); | ||
344 | lane_status &= DPCD_CHANNEL_EQ_BITS; | ||
345 | if (lane_status != DPCD_CHANNEL_EQ_BITS) | ||
346 | return -EINVAL; | ||
347 | } | ||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static unsigned char exynos_dp_get_adjust_request_voltage(u8 adjust_request[2], | ||
352 | int lane) | ||
353 | { | ||
354 | int shift = (lane & 1) * 4; | ||
355 | u8 link_value = adjust_request[lane>>1]; | ||
356 | |||
357 | return (link_value >> shift) & 0x3; | ||
358 | } | ||
359 | |||
360 | static unsigned char exynos_dp_get_adjust_request_pre_emphasis( | ||
361 | u8 adjust_request[2], | ||
362 | int lane) | ||
363 | { | ||
364 | int shift = (lane & 1) * 4; | ||
365 | u8 link_value = adjust_request[lane>>1]; | ||
366 | |||
367 | return ((link_value >> shift) & 0xc) >> 2; | ||
368 | } | ||
369 | |||
370 | static void exynos_dp_set_lane_link_training(struct exynos_dp_device *dp, | ||
371 | u8 training_lane_set, int lane) | ||
372 | { | ||
373 | switch (lane) { | ||
374 | case 0: | ||
375 | exynos_dp_set_lane0_link_training(dp, training_lane_set); | ||
376 | break; | ||
377 | case 1: | ||
378 | exynos_dp_set_lane1_link_training(dp, training_lane_set); | ||
379 | break; | ||
380 | |||
381 | case 2: | ||
382 | exynos_dp_set_lane2_link_training(dp, training_lane_set); | ||
383 | break; | ||
384 | |||
385 | case 3: | ||
386 | exynos_dp_set_lane3_link_training(dp, training_lane_set); | ||
387 | break; | ||
388 | } | ||
389 | } | ||
390 | |||
391 | static unsigned int exynos_dp_get_lane_link_training( | ||
392 | struct exynos_dp_device *dp, | ||
393 | int lane) | ||
394 | { | ||
395 | u32 reg; | ||
396 | |||
397 | switch (lane) { | ||
398 | case 0: | ||
399 | reg = exynos_dp_get_lane0_link_training(dp); | ||
400 | break; | ||
401 | case 1: | ||
402 | reg = exynos_dp_get_lane1_link_training(dp); | ||
403 | break; | ||
404 | case 2: | ||
405 | reg = exynos_dp_get_lane2_link_training(dp); | ||
406 | break; | ||
407 | case 3: | ||
408 | reg = exynos_dp_get_lane3_link_training(dp); | ||
409 | break; | ||
410 | } | ||
411 | |||
412 | return reg; | ||
413 | } | ||
414 | |||
415 | static void exynos_dp_reduce_link_rate(struct exynos_dp_device *dp) | ||
416 | { | ||
417 | if (dp->link_train.link_rate == LINK_RATE_2_70GBPS) { | ||
418 | /* set to reduced bit rate */ | ||
419 | dp->link_train.link_rate = LINK_RATE_1_62GBPS; | ||
420 | dev_err(dp->dev, "set to bandwidth %.2x\n", | ||
421 | dp->link_train.link_rate); | ||
422 | dp->link_train.lt_state = START; | ||
423 | } else { | ||
424 | exynos_dp_training_pattern_dis(dp); | ||
425 | /* set enhanced mode if available */ | ||
426 | exynos_dp_set_enhanced_mode(dp); | ||
427 | dp->link_train.lt_state = FAILED; | ||
428 | } | ||
429 | } | ||
430 | |||
431 | static void exynos_dp_get_adjust_train(struct exynos_dp_device *dp, | ||
432 | u8 adjust_request[2]) | ||
433 | { | ||
434 | int lane; | ||
435 | int lane_count; | ||
436 | u8 voltage_swing; | ||
437 | u8 pre_emphasis; | ||
438 | u8 training_lane; | ||
439 | |||
440 | lane_count = dp->link_train.lane_count; | ||
441 | for (lane = 0; lane < lane_count; lane++) { | ||
442 | voltage_swing = exynos_dp_get_adjust_request_voltage( | ||
443 | adjust_request, lane); | ||
444 | pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( | ||
445 | adjust_request, lane); | ||
446 | training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | | ||
447 | DPCD_PRE_EMPHASIS_SET(pre_emphasis); | ||
448 | |||
449 | if (voltage_swing == VOLTAGE_LEVEL_3 || | ||
450 | pre_emphasis == PRE_EMPHASIS_LEVEL_3) { | ||
451 | training_lane |= DPCD_MAX_SWING_REACHED; | ||
452 | training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; | ||
453 | } | ||
454 | dp->link_train.training_lane[lane] = training_lane; | ||
455 | } | ||
456 | } | ||
457 | |||
458 | static int exynos_dp_check_max_cr_loop(struct exynos_dp_device *dp, | ||
459 | u8 voltage_swing) | ||
460 | { | ||
461 | int lane; | ||
462 | int lane_count; | ||
463 | |||
464 | lane_count = dp->link_train.lane_count; | ||
465 | for (lane = 0; lane < lane_count; lane++) { | ||
466 | if (voltage_swing == VOLTAGE_LEVEL_3 || | ||
467 | dp->link_train.cr_loop[lane] == MAX_CR_LOOP) | ||
468 | return -EINVAL; | ||
469 | } | ||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) | ||
474 | { | ||
475 | u8 data; | ||
476 | u8 link_status[6]; | ||
477 | int lane; | ||
478 | int lane_count; | ||
479 | u8 buf[5]; | ||
480 | |||
481 | u8 *adjust_request; | ||
482 | u8 voltage_swing; | ||
483 | u8 pre_emphasis; | ||
484 | u8 training_lane; | ||
485 | |||
486 | udelay(100); | ||
487 | |||
488 | exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS, | ||
489 | 6, link_status); | ||
490 | lane_count = dp->link_train.lane_count; | ||
491 | |||
492 | if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) { | ||
493 | /* set training pattern 2 for EQ */ | ||
494 | exynos_dp_set_training_pattern(dp, TRAINING_PTN2); | ||
495 | |||
496 | adjust_request = link_status + (DPCD_ADDR_ADJUST_REQUEST_LANE0_1 | ||
497 | - DPCD_ADDR_LANE0_1_STATUS); | ||
498 | |||
499 | exynos_dp_get_adjust_train(dp, adjust_request); | ||
500 | |||
501 | buf[0] = DPCD_SCRAMBLING_DISABLED | | ||
502 | DPCD_TRAINING_PATTERN_2; | ||
503 | exynos_dp_write_byte_to_dpcd(dp, | ||
504 | DPCD_ADDR_TRAINING_LANE0_SET, | ||
505 | buf[0]); | ||
506 | |||
507 | for (lane = 0; lane < lane_count; lane++) { | ||
508 | exynos_dp_set_lane_link_training(dp, | ||
509 | dp->link_train.training_lane[lane], | ||
510 | lane); | ||
511 | buf[lane] = dp->link_train.training_lane[lane]; | ||
512 | exynos_dp_write_byte_to_dpcd(dp, | ||
513 | DPCD_ADDR_TRAINING_LANE0_SET + lane, | ||
514 | buf[lane]); | ||
515 | } | ||
516 | dp->link_train.lt_state = EQUALIZER_TRAINING; | ||
517 | } else { | ||
518 | exynos_dp_read_byte_from_dpcd(dp, | ||
519 | DPCD_ADDR_ADJUST_REQUEST_LANE0_1, | ||
520 | &data); | ||
521 | adjust_request[0] = data; | ||
522 | |||
523 | exynos_dp_read_byte_from_dpcd(dp, | ||
524 | DPCD_ADDR_ADJUST_REQUEST_LANE2_3, | ||
525 | &data); | ||
526 | adjust_request[1] = data; | ||
527 | |||
528 | for (lane = 0; lane < lane_count; lane++) { | ||
529 | training_lane = exynos_dp_get_lane_link_training( | ||
530 | dp, lane); | ||
531 | voltage_swing = exynos_dp_get_adjust_request_voltage( | ||
532 | adjust_request, lane); | ||
533 | pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( | ||
534 | adjust_request, lane); | ||
535 | if ((DPCD_VOLTAGE_SWING_GET(training_lane) == voltage_swing) && | ||
536 | (DPCD_PRE_EMPHASIS_GET(training_lane) == pre_emphasis)) | ||
537 | dp->link_train.cr_loop[lane]++; | ||
538 | dp->link_train.training_lane[lane] = training_lane; | ||
539 | } | ||
540 | |||
541 | if (exynos_dp_check_max_cr_loop(dp, voltage_swing) != 0) { | ||
542 | exynos_dp_reduce_link_rate(dp); | ||
543 | } else { | ||
544 | exynos_dp_get_adjust_train(dp, adjust_request); | ||
545 | |||
546 | for (lane = 0; lane < lane_count; lane++) { | ||
547 | exynos_dp_set_lane_link_training(dp, | ||
548 | dp->link_train.training_lane[lane], | ||
549 | lane); | ||
550 | buf[lane] = dp->link_train.training_lane[lane]; | ||
551 | exynos_dp_write_byte_to_dpcd(dp, | ||
552 | DPCD_ADDR_TRAINING_LANE0_SET + lane, | ||
553 | buf[lane]); | ||
554 | } | ||
555 | } | ||
556 | } | ||
557 | |||
558 | return 0; | ||
559 | } | ||
560 | |||
561 | static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp) | ||
562 | { | ||
563 | u8 link_status[6]; | ||
564 | int lane; | ||
565 | int lane_count; | ||
566 | u8 buf[5]; | ||
567 | u32 reg; | ||
568 | |||
569 | u8 *adjust_request; | ||
570 | |||
571 | udelay(400); | ||
572 | |||
573 | exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS, | ||
574 | 6, link_status); | ||
575 | lane_count = dp->link_train.lane_count; | ||
576 | |||
577 | if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) { | ||
578 | adjust_request = link_status + (DPCD_ADDR_ADJUST_REQUEST_LANE0_1 | ||
579 | - DPCD_ADDR_LANE0_1_STATUS); | ||
580 | |||
581 | if (exynos_dp_channel_eq_ok(link_status, lane_count) == 0) { | ||
582 | /* traing pattern Set to Normal */ | ||
583 | exynos_dp_training_pattern_dis(dp); | ||
584 | |||
585 | dev_info(dp->dev, "Link Training success!\n"); | ||
586 | |||
587 | exynos_dp_get_link_bandwidth(dp, ®); | ||
588 | dp->link_train.link_rate = reg; | ||
589 | dev_dbg(dp->dev, "final bandwidth = %.2x\n", | ||
590 | dp->link_train.link_rate); | ||
591 | |||
592 | exynos_dp_get_lane_count(dp, ®); | ||
593 | dp->link_train.lane_count = reg; | ||
594 | dev_dbg(dp->dev, "final lane count = %.2x\n", | ||
595 | dp->link_train.lane_count); | ||
596 | /* set enhanced mode if available */ | ||
597 | exynos_dp_set_enhanced_mode(dp); | ||
598 | |||
599 | dp->link_train.lt_state = FINISHED; | ||
600 | } else { | ||
601 | /* not all locked */ | ||
602 | dp->link_train.eq_loop++; | ||
603 | |||
604 | if (dp->link_train.eq_loop > MAX_EQ_LOOP) { | ||
605 | exynos_dp_reduce_link_rate(dp); | ||
606 | } else { | ||
607 | exynos_dp_get_adjust_train(dp, adjust_request); | ||
608 | |||
609 | for (lane = 0; lane < lane_count; lane++) { | ||
610 | exynos_dp_set_lane_link_training(dp, | ||
611 | dp->link_train.training_lane[lane], | ||
612 | lane); | ||
613 | buf[lane] = dp->link_train.training_lane[lane]; | ||
614 | exynos_dp_write_byte_to_dpcd(dp, | ||
615 | DPCD_ADDR_TRAINING_LANE0_SET + lane, | ||
616 | buf[lane]); | ||
617 | } | ||
618 | } | ||
619 | } | ||
620 | } else { | ||
621 | exynos_dp_reduce_link_rate(dp); | ||
622 | } | ||
623 | |||
624 | return 0; | ||
625 | } | ||
626 | |||
627 | static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp, | ||
628 | u8 *bandwidth) | ||
629 | { | ||
630 | u8 data; | ||
631 | |||
632 | /* | ||
633 | * For DP rev.1.1, Maximum link rate of Main Link lanes | ||
634 | * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps | ||
635 | */ | ||
636 | exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LINK_RATE, &data); | ||
637 | *bandwidth = data; | ||
638 | } | ||
639 | |||
640 | static void exynos_dp_get_max_rx_lane_count(struct exynos_dp_device *dp, | ||
641 | u8 *lane_count) | ||
642 | { | ||
643 | u8 data; | ||
644 | |||
645 | /* | ||
646 | * For DP rev.1.1, Maximum number of Main Link lanes | ||
647 | * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes | ||
648 | */ | ||
649 | exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data); | ||
650 | *lane_count = DPCD_MAX_LANE_COUNT(data); | ||
651 | } | ||
652 | |||
653 | static void exynos_dp_init_training(struct exynos_dp_device *dp, | ||
654 | enum link_lane_count_type max_lane, | ||
655 | enum link_rate_type max_rate) | ||
656 | { | ||
657 | /* | ||
658 | * MACRO_RST must be applied after the PLL_LOCK to avoid | ||
659 | * the DP inter pair skew issue for at least 10 us | ||
660 | */ | ||
661 | exynos_dp_reset_macro(dp); | ||
662 | |||
663 | /* Initialize by reading RX's DPCD */ | ||
664 | exynos_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate); | ||
665 | exynos_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count); | ||
666 | |||
667 | if ((dp->link_train.link_rate != LINK_RATE_1_62GBPS) && | ||
668 | (dp->link_train.link_rate != LINK_RATE_2_70GBPS)) { | ||
669 | dev_err(dp->dev, "Rx Max Link Rate is abnormal :%x !\n", | ||
670 | dp->link_train.link_rate); | ||
671 | dp->link_train.link_rate = LINK_RATE_1_62GBPS; | ||
672 | } | ||
673 | |||
674 | if (dp->link_train.lane_count == 0) { | ||
675 | dev_err(dp->dev, "Rx Max Lane count is abnormal :%x !\n", | ||
676 | dp->link_train.lane_count); | ||
677 | dp->link_train.lane_count = (u8)LANE_COUNT1; | ||
678 | } | ||
679 | |||
680 | /* Setup TX lane count & rate */ | ||
681 | if (dp->link_train.lane_count > max_lane) | ||
682 | dp->link_train.lane_count = max_lane; | ||
683 | if (dp->link_train.link_rate > max_rate) | ||
684 | dp->link_train.link_rate = max_rate; | ||
685 | |||
686 | /* All DP analog module power up */ | ||
687 | exynos_dp_set_analog_power_down(dp, POWER_ALL, 0); | ||
688 | } | ||
689 | |||
690 | static int exynos_dp_sw_link_training(struct exynos_dp_device *dp) | ||
691 | { | ||
692 | int retval = 0; | ||
693 | int training_finished; | ||
694 | |||
695 | /* Turn off unnecessary lane */ | ||
696 | if (dp->link_train.lane_count == 1) | ||
697 | exynos_dp_set_analog_power_down(dp, CH1_BLOCK, 1); | ||
698 | |||
699 | training_finished = 0; | ||
700 | |||
701 | dp->link_train.lt_state = START; | ||
702 | |||
703 | /* Process here */ | ||
704 | while (!training_finished) { | ||
705 | switch (dp->link_train.lt_state) { | ||
706 | case START: | ||
707 | exynos_dp_link_start(dp); | ||
708 | break; | ||
709 | case CLOCK_RECOVERY: | ||
710 | exynos_dp_process_clock_recovery(dp); | ||
711 | break; | ||
712 | case EQUALIZER_TRAINING: | ||
713 | exynos_dp_process_equalizer_training(dp); | ||
714 | break; | ||
715 | case FINISHED: | ||
716 | training_finished = 1; | ||
717 | break; | ||
718 | case FAILED: | ||
719 | return -EREMOTEIO; | ||
720 | } | ||
721 | } | ||
722 | |||
723 | return retval; | ||
724 | } | ||
725 | |||
726 | static int exynos_dp_set_link_train(struct exynos_dp_device *dp, | ||
727 | u32 count, | ||
728 | u32 bwtype) | ||
729 | { | ||
730 | int i; | ||
731 | int retval; | ||
732 | |||
733 | for (i = 0; i < DP_TIMEOUT_LOOP_COUNT; i++) { | ||
734 | exynos_dp_init_training(dp, count, bwtype); | ||
735 | retval = exynos_dp_sw_link_training(dp); | ||
736 | if (retval == 0) | ||
737 | break; | ||
738 | |||
739 | udelay(100); | ||
740 | } | ||
741 | |||
742 | return retval; | ||
743 | } | ||
744 | |||
745 | static int exynos_dp_config_video(struct exynos_dp_device *dp, | ||
746 | struct video_info *video_info) | ||
747 | { | ||
748 | int retval = 0; | ||
749 | int timeout_loop = 0; | ||
750 | int done_count = 0; | ||
751 | |||
752 | exynos_dp_config_video_slave_mode(dp, video_info); | ||
753 | |||
754 | exynos_dp_set_video_color_format(dp, video_info->color_depth, | ||
755 | video_info->color_space, | ||
756 | video_info->dynamic_range, | ||
757 | video_info->ycbcr_coeff); | ||
758 | |||
759 | if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { | ||
760 | dev_err(dp->dev, "PLL is not locked yet.\n"); | ||
761 | return -EINVAL; | ||
762 | } | ||
763 | |||
764 | for (;;) { | ||
765 | timeout_loop++; | ||
766 | if (exynos_dp_is_slave_video_stream_clock_on(dp) == 0) | ||
767 | break; | ||
768 | if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { | ||
769 | dev_err(dp->dev, "Timeout of video streamclk ok\n"); | ||
770 | return -ETIMEDOUT; | ||
771 | } | ||
772 | |||
773 | mdelay(100); | ||
774 | } | ||
775 | |||
776 | /* Set to use the register calculated M/N video */ | ||
777 | exynos_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0); | ||
778 | |||
779 | /* For video bist, Video timing must be generated by register */ | ||
780 | exynos_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_CAPTURE); | ||
781 | |||
782 | /* Disable video mute */ | ||
783 | exynos_dp_enable_video_mute(dp, 0); | ||
784 | |||
785 | /* Configure video slave mode */ | ||
786 | exynos_dp_enable_video_master(dp, 0); | ||
787 | |||
788 | /* Enable video */ | ||
789 | exynos_dp_start_video(dp); | ||
790 | |||
791 | timeout_loop = 0; | ||
792 | |||
793 | for (;;) { | ||
794 | timeout_loop++; | ||
795 | if (exynos_dp_is_video_stream_on(dp) == 0) { | ||
796 | done_count++; | ||
797 | if (done_count > 10) | ||
798 | break; | ||
799 | } else if (done_count) { | ||
800 | done_count = 0; | ||
801 | } | ||
802 | if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { | ||
803 | dev_err(dp->dev, "Timeout of video streamclk ok\n"); | ||
804 | return -ETIMEDOUT; | ||
805 | } | ||
806 | |||
807 | mdelay(100); | ||
808 | } | ||
809 | |||
810 | if (retval != 0) | ||
811 | dev_err(dp->dev, "Video stream is not detected!\n"); | ||
812 | |||
813 | return retval; | ||
814 | } | ||
815 | |||
816 | static void exynos_dp_enable_scramble(struct exynos_dp_device *dp, bool enable) | ||
817 | { | ||
818 | u8 data; | ||
819 | |||
820 | if (enable) { | ||
821 | exynos_dp_enable_scrambling(dp); | ||
822 | |||
823 | exynos_dp_read_byte_from_dpcd(dp, | ||
824 | DPCD_ADDR_TRAINING_PATTERN_SET, | ||
825 | &data); | ||
826 | exynos_dp_write_byte_to_dpcd(dp, | ||
827 | DPCD_ADDR_TRAINING_PATTERN_SET, | ||
828 | (u8)(data & ~DPCD_SCRAMBLING_DISABLED)); | ||
829 | } else { | ||
830 | exynos_dp_disable_scrambling(dp); | ||
831 | |||
832 | exynos_dp_read_byte_from_dpcd(dp, | ||
833 | DPCD_ADDR_TRAINING_PATTERN_SET, | ||
834 | &data); | ||
835 | exynos_dp_write_byte_to_dpcd(dp, | ||
836 | DPCD_ADDR_TRAINING_PATTERN_SET, | ||
837 | (u8)(data | DPCD_SCRAMBLING_DISABLED)); | ||
838 | } | ||
839 | } | ||
840 | |||
841 | static irqreturn_t exynos_dp_irq_handler(int irq, void *arg) | ||
842 | { | ||
843 | struct exynos_dp_device *dp = arg; | ||
844 | |||
845 | dev_err(dp->dev, "exynos_dp_irq_handler\n"); | ||
846 | return IRQ_HANDLED; | ||
847 | } | ||
848 | |||
849 | static int __devinit exynos_dp_probe(struct platform_device *pdev) | ||
850 | { | ||
851 | struct resource *res; | ||
852 | struct exynos_dp_device *dp; | ||
853 | struct exynos_dp_platdata *pdata; | ||
854 | |||
855 | int ret = 0; | ||
856 | |||
857 | pdata = pdev->dev.platform_data; | ||
858 | if (!pdata) { | ||
859 | dev_err(&pdev->dev, "no platform data\n"); | ||
860 | return -EINVAL; | ||
861 | } | ||
862 | |||
863 | dp = kzalloc(sizeof(struct exynos_dp_device), GFP_KERNEL); | ||
864 | if (!dp) { | ||
865 | dev_err(&pdev->dev, "no memory for device data\n"); | ||
866 | return -ENOMEM; | ||
867 | } | ||
868 | |||
869 | dp->dev = &pdev->dev; | ||
870 | |||
871 | dp->clock = clk_get(&pdev->dev, "dp"); | ||
872 | if (IS_ERR(dp->clock)) { | ||
873 | dev_err(&pdev->dev, "failed to get clock\n"); | ||
874 | ret = PTR_ERR(dp->clock); | ||
875 | goto err_dp; | ||
876 | } | ||
877 | |||
878 | clk_enable(dp->clock); | ||
879 | |||
880 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
881 | if (!res) { | ||
882 | dev_err(&pdev->dev, "failed to get registers\n"); | ||
883 | ret = -EINVAL; | ||
884 | goto err_clock; | ||
885 | } | ||
886 | |||
887 | res = request_mem_region(res->start, resource_size(res), | ||
888 | dev_name(&pdev->dev)); | ||
889 | if (!res) { | ||
890 | dev_err(&pdev->dev, "failed to request registers region\n"); | ||
891 | ret = -EINVAL; | ||
892 | goto err_clock; | ||
893 | } | ||
894 | |||
895 | dp->res = res; | ||
896 | |||
897 | dp->reg_base = ioremap(res->start, resource_size(res)); | ||
898 | if (!dp->reg_base) { | ||
899 | dev_err(&pdev->dev, "failed to ioremap\n"); | ||
900 | ret = -ENOMEM; | ||
901 | goto err_req_region; | ||
902 | } | ||
903 | |||
904 | dp->irq = platform_get_irq(pdev, 0); | ||
905 | if (!dp->irq) { | ||
906 | dev_err(&pdev->dev, "failed to get irq\n"); | ||
907 | ret = -ENODEV; | ||
908 | goto err_ioremap; | ||
909 | } | ||
910 | |||
911 | ret = request_irq(dp->irq, exynos_dp_irq_handler, 0, | ||
912 | "exynos-dp", dp); | ||
913 | if (ret) { | ||
914 | dev_err(&pdev->dev, "failed to request irq\n"); | ||
915 | goto err_ioremap; | ||
916 | } | ||
917 | |||
918 | dp->video_info = pdata->video_info; | ||
919 | if (pdata->phy_init) | ||
920 | pdata->phy_init(); | ||
921 | |||
922 | exynos_dp_init_dp(dp); | ||
923 | |||
924 | ret = exynos_dp_detect_hpd(dp); | ||
925 | if (ret) { | ||
926 | dev_err(&pdev->dev, "unable to detect hpd\n"); | ||
927 | goto err_irq; | ||
928 | } | ||
929 | |||
930 | exynos_dp_handle_edid(dp); | ||
931 | |||
932 | ret = exynos_dp_set_link_train(dp, dp->video_info->lane_count, | ||
933 | dp->video_info->link_rate); | ||
934 | if (ret) { | ||
935 | dev_err(&pdev->dev, "unable to do link train\n"); | ||
936 | goto err_irq; | ||
937 | } | ||
938 | |||
939 | exynos_dp_enable_scramble(dp, 1); | ||
940 | exynos_dp_enable_rx_to_enhanced_mode(dp, 1); | ||
941 | exynos_dp_enable_enhanced_mode(dp, 1); | ||
942 | |||
943 | exynos_dp_set_lane_count(dp, dp->video_info->lane_count); | ||
944 | exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate); | ||
945 | |||
946 | exynos_dp_init_video(dp); | ||
947 | ret = exynos_dp_config_video(dp, dp->video_info); | ||
948 | if (ret) { | ||
949 | dev_err(&pdev->dev, "unable to config video\n"); | ||
950 | goto err_irq; | ||
951 | } | ||
952 | |||
953 | platform_set_drvdata(pdev, dp); | ||
954 | |||
955 | return 0; | ||
956 | |||
957 | err_irq: | ||
958 | free_irq(dp->irq, dp); | ||
959 | err_ioremap: | ||
960 | iounmap(dp->reg_base); | ||
961 | err_req_region: | ||
962 | release_mem_region(res->start, resource_size(res)); | ||
963 | err_clock: | ||
964 | clk_put(dp->clock); | ||
965 | err_dp: | ||
966 | kfree(dp); | ||
967 | |||
968 | return ret; | ||
969 | } | ||
970 | |||
971 | static int __devexit exynos_dp_remove(struct platform_device *pdev) | ||
972 | { | ||
973 | struct exynos_dp_platdata *pdata = pdev->dev.platform_data; | ||
974 | struct exynos_dp_device *dp = platform_get_drvdata(pdev); | ||
975 | |||
976 | if (pdata && pdata->phy_exit) | ||
977 | pdata->phy_exit(); | ||
978 | |||
979 | free_irq(dp->irq, dp); | ||
980 | iounmap(dp->reg_base); | ||
981 | |||
982 | clk_disable(dp->clock); | ||
983 | clk_put(dp->clock); | ||
984 | |||
985 | release_mem_region(dp->res->start, resource_size(dp->res)); | ||
986 | |||
987 | kfree(dp); | ||
988 | |||
989 | return 0; | ||
990 | } | ||
991 | |||
992 | #ifdef CONFIG_PM_SLEEP | ||
993 | static int exynos_dp_suspend(struct device *dev) | ||
994 | { | ||
995 | struct platform_device *pdev = to_platform_device(dev); | ||
996 | struct exynos_dp_platdata *pdata = pdev->dev.platform_data; | ||
997 | struct exynos_dp_device *dp = platform_get_drvdata(pdev); | ||
998 | |||
999 | if (pdata && pdata->phy_exit) | ||
1000 | pdata->phy_exit(); | ||
1001 | |||
1002 | clk_disable(dp->clock); | ||
1003 | |||
1004 | return 0; | ||
1005 | } | ||
1006 | |||
1007 | static int exynos_dp_resume(struct device *dev) | ||
1008 | { | ||
1009 | struct platform_device *pdev = to_platform_device(dev); | ||
1010 | struct exynos_dp_platdata *pdata = pdev->dev.platform_data; | ||
1011 | struct exynos_dp_device *dp = platform_get_drvdata(pdev); | ||
1012 | |||
1013 | if (pdata && pdata->phy_init) | ||
1014 | pdata->phy_init(); | ||
1015 | |||
1016 | clk_enable(dp->clock); | ||
1017 | |||
1018 | exynos_dp_init_dp(dp); | ||
1019 | |||
1020 | exynos_dp_detect_hpd(dp); | ||
1021 | exynos_dp_handle_edid(dp); | ||
1022 | |||
1023 | exynos_dp_set_link_train(dp, dp->video_info->lane_count, | ||
1024 | dp->video_info->link_rate); | ||
1025 | |||
1026 | exynos_dp_enable_scramble(dp, 1); | ||
1027 | exynos_dp_enable_rx_to_enhanced_mode(dp, 1); | ||
1028 | exynos_dp_enable_enhanced_mode(dp, 1); | ||
1029 | |||
1030 | exynos_dp_set_lane_count(dp, dp->video_info->lane_count); | ||
1031 | exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate); | ||
1032 | |||
1033 | exynos_dp_init_video(dp); | ||
1034 | exynos_dp_config_video(dp, dp->video_info); | ||
1035 | |||
1036 | return 0; | ||
1037 | } | ||
1038 | #endif | ||
1039 | |||
1040 | static const struct dev_pm_ops exynos_dp_pm_ops = { | ||
1041 | SET_SYSTEM_SLEEP_PM_OPS(exynos_dp_suspend, exynos_dp_resume) | ||
1042 | }; | ||
1043 | |||
1044 | static struct platform_driver exynos_dp_driver = { | ||
1045 | .probe = exynos_dp_probe, | ||
1046 | .remove = __devexit_p(exynos_dp_remove), | ||
1047 | .driver = { | ||
1048 | .name = "exynos-dp", | ||
1049 | .owner = THIS_MODULE, | ||
1050 | .pm = &exynos_dp_pm_ops, | ||
1051 | }, | ||
1052 | }; | ||
1053 | |||
1054 | module_platform_driver(exynos_dp_driver); | ||
1055 | |||
1056 | MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>"); | ||
1057 | MODULE_DESCRIPTION("Samsung SoC DP Driver"); | ||
1058 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/exynos/exynos_dp_core.h b/drivers/video/exynos/exynos_dp_core.h new file mode 100644 index 000000000000..90ceaca0fa24 --- /dev/null +++ b/drivers/video/exynos/exynos_dp_core.h | |||
@@ -0,0 +1,206 @@ | |||
1 | /* | ||
2 | * Header file for Samsung DP (Display Port) interface driver. | ||
3 | * | ||
4 | * Copyright (C) 2012 Samsung Electronics Co., Ltd. | ||
5 | * Author: Jingoo Han <jg1.han@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #ifndef _EXYNOS_DP_CORE_H | ||
14 | #define _EXYNOS_DP_CORE_H | ||
15 | |||
16 | struct link_train { | ||
17 | int eq_loop; | ||
18 | int cr_loop[4]; | ||
19 | |||
20 | u8 link_rate; | ||
21 | u8 lane_count; | ||
22 | u8 training_lane[4]; | ||
23 | |||
24 | enum link_training_state lt_state; | ||
25 | }; | ||
26 | |||
27 | struct exynos_dp_device { | ||
28 | struct device *dev; | ||
29 | struct resource *res; | ||
30 | struct clk *clock; | ||
31 | unsigned int irq; | ||
32 | void __iomem *reg_base; | ||
33 | |||
34 | struct video_info *video_info; | ||
35 | struct link_train link_train; | ||
36 | }; | ||
37 | |||
38 | /* exynos_dp_reg.c */ | ||
39 | void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable); | ||
40 | void exynos_dp_stop_video(struct exynos_dp_device *dp); | ||
41 | void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable); | ||
42 | void exynos_dp_init_interrupt(struct exynos_dp_device *dp); | ||
43 | void exynos_dp_reset(struct exynos_dp_device *dp); | ||
44 | void exynos_dp_config_interrupt(struct exynos_dp_device *dp); | ||
45 | u32 exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp); | ||
46 | void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable); | ||
47 | void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp, | ||
48 | enum analog_power_block block, | ||
49 | bool enable); | ||
50 | void exynos_dp_init_analog_func(struct exynos_dp_device *dp); | ||
51 | void exynos_dp_init_hpd(struct exynos_dp_device *dp); | ||
52 | void exynos_dp_reset_aux(struct exynos_dp_device *dp); | ||
53 | void exynos_dp_init_aux(struct exynos_dp_device *dp); | ||
54 | int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp); | ||
55 | void exynos_dp_enable_sw_function(struct exynos_dp_device *dp); | ||
56 | int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp); | ||
57 | int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp, | ||
58 | unsigned int reg_addr, | ||
59 | unsigned char data); | ||
60 | int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp, | ||
61 | unsigned int reg_addr, | ||
62 | unsigned char *data); | ||
63 | int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp, | ||
64 | unsigned int reg_addr, | ||
65 | unsigned int count, | ||
66 | unsigned char data[]); | ||
67 | int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp, | ||
68 | unsigned int reg_addr, | ||
69 | unsigned int count, | ||
70 | unsigned char data[]); | ||
71 | int exynos_dp_select_i2c_device(struct exynos_dp_device *dp, | ||
72 | unsigned int device_addr, | ||
73 | unsigned int reg_addr); | ||
74 | int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp, | ||
75 | unsigned int device_addr, | ||
76 | unsigned int reg_addr, | ||
77 | unsigned int *data); | ||
78 | int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp, | ||
79 | unsigned int device_addr, | ||
80 | unsigned int reg_addr, | ||
81 | unsigned int count, | ||
82 | unsigned char edid[]); | ||
83 | void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype); | ||
84 | void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype); | ||
85 | void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count); | ||
86 | void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count); | ||
87 | void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype); | ||
88 | void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype); | ||
89 | void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count); | ||
90 | void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count); | ||
91 | void exynos_dp_enable_enhanced_mode(struct exynos_dp_device *dp, bool enable); | ||
92 | void exynos_dp_set_training_pattern(struct exynos_dp_device *dp, | ||
93 | enum pattern_set pattern); | ||
94 | void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level); | ||
95 | void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level); | ||
96 | void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level); | ||
97 | void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level); | ||
98 | void exynos_dp_set_lane0_link_training(struct exynos_dp_device *dp, | ||
99 | u32 training_lane); | ||
100 | void exynos_dp_set_lane1_link_training(struct exynos_dp_device *dp, | ||
101 | u32 training_lane); | ||
102 | void exynos_dp_set_lane2_link_training(struct exynos_dp_device *dp, | ||
103 | u32 training_lane); | ||
104 | void exynos_dp_set_lane3_link_training(struct exynos_dp_device *dp, | ||
105 | u32 training_lane); | ||
106 | u32 exynos_dp_get_lane0_link_training(struct exynos_dp_device *dp); | ||
107 | u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp); | ||
108 | u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp); | ||
109 | u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp); | ||
110 | void exynos_dp_reset_macro(struct exynos_dp_device *dp); | ||
111 | int exynos_dp_init_video(struct exynos_dp_device *dp); | ||
112 | |||
113 | void exynos_dp_set_video_color_format(struct exynos_dp_device *dp, | ||
114 | u32 color_depth, | ||
115 | u32 color_space, | ||
116 | u32 dynamic_range, | ||
117 | u32 ycbcr_coeff); | ||
118 | int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp); | ||
119 | void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp, | ||
120 | enum clock_recovery_m_value_type type, | ||
121 | u32 m_value, | ||
122 | u32 n_value); | ||
123 | void exynos_dp_set_video_timing_mode(struct exynos_dp_device *dp, u32 type); | ||
124 | void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable); | ||
125 | void exynos_dp_start_video(struct exynos_dp_device *dp); | ||
126 | int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp); | ||
127 | void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp, | ||
128 | struct video_info *video_info); | ||
129 | void exynos_dp_enable_scrambling(struct exynos_dp_device *dp); | ||
130 | void exynos_dp_disable_scrambling(struct exynos_dp_device *dp); | ||
131 | |||
132 | /* I2C EDID Chip ID, Slave Address */ | ||
133 | #define I2C_EDID_DEVICE_ADDR 0x50 | ||
134 | #define I2C_E_EDID_DEVICE_ADDR 0x30 | ||
135 | |||
136 | #define EDID_BLOCK_LENGTH 0x80 | ||
137 | #define EDID_HEADER_PATTERN 0x00 | ||
138 | #define EDID_EXTENSION_FLAG 0x7e | ||
139 | #define EDID_CHECKSUM 0x7f | ||
140 | |||
141 | /* Definition for DPCD Register */ | ||
142 | #define DPCD_ADDR_DPCD_REV 0x0000 | ||
143 | #define DPCD_ADDR_MAX_LINK_RATE 0x0001 | ||
144 | #define DPCD_ADDR_MAX_LANE_COUNT 0x0002 | ||
145 | #define DPCD_ADDR_LINK_BW_SET 0x0100 | ||
146 | #define DPCD_ADDR_LANE_COUNT_SET 0x0101 | ||
147 | #define DPCD_ADDR_TRAINING_PATTERN_SET 0x0102 | ||
148 | #define DPCD_ADDR_TRAINING_LANE0_SET 0x0103 | ||
149 | #define DPCD_ADDR_LANE0_1_STATUS 0x0202 | ||
150 | #define DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED 0x0204 | ||
151 | #define DPCD_ADDR_ADJUST_REQUEST_LANE0_1 0x0206 | ||
152 | #define DPCD_ADDR_ADJUST_REQUEST_LANE2_3 0x0207 | ||
153 | #define DPCD_ADDR_TEST_REQUEST 0x0218 | ||
154 | #define DPCD_ADDR_TEST_RESPONSE 0x0260 | ||
155 | #define DPCD_ADDR_TEST_EDID_CHECKSUM 0x0261 | ||
156 | #define DPCD_ADDR_SINK_POWER_STATE 0x0600 | ||
157 | |||
158 | /* DPCD_ADDR_MAX_LANE_COUNT */ | ||
159 | #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) | ||
160 | #define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f) | ||
161 | |||
162 | /* DPCD_ADDR_LANE_COUNT_SET */ | ||
163 | #define DPCD_ENHANCED_FRAME_EN (0x1 << 7) | ||
164 | #define DPCD_LANE_COUNT_SET(x) ((x) & 0x1f) | ||
165 | |||
166 | /* DPCD_ADDR_TRAINING_PATTERN_SET */ | ||
167 | #define DPCD_SCRAMBLING_DISABLED (0x1 << 5) | ||
168 | #define DPCD_SCRAMBLING_ENABLED (0x0 << 5) | ||
169 | #define DPCD_TRAINING_PATTERN_2 (0x2 << 0) | ||
170 | #define DPCD_TRAINING_PATTERN_1 (0x1 << 0) | ||
171 | #define DPCD_TRAINING_PATTERN_DISABLED (0x0 << 0) | ||
172 | |||
173 | /* DPCD_ADDR_TRAINING_LANE0_SET */ | ||
174 | #define DPCD_MAX_PRE_EMPHASIS_REACHED (0x1 << 5) | ||
175 | #define DPCD_PRE_EMPHASIS_SET(x) (((x) & 0x3) << 3) | ||
176 | #define DPCD_PRE_EMPHASIS_GET(x) (((x) >> 3) & 0x3) | ||
177 | #define DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 (0x0 << 3) | ||
178 | #define DPCD_MAX_SWING_REACHED (0x1 << 2) | ||
179 | #define DPCD_VOLTAGE_SWING_SET(x) (((x) & 0x3) << 0) | ||
180 | #define DPCD_VOLTAGE_SWING_GET(x) (((x) >> 0) & 0x3) | ||
181 | #define DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0 (0x0 << 0) | ||
182 | |||
183 | /* DPCD_ADDR_LANE0_1_STATUS */ | ||
184 | #define DPCD_LANE_SYMBOL_LOCKED (0x1 << 2) | ||
185 | #define DPCD_LANE_CHANNEL_EQ_DONE (0x1 << 1) | ||
186 | #define DPCD_LANE_CR_DONE (0x1 << 0) | ||
187 | #define DPCD_CHANNEL_EQ_BITS (DPCD_LANE_CR_DONE| \ | ||
188 | DPCD_LANE_CHANNEL_EQ_DONE|\ | ||
189 | DPCD_LANE_SYMBOL_LOCKED) | ||
190 | |||
191 | /* DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED */ | ||
192 | #define DPCD_LINK_STATUS_UPDATED (0x1 << 7) | ||
193 | #define DPCD_DOWNSTREAM_PORT_STATUS_CHANGED (0x1 << 6) | ||
194 | #define DPCD_INTERLANE_ALIGN_DONE (0x1 << 0) | ||
195 | |||
196 | /* DPCD_ADDR_TEST_REQUEST */ | ||
197 | #define DPCD_TEST_EDID_READ (0x1 << 2) | ||
198 | |||
199 | /* DPCD_ADDR_TEST_RESPONSE */ | ||
200 | #define DPCD_TEST_EDID_CHECKSUM_WRITE (0x1 << 2) | ||
201 | |||
202 | /* DPCD_ADDR_SINK_POWER_STATE */ | ||
203 | #define DPCD_SET_POWER_STATE_D0 (0x1 << 0) | ||
204 | #define DPCD_SET_POWER_STATE_D4 (0x2 << 0) | ||
205 | |||
206 | #endif /* _EXYNOS_DP_CORE_H */ | ||
diff --git a/drivers/video/exynos/exynos_dp_reg.c b/drivers/video/exynos/exynos_dp_reg.c new file mode 100644 index 000000000000..6548afa0e3d2 --- /dev/null +++ b/drivers/video/exynos/exynos_dp_reg.c | |||
@@ -0,0 +1,1173 @@ | |||
1 | /* | ||
2 | * Samsung DP (Display port) register interface driver. | ||
3 | * | ||
4 | * Copyright (C) 2012 Samsung Electronics Co., Ltd. | ||
5 | * Author: Jingoo Han <jg1.han@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/device.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <linux/delay.h> | ||
16 | |||
17 | #include <video/exynos_dp.h> | ||
18 | |||
19 | #include <plat/cpu.h> | ||
20 | |||
21 | #include "exynos_dp_core.h" | ||
22 | #include "exynos_dp_reg.h" | ||
23 | |||
24 | #define COMMON_INT_MASK_1 (0) | ||
25 | #define COMMON_INT_MASK_2 (0) | ||
26 | #define COMMON_INT_MASK_3 (0) | ||
27 | #define COMMON_INT_MASK_4 (0) | ||
28 | #define INT_STA_MASK (0) | ||
29 | |||
30 | void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable) | ||
31 | { | ||
32 | u32 reg; | ||
33 | |||
34 | if (enable) { | ||
35 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); | ||
36 | reg |= HDCP_VIDEO_MUTE; | ||
37 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); | ||
38 | } else { | ||
39 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); | ||
40 | reg &= ~HDCP_VIDEO_MUTE; | ||
41 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); | ||
42 | } | ||
43 | } | ||
44 | |||
45 | void exynos_dp_stop_video(struct exynos_dp_device *dp) | ||
46 | { | ||
47 | u32 reg; | ||
48 | |||
49 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); | ||
50 | reg &= ~VIDEO_EN; | ||
51 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); | ||
52 | } | ||
53 | |||
54 | void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable) | ||
55 | { | ||
56 | u32 reg; | ||
57 | |||
58 | if (enable) | ||
59 | reg = LANE3_MAP_LOGIC_LANE_0 | LANE2_MAP_LOGIC_LANE_1 | | ||
60 | LANE1_MAP_LOGIC_LANE_2 | LANE0_MAP_LOGIC_LANE_3; | ||
61 | else | ||
62 | reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 | | ||
63 | LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0; | ||
64 | |||
65 | writel(reg, dp->reg_base + EXYNOS_DP_LANE_MAP); | ||
66 | } | ||
67 | |||
68 | void exynos_dp_init_interrupt(struct exynos_dp_device *dp) | ||
69 | { | ||
70 | /* Set interrupt pin assertion polarity as high */ | ||
71 | writel(INT_POL, dp->reg_base + EXYNOS_DP_INT_CTL); | ||
72 | |||
73 | /* Clear pending regisers */ | ||
74 | writel(0xff, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1); | ||
75 | writel(0x4f, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_2); | ||
76 | writel(0xe0, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_3); | ||
77 | writel(0xe7, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4); | ||
78 | writel(0x63, dp->reg_base + EXYNOS_DP_INT_STA); | ||
79 | |||
80 | /* 0:mask,1: unmask */ | ||
81 | writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_1); | ||
82 | writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_2); | ||
83 | writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_3); | ||
84 | writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_4); | ||
85 | writel(0x00, dp->reg_base + EXYNOS_DP_INT_STA_MASK); | ||
86 | } | ||
87 | |||
88 | void exynos_dp_reset(struct exynos_dp_device *dp) | ||
89 | { | ||
90 | u32 reg; | ||
91 | |||
92 | writel(RESET_DP_TX, dp->reg_base + EXYNOS_DP_TX_SW_RESET); | ||
93 | |||
94 | exynos_dp_stop_video(dp); | ||
95 | exynos_dp_enable_video_mute(dp, 0); | ||
96 | |||
97 | reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N | | ||
98 | AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N | | ||
99 | HDCP_FUNC_EN_N | SW_FUNC_EN_N; | ||
100 | writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1); | ||
101 | |||
102 | reg = SSC_FUNC_EN_N | AUX_FUNC_EN_N | | ||
103 | SERDES_FIFO_FUNC_EN_N | | ||
104 | LS_CLK_DOMAIN_FUNC_EN_N; | ||
105 | writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2); | ||
106 | |||
107 | udelay(20); | ||
108 | |||
109 | exynos_dp_lane_swap(dp, 0); | ||
110 | |||
111 | writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_1); | ||
112 | writel(0x40, dp->reg_base + EXYNOS_DP_SYS_CTL_2); | ||
113 | writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_3); | ||
114 | writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
115 | |||
116 | writel(0x0, dp->reg_base + EXYNOS_DP_PKT_SEND_CTL); | ||
117 | writel(0x0, dp->reg_base + EXYNOS_DP_HDCP_CTL); | ||
118 | |||
119 | writel(0x5e, dp->reg_base + EXYNOS_DP_HPD_DEGLITCH_L); | ||
120 | writel(0x1a, dp->reg_base + EXYNOS_DP_HPD_DEGLITCH_H); | ||
121 | |||
122 | writel(0x10, dp->reg_base + EXYNOS_DP_LINK_DEBUG_CTL); | ||
123 | |||
124 | writel(0x0, dp->reg_base + EXYNOS_DP_PHY_TEST); | ||
125 | |||
126 | writel(0x0, dp->reg_base + EXYNOS_DP_VIDEO_FIFO_THRD); | ||
127 | writel(0x20, dp->reg_base + EXYNOS_DP_AUDIO_MARGIN); | ||
128 | |||
129 | writel(0x4, dp->reg_base + EXYNOS_DP_M_VID_GEN_FILTER_TH); | ||
130 | writel(0x2, dp->reg_base + EXYNOS_DP_M_AUD_GEN_FILTER_TH); | ||
131 | |||
132 | writel(0x00000101, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); | ||
133 | |||
134 | exynos_dp_init_interrupt(dp); | ||
135 | } | ||
136 | |||
137 | void exynos_dp_config_interrupt(struct exynos_dp_device *dp) | ||
138 | { | ||
139 | u32 reg; | ||
140 | |||
141 | /* 0: mask, 1: unmask */ | ||
142 | reg = COMMON_INT_MASK_1; | ||
143 | writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_1); | ||
144 | |||
145 | reg = COMMON_INT_MASK_2; | ||
146 | writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_2); | ||
147 | |||
148 | reg = COMMON_INT_MASK_3; | ||
149 | writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_3); | ||
150 | |||
151 | reg = COMMON_INT_MASK_4; | ||
152 | writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_4); | ||
153 | |||
154 | reg = INT_STA_MASK; | ||
155 | writel(reg, dp->reg_base + EXYNOS_DP_INT_STA_MASK); | ||
156 | } | ||
157 | |||
158 | u32 exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp) | ||
159 | { | ||
160 | u32 reg; | ||
161 | |||
162 | reg = readl(dp->reg_base + EXYNOS_DP_DEBUG_CTL); | ||
163 | if (reg & PLL_LOCK) | ||
164 | return PLL_LOCKED; | ||
165 | else | ||
166 | return PLL_UNLOCKED; | ||
167 | } | ||
168 | |||
169 | void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable) | ||
170 | { | ||
171 | u32 reg; | ||
172 | |||
173 | if (enable) { | ||
174 | reg = readl(dp->reg_base + EXYNOS_DP_PLL_CTL); | ||
175 | reg |= DP_PLL_PD; | ||
176 | writel(reg, dp->reg_base + EXYNOS_DP_PLL_CTL); | ||
177 | } else { | ||
178 | reg = readl(dp->reg_base + EXYNOS_DP_PLL_CTL); | ||
179 | reg &= ~DP_PLL_PD; | ||
180 | writel(reg, dp->reg_base + EXYNOS_DP_PLL_CTL); | ||
181 | } | ||
182 | } | ||
183 | |||
184 | void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp, | ||
185 | enum analog_power_block block, | ||
186 | bool enable) | ||
187 | { | ||
188 | u32 reg; | ||
189 | |||
190 | switch (block) { | ||
191 | case AUX_BLOCK: | ||
192 | if (enable) { | ||
193 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
194 | reg |= AUX_PD; | ||
195 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
196 | } else { | ||
197 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
198 | reg &= ~AUX_PD; | ||
199 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
200 | } | ||
201 | break; | ||
202 | case CH0_BLOCK: | ||
203 | if (enable) { | ||
204 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
205 | reg |= CH0_PD; | ||
206 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
207 | } else { | ||
208 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
209 | reg &= ~CH0_PD; | ||
210 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
211 | } | ||
212 | break; | ||
213 | case CH1_BLOCK: | ||
214 | if (enable) { | ||
215 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
216 | reg |= CH1_PD; | ||
217 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
218 | } else { | ||
219 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
220 | reg &= ~CH1_PD; | ||
221 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
222 | } | ||
223 | break; | ||
224 | case CH2_BLOCK: | ||
225 | if (enable) { | ||
226 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
227 | reg |= CH2_PD; | ||
228 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
229 | } else { | ||
230 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
231 | reg &= ~CH2_PD; | ||
232 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
233 | } | ||
234 | break; | ||
235 | case CH3_BLOCK: | ||
236 | if (enable) { | ||
237 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
238 | reg |= CH3_PD; | ||
239 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
240 | } else { | ||
241 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
242 | reg &= ~CH3_PD; | ||
243 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
244 | } | ||
245 | break; | ||
246 | case ANALOG_TOTAL: | ||
247 | if (enable) { | ||
248 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
249 | reg |= DP_PHY_PD; | ||
250 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
251 | } else { | ||
252 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
253 | reg &= ~DP_PHY_PD; | ||
254 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
255 | } | ||
256 | break; | ||
257 | case POWER_ALL: | ||
258 | if (enable) { | ||
259 | reg = DP_PHY_PD | AUX_PD | CH3_PD | CH2_PD | | ||
260 | CH1_PD | CH0_PD; | ||
261 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
262 | } else { | ||
263 | writel(0x00, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
264 | } | ||
265 | break; | ||
266 | default: | ||
267 | break; | ||
268 | } | ||
269 | } | ||
270 | |||
271 | void exynos_dp_init_analog_func(struct exynos_dp_device *dp) | ||
272 | { | ||
273 | u32 reg; | ||
274 | |||
275 | exynos_dp_set_analog_power_down(dp, POWER_ALL, 0); | ||
276 | |||
277 | reg = PLL_LOCK_CHG; | ||
278 | writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1); | ||
279 | |||
280 | reg = readl(dp->reg_base + EXYNOS_DP_DEBUG_CTL); | ||
281 | reg &= ~(F_PLL_LOCK | PLL_LOCK_CTRL); | ||
282 | writel(reg, dp->reg_base + EXYNOS_DP_DEBUG_CTL); | ||
283 | |||
284 | /* Power up PLL */ | ||
285 | if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) | ||
286 | exynos_dp_set_pll_power_down(dp, 0); | ||
287 | |||
288 | /* Enable Serdes FIFO function and Link symbol clock domain module */ | ||
289 | reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2); | ||
290 | reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N | ||
291 | | AUX_FUNC_EN_N); | ||
292 | writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2); | ||
293 | } | ||
294 | |||
295 | void exynos_dp_init_hpd(struct exynos_dp_device *dp) | ||
296 | { | ||
297 | u32 reg; | ||
298 | |||
299 | reg = HOTPLUG_CHG | HPD_LOST | PLUG; | ||
300 | writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4); | ||
301 | |||
302 | reg = INT_HPD; | ||
303 | writel(reg, dp->reg_base + EXYNOS_DP_INT_STA); | ||
304 | |||
305 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3); | ||
306 | reg &= ~(F_HPD | HPD_CTRL); | ||
307 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3); | ||
308 | } | ||
309 | |||
310 | void exynos_dp_reset_aux(struct exynos_dp_device *dp) | ||
311 | { | ||
312 | u32 reg; | ||
313 | |||
314 | /* Disable AUX channel module */ | ||
315 | reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2); | ||
316 | reg |= AUX_FUNC_EN_N; | ||
317 | writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2); | ||
318 | } | ||
319 | |||
320 | void exynos_dp_init_aux(struct exynos_dp_device *dp) | ||
321 | { | ||
322 | u32 reg; | ||
323 | |||
324 | /* Clear inerrupts related to AUX channel */ | ||
325 | reg = RPLY_RECEIV | AUX_ERR; | ||
326 | writel(reg, dp->reg_base + EXYNOS_DP_INT_STA); | ||
327 | |||
328 | exynos_dp_reset_aux(dp); | ||
329 | |||
330 | /* Disable AUX transaction H/W retry */ | ||
331 | reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) | AUX_HW_RETRY_COUNT_SEL(0)| | ||
332 | AUX_HW_RETRY_INTERVAL_600_MICROSECONDS; | ||
333 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_HW_RETRY_CTL) ; | ||
334 | |||
335 | /* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */ | ||
336 | reg = DEFER_CTRL_EN | DEFER_COUNT(1); | ||
337 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_DEFER_CTL); | ||
338 | |||
339 | /* Enable AUX channel module */ | ||
340 | reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2); | ||
341 | reg &= ~AUX_FUNC_EN_N; | ||
342 | writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2); | ||
343 | } | ||
344 | |||
345 | int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp) | ||
346 | { | ||
347 | u32 reg; | ||
348 | |||
349 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3); | ||
350 | if (reg & HPD_STATUS) | ||
351 | return 0; | ||
352 | |||
353 | return -EINVAL; | ||
354 | } | ||
355 | |||
356 | void exynos_dp_enable_sw_function(struct exynos_dp_device *dp) | ||
357 | { | ||
358 | u32 reg; | ||
359 | |||
360 | reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_1); | ||
361 | reg &= ~SW_FUNC_EN_N; | ||
362 | writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1); | ||
363 | } | ||
364 | |||
365 | int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp) | ||
366 | { | ||
367 | int reg; | ||
368 | int retval = 0; | ||
369 | |||
370 | /* Enable AUX CH operation */ | ||
371 | reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2); | ||
372 | reg |= AUX_EN; | ||
373 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2); | ||
374 | |||
375 | /* Is AUX CH command reply received? */ | ||
376 | reg = readl(dp->reg_base + EXYNOS_DP_INT_STA); | ||
377 | while (!(reg & RPLY_RECEIV)) | ||
378 | reg = readl(dp->reg_base + EXYNOS_DP_INT_STA); | ||
379 | |||
380 | /* Clear interrupt source for AUX CH command reply */ | ||
381 | writel(RPLY_RECEIV, dp->reg_base + EXYNOS_DP_INT_STA); | ||
382 | |||
383 | /* Clear interrupt source for AUX CH access error */ | ||
384 | reg = readl(dp->reg_base + EXYNOS_DP_INT_STA); | ||
385 | if (reg & AUX_ERR) { | ||
386 | writel(AUX_ERR, dp->reg_base + EXYNOS_DP_INT_STA); | ||
387 | return -EREMOTEIO; | ||
388 | } | ||
389 | |||
390 | /* Check AUX CH error access status */ | ||
391 | reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_STA); | ||
392 | if ((reg & AUX_STATUS_MASK) != 0) { | ||
393 | dev_err(dp->dev, "AUX CH error happens: %d\n\n", | ||
394 | reg & AUX_STATUS_MASK); | ||
395 | return -EREMOTEIO; | ||
396 | } | ||
397 | |||
398 | return retval; | ||
399 | } | ||
400 | |||
401 | int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp, | ||
402 | unsigned int reg_addr, | ||
403 | unsigned char data) | ||
404 | { | ||
405 | u32 reg; | ||
406 | int i; | ||
407 | int retval; | ||
408 | |||
409 | for (i = 0; i < 3; i++) { | ||
410 | /* Clear AUX CH data buffer */ | ||
411 | reg = BUF_CLR; | ||
412 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); | ||
413 | |||
414 | /* Select DPCD device address */ | ||
415 | reg = AUX_ADDR_7_0(reg_addr); | ||
416 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); | ||
417 | reg = AUX_ADDR_15_8(reg_addr); | ||
418 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8); | ||
419 | reg = AUX_ADDR_19_16(reg_addr); | ||
420 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16); | ||
421 | |||
422 | /* Write data buffer */ | ||
423 | reg = (unsigned int)data; | ||
424 | writel(reg, dp->reg_base + EXYNOS_DP_BUF_DATA_0); | ||
425 | |||
426 | /* | ||
427 | * Set DisplayPort transaction and write 1 byte | ||
428 | * If bit 3 is 1, DisplayPort transaction. | ||
429 | * If Bit 3 is 0, I2C transaction. | ||
430 | */ | ||
431 | reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; | ||
432 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1); | ||
433 | |||
434 | /* Start AUX transaction */ | ||
435 | retval = exynos_dp_start_aux_transaction(dp); | ||
436 | if (retval == 0) | ||
437 | break; | ||
438 | else | ||
439 | dev_err(dp->dev, "Aux Transaction fail!\n"); | ||
440 | } | ||
441 | |||
442 | return retval; | ||
443 | } | ||
444 | |||
445 | int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp, | ||
446 | unsigned int reg_addr, | ||
447 | unsigned char *data) | ||
448 | { | ||
449 | u32 reg; | ||
450 | int i; | ||
451 | int retval; | ||
452 | |||
453 | for (i = 0; i < 10; i++) { | ||
454 | /* Clear AUX CH data buffer */ | ||
455 | reg = BUF_CLR; | ||
456 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); | ||
457 | |||
458 | /* Select DPCD device address */ | ||
459 | reg = AUX_ADDR_7_0(reg_addr); | ||
460 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); | ||
461 | reg = AUX_ADDR_15_8(reg_addr); | ||
462 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8); | ||
463 | reg = AUX_ADDR_19_16(reg_addr); | ||
464 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16); | ||
465 | |||
466 | /* | ||
467 | * Set DisplayPort transaction and read 1 byte | ||
468 | * If bit 3 is 1, DisplayPort transaction. | ||
469 | * If Bit 3 is 0, I2C transaction. | ||
470 | */ | ||
471 | reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; | ||
472 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1); | ||
473 | |||
474 | /* Start AUX transaction */ | ||
475 | retval = exynos_dp_start_aux_transaction(dp); | ||
476 | if (retval == 0) | ||
477 | break; | ||
478 | else | ||
479 | dev_err(dp->dev, "Aux Transaction fail!\n"); | ||
480 | } | ||
481 | |||
482 | /* Read data buffer */ | ||
483 | reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0); | ||
484 | *data = (unsigned char)(reg & 0xff); | ||
485 | |||
486 | return retval; | ||
487 | } | ||
488 | |||
489 | int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp, | ||
490 | unsigned int reg_addr, | ||
491 | unsigned int count, | ||
492 | unsigned char data[]) | ||
493 | { | ||
494 | u32 reg; | ||
495 | unsigned int start_offset; | ||
496 | unsigned int cur_data_count; | ||
497 | unsigned int cur_data_idx; | ||
498 | int i; | ||
499 | int retval = 0; | ||
500 | |||
501 | /* Clear AUX CH data buffer */ | ||
502 | reg = BUF_CLR; | ||
503 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); | ||
504 | |||
505 | start_offset = 0; | ||
506 | while (start_offset < count) { | ||
507 | /* Buffer size of AUX CH is 16 * 4bytes */ | ||
508 | if ((count - start_offset) > 16) | ||
509 | cur_data_count = 16; | ||
510 | else | ||
511 | cur_data_count = count - start_offset; | ||
512 | |||
513 | for (i = 0; i < 10; i++) { | ||
514 | /* Select DPCD device address */ | ||
515 | reg = AUX_ADDR_7_0(reg_addr + start_offset); | ||
516 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); | ||
517 | reg = AUX_ADDR_15_8(reg_addr + start_offset); | ||
518 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8); | ||
519 | reg = AUX_ADDR_19_16(reg_addr + start_offset); | ||
520 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16); | ||
521 | |||
522 | for (cur_data_idx = 0; cur_data_idx < cur_data_count; | ||
523 | cur_data_idx++) { | ||
524 | reg = data[start_offset + cur_data_idx]; | ||
525 | writel(reg, dp->reg_base + EXYNOS_DP_BUF_DATA_0 | ||
526 | + 4 * cur_data_idx); | ||
527 | } | ||
528 | |||
529 | /* | ||
530 | * Set DisplayPort transaction and write | ||
531 | * If bit 3 is 1, DisplayPort transaction. | ||
532 | * If Bit 3 is 0, I2C transaction. | ||
533 | */ | ||
534 | reg = AUX_LENGTH(cur_data_count) | | ||
535 | AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; | ||
536 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1); | ||
537 | |||
538 | /* Start AUX transaction */ | ||
539 | retval = exynos_dp_start_aux_transaction(dp); | ||
540 | if (retval == 0) | ||
541 | break; | ||
542 | else | ||
543 | dev_err(dp->dev, "Aux Transaction fail!\n"); | ||
544 | } | ||
545 | |||
546 | start_offset += cur_data_count; | ||
547 | } | ||
548 | |||
549 | return retval; | ||
550 | } | ||
551 | |||
552 | int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp, | ||
553 | unsigned int reg_addr, | ||
554 | unsigned int count, | ||
555 | unsigned char data[]) | ||
556 | { | ||
557 | u32 reg; | ||
558 | unsigned int start_offset; | ||
559 | unsigned int cur_data_count; | ||
560 | unsigned int cur_data_idx; | ||
561 | int i; | ||
562 | int retval = 0; | ||
563 | |||
564 | /* Clear AUX CH data buffer */ | ||
565 | reg = BUF_CLR; | ||
566 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); | ||
567 | |||
568 | start_offset = 0; | ||
569 | while (start_offset < count) { | ||
570 | /* Buffer size of AUX CH is 16 * 4bytes */ | ||
571 | if ((count - start_offset) > 16) | ||
572 | cur_data_count = 16; | ||
573 | else | ||
574 | cur_data_count = count - start_offset; | ||
575 | |||
576 | /* AUX CH Request Transaction process */ | ||
577 | for (i = 0; i < 10; i++) { | ||
578 | /* Select DPCD device address */ | ||
579 | reg = AUX_ADDR_7_0(reg_addr + start_offset); | ||
580 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); | ||
581 | reg = AUX_ADDR_15_8(reg_addr + start_offset); | ||
582 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8); | ||
583 | reg = AUX_ADDR_19_16(reg_addr + start_offset); | ||
584 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16); | ||
585 | |||
586 | /* | ||
587 | * Set DisplayPort transaction and read | ||
588 | * If bit 3 is 1, DisplayPort transaction. | ||
589 | * If Bit 3 is 0, I2C transaction. | ||
590 | */ | ||
591 | reg = AUX_LENGTH(cur_data_count) | | ||
592 | AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; | ||
593 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1); | ||
594 | |||
595 | /* Start AUX transaction */ | ||
596 | retval = exynos_dp_start_aux_transaction(dp); | ||
597 | if (retval == 0) | ||
598 | break; | ||
599 | else | ||
600 | dev_err(dp->dev, "Aux Transaction fail!\n"); | ||
601 | } | ||
602 | |||
603 | for (cur_data_idx = 0; cur_data_idx < cur_data_count; | ||
604 | cur_data_idx++) { | ||
605 | reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0 | ||
606 | + 4 * cur_data_idx); | ||
607 | data[start_offset + cur_data_idx] = | ||
608 | (unsigned char)reg; | ||
609 | } | ||
610 | |||
611 | start_offset += cur_data_count; | ||
612 | } | ||
613 | |||
614 | return retval; | ||
615 | } | ||
616 | |||
617 | int exynos_dp_select_i2c_device(struct exynos_dp_device *dp, | ||
618 | unsigned int device_addr, | ||
619 | unsigned int reg_addr) | ||
620 | { | ||
621 | u32 reg; | ||
622 | int retval; | ||
623 | |||
624 | /* Set EDID device address */ | ||
625 | reg = device_addr; | ||
626 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); | ||
627 | writel(0x0, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8); | ||
628 | writel(0x0, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16); | ||
629 | |||
630 | /* Set offset from base address of EDID device */ | ||
631 | writel(reg_addr, dp->reg_base + EXYNOS_DP_BUF_DATA_0); | ||
632 | |||
633 | /* | ||
634 | * Set I2C transaction and write address | ||
635 | * If bit 3 is 1, DisplayPort transaction. | ||
636 | * If Bit 3 is 0, I2C transaction. | ||
637 | */ | ||
638 | reg = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT | | ||
639 | AUX_TX_COMM_WRITE; | ||
640 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1); | ||
641 | |||
642 | /* Start AUX transaction */ | ||
643 | retval = exynos_dp_start_aux_transaction(dp); | ||
644 | if (retval != 0) | ||
645 | dev_err(dp->dev, "Aux Transaction fail!\n"); | ||
646 | |||
647 | return retval; | ||
648 | } | ||
649 | |||
650 | int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp, | ||
651 | unsigned int device_addr, | ||
652 | unsigned int reg_addr, | ||
653 | unsigned int *data) | ||
654 | { | ||
655 | u32 reg; | ||
656 | int i; | ||
657 | int retval; | ||
658 | |||
659 | for (i = 0; i < 10; i++) { | ||
660 | /* Clear AUX CH data buffer */ | ||
661 | reg = BUF_CLR; | ||
662 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); | ||
663 | |||
664 | /* Select EDID device */ | ||
665 | retval = exynos_dp_select_i2c_device(dp, device_addr, reg_addr); | ||
666 | if (retval != 0) { | ||
667 | dev_err(dp->dev, "Select EDID device fail!\n"); | ||
668 | continue; | ||
669 | } | ||
670 | |||
671 | /* | ||
672 | * Set I2C transaction and read data | ||
673 | * If bit 3 is 1, DisplayPort transaction. | ||
674 | * If Bit 3 is 0, I2C transaction. | ||
675 | */ | ||
676 | reg = AUX_TX_COMM_I2C_TRANSACTION | | ||
677 | AUX_TX_COMM_READ; | ||
678 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1); | ||
679 | |||
680 | /* Start AUX transaction */ | ||
681 | retval = exynos_dp_start_aux_transaction(dp); | ||
682 | if (retval == 0) | ||
683 | break; | ||
684 | else | ||
685 | dev_err(dp->dev, "Aux Transaction fail!\n"); | ||
686 | } | ||
687 | |||
688 | /* Read data */ | ||
689 | if (retval == 0) | ||
690 | *data = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0); | ||
691 | |||
692 | return retval; | ||
693 | } | ||
694 | |||
695 | int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp, | ||
696 | unsigned int device_addr, | ||
697 | unsigned int reg_addr, | ||
698 | unsigned int count, | ||
699 | unsigned char edid[]) | ||
700 | { | ||
701 | u32 reg; | ||
702 | unsigned int i, j; | ||
703 | unsigned int cur_data_idx; | ||
704 | unsigned int defer = 0; | ||
705 | int retval = 0; | ||
706 | |||
707 | for (i = 0; i < count; i += 16) { | ||
708 | for (j = 0; j < 100; j++) { | ||
709 | /* Clear AUX CH data buffer */ | ||
710 | reg = BUF_CLR; | ||
711 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); | ||
712 | |||
713 | /* Set normal AUX CH command */ | ||
714 | reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2); | ||
715 | reg &= ~ADDR_ONLY; | ||
716 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2); | ||
717 | |||
718 | /* | ||
719 | * If Rx sends defer, Tx sends only reads | ||
720 | * request without sending addres | ||
721 | */ | ||
722 | if (!defer) | ||
723 | retval = exynos_dp_select_i2c_device(dp, | ||
724 | device_addr, reg_addr + i); | ||
725 | else | ||
726 | defer = 0; | ||
727 | |||
728 | if (retval == 0) { | ||
729 | /* | ||
730 | * Set I2C transaction and write data | ||
731 | * If bit 3 is 1, DisplayPort transaction. | ||
732 | * If Bit 3 is 0, I2C transaction. | ||
733 | */ | ||
734 | reg = AUX_LENGTH(16) | | ||
735 | AUX_TX_COMM_I2C_TRANSACTION | | ||
736 | AUX_TX_COMM_READ; | ||
737 | writel(reg, dp->reg_base + | ||
738 | EXYNOS_DP_AUX_CH_CTL_1); | ||
739 | |||
740 | /* Start AUX transaction */ | ||
741 | retval = exynos_dp_start_aux_transaction(dp); | ||
742 | if (retval == 0) | ||
743 | break; | ||
744 | else | ||
745 | dev_err(dp->dev, "Aux Transaction fail!\n"); | ||
746 | } | ||
747 | /* Check if Rx sends defer */ | ||
748 | reg = readl(dp->reg_base + EXYNOS_DP_AUX_RX_COMM); | ||
749 | if (reg == AUX_RX_COMM_AUX_DEFER || | ||
750 | reg == AUX_RX_COMM_I2C_DEFER) { | ||
751 | dev_err(dp->dev, "Defer: %d\n\n", reg); | ||
752 | defer = 1; | ||
753 | } | ||
754 | } | ||
755 | |||
756 | for (cur_data_idx = 0; cur_data_idx < 16; cur_data_idx++) { | ||
757 | reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0 | ||
758 | + 4 * cur_data_idx); | ||
759 | edid[i + cur_data_idx] = (unsigned char)reg; | ||
760 | } | ||
761 | } | ||
762 | |||
763 | return retval; | ||
764 | } | ||
765 | |||
766 | void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype) | ||
767 | { | ||
768 | u32 reg; | ||
769 | |||
770 | reg = bwtype; | ||
771 | if ((bwtype == LINK_RATE_2_70GBPS) || (bwtype == LINK_RATE_1_62GBPS)) | ||
772 | writel(reg, dp->reg_base + EXYNOS_DP_LINK_BW_SET); | ||
773 | } | ||
774 | |||
775 | void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype) | ||
776 | { | ||
777 | u32 reg; | ||
778 | |||
779 | reg = readl(dp->reg_base + EXYNOS_DP_LINK_BW_SET); | ||
780 | *bwtype = reg; | ||
781 | } | ||
782 | |||
783 | void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count) | ||
784 | { | ||
785 | u32 reg; | ||
786 | |||
787 | reg = count; | ||
788 | writel(reg, dp->reg_base + EXYNOS_DP_LANE_COUNT_SET); | ||
789 | } | ||
790 | |||
791 | void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count) | ||
792 | { | ||
793 | u32 reg; | ||
794 | |||
795 | reg = readl(dp->reg_base + EXYNOS_DP_LANE_COUNT_SET); | ||
796 | *count = reg; | ||
797 | } | ||
798 | |||
799 | void exynos_dp_enable_enhanced_mode(struct exynos_dp_device *dp, bool enable) | ||
800 | { | ||
801 | u32 reg; | ||
802 | |||
803 | if (enable) { | ||
804 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
805 | reg |= ENHANCED; | ||
806 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
807 | } else { | ||
808 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
809 | reg &= ~ENHANCED; | ||
810 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
811 | } | ||
812 | } | ||
813 | |||
814 | void exynos_dp_set_training_pattern(struct exynos_dp_device *dp, | ||
815 | enum pattern_set pattern) | ||
816 | { | ||
817 | u32 reg; | ||
818 | |||
819 | switch (pattern) { | ||
820 | case PRBS7: | ||
821 | reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_PRBS7; | ||
822 | writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
823 | break; | ||
824 | case D10_2: | ||
825 | reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_D10_2; | ||
826 | writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
827 | break; | ||
828 | case TRAINING_PTN1: | ||
829 | reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN1; | ||
830 | writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
831 | break; | ||
832 | case TRAINING_PTN2: | ||
833 | reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN2; | ||
834 | writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
835 | break; | ||
836 | case DP_NONE: | ||
837 | reg = SCRAMBLING_ENABLE | | ||
838 | LINK_QUAL_PATTERN_SET_DISABLE | | ||
839 | SW_TRAINING_PATTERN_SET_NORMAL; | ||
840 | writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
841 | break; | ||
842 | default: | ||
843 | break; | ||
844 | } | ||
845 | } | ||
846 | |||
847 | void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level) | ||
848 | { | ||
849 | u32 reg; | ||
850 | |||
851 | reg = level << PRE_EMPHASIS_SET_SHIFT; | ||
852 | writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL); | ||
853 | } | ||
854 | |||
855 | void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level) | ||
856 | { | ||
857 | u32 reg; | ||
858 | |||
859 | reg = level << PRE_EMPHASIS_SET_SHIFT; | ||
860 | writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL); | ||
861 | } | ||
862 | |||
863 | void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level) | ||
864 | { | ||
865 | u32 reg; | ||
866 | |||
867 | reg = level << PRE_EMPHASIS_SET_SHIFT; | ||
868 | writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL); | ||
869 | } | ||
870 | |||
871 | void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level) | ||
872 | { | ||
873 | u32 reg; | ||
874 | |||
875 | reg = level << PRE_EMPHASIS_SET_SHIFT; | ||
876 | writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL); | ||
877 | } | ||
878 | |||
879 | void exynos_dp_set_lane0_link_training(struct exynos_dp_device *dp, | ||
880 | u32 training_lane) | ||
881 | { | ||
882 | u32 reg; | ||
883 | |||
884 | reg = training_lane; | ||
885 | writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL); | ||
886 | } | ||
887 | |||
888 | void exynos_dp_set_lane1_link_training(struct exynos_dp_device *dp, | ||
889 | u32 training_lane) | ||
890 | { | ||
891 | u32 reg; | ||
892 | |||
893 | reg = training_lane; | ||
894 | writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL); | ||
895 | } | ||
896 | |||
897 | void exynos_dp_set_lane2_link_training(struct exynos_dp_device *dp, | ||
898 | u32 training_lane) | ||
899 | { | ||
900 | u32 reg; | ||
901 | |||
902 | reg = training_lane; | ||
903 | writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL); | ||
904 | } | ||
905 | |||
906 | void exynos_dp_set_lane3_link_training(struct exynos_dp_device *dp, | ||
907 | u32 training_lane) | ||
908 | { | ||
909 | u32 reg; | ||
910 | |||
911 | reg = training_lane; | ||
912 | writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL); | ||
913 | } | ||
914 | |||
915 | u32 exynos_dp_get_lane0_link_training(struct exynos_dp_device *dp) | ||
916 | { | ||
917 | u32 reg; | ||
918 | |||
919 | reg = readl(dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL); | ||
920 | return reg; | ||
921 | } | ||
922 | |||
923 | u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp) | ||
924 | { | ||
925 | u32 reg; | ||
926 | |||
927 | reg = readl(dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL); | ||
928 | return reg; | ||
929 | } | ||
930 | |||
931 | u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp) | ||
932 | { | ||
933 | u32 reg; | ||
934 | |||
935 | reg = readl(dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL); | ||
936 | return reg; | ||
937 | } | ||
938 | |||
939 | u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp) | ||
940 | { | ||
941 | u32 reg; | ||
942 | |||
943 | reg = readl(dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL); | ||
944 | return reg; | ||
945 | } | ||
946 | |||
947 | void exynos_dp_reset_macro(struct exynos_dp_device *dp) | ||
948 | { | ||
949 | u32 reg; | ||
950 | |||
951 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_TEST); | ||
952 | reg |= MACRO_RST; | ||
953 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST); | ||
954 | |||
955 | /* 10 us is the minimum reset time. */ | ||
956 | udelay(10); | ||
957 | |||
958 | reg &= ~MACRO_RST; | ||
959 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST); | ||
960 | } | ||
961 | |||
962 | int exynos_dp_init_video(struct exynos_dp_device *dp) | ||
963 | { | ||
964 | u32 reg; | ||
965 | |||
966 | reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG; | ||
967 | writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1); | ||
968 | |||
969 | reg = 0x0; | ||
970 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_1); | ||
971 | |||
972 | reg = CHA_CRI(4) | CHA_CTRL; | ||
973 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_2); | ||
974 | |||
975 | reg = 0x0; | ||
976 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3); | ||
977 | |||
978 | reg = VID_HRES_TH(2) | VID_VRES_TH(0); | ||
979 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_8); | ||
980 | |||
981 | return 0; | ||
982 | } | ||
983 | |||
984 | void exynos_dp_set_video_color_format(struct exynos_dp_device *dp, | ||
985 | u32 color_depth, | ||
986 | u32 color_space, | ||
987 | u32 dynamic_range, | ||
988 | u32 ycbcr_coeff) | ||
989 | { | ||
990 | u32 reg; | ||
991 | |||
992 | /* Configure the input color depth, color space, dynamic range */ | ||
993 | reg = (dynamic_range << IN_D_RANGE_SHIFT) | | ||
994 | (color_depth << IN_BPC_SHIFT) | | ||
995 | (color_space << IN_COLOR_F_SHIFT); | ||
996 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_2); | ||
997 | |||
998 | /* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */ | ||
999 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_3); | ||
1000 | reg &= ~IN_YC_COEFFI_MASK; | ||
1001 | if (ycbcr_coeff) | ||
1002 | reg |= IN_YC_COEFFI_ITU709; | ||
1003 | else | ||
1004 | reg |= IN_YC_COEFFI_ITU601; | ||
1005 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_3); | ||
1006 | } | ||
1007 | |||
1008 | int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp) | ||
1009 | { | ||
1010 | u32 reg; | ||
1011 | |||
1012 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_1); | ||
1013 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_1); | ||
1014 | |||
1015 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_1); | ||
1016 | |||
1017 | if (!(reg & DET_STA)) { | ||
1018 | dev_dbg(dp->dev, "Input stream clock not detected.\n"); | ||
1019 | return -EINVAL; | ||
1020 | } | ||
1021 | |||
1022 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_2); | ||
1023 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_2); | ||
1024 | |||
1025 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_2); | ||
1026 | dev_dbg(dp->dev, "wait SYS_CTL_2.\n"); | ||
1027 | |||
1028 | if (reg & CHA_STA) { | ||
1029 | dev_dbg(dp->dev, "Input stream clk is changing\n"); | ||
1030 | return -EINVAL; | ||
1031 | } | ||
1032 | |||
1033 | return 0; | ||
1034 | } | ||
1035 | |||
1036 | void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp, | ||
1037 | enum clock_recovery_m_value_type type, | ||
1038 | u32 m_value, | ||
1039 | u32 n_value) | ||
1040 | { | ||
1041 | u32 reg; | ||
1042 | |||
1043 | if (type == REGISTER_M) { | ||
1044 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
1045 | reg |= FIX_M_VID; | ||
1046 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
1047 | reg = m_value & 0xff; | ||
1048 | writel(reg, dp->reg_base + EXYNOS_DP_M_VID_0); | ||
1049 | reg = (m_value >> 8) & 0xff; | ||
1050 | writel(reg, dp->reg_base + EXYNOS_DP_M_VID_1); | ||
1051 | reg = (m_value >> 16) & 0xff; | ||
1052 | writel(reg, dp->reg_base + EXYNOS_DP_M_VID_2); | ||
1053 | |||
1054 | reg = n_value & 0xff; | ||
1055 | writel(reg, dp->reg_base + EXYNOS_DP_N_VID_0); | ||
1056 | reg = (n_value >> 8) & 0xff; | ||
1057 | writel(reg, dp->reg_base + EXYNOS_DP_N_VID_1); | ||
1058 | reg = (n_value >> 16) & 0xff; | ||
1059 | writel(reg, dp->reg_base + EXYNOS_DP_N_VID_2); | ||
1060 | } else { | ||
1061 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
1062 | reg &= ~FIX_M_VID; | ||
1063 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
1064 | |||
1065 | writel(0x00, dp->reg_base + EXYNOS_DP_N_VID_0); | ||
1066 | writel(0x80, dp->reg_base + EXYNOS_DP_N_VID_1); | ||
1067 | writel(0x00, dp->reg_base + EXYNOS_DP_N_VID_2); | ||
1068 | } | ||
1069 | } | ||
1070 | |||
1071 | void exynos_dp_set_video_timing_mode(struct exynos_dp_device *dp, u32 type) | ||
1072 | { | ||
1073 | u32 reg; | ||
1074 | |||
1075 | if (type == VIDEO_TIMING_FROM_CAPTURE) { | ||
1076 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1077 | reg &= ~FORMAT_SEL; | ||
1078 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1079 | } else { | ||
1080 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1081 | reg |= FORMAT_SEL; | ||
1082 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1083 | } | ||
1084 | } | ||
1085 | |||
1086 | void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable) | ||
1087 | { | ||
1088 | u32 reg; | ||
1089 | |||
1090 | if (enable) { | ||
1091 | reg = readl(dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); | ||
1092 | reg &= ~VIDEO_MODE_MASK; | ||
1093 | reg |= VIDEO_MASTER_MODE_EN | VIDEO_MODE_MASTER_MODE; | ||
1094 | writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); | ||
1095 | } else { | ||
1096 | reg = readl(dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); | ||
1097 | reg &= ~VIDEO_MODE_MASK; | ||
1098 | reg |= VIDEO_MODE_SLAVE_MODE; | ||
1099 | writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); | ||
1100 | } | ||
1101 | } | ||
1102 | |||
1103 | void exynos_dp_start_video(struct exynos_dp_device *dp) | ||
1104 | { | ||
1105 | u32 reg; | ||
1106 | |||
1107 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); | ||
1108 | reg |= VIDEO_EN; | ||
1109 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); | ||
1110 | } | ||
1111 | |||
1112 | int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp) | ||
1113 | { | ||
1114 | u32 reg; | ||
1115 | |||
1116 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3); | ||
1117 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3); | ||
1118 | |||
1119 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3); | ||
1120 | if (!(reg & STRM_VALID)) { | ||
1121 | dev_dbg(dp->dev, "Input video stream is not detected.\n"); | ||
1122 | return -EINVAL; | ||
1123 | } | ||
1124 | |||
1125 | return 0; | ||
1126 | } | ||
1127 | |||
1128 | void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp, | ||
1129 | struct video_info *video_info) | ||
1130 | { | ||
1131 | u32 reg; | ||
1132 | |||
1133 | reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_1); | ||
1134 | reg &= ~(MASTER_VID_FUNC_EN_N|SLAVE_VID_FUNC_EN_N); | ||
1135 | reg |= MASTER_VID_FUNC_EN_N; | ||
1136 | writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1); | ||
1137 | |||
1138 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1139 | reg &= ~INTERACE_SCAN_CFG; | ||
1140 | reg |= (video_info->interlaced << 2); | ||
1141 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1142 | |||
1143 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1144 | reg &= ~VSYNC_POLARITY_CFG; | ||
1145 | reg |= (video_info->v_sync_polarity << 1); | ||
1146 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1147 | |||
1148 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1149 | reg &= ~HSYNC_POLARITY_CFG; | ||
1150 | reg |= (video_info->h_sync_polarity << 0); | ||
1151 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1152 | |||
1153 | reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE; | ||
1154 | writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); | ||
1155 | } | ||
1156 | |||
1157 | void exynos_dp_enable_scrambling(struct exynos_dp_device *dp) | ||
1158 | { | ||
1159 | u32 reg; | ||
1160 | |||
1161 | reg = readl(dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
1162 | reg &= ~SCRAMBLING_DISABLE; | ||
1163 | writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
1164 | } | ||
1165 | |||
1166 | void exynos_dp_disable_scrambling(struct exynos_dp_device *dp) | ||
1167 | { | ||
1168 | u32 reg; | ||
1169 | |||
1170 | reg = readl(dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
1171 | reg |= SCRAMBLING_DISABLE; | ||
1172 | writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
1173 | } | ||
diff --git a/drivers/video/exynos/exynos_dp_reg.h b/drivers/video/exynos/exynos_dp_reg.h new file mode 100644 index 000000000000..42f608e2a43e --- /dev/null +++ b/drivers/video/exynos/exynos_dp_reg.h | |||
@@ -0,0 +1,335 @@ | |||
1 | /* | ||
2 | * Register definition file for Samsung DP driver | ||
3 | * | ||
4 | * Copyright (C) 2012 Samsung Electronics Co., Ltd. | ||
5 | * Author: Jingoo Han <jg1.han@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef _EXYNOS_DP_REG_H | ||
13 | #define _EXYNOS_DP_REG_H | ||
14 | |||
15 | #define EXYNOS_DP_TX_SW_RESET 0x14 | ||
16 | #define EXYNOS_DP_FUNC_EN_1 0x18 | ||
17 | #define EXYNOS_DP_FUNC_EN_2 0x1C | ||
18 | #define EXYNOS_DP_VIDEO_CTL_1 0x20 | ||
19 | #define EXYNOS_DP_VIDEO_CTL_2 0x24 | ||
20 | #define EXYNOS_DP_VIDEO_CTL_3 0x28 | ||
21 | |||
22 | #define EXYNOS_DP_VIDEO_CTL_8 0x3C | ||
23 | #define EXYNOS_DP_VIDEO_CTL_10 0x44 | ||
24 | |||
25 | #define EXYNOS_DP_LANE_MAP 0x35C | ||
26 | |||
27 | #define EXYNOS_DP_AUX_HW_RETRY_CTL 0x390 | ||
28 | |||
29 | #define EXYNOS_DP_COMMON_INT_STA_1 0x3C4 | ||
30 | #define EXYNOS_DP_COMMON_INT_STA_2 0x3C8 | ||
31 | #define EXYNOS_DP_COMMON_INT_STA_3 0x3CC | ||
32 | #define EXYNOS_DP_COMMON_INT_STA_4 0x3D0 | ||
33 | #define EXYNOS_DP_INT_STA 0x3DC | ||
34 | #define EXYNOS_DP_COMMON_INT_MASK_1 0x3E0 | ||
35 | #define EXYNOS_DP_COMMON_INT_MASK_2 0x3E4 | ||
36 | #define EXYNOS_DP_COMMON_INT_MASK_3 0x3E8 | ||
37 | #define EXYNOS_DP_COMMON_INT_MASK_4 0x3EC | ||
38 | #define EXYNOS_DP_INT_STA_MASK 0x3F8 | ||
39 | #define EXYNOS_DP_INT_CTL 0x3FC | ||
40 | |||
41 | #define EXYNOS_DP_SYS_CTL_1 0x600 | ||
42 | #define EXYNOS_DP_SYS_CTL_2 0x604 | ||
43 | #define EXYNOS_DP_SYS_CTL_3 0x608 | ||
44 | #define EXYNOS_DP_SYS_CTL_4 0x60C | ||
45 | |||
46 | #define EXYNOS_DP_PKT_SEND_CTL 0x640 | ||
47 | #define EXYNOS_DP_HDCP_CTL 0x648 | ||
48 | |||
49 | #define EXYNOS_DP_LINK_BW_SET 0x680 | ||
50 | #define EXYNOS_DP_LANE_COUNT_SET 0x684 | ||
51 | #define EXYNOS_DP_TRAINING_PTN_SET 0x688 | ||
52 | #define EXYNOS_DP_LN0_LINK_TRAINING_CTL 0x68C | ||
53 | #define EXYNOS_DP_LN1_LINK_TRAINING_CTL 0x690 | ||
54 | #define EXYNOS_DP_LN2_LINK_TRAINING_CTL 0x694 | ||
55 | #define EXYNOS_DP_LN3_LINK_TRAINING_CTL 0x698 | ||
56 | |||
57 | #define EXYNOS_DP_DEBUG_CTL 0x6C0 | ||
58 | #define EXYNOS_DP_HPD_DEGLITCH_L 0x6C4 | ||
59 | #define EXYNOS_DP_HPD_DEGLITCH_H 0x6C8 | ||
60 | #define EXYNOS_DP_LINK_DEBUG_CTL 0x6E0 | ||
61 | |||
62 | #define EXYNOS_DP_M_VID_0 0x700 | ||
63 | #define EXYNOS_DP_M_VID_1 0x704 | ||
64 | #define EXYNOS_DP_M_VID_2 0x708 | ||
65 | #define EXYNOS_DP_N_VID_0 0x70C | ||
66 | #define EXYNOS_DP_N_VID_1 0x710 | ||
67 | #define EXYNOS_DP_N_VID_2 0x714 | ||
68 | |||
69 | #define EXYNOS_DP_PLL_CTL 0x71C | ||
70 | #define EXYNOS_DP_PHY_PD 0x720 | ||
71 | #define EXYNOS_DP_PHY_TEST 0x724 | ||
72 | |||
73 | #define EXYNOS_DP_VIDEO_FIFO_THRD 0x730 | ||
74 | #define EXYNOS_DP_AUDIO_MARGIN 0x73C | ||
75 | |||
76 | #define EXYNOS_DP_M_VID_GEN_FILTER_TH 0x764 | ||
77 | #define EXYNOS_DP_M_AUD_GEN_FILTER_TH 0x778 | ||
78 | #define EXYNOS_DP_AUX_CH_STA 0x780 | ||
79 | #define EXYNOS_DP_AUX_CH_DEFER_CTL 0x788 | ||
80 | #define EXYNOS_DP_AUX_RX_COMM 0x78C | ||
81 | #define EXYNOS_DP_BUFFER_DATA_CTL 0x790 | ||
82 | #define EXYNOS_DP_AUX_CH_CTL_1 0x794 | ||
83 | #define EXYNOS_DP_AUX_ADDR_7_0 0x798 | ||
84 | #define EXYNOS_DP_AUX_ADDR_15_8 0x79C | ||
85 | #define EXYNOS_DP_AUX_ADDR_19_16 0x7A0 | ||
86 | #define EXYNOS_DP_AUX_CH_CTL_2 0x7A4 | ||
87 | |||
88 | #define EXYNOS_DP_BUF_DATA_0 0x7C0 | ||
89 | |||
90 | #define EXYNOS_DP_SOC_GENERAL_CTL 0x800 | ||
91 | |||
92 | /* EXYNOS_DP_TX_SW_RESET */ | ||
93 | #define RESET_DP_TX (0x1 << 0) | ||
94 | |||
95 | /* EXYNOS_DP_FUNC_EN_1 */ | ||
96 | #define MASTER_VID_FUNC_EN_N (0x1 << 7) | ||
97 | #define SLAVE_VID_FUNC_EN_N (0x1 << 5) | ||
98 | #define AUD_FIFO_FUNC_EN_N (0x1 << 4) | ||
99 | #define AUD_FUNC_EN_N (0x1 << 3) | ||
100 | #define HDCP_FUNC_EN_N (0x1 << 2) | ||
101 | #define CRC_FUNC_EN_N (0x1 << 1) | ||
102 | #define SW_FUNC_EN_N (0x1 << 0) | ||
103 | |||
104 | /* EXYNOS_DP_FUNC_EN_2 */ | ||
105 | #define SSC_FUNC_EN_N (0x1 << 7) | ||
106 | #define AUX_FUNC_EN_N (0x1 << 2) | ||
107 | #define SERDES_FIFO_FUNC_EN_N (0x1 << 1) | ||
108 | #define LS_CLK_DOMAIN_FUNC_EN_N (0x1 << 0) | ||
109 | |||
110 | /* EXYNOS_DP_VIDEO_CTL_1 */ | ||
111 | #define VIDEO_EN (0x1 << 7) | ||
112 | #define HDCP_VIDEO_MUTE (0x1 << 6) | ||
113 | |||
114 | /* EXYNOS_DP_VIDEO_CTL_1 */ | ||
115 | #define IN_D_RANGE_MASK (0x1 << 7) | ||
116 | #define IN_D_RANGE_SHIFT (7) | ||
117 | #define IN_D_RANGE_CEA (0x1 << 7) | ||
118 | #define IN_D_RANGE_VESA (0x0 << 7) | ||
119 | #define IN_BPC_MASK (0x7 << 4) | ||
120 | #define IN_BPC_SHIFT (4) | ||
121 | #define IN_BPC_12_BITS (0x3 << 4) | ||
122 | #define IN_BPC_10_BITS (0x2 << 4) | ||
123 | #define IN_BPC_8_BITS (0x1 << 4) | ||
124 | #define IN_BPC_6_BITS (0x0 << 4) | ||
125 | #define IN_COLOR_F_MASK (0x3 << 0) | ||
126 | #define IN_COLOR_F_SHIFT (0) | ||
127 | #define IN_COLOR_F_YCBCR444 (0x2 << 0) | ||
128 | #define IN_COLOR_F_YCBCR422 (0x1 << 0) | ||
129 | #define IN_COLOR_F_RGB (0x0 << 0) | ||
130 | |||
131 | /* EXYNOS_DP_VIDEO_CTL_3 */ | ||
132 | #define IN_YC_COEFFI_MASK (0x1 << 7) | ||
133 | #define IN_YC_COEFFI_SHIFT (7) | ||
134 | #define IN_YC_COEFFI_ITU709 (0x1 << 7) | ||
135 | #define IN_YC_COEFFI_ITU601 (0x0 << 7) | ||
136 | #define VID_CHK_UPDATE_TYPE_MASK (0x1 << 4) | ||
137 | #define VID_CHK_UPDATE_TYPE_SHIFT (4) | ||
138 | #define VID_CHK_UPDATE_TYPE_1 (0x1 << 4) | ||
139 | #define VID_CHK_UPDATE_TYPE_0 (0x0 << 4) | ||
140 | |||
141 | /* EXYNOS_DP_VIDEO_CTL_8 */ | ||
142 | #define VID_HRES_TH(x) (((x) & 0xf) << 4) | ||
143 | #define VID_VRES_TH(x) (((x) & 0xf) << 0) | ||
144 | |||
145 | /* EXYNOS_DP_VIDEO_CTL_10 */ | ||
146 | #define FORMAT_SEL (0x1 << 4) | ||
147 | #define INTERACE_SCAN_CFG (0x1 << 2) | ||
148 | #define VSYNC_POLARITY_CFG (0x1 << 1) | ||
149 | #define HSYNC_POLARITY_CFG (0x1 << 0) | ||
150 | |||
151 | /* EXYNOS_DP_LANE_MAP */ | ||
152 | #define LANE3_MAP_LOGIC_LANE_0 (0x0 << 6) | ||
153 | #define LANE3_MAP_LOGIC_LANE_1 (0x1 << 6) | ||
154 | #define LANE3_MAP_LOGIC_LANE_2 (0x2 << 6) | ||
155 | #define LANE3_MAP_LOGIC_LANE_3 (0x3 << 6) | ||
156 | #define LANE2_MAP_LOGIC_LANE_0 (0x0 << 4) | ||
157 | #define LANE2_MAP_LOGIC_LANE_1 (0x1 << 4) | ||
158 | #define LANE2_MAP_LOGIC_LANE_2 (0x2 << 4) | ||
159 | #define LANE2_MAP_LOGIC_LANE_3 (0x3 << 4) | ||
160 | #define LANE1_MAP_LOGIC_LANE_0 (0x0 << 2) | ||
161 | #define LANE1_MAP_LOGIC_LANE_1 (0x1 << 2) | ||
162 | #define LANE1_MAP_LOGIC_LANE_2 (0x2 << 2) | ||
163 | #define LANE1_MAP_LOGIC_LANE_3 (0x3 << 2) | ||
164 | #define LANE0_MAP_LOGIC_LANE_0 (0x0 << 0) | ||
165 | #define LANE0_MAP_LOGIC_LANE_1 (0x1 << 0) | ||
166 | #define LANE0_MAP_LOGIC_LANE_2 (0x2 << 0) | ||
167 | #define LANE0_MAP_LOGIC_LANE_3 (0x3 << 0) | ||
168 | |||
169 | /* EXYNOS_DP_AUX_HW_RETRY_CTL */ | ||
170 | #define AUX_BIT_PERIOD_EXPECTED_DELAY(x) (((x) & 0x7) << 8) | ||
171 | #define AUX_HW_RETRY_INTERVAL_MASK (0x3 << 3) | ||
172 | #define AUX_HW_RETRY_INTERVAL_600_MICROSECONDS (0x0 << 3) | ||
173 | #define AUX_HW_RETRY_INTERVAL_800_MICROSECONDS (0x1 << 3) | ||
174 | #define AUX_HW_RETRY_INTERVAL_1000_MICROSECONDS (0x2 << 3) | ||
175 | #define AUX_HW_RETRY_INTERVAL_1800_MICROSECONDS (0x3 << 3) | ||
176 | #define AUX_HW_RETRY_COUNT_SEL(x) (((x) & 0x7) << 0) | ||
177 | |||
178 | /* EXYNOS_DP_COMMON_INT_STA_1 */ | ||
179 | #define VSYNC_DET (0x1 << 7) | ||
180 | #define PLL_LOCK_CHG (0x1 << 6) | ||
181 | #define SPDIF_ERR (0x1 << 5) | ||
182 | #define SPDIF_UNSTBL (0x1 << 4) | ||
183 | #define VID_FORMAT_CHG (0x1 << 3) | ||
184 | #define AUD_CLK_CHG (0x1 << 2) | ||
185 | #define VID_CLK_CHG (0x1 << 1) | ||
186 | #define SW_INT (0x1 << 0) | ||
187 | |||
188 | /* EXYNOS_DP_COMMON_INT_STA_2 */ | ||
189 | #define ENC_EN_CHG (0x1 << 6) | ||
190 | #define HW_BKSV_RDY (0x1 << 3) | ||
191 | #define HW_SHA_DONE (0x1 << 2) | ||
192 | #define HW_AUTH_STATE_CHG (0x1 << 1) | ||
193 | #define HW_AUTH_DONE (0x1 << 0) | ||
194 | |||
195 | /* EXYNOS_DP_COMMON_INT_STA_3 */ | ||
196 | #define AFIFO_UNDER (0x1 << 7) | ||
197 | #define AFIFO_OVER (0x1 << 6) | ||
198 | #define R0_CHK_FLAG (0x1 << 5) | ||
199 | |||
200 | /* EXYNOS_DP_COMMON_INT_STA_4 */ | ||
201 | #define PSR_ACTIVE (0x1 << 7) | ||
202 | #define PSR_INACTIVE (0x1 << 6) | ||
203 | #define SPDIF_BI_PHASE_ERR (0x1 << 5) | ||
204 | #define HOTPLUG_CHG (0x1 << 2) | ||
205 | #define HPD_LOST (0x1 << 1) | ||
206 | #define PLUG (0x1 << 0) | ||
207 | |||
208 | /* EXYNOS_DP_INT_STA */ | ||
209 | #define INT_HPD (0x1 << 6) | ||
210 | #define HW_TRAINING_FINISH (0x1 << 5) | ||
211 | #define RPLY_RECEIV (0x1 << 1) | ||
212 | #define AUX_ERR (0x1 << 0) | ||
213 | |||
214 | /* EXYNOS_DP_INT_CTL */ | ||
215 | #define SOFT_INT_CTRL (0x1 << 2) | ||
216 | #define INT_POL (0x1 << 0) | ||
217 | |||
218 | /* EXYNOS_DP_SYS_CTL_1 */ | ||
219 | #define DET_STA (0x1 << 2) | ||
220 | #define FORCE_DET (0x1 << 1) | ||
221 | #define DET_CTRL (0x1 << 0) | ||
222 | |||
223 | /* EXYNOS_DP_SYS_CTL_2 */ | ||
224 | #define CHA_CRI(x) (((x) & 0xf) << 4) | ||
225 | #define CHA_STA (0x1 << 2) | ||
226 | #define FORCE_CHA (0x1 << 1) | ||
227 | #define CHA_CTRL (0x1 << 0) | ||
228 | |||
229 | /* EXYNOS_DP_SYS_CTL_3 */ | ||
230 | #define HPD_STATUS (0x1 << 6) | ||
231 | #define F_HPD (0x1 << 5) | ||
232 | #define HPD_CTRL (0x1 << 4) | ||
233 | #define HDCP_RDY (0x1 << 3) | ||
234 | #define STRM_VALID (0x1 << 2) | ||
235 | #define F_VALID (0x1 << 1) | ||
236 | #define VALID_CTRL (0x1 << 0) | ||
237 | |||
238 | /* EXYNOS_DP_SYS_CTL_4 */ | ||
239 | #define FIX_M_AUD (0x1 << 4) | ||
240 | #define ENHANCED (0x1 << 3) | ||
241 | #define FIX_M_VID (0x1 << 2) | ||
242 | #define M_VID_UPDATE_CTRL (0x3 << 0) | ||
243 | |||
244 | /* EXYNOS_DP_TRAINING_PTN_SET */ | ||
245 | #define SCRAMBLER_TYPE (0x1 << 9) | ||
246 | #define HW_LINK_TRAINING_PATTERN (0x1 << 8) | ||
247 | #define SCRAMBLING_DISABLE (0x1 << 5) | ||
248 | #define SCRAMBLING_ENABLE (0x0 << 5) | ||
249 | #define LINK_QUAL_PATTERN_SET_MASK (0x3 << 2) | ||
250 | #define LINK_QUAL_PATTERN_SET_PRBS7 (0x3 << 2) | ||
251 | #define LINK_QUAL_PATTERN_SET_D10_2 (0x1 << 2) | ||
252 | #define LINK_QUAL_PATTERN_SET_DISABLE (0x0 << 2) | ||
253 | #define SW_TRAINING_PATTERN_SET_MASK (0x3 << 0) | ||
254 | #define SW_TRAINING_PATTERN_SET_PTN2 (0x2 << 0) | ||
255 | #define SW_TRAINING_PATTERN_SET_PTN1 (0x1 << 0) | ||
256 | #define SW_TRAINING_PATTERN_SET_NORMAL (0x0 << 0) | ||
257 | |||
258 | /* EXYNOS_DP_LN0_LINK_TRAINING_CTL */ | ||
259 | #define PRE_EMPHASIS_SET_SHIFT (3) | ||
260 | |||
261 | /* EXYNOS_DP_DEBUG_CTL */ | ||
262 | #define PLL_LOCK (0x1 << 4) | ||
263 | #define F_PLL_LOCK (0x1 << 3) | ||
264 | #define PLL_LOCK_CTRL (0x1 << 2) | ||
265 | #define PN_INV (0x1 << 0) | ||
266 | |||
267 | /* EXYNOS_DP_PLL_CTL */ | ||
268 | #define DP_PLL_PD (0x1 << 7) | ||
269 | #define DP_PLL_RESET (0x1 << 6) | ||
270 | #define DP_PLL_LOOP_BIT_DEFAULT (0x1 << 4) | ||
271 | #define DP_PLL_REF_BIT_1_1250V (0x5 << 0) | ||
272 | #define DP_PLL_REF_BIT_1_2500V (0x7 << 0) | ||
273 | |||
274 | /* EXYNOS_DP_PHY_PD */ | ||
275 | #define DP_PHY_PD (0x1 << 5) | ||
276 | #define AUX_PD (0x1 << 4) | ||
277 | #define CH3_PD (0x1 << 3) | ||
278 | #define CH2_PD (0x1 << 2) | ||
279 | #define CH1_PD (0x1 << 1) | ||
280 | #define CH0_PD (0x1 << 0) | ||
281 | |||
282 | /* EXYNOS_DP_PHY_TEST */ | ||
283 | #define MACRO_RST (0x1 << 5) | ||
284 | #define CH1_TEST (0x1 << 1) | ||
285 | #define CH0_TEST (0x1 << 0) | ||
286 | |||
287 | /* EXYNOS_DP_AUX_CH_STA */ | ||
288 | #define AUX_BUSY (0x1 << 4) | ||
289 | #define AUX_STATUS_MASK (0xf << 0) | ||
290 | |||
291 | /* EXYNOS_DP_AUX_CH_DEFER_CTL */ | ||
292 | #define DEFER_CTRL_EN (0x1 << 7) | ||
293 | #define DEFER_COUNT(x) (((x) & 0x7f) << 0) | ||
294 | |||
295 | /* EXYNOS_DP_AUX_RX_COMM */ | ||
296 | #define AUX_RX_COMM_I2C_DEFER (0x2 << 2) | ||
297 | #define AUX_RX_COMM_AUX_DEFER (0x2 << 0) | ||
298 | |||
299 | /* EXYNOS_DP_BUFFER_DATA_CTL */ | ||
300 | #define BUF_CLR (0x1 << 7) | ||
301 | #define BUF_DATA_COUNT(x) (((x) & 0x1f) << 0) | ||
302 | |||
303 | /* EXYNOS_DP_AUX_CH_CTL_1 */ | ||
304 | #define AUX_LENGTH(x) (((x - 1) & 0xf) << 4) | ||
305 | #define AUX_TX_COMM_MASK (0xf << 0) | ||
306 | #define AUX_TX_COMM_DP_TRANSACTION (0x1 << 3) | ||
307 | #define AUX_TX_COMM_I2C_TRANSACTION (0x0 << 3) | ||
308 | #define AUX_TX_COMM_MOT (0x1 << 2) | ||
309 | #define AUX_TX_COMM_WRITE (0x0 << 0) | ||
310 | #define AUX_TX_COMM_READ (0x1 << 0) | ||
311 | |||
312 | /* EXYNOS_DP_AUX_ADDR_7_0 */ | ||
313 | #define AUX_ADDR_7_0(x) (((x) >> 0) & 0xff) | ||
314 | |||
315 | /* EXYNOS_DP_AUX_ADDR_15_8 */ | ||
316 | #define AUX_ADDR_15_8(x) (((x) >> 8) & 0xff) | ||
317 | |||
318 | /* EXYNOS_DP_AUX_ADDR_19_16 */ | ||
319 | #define AUX_ADDR_19_16(x) (((x) >> 16) & 0x0f) | ||
320 | |||
321 | /* EXYNOS_DP_AUX_CH_CTL_2 */ | ||
322 | #define ADDR_ONLY (0x1 << 1) | ||
323 | #define AUX_EN (0x1 << 0) | ||
324 | |||
325 | /* EXYNOS_DP_SOC_GENERAL_CTL */ | ||
326 | #define AUDIO_MODE_SPDIF_MODE (0x1 << 8) | ||
327 | #define AUDIO_MODE_MASTER_MODE (0x0 << 8) | ||
328 | #define MASTER_VIDEO_INTERLACE_EN (0x1 << 4) | ||
329 | #define VIDEO_MASTER_CLK_SEL (0x1 << 2) | ||
330 | #define VIDEO_MASTER_MODE_EN (0x1 << 1) | ||
331 | #define VIDEO_MODE_MASK (0x1 << 0) | ||
332 | #define VIDEO_MODE_SLAVE_MODE (0x1 << 0) | ||
333 | #define VIDEO_MODE_MASTER_MODE (0x0 << 0) | ||
334 | |||
335 | #endif /* _EXYNOS_DP_REG_H */ | ||
diff --git a/drivers/video/exynos/exynos_mipi_dsi.c b/drivers/video/exynos/exynos_mipi_dsi.c new file mode 100644 index 000000000000..557091dc0e97 --- /dev/null +++ b/drivers/video/exynos/exynos_mipi_dsi.c | |||
@@ -0,0 +1,600 @@ | |||
1 | /* linux/drivers/video/exynos/exynos_mipi_dsi.c | ||
2 | * | ||
3 | * Samsung SoC MIPI-DSIM driver. | ||
4 | * | ||
5 | * Copyright (c) 2012 Samsung Electronics Co., Ltd | ||
6 | * | ||
7 | * InKi Dae, <inki.dae@samsung.com> | ||
8 | * Donghwa Lee, <dh09.lee@samsung.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/errno.h> | ||
18 | #include <linux/clk.h> | ||
19 | #include <linux/mutex.h> | ||
20 | #include <linux/wait.h> | ||
21 | #include <linux/fs.h> | ||
22 | #include <linux/mm.h> | ||
23 | #include <linux/fb.h> | ||
24 | #include <linux/ctype.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <linux/irq.h> | ||
28 | #include <linux/memory.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/kthread.h> | ||
32 | #include <linux/notifier.h> | ||
33 | #include <linux/regulator/consumer.h> | ||
34 | #include <linux/pm_runtime.h> | ||
35 | |||
36 | #include <video/exynos_mipi_dsim.h> | ||
37 | |||
38 | #include <plat/fb.h> | ||
39 | |||
40 | #include "exynos_mipi_dsi_common.h" | ||
41 | #include "exynos_mipi_dsi_lowlevel.h" | ||
42 | |||
43 | struct mipi_dsim_ddi { | ||
44 | int bus_id; | ||
45 | struct list_head list; | ||
46 | struct mipi_dsim_lcd_device *dsim_lcd_dev; | ||
47 | struct mipi_dsim_lcd_driver *dsim_lcd_drv; | ||
48 | }; | ||
49 | |||
50 | static LIST_HEAD(dsim_ddi_list); | ||
51 | |||
52 | static DEFINE_MUTEX(mipi_dsim_lock); | ||
53 | |||
54 | static struct mipi_dsim_platform_data *to_dsim_plat(struct platform_device | ||
55 | *pdev) | ||
56 | { | ||
57 | return pdev->dev.platform_data; | ||
58 | } | ||
59 | |||
60 | static struct regulator_bulk_data supplies[] = { | ||
61 | { .supply = "vdd10", }, | ||
62 | { .supply = "vdd18", }, | ||
63 | }; | ||
64 | |||
65 | static int exynos_mipi_regulator_enable(struct mipi_dsim_device *dsim) | ||
66 | { | ||
67 | int ret; | ||
68 | |||
69 | mutex_lock(&dsim->lock); | ||
70 | ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies); | ||
71 | mutex_unlock(&dsim->lock); | ||
72 | |||
73 | return ret; | ||
74 | } | ||
75 | |||
76 | static int exynos_mipi_regulator_disable(struct mipi_dsim_device *dsim) | ||
77 | { | ||
78 | int ret; | ||
79 | |||
80 | mutex_lock(&dsim->lock); | ||
81 | ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies); | ||
82 | mutex_unlock(&dsim->lock); | ||
83 | |||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | /* update all register settings to MIPI DSI controller. */ | ||
88 | static void exynos_mipi_update_cfg(struct mipi_dsim_device *dsim) | ||
89 | { | ||
90 | /* | ||
91 | * data from Display controller(FIMD) is not transferred in video mode | ||
92 | * but in case of command mode, all settings is not updated to | ||
93 | * registers. | ||
94 | */ | ||
95 | exynos_mipi_dsi_stand_by(dsim, 0); | ||
96 | |||
97 | exynos_mipi_dsi_init_dsim(dsim); | ||
98 | exynos_mipi_dsi_init_link(dsim); | ||
99 | |||
100 | exynos_mipi_dsi_set_hs_enable(dsim); | ||
101 | |||
102 | /* set display timing. */ | ||
103 | exynos_mipi_dsi_set_display_mode(dsim, dsim->dsim_config); | ||
104 | |||
105 | /* | ||
106 | * data from Display controller(FIMD) is transferred in video mode | ||
107 | * but in case of command mode, all settigs is updated to registers. | ||
108 | */ | ||
109 | exynos_mipi_dsi_stand_by(dsim, 1); | ||
110 | } | ||
111 | |||
112 | static int exynos_mipi_dsi_early_blank_mode(struct mipi_dsim_device *dsim, | ||
113 | int power) | ||
114 | { | ||
115 | struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv; | ||
116 | struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev; | ||
117 | |||
118 | switch (power) { | ||
119 | case FB_BLANK_POWERDOWN: | ||
120 | if (dsim->suspended) | ||
121 | return 0; | ||
122 | |||
123 | if (client_drv && client_drv->suspend) | ||
124 | client_drv->suspend(client_dev); | ||
125 | |||
126 | clk_disable(dsim->clock); | ||
127 | |||
128 | exynos_mipi_regulator_disable(dsim); | ||
129 | |||
130 | dsim->suspended = true; | ||
131 | |||
132 | break; | ||
133 | default: | ||
134 | break; | ||
135 | } | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static int exynos_mipi_dsi_blank_mode(struct mipi_dsim_device *dsim, int power) | ||
141 | { | ||
142 | struct platform_device *pdev = to_platform_device(dsim->dev); | ||
143 | struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv; | ||
144 | struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev; | ||
145 | |||
146 | switch (power) { | ||
147 | case FB_BLANK_UNBLANK: | ||
148 | if (!dsim->suspended) | ||
149 | return 0; | ||
150 | |||
151 | /* lcd panel power on. */ | ||
152 | if (client_drv && client_drv->power_on) | ||
153 | client_drv->power_on(client_dev, 1); | ||
154 | |||
155 | exynos_mipi_regulator_disable(dsim); | ||
156 | |||
157 | /* enable MIPI-DSI PHY. */ | ||
158 | if (dsim->pd->phy_enable) | ||
159 | dsim->pd->phy_enable(pdev, true); | ||
160 | |||
161 | clk_enable(dsim->clock); | ||
162 | |||
163 | exynos_mipi_update_cfg(dsim); | ||
164 | |||
165 | /* set lcd panel sequence commands. */ | ||
166 | if (client_drv && client_drv->set_sequence) | ||
167 | client_drv->set_sequence(client_dev); | ||
168 | |||
169 | dsim->suspended = false; | ||
170 | |||
171 | break; | ||
172 | case FB_BLANK_NORMAL: | ||
173 | /* TODO. */ | ||
174 | break; | ||
175 | default: | ||
176 | break; | ||
177 | } | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev) | ||
183 | { | ||
184 | struct mipi_dsim_ddi *dsim_ddi; | ||
185 | |||
186 | if (!lcd_dev->name) { | ||
187 | pr_err("dsim_lcd_device name is NULL.\n"); | ||
188 | return -EFAULT; | ||
189 | } | ||
190 | |||
191 | dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL); | ||
192 | if (!dsim_ddi) { | ||
193 | pr_err("failed to allocate dsim_ddi object.\n"); | ||
194 | return -ENOMEM; | ||
195 | } | ||
196 | |||
197 | dsim_ddi->dsim_lcd_dev = lcd_dev; | ||
198 | |||
199 | mutex_lock(&mipi_dsim_lock); | ||
200 | list_add_tail(&dsim_ddi->list, &dsim_ddi_list); | ||
201 | mutex_unlock(&mipi_dsim_lock); | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | struct mipi_dsim_ddi *exynos_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv) | ||
207 | { | ||
208 | struct mipi_dsim_ddi *dsim_ddi, *next; | ||
209 | struct mipi_dsim_lcd_device *lcd_dev; | ||
210 | |||
211 | mutex_lock(&mipi_dsim_lock); | ||
212 | |||
213 | list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) { | ||
214 | if (!dsim_ddi) | ||
215 | goto out; | ||
216 | |||
217 | lcd_dev = dsim_ddi->dsim_lcd_dev; | ||
218 | if (!lcd_dev) | ||
219 | continue; | ||
220 | |||
221 | if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0) { | ||
222 | /** | ||
223 | * bus_id would be used to identify | ||
224 | * connected bus. | ||
225 | */ | ||
226 | dsim_ddi->bus_id = lcd_dev->bus_id; | ||
227 | mutex_unlock(&mipi_dsim_lock); | ||
228 | |||
229 | return dsim_ddi; | ||
230 | } | ||
231 | |||
232 | list_del(&dsim_ddi->list); | ||
233 | kfree(dsim_ddi); | ||
234 | } | ||
235 | |||
236 | out: | ||
237 | mutex_unlock(&mipi_dsim_lock); | ||
238 | |||
239 | return NULL; | ||
240 | } | ||
241 | |||
242 | int exynos_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv) | ||
243 | { | ||
244 | struct mipi_dsim_ddi *dsim_ddi; | ||
245 | |||
246 | if (!lcd_drv->name) { | ||
247 | pr_err("dsim_lcd_driver name is NULL.\n"); | ||
248 | return -EFAULT; | ||
249 | } | ||
250 | |||
251 | dsim_ddi = exynos_mipi_dsi_find_lcd_device(lcd_drv); | ||
252 | if (!dsim_ddi) { | ||
253 | pr_err("mipi_dsim_ddi object not found.\n"); | ||
254 | return -EFAULT; | ||
255 | } | ||
256 | |||
257 | dsim_ddi->dsim_lcd_drv = lcd_drv; | ||
258 | |||
259 | pr_info("registered panel driver(%s) to mipi-dsi driver.\n", | ||
260 | lcd_drv->name); | ||
261 | |||
262 | return 0; | ||
263 | |||
264 | } | ||
265 | |||
266 | struct mipi_dsim_ddi *exynos_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim, | ||
267 | const char *name) | ||
268 | { | ||
269 | struct mipi_dsim_ddi *dsim_ddi, *next; | ||
270 | struct mipi_dsim_lcd_driver *lcd_drv; | ||
271 | struct mipi_dsim_lcd_device *lcd_dev; | ||
272 | int ret; | ||
273 | |||
274 | mutex_lock(&dsim->lock); | ||
275 | |||
276 | list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) { | ||
277 | lcd_drv = dsim_ddi->dsim_lcd_drv; | ||
278 | lcd_dev = dsim_ddi->dsim_lcd_dev; | ||
279 | if (!lcd_drv || !lcd_dev || | ||
280 | (dsim->id != dsim_ddi->bus_id)) | ||
281 | continue; | ||
282 | |||
283 | dev_dbg(dsim->dev, "lcd_drv->id = %d, lcd_dev->id = %d\n", | ||
284 | lcd_drv->id, lcd_dev->id); | ||
285 | dev_dbg(dsim->dev, "lcd_dev->bus_id = %d, dsim->id = %d\n", | ||
286 | lcd_dev->bus_id, dsim->id); | ||
287 | |||
288 | if ((strcmp(lcd_drv->name, name) == 0)) { | ||
289 | lcd_dev->master = dsim; | ||
290 | |||
291 | lcd_dev->dev.parent = dsim->dev; | ||
292 | dev_set_name(&lcd_dev->dev, "%s", lcd_drv->name); | ||
293 | |||
294 | ret = device_register(&lcd_dev->dev); | ||
295 | if (ret < 0) { | ||
296 | dev_err(dsim->dev, | ||
297 | "can't register %s, status %d\n", | ||
298 | dev_name(&lcd_dev->dev), ret); | ||
299 | mutex_unlock(&dsim->lock); | ||
300 | |||
301 | return NULL; | ||
302 | } | ||
303 | |||
304 | dsim->dsim_lcd_dev = lcd_dev; | ||
305 | dsim->dsim_lcd_drv = lcd_drv; | ||
306 | |||
307 | mutex_unlock(&dsim->lock); | ||
308 | |||
309 | return dsim_ddi; | ||
310 | } | ||
311 | } | ||
312 | |||
313 | mutex_unlock(&dsim->lock); | ||
314 | |||
315 | return NULL; | ||
316 | } | ||
317 | |||
318 | /* define MIPI-DSI Master operations. */ | ||
319 | static struct mipi_dsim_master_ops master_ops = { | ||
320 | .cmd_read = exynos_mipi_dsi_rd_data, | ||
321 | .cmd_write = exynos_mipi_dsi_wr_data, | ||
322 | .get_dsim_frame_done = exynos_mipi_dsi_get_frame_done_status, | ||
323 | .clear_dsim_frame_done = exynos_mipi_dsi_clear_frame_done, | ||
324 | .set_early_blank_mode = exynos_mipi_dsi_early_blank_mode, | ||
325 | .set_blank_mode = exynos_mipi_dsi_blank_mode, | ||
326 | }; | ||
327 | |||
328 | static int exynos_mipi_dsi_probe(struct platform_device *pdev) | ||
329 | { | ||
330 | struct resource *res; | ||
331 | struct mipi_dsim_device *dsim; | ||
332 | struct mipi_dsim_config *dsim_config; | ||
333 | struct mipi_dsim_platform_data *dsim_pd; | ||
334 | struct mipi_dsim_ddi *dsim_ddi; | ||
335 | int ret = -EINVAL; | ||
336 | |||
337 | dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL); | ||
338 | if (!dsim) { | ||
339 | dev_err(&pdev->dev, "failed to allocate dsim object.\n"); | ||
340 | return -ENOMEM; | ||
341 | } | ||
342 | |||
343 | dsim->pd = to_dsim_plat(pdev); | ||
344 | dsim->dev = &pdev->dev; | ||
345 | dsim->id = pdev->id; | ||
346 | |||
347 | /* get mipi_dsim_platform_data. */ | ||
348 | dsim_pd = (struct mipi_dsim_platform_data *)dsim->pd; | ||
349 | if (dsim_pd == NULL) { | ||
350 | dev_err(&pdev->dev, "failed to get platform data for dsim.\n"); | ||
351 | goto err_clock_get; | ||
352 | } | ||
353 | /* get mipi_dsim_config. */ | ||
354 | dsim_config = dsim_pd->dsim_config; | ||
355 | if (dsim_config == NULL) { | ||
356 | dev_err(&pdev->dev, "failed to get dsim config data.\n"); | ||
357 | goto err_clock_get; | ||
358 | } | ||
359 | |||
360 | dsim->dsim_config = dsim_config; | ||
361 | dsim->master_ops = &master_ops; | ||
362 | |||
363 | mutex_init(&dsim->lock); | ||
364 | |||
365 | ret = regulator_bulk_get(&pdev->dev, ARRAY_SIZE(supplies), supplies); | ||
366 | if (ret) { | ||
367 | dev_err(&pdev->dev, "Failed to get regulators: %d\n", ret); | ||
368 | goto err_clock_get; | ||
369 | } | ||
370 | |||
371 | dsim->clock = clk_get(&pdev->dev, "dsim0"); | ||
372 | if (IS_ERR(dsim->clock)) { | ||
373 | dev_err(&pdev->dev, "failed to get dsim clock source\n"); | ||
374 | goto err_clock_get; | ||
375 | } | ||
376 | |||
377 | clk_enable(dsim->clock); | ||
378 | |||
379 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
380 | if (!res) { | ||
381 | dev_err(&pdev->dev, "failed to get io memory region\n"); | ||
382 | goto err_platform_get; | ||
383 | } | ||
384 | |||
385 | dsim->res = request_mem_region(res->start, resource_size(res), | ||
386 | dev_name(&pdev->dev)); | ||
387 | if (!dsim->res) { | ||
388 | dev_err(&pdev->dev, "failed to request io memory region\n"); | ||
389 | ret = -ENOMEM; | ||
390 | goto err_mem_region; | ||
391 | } | ||
392 | |||
393 | dsim->reg_base = ioremap(res->start, resource_size(res)); | ||
394 | if (!dsim->reg_base) { | ||
395 | dev_err(&pdev->dev, "failed to remap io region\n"); | ||
396 | ret = -ENOMEM; | ||
397 | goto err_ioremap; | ||
398 | } | ||
399 | |||
400 | mutex_init(&dsim->lock); | ||
401 | |||
402 | /* bind lcd ddi matched with panel name. */ | ||
403 | dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name); | ||
404 | if (!dsim_ddi) { | ||
405 | dev_err(&pdev->dev, "mipi_dsim_ddi object not found.\n"); | ||
406 | goto err_bind; | ||
407 | } | ||
408 | |||
409 | dsim->irq = platform_get_irq(pdev, 0); | ||
410 | if (dsim->irq < 0) { | ||
411 | dev_err(&pdev->dev, "failed to request dsim irq resource\n"); | ||
412 | ret = -EINVAL; | ||
413 | goto err_platform_get_irq; | ||
414 | } | ||
415 | |||
416 | ret = request_irq(dsim->irq, exynos_mipi_dsi_interrupt_handler, | ||
417 | IRQF_SHARED, pdev->name, dsim); | ||
418 | if (ret != 0) { | ||
419 | dev_err(&pdev->dev, "failed to request dsim irq\n"); | ||
420 | ret = -EINVAL; | ||
421 | goto err_bind; | ||
422 | } | ||
423 | |||
424 | init_completion(&dsim_wr_comp); | ||
425 | init_completion(&dsim_rd_comp); | ||
426 | |||
427 | /* enable interrupt */ | ||
428 | exynos_mipi_dsi_init_interrupt(dsim); | ||
429 | |||
430 | /* initialize mipi-dsi client(lcd panel). */ | ||
431 | if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->probe) | ||
432 | dsim_ddi->dsim_lcd_drv->probe(dsim_ddi->dsim_lcd_dev); | ||
433 | |||
434 | /* in case that mipi got enabled at bootloader. */ | ||
435 | if (dsim_pd->enabled) | ||
436 | goto out; | ||
437 | |||
438 | /* lcd panel power on. */ | ||
439 | if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->power_on) | ||
440 | dsim_ddi->dsim_lcd_drv->power_on(dsim_ddi->dsim_lcd_dev, 1); | ||
441 | |||
442 | exynos_mipi_regulator_enable(dsim); | ||
443 | |||
444 | /* enable MIPI-DSI PHY. */ | ||
445 | if (dsim->pd->phy_enable) | ||
446 | dsim->pd->phy_enable(pdev, true); | ||
447 | |||
448 | exynos_mipi_update_cfg(dsim); | ||
449 | |||
450 | /* set lcd panel sequence commands. */ | ||
451 | if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->set_sequence) | ||
452 | dsim_ddi->dsim_lcd_drv->set_sequence(dsim_ddi->dsim_lcd_dev); | ||
453 | |||
454 | dsim->suspended = false; | ||
455 | |||
456 | out: | ||
457 | platform_set_drvdata(pdev, dsim); | ||
458 | |||
459 | dev_dbg(&pdev->dev, "mipi-dsi driver(%s mode) has been probed.\n", | ||
460 | (dsim_config->e_interface == DSIM_COMMAND) ? | ||
461 | "CPU" : "RGB"); | ||
462 | |||
463 | return 0; | ||
464 | |||
465 | err_bind: | ||
466 | iounmap(dsim->reg_base); | ||
467 | |||
468 | err_ioremap: | ||
469 | release_mem_region(dsim->res->start, resource_size(dsim->res)); | ||
470 | |||
471 | err_mem_region: | ||
472 | release_resource(dsim->res); | ||
473 | |||
474 | err_platform_get: | ||
475 | clk_disable(dsim->clock); | ||
476 | clk_put(dsim->clock); | ||
477 | err_clock_get: | ||
478 | kfree(dsim); | ||
479 | |||
480 | err_platform_get_irq: | ||
481 | return ret; | ||
482 | } | ||
483 | |||
484 | static int __devexit exynos_mipi_dsi_remove(struct platform_device *pdev) | ||
485 | { | ||
486 | struct mipi_dsim_device *dsim = platform_get_drvdata(pdev); | ||
487 | struct mipi_dsim_ddi *dsim_ddi, *next; | ||
488 | struct mipi_dsim_lcd_driver *dsim_lcd_drv; | ||
489 | |||
490 | iounmap(dsim->reg_base); | ||
491 | |||
492 | clk_disable(dsim->clock); | ||
493 | clk_put(dsim->clock); | ||
494 | |||
495 | release_resource(dsim->res); | ||
496 | release_mem_region(dsim->res->start, resource_size(dsim->res)); | ||
497 | |||
498 | list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) { | ||
499 | if (dsim_ddi) { | ||
500 | if (dsim->id != dsim_ddi->bus_id) | ||
501 | continue; | ||
502 | |||
503 | dsim_lcd_drv = dsim_ddi->dsim_lcd_drv; | ||
504 | |||
505 | if (dsim_lcd_drv->remove) | ||
506 | dsim_lcd_drv->remove(dsim_ddi->dsim_lcd_dev); | ||
507 | |||
508 | kfree(dsim_ddi); | ||
509 | } | ||
510 | } | ||
511 | |||
512 | regulator_bulk_free(ARRAY_SIZE(supplies), supplies); | ||
513 | kfree(dsim); | ||
514 | |||
515 | return 0; | ||
516 | } | ||
517 | |||
518 | #ifdef CONFIG_PM | ||
519 | static int exynos_mipi_dsi_suspend(struct platform_device *pdev, | ||
520 | pm_message_t state) | ||
521 | { | ||
522 | struct mipi_dsim_device *dsim = platform_get_drvdata(pdev); | ||
523 | struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv; | ||
524 | struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev; | ||
525 | |||
526 | disable_irq(dsim->irq); | ||
527 | |||
528 | if (dsim->suspended) | ||
529 | return 0; | ||
530 | |||
531 | if (client_drv && client_drv->suspend) | ||
532 | client_drv->suspend(client_dev); | ||
533 | |||
534 | /* enable MIPI-DSI PHY. */ | ||
535 | if (dsim->pd->phy_enable) | ||
536 | dsim->pd->phy_enable(pdev, false); | ||
537 | |||
538 | clk_disable(dsim->clock); | ||
539 | |||
540 | exynos_mipi_regulator_disable(dsim); | ||
541 | |||
542 | dsim->suspended = true; | ||
543 | |||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | static int exynos_mipi_dsi_resume(struct platform_device *pdev) | ||
548 | { | ||
549 | struct mipi_dsim_device *dsim = platform_get_drvdata(pdev); | ||
550 | struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv; | ||
551 | struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev; | ||
552 | |||
553 | enable_irq(dsim->irq); | ||
554 | |||
555 | if (!dsim->suspended) | ||
556 | return 0; | ||
557 | |||
558 | /* lcd panel power on. */ | ||
559 | if (client_drv && client_drv->power_on) | ||
560 | client_drv->power_on(client_dev, 1); | ||
561 | |||
562 | exynos_mipi_regulator_enable(dsim); | ||
563 | |||
564 | /* enable MIPI-DSI PHY. */ | ||
565 | if (dsim->pd->phy_enable) | ||
566 | dsim->pd->phy_enable(pdev, true); | ||
567 | |||
568 | clk_enable(dsim->clock); | ||
569 | |||
570 | exynos_mipi_update_cfg(dsim); | ||
571 | |||
572 | /* set lcd panel sequence commands. */ | ||
573 | if (client_drv && client_drv->set_sequence) | ||
574 | client_drv->set_sequence(client_dev); | ||
575 | |||
576 | dsim->suspended = false; | ||
577 | |||
578 | return 0; | ||
579 | } | ||
580 | #else | ||
581 | #define exynos_mipi_dsi_suspend NULL | ||
582 | #define exynos_mipi_dsi_resume NULL | ||
583 | #endif | ||
584 | |||
585 | static struct platform_driver exynos_mipi_dsi_driver = { | ||
586 | .probe = exynos_mipi_dsi_probe, | ||
587 | .remove = __devexit_p(exynos_mipi_dsi_remove), | ||
588 | .suspend = exynos_mipi_dsi_suspend, | ||
589 | .resume = exynos_mipi_dsi_resume, | ||
590 | .driver = { | ||
591 | .name = "exynos-mipi-dsim", | ||
592 | .owner = THIS_MODULE, | ||
593 | }, | ||
594 | }; | ||
595 | |||
596 | module_platform_driver(exynos_mipi_dsi_driver); | ||
597 | |||
598 | MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>"); | ||
599 | MODULE_DESCRIPTION("Samusung SoC MIPI-DSI driver"); | ||
600 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/exynos/exynos_mipi_dsi_common.c b/drivers/video/exynos/exynos_mipi_dsi_common.c new file mode 100644 index 000000000000..14909c1d3832 --- /dev/null +++ b/drivers/video/exynos/exynos_mipi_dsi_common.c | |||
@@ -0,0 +1,896 @@ | |||
1 | /* linux/drivers/video/exynos/exynos_mipi_dsi_common.c | ||
2 | * | ||
3 | * Samsung SoC MIPI-DSI common driver. | ||
4 | * | ||
5 | * Copyright (c) 2012 Samsung Electronics Co., Ltd | ||
6 | * | ||
7 | * InKi Dae, <inki.dae@samsung.com> | ||
8 | * Donghwa Lee, <dh09.lee@samsung.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/errno.h> | ||
18 | #include <linux/mutex.h> | ||
19 | #include <linux/wait.h> | ||
20 | #include <linux/fs.h> | ||
21 | #include <linux/mm.h> | ||
22 | #include <linux/fb.h> | ||
23 | #include <linux/ctype.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <linux/memory.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/kthread.h> | ||
29 | |||
30 | #include <video/mipi_display.h> | ||
31 | #include <video/exynos_mipi_dsim.h> | ||
32 | |||
33 | #include <mach/map.h> | ||
34 | |||
35 | #include "exynos_mipi_dsi_regs.h" | ||
36 | #include "exynos_mipi_dsi_lowlevel.h" | ||
37 | #include "exynos_mipi_dsi_common.h" | ||
38 | |||
39 | #define MIPI_FIFO_TIMEOUT msecs_to_jiffies(250) | ||
40 | #define MIPI_RX_FIFO_READ_DONE 0x30800002 | ||
41 | #define MIPI_MAX_RX_FIFO 20 | ||
42 | #define MHZ (1000 * 1000) | ||
43 | #define FIN_HZ (24 * MHZ) | ||
44 | |||
45 | #define DFIN_PLL_MIN_HZ (6 * MHZ) | ||
46 | #define DFIN_PLL_MAX_HZ (12 * MHZ) | ||
47 | |||
48 | #define DFVCO_MIN_HZ (500 * MHZ) | ||
49 | #define DFVCO_MAX_HZ (1000 * MHZ) | ||
50 | |||
51 | #define TRY_GET_FIFO_TIMEOUT (5000 * 2) | ||
52 | #define TRY_FIFO_CLEAR (10) | ||
53 | |||
54 | /* MIPI-DSIM status types. */ | ||
55 | enum { | ||
56 | DSIM_STATE_INIT, /* should be initialized. */ | ||
57 | DSIM_STATE_STOP, /* CPU and LCDC are LP mode. */ | ||
58 | DSIM_STATE_HSCLKEN, /* HS clock was enabled. */ | ||
59 | DSIM_STATE_ULPS | ||
60 | }; | ||
61 | |||
62 | /* define DSI lane types. */ | ||
63 | enum { | ||
64 | DSIM_LANE_CLOCK = (1 << 0), | ||
65 | DSIM_LANE_DATA0 = (1 << 1), | ||
66 | DSIM_LANE_DATA1 = (1 << 2), | ||
67 | DSIM_LANE_DATA2 = (1 << 3), | ||
68 | DSIM_LANE_DATA3 = (1 << 4) | ||
69 | }; | ||
70 | |||
71 | static unsigned int dpll_table[15] = { | ||
72 | 100, 120, 170, 220, 270, | ||
73 | 320, 390, 450, 510, 560, | ||
74 | 640, 690, 770, 870, 950 | ||
75 | }; | ||
76 | |||
77 | irqreturn_t exynos_mipi_dsi_interrupt_handler(int irq, void *dev_id) | ||
78 | { | ||
79 | unsigned int intsrc = 0; | ||
80 | unsigned int intmsk = 0; | ||
81 | struct mipi_dsim_device *dsim = NULL; | ||
82 | |||
83 | dsim = dev_id; | ||
84 | if (!dsim) { | ||
85 | dev_dbg(dsim->dev, KERN_ERR "%s:error: wrong parameter\n", | ||
86 | __func__); | ||
87 | return IRQ_HANDLED; | ||
88 | } | ||
89 | |||
90 | intsrc = exynos_mipi_dsi_read_interrupt(dsim); | ||
91 | intmsk = exynos_mipi_dsi_read_interrupt_mask(dsim); | ||
92 | |||
93 | intmsk = ~(intmsk) & intsrc; | ||
94 | |||
95 | switch (intmsk) { | ||
96 | case INTMSK_RX_DONE: | ||
97 | complete(&dsim_rd_comp); | ||
98 | dev_dbg(dsim->dev, "MIPI INTMSK_RX_DONE\n"); | ||
99 | break; | ||
100 | case INTMSK_FIFO_EMPTY: | ||
101 | complete(&dsim_wr_comp); | ||
102 | dev_dbg(dsim->dev, "MIPI INTMSK_FIFO_EMPTY\n"); | ||
103 | break; | ||
104 | default: | ||
105 | break; | ||
106 | } | ||
107 | |||
108 | exynos_mipi_dsi_clear_interrupt(dsim, intmsk); | ||
109 | |||
110 | return IRQ_HANDLED; | ||
111 | } | ||
112 | |||
113 | /* | ||
114 | * write long packet to mipi dsi slave | ||
115 | * @dsim: mipi dsim device structure. | ||
116 | * @data0: packet data to send. | ||
117 | * @data1: size of packet data | ||
118 | */ | ||
119 | static void exynos_mipi_dsi_long_data_wr(struct mipi_dsim_device *dsim, | ||
120 | const unsigned char *data0, unsigned int data_size) | ||
121 | { | ||
122 | unsigned int data_cnt = 0, payload = 0; | ||
123 | |||
124 | /* in case that data count is more then 4 */ | ||
125 | for (data_cnt = 0; data_cnt < data_size; data_cnt += 4) { | ||
126 | /* | ||
127 | * after sending 4bytes per one time, | ||
128 | * send remainder data less then 4. | ||
129 | */ | ||
130 | if ((data_size - data_cnt) < 4) { | ||
131 | if ((data_size - data_cnt) == 3) { | ||
132 | payload = data0[data_cnt] | | ||
133 | data0[data_cnt + 1] << 8 | | ||
134 | data0[data_cnt + 2] << 16; | ||
135 | dev_dbg(dsim->dev, "count = 3 payload = %x, %x %x %x\n", | ||
136 | payload, data0[data_cnt], | ||
137 | data0[data_cnt + 1], | ||
138 | data0[data_cnt + 2]); | ||
139 | } else if ((data_size - data_cnt) == 2) { | ||
140 | payload = data0[data_cnt] | | ||
141 | data0[data_cnt + 1] << 8; | ||
142 | dev_dbg(dsim->dev, | ||
143 | "count = 2 payload = %x, %x %x\n", payload, | ||
144 | data0[data_cnt], | ||
145 | data0[data_cnt + 1]); | ||
146 | } else if ((data_size - data_cnt) == 1) { | ||
147 | payload = data0[data_cnt]; | ||
148 | } | ||
149 | |||
150 | exynos_mipi_dsi_wr_tx_data(dsim, payload); | ||
151 | /* send 4bytes per one time. */ | ||
152 | } else { | ||
153 | payload = data0[data_cnt] | | ||
154 | data0[data_cnt + 1] << 8 | | ||
155 | data0[data_cnt + 2] << 16 | | ||
156 | data0[data_cnt + 3] << 24; | ||
157 | |||
158 | dev_dbg(dsim->dev, | ||
159 | "count = 4 payload = %x, %x %x %x %x\n", | ||
160 | payload, *(u8 *)(data0 + data_cnt), | ||
161 | data0[data_cnt + 1], | ||
162 | data0[data_cnt + 2], | ||
163 | data0[data_cnt + 3]); | ||
164 | |||
165 | exynos_mipi_dsi_wr_tx_data(dsim, payload); | ||
166 | } | ||
167 | } | ||
168 | } | ||
169 | |||
170 | int exynos_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id, | ||
171 | const unsigned char *data0, unsigned int data_size) | ||
172 | { | ||
173 | unsigned int check_rx_ack = 0; | ||
174 | |||
175 | if (dsim->state == DSIM_STATE_ULPS) { | ||
176 | dev_err(dsim->dev, "state is ULPS.\n"); | ||
177 | |||
178 | return -EINVAL; | ||
179 | } | ||
180 | |||
181 | /* FIXME!!! why does it need this delay? */ | ||
182 | msleep(20); | ||
183 | |||
184 | mutex_lock(&dsim->lock); | ||
185 | |||
186 | switch (data_id) { | ||
187 | /* short packet types of packet types for command. */ | ||
188 | case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM: | ||
189 | case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM: | ||
190 | case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: | ||
191 | case MIPI_DSI_DCS_SHORT_WRITE: | ||
192 | case MIPI_DSI_DCS_SHORT_WRITE_PARAM: | ||
193 | case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE: | ||
194 | exynos_mipi_dsi_wr_tx_header(dsim, data_id, data0[0], data0[1]); | ||
195 | if (check_rx_ack) { | ||
196 | /* process response func should be implemented */ | ||
197 | mutex_unlock(&dsim->lock); | ||
198 | return 0; | ||
199 | } else { | ||
200 | mutex_unlock(&dsim->lock); | ||
201 | return -EINVAL; | ||
202 | } | ||
203 | |||
204 | /* general command */ | ||
205 | case MIPI_DSI_COLOR_MODE_OFF: | ||
206 | case MIPI_DSI_COLOR_MODE_ON: | ||
207 | case MIPI_DSI_SHUTDOWN_PERIPHERAL: | ||
208 | case MIPI_DSI_TURN_ON_PERIPHERAL: | ||
209 | exynos_mipi_dsi_wr_tx_header(dsim, data_id, data0[0], data0[1]); | ||
210 | if (check_rx_ack) { | ||
211 | /* process response func should be implemented. */ | ||
212 | mutex_unlock(&dsim->lock); | ||
213 | return 0; | ||
214 | } else { | ||
215 | mutex_unlock(&dsim->lock); | ||
216 | return -EINVAL; | ||
217 | } | ||
218 | |||
219 | /* packet types for video data */ | ||
220 | case MIPI_DSI_V_SYNC_START: | ||
221 | case MIPI_DSI_V_SYNC_END: | ||
222 | case MIPI_DSI_H_SYNC_START: | ||
223 | case MIPI_DSI_H_SYNC_END: | ||
224 | case MIPI_DSI_END_OF_TRANSMISSION: | ||
225 | mutex_unlock(&dsim->lock); | ||
226 | return 0; | ||
227 | |||
228 | /* long packet type and null packet */ | ||
229 | case MIPI_DSI_NULL_PACKET: | ||
230 | case MIPI_DSI_BLANKING_PACKET: | ||
231 | mutex_unlock(&dsim->lock); | ||
232 | return 0; | ||
233 | case MIPI_DSI_GENERIC_LONG_WRITE: | ||
234 | case MIPI_DSI_DCS_LONG_WRITE: | ||
235 | { | ||
236 | unsigned int size, payload = 0; | ||
237 | INIT_COMPLETION(dsim_wr_comp); | ||
238 | |||
239 | size = data_size * 4; | ||
240 | |||
241 | /* if data count is less then 4, then send 3bytes data. */ | ||
242 | if (data_size < 4) { | ||
243 | payload = data0[0] | | ||
244 | data0[1] << 8 | | ||
245 | data0[2] << 16; | ||
246 | |||
247 | exynos_mipi_dsi_wr_tx_data(dsim, payload); | ||
248 | |||
249 | dev_dbg(dsim->dev, "count = %d payload = %x,%x %x %x\n", | ||
250 | data_size, payload, data0[0], | ||
251 | data0[1], data0[2]); | ||
252 | |||
253 | /* in case that data count is more then 4 */ | ||
254 | } else | ||
255 | exynos_mipi_dsi_long_data_wr(dsim, data0, data_size); | ||
256 | |||
257 | /* put data into header fifo */ | ||
258 | exynos_mipi_dsi_wr_tx_header(dsim, data_id, data_size & 0xff, | ||
259 | (data_size & 0xff00) >> 8); | ||
260 | |||
261 | if (!wait_for_completion_interruptible_timeout(&dsim_wr_comp, | ||
262 | MIPI_FIFO_TIMEOUT)) { | ||
263 | dev_warn(dsim->dev, "command write timeout.\n"); | ||
264 | mutex_unlock(&dsim->lock); | ||
265 | return -EAGAIN; | ||
266 | } | ||
267 | |||
268 | if (check_rx_ack) { | ||
269 | /* process response func should be implemented. */ | ||
270 | mutex_unlock(&dsim->lock); | ||
271 | return 0; | ||
272 | } else { | ||
273 | mutex_unlock(&dsim->lock); | ||
274 | return -EINVAL; | ||
275 | } | ||
276 | } | ||
277 | |||
278 | /* packet typo for video data */ | ||
279 | case MIPI_DSI_PACKED_PIXEL_STREAM_16: | ||
280 | case MIPI_DSI_PACKED_PIXEL_STREAM_18: | ||
281 | case MIPI_DSI_PIXEL_STREAM_3BYTE_18: | ||
282 | case MIPI_DSI_PACKED_PIXEL_STREAM_24: | ||
283 | if (check_rx_ack) { | ||
284 | /* process response func should be implemented. */ | ||
285 | mutex_unlock(&dsim->lock); | ||
286 | return 0; | ||
287 | } else { | ||
288 | mutex_unlock(&dsim->lock); | ||
289 | return -EINVAL; | ||
290 | } | ||
291 | default: | ||
292 | dev_warn(dsim->dev, | ||
293 | "data id %x is not supported current DSI spec.\n", | ||
294 | data_id); | ||
295 | |||
296 | mutex_unlock(&dsim->lock); | ||
297 | return -EINVAL; | ||
298 | } | ||
299 | |||
300 | mutex_unlock(&dsim->lock); | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | static unsigned int exynos_mipi_dsi_long_data_rd(struct mipi_dsim_device *dsim, | ||
305 | unsigned int req_size, unsigned int rx_data, u8 *rx_buf) | ||
306 | { | ||
307 | unsigned int rcv_pkt, i, j; | ||
308 | u16 rxsize; | ||
309 | |||
310 | /* for long packet */ | ||
311 | rxsize = (u16)((rx_data & 0x00ffff00) >> 8); | ||
312 | dev_dbg(dsim->dev, "mipi dsi rx size : %d\n", rxsize); | ||
313 | if (rxsize != req_size) { | ||
314 | dev_dbg(dsim->dev, | ||
315 | "received size mismatch received: %d, requested: %d\n", | ||
316 | rxsize, req_size); | ||
317 | goto err; | ||
318 | } | ||
319 | |||
320 | for (i = 0; i < (rxsize >> 2); i++) { | ||
321 | rcv_pkt = exynos_mipi_dsi_rd_rx_fifo(dsim); | ||
322 | dev_dbg(dsim->dev, "received pkt : %08x\n", rcv_pkt); | ||
323 | for (j = 0; j < 4; j++) { | ||
324 | rx_buf[(i * 4) + j] = | ||
325 | (u8)(rcv_pkt >> (j * 8)) & 0xff; | ||
326 | dev_dbg(dsim->dev, "received value : %02x\n", | ||
327 | (rcv_pkt >> (j * 8)) & 0xff); | ||
328 | } | ||
329 | } | ||
330 | if (rxsize % 4) { | ||
331 | rcv_pkt = exynos_mipi_dsi_rd_rx_fifo(dsim); | ||
332 | dev_dbg(dsim->dev, "received pkt : %08x\n", rcv_pkt); | ||
333 | for (j = 0; j < (rxsize % 4); j++) { | ||
334 | rx_buf[(i * 4) + j] = | ||
335 | (u8)(rcv_pkt >> (j * 8)) & 0xff; | ||
336 | dev_dbg(dsim->dev, "received value : %02x\n", | ||
337 | (rcv_pkt >> (j * 8)) & 0xff); | ||
338 | } | ||
339 | } | ||
340 | |||
341 | return rxsize; | ||
342 | |||
343 | err: | ||
344 | return -EINVAL; | ||
345 | } | ||
346 | |||
347 | static unsigned int exynos_mipi_dsi_response_size(unsigned int req_size) | ||
348 | { | ||
349 | switch (req_size) { | ||
350 | case 1: | ||
351 | return MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE; | ||
352 | case 2: | ||
353 | return MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE; | ||
354 | default: | ||
355 | return MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE; | ||
356 | } | ||
357 | } | ||
358 | |||
359 | int exynos_mipi_dsi_rd_data(struct mipi_dsim_device *dsim, unsigned int data_id, | ||
360 | unsigned int data0, unsigned int req_size, u8 *rx_buf) | ||
361 | { | ||
362 | unsigned int rx_data, rcv_pkt, i; | ||
363 | u8 response = 0; | ||
364 | u16 rxsize; | ||
365 | |||
366 | if (dsim->state == DSIM_STATE_ULPS) { | ||
367 | dev_err(dsim->dev, "state is ULPS.\n"); | ||
368 | |||
369 | return -EINVAL; | ||
370 | } | ||
371 | |||
372 | /* FIXME!!! */ | ||
373 | msleep(20); | ||
374 | |||
375 | mutex_lock(&dsim->lock); | ||
376 | INIT_COMPLETION(dsim_rd_comp); | ||
377 | exynos_mipi_dsi_rd_tx_header(dsim, | ||
378 | MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, req_size); | ||
379 | |||
380 | response = exynos_mipi_dsi_response_size(req_size); | ||
381 | |||
382 | switch (data_id) { | ||
383 | case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM: | ||
384 | case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM: | ||
385 | case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM: | ||
386 | case MIPI_DSI_DCS_READ: | ||
387 | exynos_mipi_dsi_rd_tx_header(dsim, | ||
388 | data_id, data0); | ||
389 | /* process response func should be implemented. */ | ||
390 | break; | ||
391 | default: | ||
392 | dev_warn(dsim->dev, | ||
393 | "data id %x is not supported current DSI spec.\n", | ||
394 | data_id); | ||
395 | |||
396 | return -EINVAL; | ||
397 | } | ||
398 | |||
399 | if (!wait_for_completion_interruptible_timeout(&dsim_rd_comp, | ||
400 | MIPI_FIFO_TIMEOUT)) { | ||
401 | pr_err("RX done interrupt timeout\n"); | ||
402 | mutex_unlock(&dsim->lock); | ||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | msleep(20); | ||
407 | |||
408 | rx_data = exynos_mipi_dsi_rd_rx_fifo(dsim); | ||
409 | |||
410 | if ((u8)(rx_data & 0xff) != response) { | ||
411 | printk(KERN_ERR | ||
412 | "mipi dsi wrong response rx_data : %x, response:%x\n", | ||
413 | rx_data, response); | ||
414 | goto clear_rx_fifo; | ||
415 | } | ||
416 | |||
417 | if (req_size <= 2) { | ||
418 | /* for short packet */ | ||
419 | for (i = 0; i < req_size; i++) | ||
420 | rx_buf[i] = (rx_data >> (8 + (i * 8))) & 0xff; | ||
421 | rxsize = req_size; | ||
422 | } else { | ||
423 | /* for long packet */ | ||
424 | rxsize = exynos_mipi_dsi_long_data_rd(dsim, req_size, rx_data, | ||
425 | rx_buf); | ||
426 | if (rxsize != req_size) | ||
427 | goto clear_rx_fifo; | ||
428 | } | ||
429 | |||
430 | rcv_pkt = exynos_mipi_dsi_rd_rx_fifo(dsim); | ||
431 | |||
432 | msleep(20); | ||
433 | |||
434 | if (rcv_pkt != MIPI_RX_FIFO_READ_DONE) { | ||
435 | dev_info(dsim->dev, | ||
436 | "Can't found RX FIFO READ DONE FLAG : %x\n", rcv_pkt); | ||
437 | goto clear_rx_fifo; | ||
438 | } | ||
439 | |||
440 | mutex_unlock(&dsim->lock); | ||
441 | |||
442 | return rxsize; | ||
443 | |||
444 | clear_rx_fifo: | ||
445 | i = 0; | ||
446 | while (1) { | ||
447 | rcv_pkt = exynos_mipi_dsi_rd_rx_fifo(dsim); | ||
448 | if ((rcv_pkt == MIPI_RX_FIFO_READ_DONE) | ||
449 | || (i > MIPI_MAX_RX_FIFO)) | ||
450 | break; | ||
451 | dev_dbg(dsim->dev, | ||
452 | "mipi dsi clear rx fifo : %08x\n", rcv_pkt); | ||
453 | i++; | ||
454 | } | ||
455 | dev_info(dsim->dev, | ||
456 | "mipi dsi rx done count : %d, rcv_pkt : %08x\n", i, rcv_pkt); | ||
457 | |||
458 | mutex_unlock(&dsim->lock); | ||
459 | |||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | static int exynos_mipi_dsi_pll_on(struct mipi_dsim_device *dsim, | ||
464 | unsigned int enable) | ||
465 | { | ||
466 | int sw_timeout; | ||
467 | |||
468 | if (enable) { | ||
469 | sw_timeout = 1000; | ||
470 | |||
471 | exynos_mipi_dsi_enable_pll(dsim, 1); | ||
472 | while (1) { | ||
473 | sw_timeout--; | ||
474 | if (exynos_mipi_dsi_is_pll_stable(dsim)) | ||
475 | return 0; | ||
476 | if (sw_timeout == 0) | ||
477 | return -EINVAL; | ||
478 | } | ||
479 | } else | ||
480 | exynos_mipi_dsi_enable_pll(dsim, 0); | ||
481 | |||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | static unsigned long exynos_mipi_dsi_change_pll(struct mipi_dsim_device *dsim, | ||
486 | unsigned int pre_divider, unsigned int main_divider, | ||
487 | unsigned int scaler) | ||
488 | { | ||
489 | unsigned long dfin_pll, dfvco, dpll_out; | ||
490 | unsigned int i, freq_band = 0xf; | ||
491 | |||
492 | dfin_pll = (FIN_HZ / pre_divider); | ||
493 | |||
494 | /****************************************************** | ||
495 | * Serial Clock(=ByteClk X 8) FreqBand[3:0] * | ||
496 | ****************************************************** | ||
497 | * ~ 99.99 MHz 0000 | ||
498 | * 100 ~ 119.99 MHz 0001 | ||
499 | * 120 ~ 159.99 MHz 0010 | ||
500 | * 160 ~ 199.99 MHz 0011 | ||
501 | * 200 ~ 239.99 MHz 0100 | ||
502 | * 140 ~ 319.99 MHz 0101 | ||
503 | * 320 ~ 389.99 MHz 0110 | ||
504 | * 390 ~ 449.99 MHz 0111 | ||
505 | * 450 ~ 509.99 MHz 1000 | ||
506 | * 510 ~ 559.99 MHz 1001 | ||
507 | * 560 ~ 639.99 MHz 1010 | ||
508 | * 640 ~ 689.99 MHz 1011 | ||
509 | * 690 ~ 769.99 MHz 1100 | ||
510 | * 770 ~ 869.99 MHz 1101 | ||
511 | * 870 ~ 949.99 MHz 1110 | ||
512 | * 950 ~ 1000 MHz 1111 | ||
513 | ******************************************************/ | ||
514 | if (dfin_pll < DFIN_PLL_MIN_HZ || dfin_pll > DFIN_PLL_MAX_HZ) { | ||
515 | dev_warn(dsim->dev, "fin_pll range should be 6MHz ~ 12MHz\n"); | ||
516 | exynos_mipi_dsi_enable_afc(dsim, 0, 0); | ||
517 | } else { | ||
518 | if (dfin_pll < 7 * MHZ) | ||
519 | exynos_mipi_dsi_enable_afc(dsim, 1, 0x1); | ||
520 | else if (dfin_pll < 8 * MHZ) | ||
521 | exynos_mipi_dsi_enable_afc(dsim, 1, 0x0); | ||
522 | else if (dfin_pll < 9 * MHZ) | ||
523 | exynos_mipi_dsi_enable_afc(dsim, 1, 0x3); | ||
524 | else if (dfin_pll < 10 * MHZ) | ||
525 | exynos_mipi_dsi_enable_afc(dsim, 1, 0x2); | ||
526 | else if (dfin_pll < 11 * MHZ) | ||
527 | exynos_mipi_dsi_enable_afc(dsim, 1, 0x5); | ||
528 | else | ||
529 | exynos_mipi_dsi_enable_afc(dsim, 1, 0x4); | ||
530 | } | ||
531 | |||
532 | dfvco = dfin_pll * main_divider; | ||
533 | dev_dbg(dsim->dev, "dfvco = %lu, dfin_pll = %lu, main_divider = %d\n", | ||
534 | dfvco, dfin_pll, main_divider); | ||
535 | if (dfvco < DFVCO_MIN_HZ || dfvco > DFVCO_MAX_HZ) | ||
536 | dev_warn(dsim->dev, "fvco range should be 500MHz ~ 1000MHz\n"); | ||
537 | |||
538 | dpll_out = dfvco / (1 << scaler); | ||
539 | dev_dbg(dsim->dev, "dpll_out = %lu, dfvco = %lu, scaler = %d\n", | ||
540 | dpll_out, dfvco, scaler); | ||
541 | |||
542 | for (i = 0; i < ARRAY_SIZE(dpll_table); i++) { | ||
543 | if (dpll_out < dpll_table[i] * MHZ) { | ||
544 | freq_band = i; | ||
545 | break; | ||
546 | } | ||
547 | } | ||
548 | |||
549 | dev_dbg(dsim->dev, "freq_band = %d\n", freq_band); | ||
550 | |||
551 | exynos_mipi_dsi_pll_freq(dsim, pre_divider, main_divider, scaler); | ||
552 | |||
553 | exynos_mipi_dsi_hs_zero_ctrl(dsim, 0); | ||
554 | exynos_mipi_dsi_prep_ctrl(dsim, 0); | ||
555 | |||
556 | /* Freq Band */ | ||
557 | exynos_mipi_dsi_pll_freq_band(dsim, freq_band); | ||
558 | |||
559 | /* Stable time */ | ||
560 | exynos_mipi_dsi_pll_stable_time(dsim, dsim->dsim_config->pll_stable_time); | ||
561 | |||
562 | /* Enable PLL */ | ||
563 | dev_dbg(dsim->dev, "FOUT of mipi dphy pll is %luMHz\n", | ||
564 | (dpll_out / MHZ)); | ||
565 | |||
566 | return dpll_out; | ||
567 | } | ||
568 | |||
569 | static int exynos_mipi_dsi_set_clock(struct mipi_dsim_device *dsim, | ||
570 | unsigned int byte_clk_sel, unsigned int enable) | ||
571 | { | ||
572 | unsigned int esc_div; | ||
573 | unsigned long esc_clk_error_rate; | ||
574 | unsigned long hs_clk = 0, byte_clk = 0, escape_clk = 0; | ||
575 | |||
576 | if (enable) { | ||
577 | dsim->e_clk_src = byte_clk_sel; | ||
578 | |||
579 | /* Escape mode clock and byte clock source */ | ||
580 | exynos_mipi_dsi_set_byte_clock_src(dsim, byte_clk_sel); | ||
581 | |||
582 | /* DPHY, DSIM Link : D-PHY clock out */ | ||
583 | if (byte_clk_sel == DSIM_PLL_OUT_DIV8) { | ||
584 | hs_clk = exynos_mipi_dsi_change_pll(dsim, | ||
585 | dsim->dsim_config->p, dsim->dsim_config->m, | ||
586 | dsim->dsim_config->s); | ||
587 | if (hs_clk == 0) { | ||
588 | dev_err(dsim->dev, | ||
589 | "failed to get hs clock.\n"); | ||
590 | return -EINVAL; | ||
591 | } | ||
592 | |||
593 | byte_clk = hs_clk / 8; | ||
594 | exynos_mipi_dsi_enable_pll_bypass(dsim, 0); | ||
595 | exynos_mipi_dsi_pll_on(dsim, 1); | ||
596 | /* DPHY : D-PHY clock out, DSIM link : external clock out */ | ||
597 | } else if (byte_clk_sel == DSIM_EXT_CLK_DIV8) { | ||
598 | dev_warn(dsim->dev, "this project is not support\n"); | ||
599 | dev_warn(dsim->dev, | ||
600 | "external clock source for MIPI DSIM.\n"); | ||
601 | } else if (byte_clk_sel == DSIM_EXT_CLK_BYPASS) { | ||
602 | dev_warn(dsim->dev, "this project is not support\n"); | ||
603 | dev_warn(dsim->dev, | ||
604 | "external clock source for MIPI DSIM\n"); | ||
605 | } | ||
606 | |||
607 | /* escape clock divider */ | ||
608 | esc_div = byte_clk / (dsim->dsim_config->esc_clk); | ||
609 | dev_dbg(dsim->dev, | ||
610 | "esc_div = %d, byte_clk = %lu, esc_clk = %lu\n", | ||
611 | esc_div, byte_clk, dsim->dsim_config->esc_clk); | ||
612 | if ((byte_clk / esc_div) >= (20 * MHZ) || | ||
613 | (byte_clk / esc_div) > | ||
614 | dsim->dsim_config->esc_clk) | ||
615 | esc_div += 1; | ||
616 | |||
617 | escape_clk = byte_clk / esc_div; | ||
618 | dev_dbg(dsim->dev, | ||
619 | "escape_clk = %lu, byte_clk = %lu, esc_div = %d\n", | ||
620 | escape_clk, byte_clk, esc_div); | ||
621 | |||
622 | /* enable escape clock. */ | ||
623 | exynos_mipi_dsi_enable_byte_clock(dsim, 1); | ||
624 | |||
625 | /* enable byte clk and escape clock */ | ||
626 | exynos_mipi_dsi_set_esc_clk_prs(dsim, 1, esc_div); | ||
627 | /* escape clock on lane */ | ||
628 | exynos_mipi_dsi_enable_esc_clk_on_lane(dsim, | ||
629 | (DSIM_LANE_CLOCK | dsim->data_lane), 1); | ||
630 | |||
631 | dev_dbg(dsim->dev, "byte clock is %luMHz\n", | ||
632 | (byte_clk / MHZ)); | ||
633 | dev_dbg(dsim->dev, "escape clock that user's need is %lu\n", | ||
634 | (dsim->dsim_config->esc_clk / MHZ)); | ||
635 | dev_dbg(dsim->dev, "escape clock divider is %x\n", esc_div); | ||
636 | dev_dbg(dsim->dev, "escape clock is %luMHz\n", | ||
637 | ((byte_clk / esc_div) / MHZ)); | ||
638 | |||
639 | if ((byte_clk / esc_div) > escape_clk) { | ||
640 | esc_clk_error_rate = escape_clk / | ||
641 | (byte_clk / esc_div); | ||
642 | dev_warn(dsim->dev, "error rate is %lu over.\n", | ||
643 | (esc_clk_error_rate / 100)); | ||
644 | } else if ((byte_clk / esc_div) < (escape_clk)) { | ||
645 | esc_clk_error_rate = (byte_clk / esc_div) / | ||
646 | escape_clk; | ||
647 | dev_warn(dsim->dev, "error rate is %lu under.\n", | ||
648 | (esc_clk_error_rate / 100)); | ||
649 | } | ||
650 | } else { | ||
651 | exynos_mipi_dsi_enable_esc_clk_on_lane(dsim, | ||
652 | (DSIM_LANE_CLOCK | dsim->data_lane), 0); | ||
653 | exynos_mipi_dsi_set_esc_clk_prs(dsim, 0, 0); | ||
654 | |||
655 | /* disable escape clock. */ | ||
656 | exynos_mipi_dsi_enable_byte_clock(dsim, 0); | ||
657 | |||
658 | if (byte_clk_sel == DSIM_PLL_OUT_DIV8) | ||
659 | exynos_mipi_dsi_pll_on(dsim, 0); | ||
660 | } | ||
661 | |||
662 | return 0; | ||
663 | } | ||
664 | |||
665 | int exynos_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim) | ||
666 | { | ||
667 | dsim->state = DSIM_STATE_INIT; | ||
668 | |||
669 | switch (dsim->dsim_config->e_no_data_lane) { | ||
670 | case DSIM_DATA_LANE_1: | ||
671 | dsim->data_lane = DSIM_LANE_DATA0; | ||
672 | break; | ||
673 | case DSIM_DATA_LANE_2: | ||
674 | dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1; | ||
675 | break; | ||
676 | case DSIM_DATA_LANE_3: | ||
677 | dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 | | ||
678 | DSIM_LANE_DATA2; | ||
679 | break; | ||
680 | case DSIM_DATA_LANE_4: | ||
681 | dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 | | ||
682 | DSIM_LANE_DATA2 | DSIM_LANE_DATA3; | ||
683 | break; | ||
684 | default: | ||
685 | dev_info(dsim->dev, "data lane is invalid.\n"); | ||
686 | return -EINVAL; | ||
687 | }; | ||
688 | |||
689 | exynos_mipi_dsi_sw_reset(dsim); | ||
690 | exynos_mipi_dsi_func_reset(dsim); | ||
691 | |||
692 | exynos_mipi_dsi_dp_dn_swap(dsim, 0); | ||
693 | |||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | void exynos_mipi_dsi_init_interrupt(struct mipi_dsim_device *dsim) | ||
698 | { | ||
699 | unsigned int src = 0; | ||
700 | |||
701 | src = (INTSRC_SFR_FIFO_EMPTY | INTSRC_RX_DATA_DONE); | ||
702 | exynos_mipi_dsi_set_interrupt(dsim, src, 1); | ||
703 | |||
704 | src = 0; | ||
705 | src = ~(INTMSK_RX_DONE | INTMSK_FIFO_EMPTY); | ||
706 | exynos_mipi_dsi_set_interrupt_mask(dsim, src, 1); | ||
707 | } | ||
708 | |||
709 | int exynos_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim, | ||
710 | unsigned int enable) | ||
711 | { | ||
712 | /* enable only frame done interrupt */ | ||
713 | exynos_mipi_dsi_set_interrupt_mask(dsim, INTMSK_FRAME_DONE, enable); | ||
714 | |||
715 | return 0; | ||
716 | } | ||
717 | |||
718 | void exynos_mipi_dsi_stand_by(struct mipi_dsim_device *dsim, | ||
719 | unsigned int enable) | ||
720 | { | ||
721 | |||
722 | /* consider Main display and Sub display. */ | ||
723 | |||
724 | exynos_mipi_dsi_set_main_stand_by(dsim, enable); | ||
725 | } | ||
726 | |||
727 | int exynos_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim, | ||
728 | struct mipi_dsim_config *dsim_config) | ||
729 | { | ||
730 | struct mipi_dsim_platform_data *dsim_pd; | ||
731 | struct fb_videomode *timing; | ||
732 | |||
733 | dsim_pd = (struct mipi_dsim_platform_data *)dsim->pd; | ||
734 | timing = (struct fb_videomode *)dsim_pd->lcd_panel_info; | ||
735 | |||
736 | /* in case of VIDEO MODE (RGB INTERFACE), it sets polarities. */ | ||
737 | if (dsim_config->e_interface == (u32) DSIM_VIDEO) { | ||
738 | if (dsim_config->auto_vertical_cnt == 0) { | ||
739 | exynos_mipi_dsi_set_main_disp_vporch(dsim, | ||
740 | dsim_config->cmd_allow, | ||
741 | timing->upper_margin, | ||
742 | timing->lower_margin); | ||
743 | exynos_mipi_dsi_set_main_disp_hporch(dsim, | ||
744 | timing->left_margin, | ||
745 | timing->right_margin); | ||
746 | exynos_mipi_dsi_set_main_disp_sync_area(dsim, | ||
747 | timing->vsync_len, | ||
748 | timing->hsync_len); | ||
749 | } | ||
750 | } | ||
751 | |||
752 | exynos_mipi_dsi_set_main_disp_resol(dsim, timing->xres, | ||
753 | timing->yres); | ||
754 | |||
755 | exynos_mipi_dsi_display_config(dsim, dsim_config); | ||
756 | |||
757 | dev_info(dsim->dev, "lcd panel ==> width = %d, height = %d\n", | ||
758 | timing->xres, timing->yres); | ||
759 | |||
760 | return 0; | ||
761 | } | ||
762 | |||
763 | int exynos_mipi_dsi_init_link(struct mipi_dsim_device *dsim) | ||
764 | { | ||
765 | unsigned int time_out = 100; | ||
766 | |||
767 | switch (dsim->state) { | ||
768 | case DSIM_STATE_INIT: | ||
769 | exynos_mipi_dsi_init_fifo_pointer(dsim, 0x1f); | ||
770 | |||
771 | /* dsi configuration */ | ||
772 | exynos_mipi_dsi_init_config(dsim); | ||
773 | exynos_mipi_dsi_enable_lane(dsim, DSIM_LANE_CLOCK, 1); | ||
774 | exynos_mipi_dsi_enable_lane(dsim, dsim->data_lane, 1); | ||
775 | |||
776 | /* set clock configuration */ | ||
777 | exynos_mipi_dsi_set_clock(dsim, dsim->dsim_config->e_byte_clk, 1); | ||
778 | |||
779 | /* check clock and data lane state are stop state */ | ||
780 | while (!(exynos_mipi_dsi_is_lane_state(dsim))) { | ||
781 | time_out--; | ||
782 | if (time_out == 0) { | ||
783 | dev_err(dsim->dev, | ||
784 | "DSI Master is not stop state.\n"); | ||
785 | dev_err(dsim->dev, | ||
786 | "Check initialization process\n"); | ||
787 | |||
788 | return -EINVAL; | ||
789 | } | ||
790 | } | ||
791 | if (time_out != 0) { | ||
792 | dev_info(dsim->dev, | ||
793 | "DSI Master driver has been completed.\n"); | ||
794 | dev_info(dsim->dev, "DSI Master state is stop state\n"); | ||
795 | } | ||
796 | |||
797 | dsim->state = DSIM_STATE_STOP; | ||
798 | |||
799 | /* BTA sequence counters */ | ||
800 | exynos_mipi_dsi_set_stop_state_counter(dsim, | ||
801 | dsim->dsim_config->stop_holding_cnt); | ||
802 | exynos_mipi_dsi_set_bta_timeout(dsim, | ||
803 | dsim->dsim_config->bta_timeout); | ||
804 | exynos_mipi_dsi_set_lpdr_timeout(dsim, | ||
805 | dsim->dsim_config->rx_timeout); | ||
806 | |||
807 | return 0; | ||
808 | default: | ||
809 | dev_info(dsim->dev, "DSI Master is already init.\n"); | ||
810 | return 0; | ||
811 | } | ||
812 | |||
813 | return 0; | ||
814 | } | ||
815 | |||
816 | int exynos_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim) | ||
817 | { | ||
818 | if (dsim->state != DSIM_STATE_STOP) { | ||
819 | dev_warn(dsim->dev, "DSIM is not in stop state.\n"); | ||
820 | return 0; | ||
821 | } | ||
822 | |||
823 | if (dsim->e_clk_src == DSIM_EXT_CLK_BYPASS) { | ||
824 | dev_warn(dsim->dev, "clock source is external bypass.\n"); | ||
825 | return 0; | ||
826 | } | ||
827 | |||
828 | dsim->state = DSIM_STATE_HSCLKEN; | ||
829 | |||
830 | /* set LCDC and CPU transfer mode to HS. */ | ||
831 | exynos_mipi_dsi_set_lcdc_transfer_mode(dsim, 0); | ||
832 | exynos_mipi_dsi_set_cpu_transfer_mode(dsim, 0); | ||
833 | exynos_mipi_dsi_enable_hs_clock(dsim, 1); | ||
834 | |||
835 | return 0; | ||
836 | } | ||
837 | |||
838 | int exynos_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim, | ||
839 | unsigned int mode) | ||
840 | { | ||
841 | if (mode) { | ||
842 | if (dsim->state != DSIM_STATE_HSCLKEN) { | ||
843 | dev_err(dsim->dev, "HS Clock lane is not enabled.\n"); | ||
844 | return -EINVAL; | ||
845 | } | ||
846 | |||
847 | exynos_mipi_dsi_set_lcdc_transfer_mode(dsim, 0); | ||
848 | } else { | ||
849 | if (dsim->state == DSIM_STATE_INIT || dsim->state == | ||
850 | DSIM_STATE_ULPS) { | ||
851 | dev_err(dsim->dev, | ||
852 | "DSI Master is not STOP or HSDT state.\n"); | ||
853 | return -EINVAL; | ||
854 | } | ||
855 | |||
856 | exynos_mipi_dsi_set_cpu_transfer_mode(dsim, 0); | ||
857 | } | ||
858 | |||
859 | return 0; | ||
860 | } | ||
861 | |||
862 | int exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim) | ||
863 | { | ||
864 | return _exynos_mipi_dsi_get_frame_done_status(dsim); | ||
865 | } | ||
866 | |||
867 | int exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim) | ||
868 | { | ||
869 | _exynos_mipi_dsi_clear_frame_done(dsim); | ||
870 | |||
871 | return 0; | ||
872 | } | ||
873 | |||
874 | int exynos_mipi_dsi_fifo_clear(struct mipi_dsim_device *dsim, | ||
875 | unsigned int val) | ||
876 | { | ||
877 | int try = TRY_FIFO_CLEAR; | ||
878 | |||
879 | exynos_mipi_dsi_sw_reset_release(dsim); | ||
880 | exynos_mipi_dsi_func_reset(dsim); | ||
881 | |||
882 | do { | ||
883 | if (exynos_mipi_dsi_get_sw_reset_release(dsim)) { | ||
884 | exynos_mipi_dsi_init_interrupt(dsim); | ||
885 | dev_dbg(dsim->dev, "reset release done.\n"); | ||
886 | return 0; | ||
887 | } | ||
888 | } while (--try); | ||
889 | |||
890 | dev_err(dsim->dev, "failed to clear dsim fifo.\n"); | ||
891 | return -EAGAIN; | ||
892 | } | ||
893 | |||
894 | MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>"); | ||
895 | MODULE_DESCRIPTION("Samusung SoC MIPI-DSI common driver"); | ||
896 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/exynos/exynos_mipi_dsi_common.h b/drivers/video/exynos/exynos_mipi_dsi_common.h new file mode 100644 index 000000000000..412552274df3 --- /dev/null +++ b/drivers/video/exynos/exynos_mipi_dsi_common.h | |||
@@ -0,0 +1,46 @@ | |||
1 | /* linux/drivers/video/exynos_mipi_dsi_common.h | ||
2 | * | ||
3 | * Header file for Samsung SoC MIPI-DSI common driver. | ||
4 | * | ||
5 | * Copyright (c) 2012 Samsung Electronics Co., Ltd | ||
6 | * | ||
7 | * InKi Dae <inki.dae@samsung.com> | ||
8 | * Donghwa Lee <dh09.lee@samsung.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #ifndef _EXYNOS_MIPI_DSI_COMMON_H | ||
16 | #define _EXYNOS_MIPI_DSI_COMMON_H | ||
17 | |||
18 | static DECLARE_COMPLETION(dsim_rd_comp); | ||
19 | static DECLARE_COMPLETION(dsim_wr_comp); | ||
20 | |||
21 | int exynos_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id, | ||
22 | const unsigned char *data0, unsigned int data_size); | ||
23 | int exynos_mipi_dsi_rd_data(struct mipi_dsim_device *dsim, unsigned int data_id, | ||
24 | unsigned int data0, unsigned int req_size, u8 *rx_buf); | ||
25 | irqreturn_t exynos_mipi_dsi_interrupt_handler(int irq, void *dev_id); | ||
26 | void exynos_mipi_dsi_init_interrupt(struct mipi_dsim_device *dsim); | ||
27 | int exynos_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim); | ||
28 | void exynos_mipi_dsi_stand_by(struct mipi_dsim_device *dsim, | ||
29 | unsigned int enable); | ||
30 | int exynos_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim, | ||
31 | struct mipi_dsim_config *dsim_info); | ||
32 | int exynos_mipi_dsi_init_link(struct mipi_dsim_device *dsim); | ||
33 | int exynos_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim); | ||
34 | int exynos_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim, | ||
35 | unsigned int mode); | ||
36 | int exynos_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim, | ||
37 | unsigned int enable); | ||
38 | int exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim); | ||
39 | int exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim); | ||
40 | |||
41 | extern struct fb_info *registered_fb[FB_MAX] __read_mostly; | ||
42 | |||
43 | int exynos_mipi_dsi_fifo_clear(struct mipi_dsim_device *dsim, | ||
44 | unsigned int val); | ||
45 | |||
46 | #endif /* _EXYNOS_MIPI_DSI_COMMON_H */ | ||
diff --git a/drivers/video/exynos/exynos_mipi_dsi_lowlevel.c b/drivers/video/exynos/exynos_mipi_dsi_lowlevel.c new file mode 100644 index 000000000000..0ef38ce72af6 --- /dev/null +++ b/drivers/video/exynos/exynos_mipi_dsi_lowlevel.c | |||
@@ -0,0 +1,618 @@ | |||
1 | /* linux/drivers/video/exynos/exynos_mipi_dsi_lowlevel.c | ||
2 | * | ||
3 | * Samsung SoC MIPI-DSI lowlevel driver. | ||
4 | * | ||
5 | * Copyright (c) 2012 Samsung Electronics Co., Ltd | ||
6 | * | ||
7 | * InKi Dae, <inki.dae@samsung.com> | ||
8 | * Donghwa Lee, <dh09.lee@samsung.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/errno.h> | ||
18 | #include <linux/mutex.h> | ||
19 | #include <linux/wait.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/fs.h> | ||
22 | #include <linux/mm.h> | ||
23 | #include <linux/ctype.h> | ||
24 | #include <linux/io.h> | ||
25 | |||
26 | #include <video/exynos_mipi_dsim.h> | ||
27 | |||
28 | #include <mach/map.h> | ||
29 | |||
30 | #include "exynos_mipi_dsi_regs.h" | ||
31 | |||
32 | void exynos_mipi_dsi_func_reset(struct mipi_dsim_device *dsim) | ||
33 | { | ||
34 | unsigned int reg; | ||
35 | |||
36 | reg = readl(dsim->reg_base + EXYNOS_DSIM_SWRST); | ||
37 | |||
38 | reg |= DSIM_FUNCRST; | ||
39 | |||
40 | writel(reg, dsim->reg_base + EXYNOS_DSIM_SWRST); | ||
41 | } | ||
42 | |||
43 | void exynos_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim) | ||
44 | { | ||
45 | unsigned int reg; | ||
46 | |||
47 | reg = readl(dsim->reg_base + EXYNOS_DSIM_SWRST); | ||
48 | |||
49 | reg |= DSIM_SWRST; | ||
50 | |||
51 | writel(reg, dsim->reg_base + EXYNOS_DSIM_SWRST); | ||
52 | } | ||
53 | |||
54 | void exynos_mipi_dsi_sw_reset_release(struct mipi_dsim_device *dsim) | ||
55 | { | ||
56 | unsigned int reg; | ||
57 | |||
58 | reg = readl(dsim->reg_base + EXYNOS_DSIM_INTSRC); | ||
59 | |||
60 | reg |= INTSRC_SW_RST_RELEASE; | ||
61 | |||
62 | writel(reg, dsim->reg_base + EXYNOS_DSIM_INTSRC); | ||
63 | } | ||
64 | |||
65 | int exynos_mipi_dsi_get_sw_reset_release(struct mipi_dsim_device *dsim) | ||
66 | { | ||
67 | return (readl(dsim->reg_base + EXYNOS_DSIM_INTSRC)) & | ||
68 | INTSRC_SW_RST_RELEASE; | ||
69 | } | ||
70 | |||
71 | unsigned int exynos_mipi_dsi_read_interrupt_mask(struct mipi_dsim_device *dsim) | ||
72 | { | ||
73 | unsigned int reg; | ||
74 | |||
75 | reg = readl(dsim->reg_base + EXYNOS_DSIM_INTMSK); | ||
76 | |||
77 | return reg; | ||
78 | } | ||
79 | |||
80 | void exynos_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim, | ||
81 | unsigned int mode, unsigned int mask) | ||
82 | { | ||
83 | unsigned int reg = 0; | ||
84 | |||
85 | if (mask) | ||
86 | reg |= mode; | ||
87 | else | ||
88 | reg &= ~mode; | ||
89 | |||
90 | writel(reg, dsim->reg_base + EXYNOS_DSIM_INTMSK); | ||
91 | } | ||
92 | |||
93 | void exynos_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim, | ||
94 | unsigned int cfg) | ||
95 | { | ||
96 | unsigned int reg; | ||
97 | |||
98 | reg = readl(dsim->reg_base + EXYNOS_DSIM_FIFOCTRL); | ||
99 | |||
100 | writel(reg & ~(cfg), dsim->reg_base + EXYNOS_DSIM_FIFOCTRL); | ||
101 | mdelay(10); | ||
102 | reg |= cfg; | ||
103 | |||
104 | writel(reg, dsim->reg_base + EXYNOS_DSIM_FIFOCTRL); | ||
105 | } | ||
106 | |||
107 | /* | ||
108 | * this function set PLL P, M and S value in D-PHY | ||
109 | */ | ||
110 | void exynos_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim, | ||
111 | unsigned int value) | ||
112 | { | ||
113 | writel(DSIM_AFC_CTL(value), dsim->reg_base + EXYNOS_DSIM_PHYACCHR); | ||
114 | } | ||
115 | |||
116 | void exynos_mipi_dsi_set_main_stand_by(struct mipi_dsim_device *dsim, | ||
117 | unsigned int enable) | ||
118 | { | ||
119 | unsigned int reg; | ||
120 | |||
121 | reg = readl(dsim->reg_base + EXYNOS_DSIM_MDRESOL); | ||
122 | |||
123 | reg &= ~DSIM_MAIN_STAND_BY; | ||
124 | |||
125 | if (enable) | ||
126 | reg |= DSIM_MAIN_STAND_BY; | ||
127 | |||
128 | writel(reg, dsim->reg_base + EXYNOS_DSIM_MDRESOL); | ||
129 | } | ||
130 | |||
131 | void exynos_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim, | ||
132 | unsigned int width_resol, unsigned int height_resol) | ||
133 | { | ||
134 | unsigned int reg; | ||
135 | |||
136 | /* standby should be set after configuration so set to not ready*/ | ||
137 | reg = (readl(dsim->reg_base + EXYNOS_DSIM_MDRESOL)) & | ||
138 | ~(DSIM_MAIN_STAND_BY); | ||
139 | writel(reg, dsim->reg_base + EXYNOS_DSIM_MDRESOL); | ||
140 | |||
141 | reg &= ~((0x7ff << 16) | (0x7ff << 0)); | ||
142 | reg |= DSIM_MAIN_VRESOL(height_resol) | DSIM_MAIN_HRESOL(width_resol); | ||
143 | |||
144 | reg |= DSIM_MAIN_STAND_BY; | ||
145 | writel(reg, dsim->reg_base + EXYNOS_DSIM_MDRESOL); | ||
146 | } | ||
147 | |||
148 | void exynos_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim, | ||
149 | unsigned int cmd_allow, unsigned int vfront, unsigned int vback) | ||
150 | { | ||
151 | unsigned int reg; | ||
152 | |||
153 | reg = (readl(dsim->reg_base + EXYNOS_DSIM_MVPORCH)) & | ||
154 | ~((DSIM_CMD_ALLOW_MASK) | (DSIM_STABLE_VFP_MASK) | | ||
155 | (DSIM_MAIN_VBP_MASK)); | ||
156 | |||
157 | reg |= (DSIM_CMD_ALLOW_SHIFT(cmd_allow & 0xf) | | ||
158 | DSIM_STABLE_VFP_SHIFT(vfront & 0x7ff) | | ||
159 | DSIM_MAIN_VBP_SHIFT(vback & 0x7ff)); | ||
160 | |||
161 | writel(reg, dsim->reg_base + EXYNOS_DSIM_MVPORCH); | ||
162 | } | ||
163 | |||
164 | void exynos_mipi_dsi_set_main_disp_hporch(struct mipi_dsim_device *dsim, | ||
165 | unsigned int front, unsigned int back) | ||
166 | { | ||
167 | unsigned int reg; | ||
168 | |||
169 | reg = (readl(dsim->reg_base + EXYNOS_DSIM_MHPORCH)) & | ||
170 | ~((DSIM_MAIN_HFP_MASK) | (DSIM_MAIN_HBP_MASK)); | ||
171 | |||
172 | reg |= DSIM_MAIN_HFP_SHIFT(front) | DSIM_MAIN_HBP_SHIFT(back); | ||
173 | |||
174 | writel(reg, dsim->reg_base + EXYNOS_DSIM_MHPORCH); | ||
175 | } | ||
176 | |||
177 | void exynos_mipi_dsi_set_main_disp_sync_area(struct mipi_dsim_device *dsim, | ||
178 | unsigned int vert, unsigned int hori) | ||
179 | { | ||
180 | unsigned int reg; | ||
181 | |||
182 | reg = (readl(dsim->reg_base + EXYNOS_DSIM_MSYNC)) & | ||
183 | ~((DSIM_MAIN_VSA_MASK) | (DSIM_MAIN_HSA_MASK)); | ||
184 | |||
185 | reg |= (DSIM_MAIN_VSA_SHIFT(vert & 0x3ff) | | ||
186 | DSIM_MAIN_HSA_SHIFT(hori)); | ||
187 | |||
188 | writel(reg, dsim->reg_base + EXYNOS_DSIM_MSYNC); | ||
189 | } | ||
190 | |||
191 | void exynos_mipi_dsi_set_sub_disp_resol(struct mipi_dsim_device *dsim, | ||
192 | unsigned int vert, unsigned int hori) | ||
193 | { | ||
194 | unsigned int reg; | ||
195 | |||
196 | reg = (readl(dsim->reg_base + EXYNOS_DSIM_SDRESOL)) & | ||
197 | ~(DSIM_SUB_STANDY_MASK); | ||
198 | |||
199 | writel(reg, dsim->reg_base + EXYNOS_DSIM_SDRESOL); | ||
200 | |||
201 | reg &= ~(DSIM_SUB_VRESOL_MASK) | ~(DSIM_SUB_HRESOL_MASK); | ||
202 | reg |= (DSIM_SUB_VRESOL_SHIFT(vert & 0x7ff) | | ||
203 | DSIM_SUB_HRESOL_SHIFT(hori & 0x7ff)); | ||
204 | writel(reg, dsim->reg_base + EXYNOS_DSIM_SDRESOL); | ||
205 | |||
206 | reg |= DSIM_SUB_STANDY_SHIFT(1); | ||
207 | writel(reg, dsim->reg_base + EXYNOS_DSIM_SDRESOL); | ||
208 | } | ||
209 | |||
210 | void exynos_mipi_dsi_init_config(struct mipi_dsim_device *dsim) | ||
211 | { | ||
212 | struct mipi_dsim_config *dsim_config = dsim->dsim_config; | ||
213 | |||
214 | unsigned int cfg = (readl(dsim->reg_base + EXYNOS_DSIM_CONFIG)) & | ||
215 | ~((1 << 28) | (0x1f << 20) | (0x3 << 5)); | ||
216 | |||
217 | cfg = ((DSIM_AUTO_FLUSH(dsim_config->auto_flush)) | | ||
218 | (DSIM_EOT_DISABLE(dsim_config->eot_disable)) | | ||
219 | (DSIM_AUTO_MODE_SHIFT(dsim_config->auto_vertical_cnt)) | | ||
220 | (DSIM_HSE_MODE_SHIFT(dsim_config->hse)) | | ||
221 | (DSIM_HFP_MODE_SHIFT(dsim_config->hfp)) | | ||
222 | (DSIM_HBP_MODE_SHIFT(dsim_config->hbp)) | | ||
223 | (DSIM_HSA_MODE_SHIFT(dsim_config->hsa)) | | ||
224 | (DSIM_NUM_OF_DATALANE_SHIFT(dsim_config->e_no_data_lane))); | ||
225 | |||
226 | writel(cfg, dsim->reg_base + EXYNOS_DSIM_CONFIG); | ||
227 | } | ||
228 | |||
229 | void exynos_mipi_dsi_display_config(struct mipi_dsim_device *dsim, | ||
230 | struct mipi_dsim_config *dsim_config) | ||
231 | { | ||
232 | u32 reg = (readl(dsim->reg_base + EXYNOS_DSIM_CONFIG)) & | ||
233 | ~((0x3 << 26) | (1 << 25) | (0x3 << 18) | (0x7 << 12) | | ||
234 | (0x3 << 16) | (0x7 << 8)); | ||
235 | |||
236 | if (dsim_config->e_interface == DSIM_VIDEO) | ||
237 | reg |= (1 << 25); | ||
238 | else if (dsim_config->e_interface == DSIM_COMMAND) | ||
239 | reg &= ~(1 << 25); | ||
240 | else { | ||
241 | dev_err(dsim->dev, "unknown lcd type.\n"); | ||
242 | return; | ||
243 | } | ||
244 | |||
245 | /* main lcd */ | ||
246 | reg |= ((u8) (dsim_config->e_burst_mode) & 0x3) << 26 | | ||
247 | ((u8) (dsim_config->e_virtual_ch) & 0x3) << 18 | | ||
248 | ((u8) (dsim_config->e_pixel_format) & 0x7) << 12; | ||
249 | |||
250 | writel(reg, dsim->reg_base + EXYNOS_DSIM_CONFIG); | ||
251 | } | ||
252 | |||
253 | void exynos_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim, unsigned int lane, | ||
254 | unsigned int enable) | ||
255 | { | ||
256 | unsigned int reg; | ||
257 | |||
258 | reg = readl(dsim->reg_base + EXYNOS_DSIM_CONFIG); | ||
259 | |||
260 | if (enable) | ||
261 | reg |= DSIM_LANE_ENx(lane); | ||
262 | else | ||
263 | reg &= ~DSIM_LANE_ENx(lane); | ||
264 | |||
265 | writel(reg, dsim->reg_base + EXYNOS_DSIM_CONFIG); | ||
266 | } | ||
267 | |||
268 | |||
269 | void exynos_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim, | ||
270 | unsigned int count) | ||
271 | { | ||
272 | unsigned int cfg; | ||
273 | |||
274 | /* get the data lane number. */ | ||
275 | cfg = DSIM_NUM_OF_DATALANE_SHIFT(count); | ||
276 | |||
277 | writel(cfg, dsim->reg_base + EXYNOS_DSIM_CONFIG); | ||
278 | } | ||
279 | |||
280 | void exynos_mipi_dsi_enable_afc(struct mipi_dsim_device *dsim, unsigned int enable, | ||
281 | unsigned int afc_code) | ||
282 | { | ||
283 | unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_PHYACCHR); | ||
284 | |||
285 | if (enable) { | ||
286 | reg |= (1 << 14); | ||
287 | reg &= ~(0x7 << 5); | ||
288 | reg |= (afc_code & 0x7) << 5; | ||
289 | } else | ||
290 | reg &= ~(1 << 14); | ||
291 | |||
292 | writel(reg, dsim->reg_base + EXYNOS_DSIM_PHYACCHR); | ||
293 | } | ||
294 | |||
295 | void exynos_mipi_dsi_enable_pll_bypass(struct mipi_dsim_device *dsim, | ||
296 | unsigned int enable) | ||
297 | { | ||
298 | unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_CLKCTRL)) & | ||
299 | ~(DSIM_PLL_BYPASS_SHIFT(0x1)); | ||
300 | |||
301 | reg |= DSIM_PLL_BYPASS_SHIFT(enable); | ||
302 | |||
303 | writel(reg, dsim->reg_base + EXYNOS_DSIM_CLKCTRL); | ||
304 | } | ||
305 | |||
306 | void exynos_mipi_dsi_set_pll_pms(struct mipi_dsim_device *dsim, unsigned int p, | ||
307 | unsigned int m, unsigned int s) | ||
308 | { | ||
309 | unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_PLLCTRL); | ||
310 | |||
311 | reg |= ((p & 0x3f) << 13) | ((m & 0x1ff) << 4) | ((s & 0x7) << 1); | ||
312 | |||
313 | writel(reg, dsim->reg_base + EXYNOS_DSIM_PLLCTRL); | ||
314 | } | ||
315 | |||
316 | void exynos_mipi_dsi_pll_freq_band(struct mipi_dsim_device *dsim, | ||
317 | unsigned int freq_band) | ||
318 | { | ||
319 | unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_PLLCTRL)) & | ||
320 | ~(DSIM_FREQ_BAND_SHIFT(0x1f)); | ||
321 | |||
322 | reg |= DSIM_FREQ_BAND_SHIFT(freq_band & 0x1f); | ||
323 | |||
324 | writel(reg, dsim->reg_base + EXYNOS_DSIM_PLLCTRL); | ||
325 | } | ||
326 | |||
327 | void exynos_mipi_dsi_pll_freq(struct mipi_dsim_device *dsim, | ||
328 | unsigned int pre_divider, unsigned int main_divider, | ||
329 | unsigned int scaler) | ||
330 | { | ||
331 | unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_PLLCTRL)) & | ||
332 | ~(0x7ffff << 1); | ||
333 | |||
334 | reg |= (pre_divider & 0x3f) << 13 | (main_divider & 0x1ff) << 4 | | ||
335 | (scaler & 0x7) << 1; | ||
336 | |||
337 | writel(reg, dsim->reg_base + EXYNOS_DSIM_PLLCTRL); | ||
338 | } | ||
339 | |||
340 | void exynos_mipi_dsi_pll_stable_time(struct mipi_dsim_device *dsim, | ||
341 | unsigned int lock_time) | ||
342 | { | ||
343 | writel(lock_time, dsim->reg_base + EXYNOS_DSIM_PLLTMR); | ||
344 | } | ||
345 | |||
346 | void exynos_mipi_dsi_enable_pll(struct mipi_dsim_device *dsim, unsigned int enable) | ||
347 | { | ||
348 | unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_PLLCTRL)) & | ||
349 | ~(DSIM_PLL_EN_SHIFT(0x1)); | ||
350 | |||
351 | reg |= DSIM_PLL_EN_SHIFT(enable & 0x1); | ||
352 | |||
353 | writel(reg, dsim->reg_base + EXYNOS_DSIM_PLLCTRL); | ||
354 | } | ||
355 | |||
356 | void exynos_mipi_dsi_set_byte_clock_src(struct mipi_dsim_device *dsim, | ||
357 | unsigned int src) | ||
358 | { | ||
359 | unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_CLKCTRL)) & | ||
360 | ~(DSIM_BYTE_CLK_SRC_SHIFT(0x3)); | ||
361 | |||
362 | reg |= (DSIM_BYTE_CLK_SRC_SHIFT(src)); | ||
363 | |||
364 | writel(reg, dsim->reg_base + EXYNOS_DSIM_CLKCTRL); | ||
365 | } | ||
366 | |||
367 | void exynos_mipi_dsi_enable_byte_clock(struct mipi_dsim_device *dsim, | ||
368 | unsigned int enable) | ||
369 | { | ||
370 | unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_CLKCTRL)) & | ||
371 | ~(DSIM_BYTE_CLKEN_SHIFT(0x1)); | ||
372 | |||
373 | reg |= DSIM_BYTE_CLKEN_SHIFT(enable); | ||
374 | |||
375 | writel(reg, dsim->reg_base + EXYNOS_DSIM_CLKCTRL); | ||
376 | } | ||
377 | |||
378 | void exynos_mipi_dsi_set_esc_clk_prs(struct mipi_dsim_device *dsim, | ||
379 | unsigned int enable, unsigned int prs_val) | ||
380 | { | ||
381 | unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_CLKCTRL)) & | ||
382 | ~(DSIM_ESC_CLKEN_SHIFT(0x1) | 0xffff); | ||
383 | |||
384 | reg |= DSIM_ESC_CLKEN_SHIFT(enable); | ||
385 | if (enable) | ||
386 | reg |= prs_val; | ||
387 | |||
388 | writel(reg, dsim->reg_base + EXYNOS_DSIM_CLKCTRL); | ||
389 | } | ||
390 | |||
391 | void exynos_mipi_dsi_enable_esc_clk_on_lane(struct mipi_dsim_device *dsim, | ||
392 | unsigned int lane_sel, unsigned int enable) | ||
393 | { | ||
394 | unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_CLKCTRL); | ||
395 | |||
396 | if (enable) | ||
397 | reg |= DSIM_LANE_ESC_CLKEN(lane_sel); | ||
398 | else | ||
399 | |||
400 | reg &= ~DSIM_LANE_ESC_CLKEN(lane_sel); | ||
401 | |||
402 | writel(reg, dsim->reg_base + EXYNOS_DSIM_CLKCTRL); | ||
403 | } | ||
404 | |||
405 | void exynos_mipi_dsi_force_dphy_stop_state(struct mipi_dsim_device *dsim, | ||
406 | unsigned int enable) | ||
407 | { | ||
408 | unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_ESCMODE)) & | ||
409 | ~(DSIM_FORCE_STOP_STATE_SHIFT(0x1)); | ||
410 | |||
411 | reg |= (DSIM_FORCE_STOP_STATE_SHIFT(enable & 0x1)); | ||
412 | |||
413 | writel(reg, dsim->reg_base + EXYNOS_DSIM_ESCMODE); | ||
414 | } | ||
415 | |||
416 | unsigned int exynos_mipi_dsi_is_lane_state(struct mipi_dsim_device *dsim) | ||
417 | { | ||
418 | unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_STATUS); | ||
419 | |||
420 | /** | ||
421 | * check clock and data lane states. | ||
422 | * if MIPI-DSI controller was enabled at bootloader then | ||
423 | * TX_READY_HS_CLK is enabled otherwise STOP_STATE_CLK. | ||
424 | * so it should be checked for two case. | ||
425 | */ | ||
426 | if ((reg & DSIM_STOP_STATE_DAT(0xf)) && | ||
427 | ((reg & DSIM_STOP_STATE_CLK) || | ||
428 | (reg & DSIM_TX_READY_HS_CLK))) | ||
429 | return 1; | ||
430 | |||
431 | return 0; | ||
432 | } | ||
433 | |||
434 | void exynos_mipi_dsi_set_stop_state_counter(struct mipi_dsim_device *dsim, | ||
435 | unsigned int cnt_val) | ||
436 | { | ||
437 | unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_ESCMODE)) & | ||
438 | ~(DSIM_STOP_STATE_CNT_SHIFT(0x7ff)); | ||
439 | |||
440 | reg |= (DSIM_STOP_STATE_CNT_SHIFT(cnt_val & 0x7ff)); | ||
441 | |||
442 | writel(reg, dsim->reg_base + EXYNOS_DSIM_ESCMODE); | ||
443 | } | ||
444 | |||
445 | void exynos_mipi_dsi_set_bta_timeout(struct mipi_dsim_device *dsim, | ||
446 | unsigned int timeout) | ||
447 | { | ||
448 | unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_TIMEOUT)) & | ||
449 | ~(DSIM_BTA_TOUT_SHIFT(0xff)); | ||
450 | |||
451 | reg |= (DSIM_BTA_TOUT_SHIFT(timeout)); | ||
452 | |||
453 | writel(reg, dsim->reg_base + EXYNOS_DSIM_TIMEOUT); | ||
454 | } | ||
455 | |||
456 | void exynos_mipi_dsi_set_lpdr_timeout(struct mipi_dsim_device *dsim, | ||
457 | unsigned int timeout) | ||
458 | { | ||
459 | unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_TIMEOUT)) & | ||
460 | ~(DSIM_LPDR_TOUT_SHIFT(0xffff)); | ||
461 | |||
462 | reg |= (DSIM_LPDR_TOUT_SHIFT(timeout)); | ||
463 | |||
464 | writel(reg, dsim->reg_base + EXYNOS_DSIM_TIMEOUT); | ||
465 | } | ||
466 | |||
467 | void exynos_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim, | ||
468 | unsigned int lp) | ||
469 | { | ||
470 | unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_ESCMODE); | ||
471 | |||
472 | reg &= ~DSIM_CMD_LPDT_LP; | ||
473 | |||
474 | if (lp) | ||
475 | reg |= DSIM_CMD_LPDT_LP; | ||
476 | |||
477 | writel(reg, dsim->reg_base + EXYNOS_DSIM_ESCMODE); | ||
478 | } | ||
479 | |||
480 | void exynos_mipi_dsi_set_lcdc_transfer_mode(struct mipi_dsim_device *dsim, | ||
481 | unsigned int lp) | ||
482 | { | ||
483 | unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_ESCMODE); | ||
484 | |||
485 | reg &= ~DSIM_TX_LPDT_LP; | ||
486 | |||
487 | if (lp) | ||
488 | reg |= DSIM_TX_LPDT_LP; | ||
489 | |||
490 | writel(reg, dsim->reg_base + EXYNOS_DSIM_ESCMODE); | ||
491 | } | ||
492 | |||
493 | void exynos_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim, | ||
494 | unsigned int enable) | ||
495 | { | ||
496 | unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_CLKCTRL)) & | ||
497 | ~(DSIM_TX_REQUEST_HSCLK_SHIFT(0x1)); | ||
498 | |||
499 | reg |= DSIM_TX_REQUEST_HSCLK_SHIFT(enable); | ||
500 | |||
501 | writel(reg, dsim->reg_base + EXYNOS_DSIM_CLKCTRL); | ||
502 | } | ||
503 | |||
504 | void exynos_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim, | ||
505 | unsigned int swap_en) | ||
506 | { | ||
507 | unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_PHYACCHR1); | ||
508 | |||
509 | reg &= ~(0x3 << 0); | ||
510 | reg |= (swap_en & 0x3) << 0; | ||
511 | |||
512 | writel(reg, dsim->reg_base + EXYNOS_DSIM_PHYACCHR1); | ||
513 | } | ||
514 | |||
515 | void exynos_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim, | ||
516 | unsigned int hs_zero) | ||
517 | { | ||
518 | unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_PLLCTRL)) & | ||
519 | ~(0xf << 28); | ||
520 | |||
521 | reg |= ((hs_zero & 0xf) << 28); | ||
522 | |||
523 | writel(reg, dsim->reg_base + EXYNOS_DSIM_PLLCTRL); | ||
524 | } | ||
525 | |||
526 | void exynos_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim, unsigned int prep) | ||
527 | { | ||
528 | unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_PLLCTRL)) & | ||
529 | ~(0x7 << 20); | ||
530 | |||
531 | reg |= ((prep & 0x7) << 20); | ||
532 | |||
533 | writel(reg, dsim->reg_base + EXYNOS_DSIM_PLLCTRL); | ||
534 | } | ||
535 | |||
536 | unsigned int exynos_mipi_dsi_read_interrupt(struct mipi_dsim_device *dsim) | ||
537 | { | ||
538 | return readl(dsim->reg_base + EXYNOS_DSIM_INTSRC); | ||
539 | } | ||
540 | |||
541 | void exynos_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim, | ||
542 | unsigned int src) | ||
543 | { | ||
544 | unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_INTSRC); | ||
545 | |||
546 | reg |= src; | ||
547 | |||
548 | writel(reg, dsim->reg_base + EXYNOS_DSIM_INTSRC); | ||
549 | } | ||
550 | |||
551 | void exynos_mipi_dsi_set_interrupt(struct mipi_dsim_device *dsim, | ||
552 | unsigned int src, unsigned int enable) | ||
553 | { | ||
554 | unsigned int reg = 0; | ||
555 | |||
556 | if (enable) | ||
557 | reg |= src; | ||
558 | else | ||
559 | reg &= ~src; | ||
560 | |||
561 | writel(reg, dsim->reg_base + EXYNOS_DSIM_INTSRC); | ||
562 | } | ||
563 | |||
564 | unsigned int exynos_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim) | ||
565 | { | ||
566 | unsigned int reg; | ||
567 | |||
568 | reg = readl(dsim->reg_base + EXYNOS_DSIM_STATUS); | ||
569 | |||
570 | return reg & (1 << 31) ? 1 : 0; | ||
571 | } | ||
572 | |||
573 | unsigned int exynos_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim) | ||
574 | { | ||
575 | return readl(dsim->reg_base + EXYNOS_DSIM_FIFOCTRL) & ~(0x1f); | ||
576 | } | ||
577 | |||
578 | void exynos_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim, | ||
579 | unsigned int di, unsigned int data0, unsigned int data1) | ||
580 | { | ||
581 | unsigned int reg = (data1 << 16) | (data0 << 8) | ((di & 0x3f) << 0); | ||
582 | |||
583 | writel(reg, dsim->reg_base + EXYNOS_DSIM_PKTHDR); | ||
584 | } | ||
585 | |||
586 | void exynos_mipi_dsi_rd_tx_header(struct mipi_dsim_device *dsim, | ||
587 | unsigned int di, unsigned int data0) | ||
588 | { | ||
589 | unsigned int reg = (data0 << 8) | (di << 0); | ||
590 | |||
591 | writel(reg, dsim->reg_base + EXYNOS_DSIM_PKTHDR); | ||
592 | } | ||
593 | |||
594 | unsigned int exynos_mipi_dsi_rd_rx_fifo(struct mipi_dsim_device *dsim) | ||
595 | { | ||
596 | return readl(dsim->reg_base + EXYNOS_DSIM_RXFIFO); | ||
597 | } | ||
598 | |||
599 | unsigned int _exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim) | ||
600 | { | ||
601 | unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_INTSRC); | ||
602 | |||
603 | return (reg & INTSRC_FRAME_DONE) ? 1 : 0; | ||
604 | } | ||
605 | |||
606 | void _exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim) | ||
607 | { | ||
608 | unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_INTSRC); | ||
609 | |||
610 | writel(reg | INTSRC_FRAME_DONE, dsim->reg_base + | ||
611 | EXYNOS_DSIM_INTSRC); | ||
612 | } | ||
613 | |||
614 | void exynos_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim, | ||
615 | unsigned int tx_data) | ||
616 | { | ||
617 | writel(tx_data, dsim->reg_base + EXYNOS_DSIM_PAYLOAD); | ||
618 | } | ||
diff --git a/drivers/video/exynos/exynos_mipi_dsi_lowlevel.h b/drivers/video/exynos/exynos_mipi_dsi_lowlevel.h new file mode 100644 index 000000000000..85460701c7ea --- /dev/null +++ b/drivers/video/exynos/exynos_mipi_dsi_lowlevel.h | |||
@@ -0,0 +1,112 @@ | |||
1 | /* linux/drivers/video/exynos/exynos_mipi_dsi_lowlevel.h | ||
2 | * | ||
3 | * Header file for Samsung SoC MIPI-DSI lowlevel driver. | ||
4 | * | ||
5 | * Copyright (c) 2012 Samsung Electronics Co., Ltd | ||
6 | * | ||
7 | * InKi Dae <inki.dae@samsung.com> | ||
8 | * Donghwa Lee <dh09.lee@samsung.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #ifndef _EXYNOS_MIPI_DSI_LOWLEVEL_H | ||
16 | #define _EXYNOS_MIPI_DSI_LOWLEVEL_H | ||
17 | |||
18 | void exynos_mipi_dsi_func_reset(struct mipi_dsim_device *dsim); | ||
19 | void exynos_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim); | ||
20 | void exynos_mipi_dsi_sw_reset_release(struct mipi_dsim_device *dsim); | ||
21 | int exynos_mipi_dsi_get_sw_reset_release(struct mipi_dsim_device *dsim); | ||
22 | void exynos_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim, | ||
23 | unsigned int mode, unsigned int mask); | ||
24 | void exynos_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim, | ||
25 | unsigned int count); | ||
26 | void exynos_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim, | ||
27 | unsigned int cfg); | ||
28 | void exynos_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim, | ||
29 | unsigned int value); | ||
30 | void exynos_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim, | ||
31 | unsigned int value); | ||
32 | void exynos_mipi_dsi_set_main_stand_by(struct mipi_dsim_device *dsim, | ||
33 | unsigned int enable); | ||
34 | void exynos_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim, | ||
35 | unsigned int width_resol, unsigned int height_resol); | ||
36 | void exynos_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim, | ||
37 | unsigned int cmd_allow, unsigned int vfront, unsigned int vback); | ||
38 | void exynos_mipi_dsi_set_main_disp_hporch(struct mipi_dsim_device *dsim, | ||
39 | unsigned int front, unsigned int back); | ||
40 | void exynos_mipi_dsi_set_main_disp_sync_area(struct mipi_dsim_device *dsim, | ||
41 | unsigned int vert, unsigned int hori); | ||
42 | void exynos_mipi_dsi_set_sub_disp_resol(struct mipi_dsim_device *dsim, | ||
43 | unsigned int vert, unsigned int hori); | ||
44 | void exynos_mipi_dsi_init_config(struct mipi_dsim_device *dsim); | ||
45 | void exynos_mipi_dsi_display_config(struct mipi_dsim_device *dsim, | ||
46 | struct mipi_dsim_config *dsim_config); | ||
47 | void exynos_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim, | ||
48 | unsigned int count); | ||
49 | void exynos_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim, unsigned int lane, | ||
50 | unsigned int enable); | ||
51 | void exynos_mipi_dsi_enable_afc(struct mipi_dsim_device *dsim, unsigned int enable, | ||
52 | unsigned int afc_code); | ||
53 | void exynos_mipi_dsi_enable_pll_bypass(struct mipi_dsim_device *dsim, | ||
54 | unsigned int enable); | ||
55 | void exynos_mipi_dsi_set_pll_pms(struct mipi_dsim_device *dsim, unsigned int p, | ||
56 | unsigned int m, unsigned int s); | ||
57 | void exynos_mipi_dsi_pll_freq_band(struct mipi_dsim_device *dsim, | ||
58 | unsigned int freq_band); | ||
59 | void exynos_mipi_dsi_pll_freq(struct mipi_dsim_device *dsim, | ||
60 | unsigned int pre_divider, unsigned int main_divider, | ||
61 | unsigned int scaler); | ||
62 | void exynos_mipi_dsi_pll_stable_time(struct mipi_dsim_device *dsim, | ||
63 | unsigned int lock_time); | ||
64 | void exynos_mipi_dsi_enable_pll(struct mipi_dsim_device *dsim, | ||
65 | unsigned int enable); | ||
66 | void exynos_mipi_dsi_set_byte_clock_src(struct mipi_dsim_device *dsim, | ||
67 | unsigned int src); | ||
68 | void exynos_mipi_dsi_enable_byte_clock(struct mipi_dsim_device *dsim, | ||
69 | unsigned int enable); | ||
70 | void exynos_mipi_dsi_set_esc_clk_prs(struct mipi_dsim_device *dsim, | ||
71 | unsigned int enable, unsigned int prs_val); | ||
72 | void exynos_mipi_dsi_enable_esc_clk_on_lane(struct mipi_dsim_device *dsim, | ||
73 | unsigned int lane_sel, unsigned int enable); | ||
74 | void exynos_mipi_dsi_force_dphy_stop_state(struct mipi_dsim_device *dsim, | ||
75 | unsigned int enable); | ||
76 | unsigned int exynos_mipi_dsi_is_lane_state(struct mipi_dsim_device *dsim); | ||
77 | void exynos_mipi_dsi_set_stop_state_counter(struct mipi_dsim_device *dsim, | ||
78 | unsigned int cnt_val); | ||
79 | void exynos_mipi_dsi_set_bta_timeout(struct mipi_dsim_device *dsim, | ||
80 | unsigned int timeout); | ||
81 | void exynos_mipi_dsi_set_lpdr_timeout(struct mipi_dsim_device *dsim, | ||
82 | unsigned int timeout); | ||
83 | void exynos_mipi_dsi_set_lcdc_transfer_mode(struct mipi_dsim_device *dsim, | ||
84 | unsigned int lp); | ||
85 | void exynos_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim, | ||
86 | unsigned int lp); | ||
87 | void exynos_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim, | ||
88 | unsigned int enable); | ||
89 | void exynos_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim, | ||
90 | unsigned int swap_en); | ||
91 | void exynos_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim, | ||
92 | unsigned int hs_zero); | ||
93 | void exynos_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim, unsigned int prep); | ||
94 | unsigned int exynos_mipi_dsi_read_interrupt(struct mipi_dsim_device *dsim); | ||
95 | unsigned int exynos_mipi_dsi_read_interrupt_mask(struct mipi_dsim_device *dsim); | ||
96 | void exynos_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim, | ||
97 | unsigned int src); | ||
98 | void exynos_mipi_dsi_set_interrupt(struct mipi_dsim_device *dsim, | ||
99 | unsigned int src, unsigned int enable); | ||
100 | unsigned int exynos_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim); | ||
101 | unsigned int exynos_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim); | ||
102 | unsigned int _exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim); | ||
103 | void _exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim); | ||
104 | void exynos_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim, unsigned int di, | ||
105 | unsigned int data0, unsigned int data1); | ||
106 | void exynos_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim, | ||
107 | unsigned int tx_data); | ||
108 | void exynos_mipi_dsi_rd_tx_header(struct mipi_dsim_device *dsim, | ||
109 | unsigned int data0, unsigned int data1); | ||
110 | unsigned int exynos_mipi_dsi_rd_rx_fifo(struct mipi_dsim_device *dsim); | ||
111 | |||
112 | #endif /* _EXYNOS_MIPI_DSI_LOWLEVEL_H */ | ||
diff --git a/drivers/video/exynos/exynos_mipi_dsi_regs.h b/drivers/video/exynos/exynos_mipi_dsi_regs.h new file mode 100644 index 000000000000..4227106d3fd0 --- /dev/null +++ b/drivers/video/exynos/exynos_mipi_dsi_regs.h | |||
@@ -0,0 +1,149 @@ | |||
1 | /* linux/driver/video/exynos/exynos_mipi_dsi_regs.h | ||
2 | * | ||
3 | * Register definition file for Samsung MIPI-DSIM driver | ||
4 | * | ||
5 | * Copyright (c) 2012 Samsung Electronics Co., Ltd | ||
6 | * | ||
7 | * InKi Dae <inki.dae@samsung.com> | ||
8 | * Donghwa Lee <dh09.lee@samsung.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #ifndef _EXYNOS_MIPI_DSI_REGS_H | ||
16 | #define _EXYNOS_MIPI_DSI_REGS_H | ||
17 | |||
18 | #define EXYNOS_DSIM_STATUS 0x0 /* Status register */ | ||
19 | #define EXYNOS_DSIM_SWRST 0x4 /* Software reset register */ | ||
20 | #define EXYNOS_DSIM_CLKCTRL 0x8 /* Clock control register */ | ||
21 | #define EXYNOS_DSIM_TIMEOUT 0xc /* Time out register */ | ||
22 | #define EXYNOS_DSIM_CONFIG 0x10 /* Configuration register */ | ||
23 | #define EXYNOS_DSIM_ESCMODE 0x14 /* Escape mode register */ | ||
24 | |||
25 | /* Main display image resolution register */ | ||
26 | #define EXYNOS_DSIM_MDRESOL 0x18 | ||
27 | #define EXYNOS_DSIM_MVPORCH 0x1c /* Main display Vporch register */ | ||
28 | #define EXYNOS_DSIM_MHPORCH 0x20 /* Main display Hporch register */ | ||
29 | #define EXYNOS_DSIM_MSYNC 0x24 /* Main display sync area register */ | ||
30 | |||
31 | /* Sub display image resolution register */ | ||
32 | #define EXYNOS_DSIM_SDRESOL 0x28 | ||
33 | #define EXYNOS_DSIM_INTSRC 0x2c /* Interrupt source register */ | ||
34 | #define EXYNOS_DSIM_INTMSK 0x30 /* Interrupt mask register */ | ||
35 | #define EXYNOS_DSIM_PKTHDR 0x34 /* Packet Header FIFO register */ | ||
36 | #define EXYNOS_DSIM_PAYLOAD 0x38 /* Payload FIFO register */ | ||
37 | #define EXYNOS_DSIM_RXFIFO 0x3c /* Read FIFO register */ | ||
38 | #define EXYNOS_DSIM_FIFOTHLD 0x40 /* FIFO threshold level register */ | ||
39 | #define EXYNOS_DSIM_FIFOCTRL 0x44 /* FIFO status and control register */ | ||
40 | |||
41 | /* FIFO memory AC characteristic register */ | ||
42 | #define EXYNOS_DSIM_PLLCTRL 0x4c /* PLL control register */ | ||
43 | #define EXYNOS_DSIM_PLLTMR 0x50 /* PLL timer register */ | ||
44 | #define EXYNOS_DSIM_PHYACCHR 0x54 /* D-PHY AC characteristic register */ | ||
45 | #define EXYNOS_DSIM_PHYACCHR1 0x58 /* D-PHY AC characteristic register1 */ | ||
46 | |||
47 | /* DSIM_STATUS */ | ||
48 | #define DSIM_STOP_STATE_DAT(x) (((x) & 0xf) << 0) | ||
49 | #define DSIM_STOP_STATE_CLK (1 << 8) | ||
50 | #define DSIM_TX_READY_HS_CLK (1 << 10) | ||
51 | |||
52 | /* DSIM_SWRST */ | ||
53 | #define DSIM_FUNCRST (1 << 16) | ||
54 | #define DSIM_SWRST (1 << 0) | ||
55 | |||
56 | /* EXYNOS_DSIM_TIMEOUT */ | ||
57 | #define DSIM_LPDR_TOUT_SHIFT(x) ((x) << 0) | ||
58 | #define DSIM_BTA_TOUT_SHIFT(x) ((x) << 16) | ||
59 | |||
60 | /* EXYNOS_DSIM_CLKCTRL */ | ||
61 | #define DSIM_LANE_ESC_CLKEN(x) (((x) & 0x1f) << 19) | ||
62 | #define DSIM_BYTE_CLKEN_SHIFT(x) ((x) << 24) | ||
63 | #define DSIM_BYTE_CLK_SRC_SHIFT(x) ((x) << 25) | ||
64 | #define DSIM_PLL_BYPASS_SHIFT(x) ((x) << 27) | ||
65 | #define DSIM_ESC_CLKEN_SHIFT(x) ((x) << 28) | ||
66 | #define DSIM_TX_REQUEST_HSCLK_SHIFT(x) ((x) << 31) | ||
67 | |||
68 | /* EXYNOS_DSIM_CONFIG */ | ||
69 | #define DSIM_LANE_ENx(x) (((x) & 0x1f) << 0) | ||
70 | #define DSIM_NUM_OF_DATALANE_SHIFT(x) ((x) << 5) | ||
71 | #define DSIM_HSA_MODE_SHIFT(x) ((x) << 20) | ||
72 | #define DSIM_HBP_MODE_SHIFT(x) ((x) << 21) | ||
73 | #define DSIM_HFP_MODE_SHIFT(x) ((x) << 22) | ||
74 | #define DSIM_HSE_MODE_SHIFT(x) ((x) << 23) | ||
75 | #define DSIM_AUTO_MODE_SHIFT(x) ((x) << 24) | ||
76 | #define DSIM_EOT_DISABLE(x) ((x) << 28) | ||
77 | #define DSIM_AUTO_FLUSH(x) ((x) << 29) | ||
78 | |||
79 | #define DSIM_NUM_OF_DATA_LANE(x) ((x) << DSIM_NUM_OF_DATALANE_SHIFT) | ||
80 | |||
81 | /* EXYNOS_DSIM_ESCMODE */ | ||
82 | #define DSIM_TX_LPDT_LP (1 << 6) | ||
83 | #define DSIM_CMD_LPDT_LP (1 << 7) | ||
84 | #define DSIM_FORCE_STOP_STATE_SHIFT(x) ((x) << 20) | ||
85 | #define DSIM_STOP_STATE_CNT_SHIFT(x) ((x) << 21) | ||
86 | |||
87 | /* EXYNOS_DSIM_MDRESOL */ | ||
88 | #define DSIM_MAIN_STAND_BY (1 << 31) | ||
89 | #define DSIM_MAIN_VRESOL(x) (((x) & 0x7ff) << 16) | ||
90 | #define DSIM_MAIN_HRESOL(x) (((x) & 0X7ff) << 0) | ||
91 | |||
92 | /* EXYNOS_DSIM_MVPORCH */ | ||
93 | #define DSIM_CMD_ALLOW_SHIFT(x) ((x) << 28) | ||
94 | #define DSIM_STABLE_VFP_SHIFT(x) ((x) << 16) | ||
95 | #define DSIM_MAIN_VBP_SHIFT(x) ((x) << 0) | ||
96 | #define DSIM_CMD_ALLOW_MASK (0xf << 28) | ||
97 | #define DSIM_STABLE_VFP_MASK (0x7ff << 16) | ||
98 | #define DSIM_MAIN_VBP_MASK (0x7ff << 0) | ||
99 | |||
100 | /* EXYNOS_DSIM_MHPORCH */ | ||
101 | #define DSIM_MAIN_HFP_SHIFT(x) ((x) << 16) | ||
102 | #define DSIM_MAIN_HBP_SHIFT(x) ((x) << 0) | ||
103 | #define DSIM_MAIN_HFP_MASK ((0xffff) << 16) | ||
104 | #define DSIM_MAIN_HBP_MASK ((0xffff) << 0) | ||
105 | |||
106 | /* EXYNOS_DSIM_MSYNC */ | ||
107 | #define DSIM_MAIN_VSA_SHIFT(x) ((x) << 22) | ||
108 | #define DSIM_MAIN_HSA_SHIFT(x) ((x) << 0) | ||
109 | #define DSIM_MAIN_VSA_MASK ((0x3ff) << 22) | ||
110 | #define DSIM_MAIN_HSA_MASK ((0xffff) << 0) | ||
111 | |||
112 | /* EXYNOS_DSIM_SDRESOL */ | ||
113 | #define DSIM_SUB_STANDY_SHIFT(x) ((x) << 31) | ||
114 | #define DSIM_SUB_VRESOL_SHIFT(x) ((x) << 16) | ||
115 | #define DSIM_SUB_HRESOL_SHIFT(x) ((x) << 0) | ||
116 | #define DSIM_SUB_STANDY_MASK ((0x1) << 31) | ||
117 | #define DSIM_SUB_VRESOL_MASK ((0x7ff) << 16) | ||
118 | #define DSIM_SUB_HRESOL_MASK ((0x7ff) << 0) | ||
119 | |||
120 | /* EXYNOS_DSIM_INTSRC */ | ||
121 | #define INTSRC_PLL_STABLE (1 << 31) | ||
122 | #define INTSRC_SW_RST_RELEASE (1 << 30) | ||
123 | #define INTSRC_SFR_FIFO_EMPTY (1 << 29) | ||
124 | #define INTSRC_FRAME_DONE (1 << 24) | ||
125 | #define INTSRC_RX_DATA_DONE (1 << 18) | ||
126 | |||
127 | /* EXYNOS_DSIM_INTMSK */ | ||
128 | #define INTMSK_FIFO_EMPTY (1 << 29) | ||
129 | #define INTMSK_BTA (1 << 25) | ||
130 | #define INTMSK_FRAME_DONE (1 << 24) | ||
131 | #define INTMSK_RX_TIMEOUT (1 << 21) | ||
132 | #define INTMSK_BTA_TIMEOUT (1 << 20) | ||
133 | #define INTMSK_RX_DONE (1 << 18) | ||
134 | #define INTMSK_RX_TE (1 << 17) | ||
135 | #define INTMSK_RX_ACK (1 << 16) | ||
136 | #define INTMSK_RX_ECC_ERR (1 << 15) | ||
137 | #define INTMSK_RX_CRC_ERR (1 << 14) | ||
138 | |||
139 | /* EXYNOS_DSIM_FIFOCTRL */ | ||
140 | #define SFR_HEADER_EMPTY (1 << 22) | ||
141 | |||
142 | /* EXYNOS_DSIM_PHYACCHR */ | ||
143 | #define DSIM_AFC_CTL(x) (((x) & 0x7) << 5) | ||
144 | |||
145 | /* EXYNOS_DSIM_PLLCTRL */ | ||
146 | #define DSIM_PLL_EN_SHIFT(x) ((x) << 23) | ||
147 | #define DSIM_FREQ_BAND_SHIFT(x) ((x) << 24) | ||
148 | |||
149 | #endif /* _EXYNOS_MIPI_DSI_REGS_H */ | ||
diff --git a/drivers/video/exynos/s6e8ax0.c b/drivers/video/exynos/s6e8ax0.c new file mode 100644 index 000000000000..4aa9ac6218bf --- /dev/null +++ b/drivers/video/exynos/s6e8ax0.c | |||
@@ -0,0 +1,898 @@ | |||
1 | /* linux/drivers/video/exynos/s6e8ax0.c | ||
2 | * | ||
3 | * MIPI-DSI based s6e8ax0 AMOLED lcd 4.65 inch panel driver. | ||
4 | * | ||
5 | * Inki Dae, <inki.dae@samsung.com> | ||
6 | * Donghwa Lee, <dh09.lee@samsung.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/errno.h> | ||
16 | #include <linux/mutex.h> | ||
17 | #include <linux/wait.h> | ||
18 | #include <linux/ctype.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/irq.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/lcd.h> | ||
24 | #include <linux/fb.h> | ||
25 | #include <linux/backlight.h> | ||
26 | #include <linux/regulator/consumer.h> | ||
27 | |||
28 | #include <video/mipi_display.h> | ||
29 | #include <video/exynos_mipi_dsim.h> | ||
30 | |||
31 | #define LDI_MTP_LENGTH 24 | ||
32 | #define DSIM_PM_STABLE_TIME 10 | ||
33 | #define MIN_BRIGHTNESS 0 | ||
34 | #define MAX_BRIGHTNESS 24 | ||
35 | #define GAMMA_TABLE_COUNT 26 | ||
36 | |||
37 | #define POWER_IS_ON(pwr) ((pwr) == FB_BLANK_UNBLANK) | ||
38 | #define POWER_IS_OFF(pwr) ((pwr) == FB_BLANK_POWERDOWN) | ||
39 | #define POWER_IS_NRM(pwr) ((pwr) == FB_BLANK_NORMAL) | ||
40 | |||
41 | #define lcd_to_master(a) (a->dsim_dev->master) | ||
42 | #define lcd_to_master_ops(a) ((lcd_to_master(a))->master_ops) | ||
43 | |||
44 | enum { | ||
45 | DSIM_NONE_STATE = 0, | ||
46 | DSIM_RESUME_COMPLETE = 1, | ||
47 | DSIM_FRAME_DONE = 2, | ||
48 | }; | ||
49 | |||
50 | struct s6e8ax0 { | ||
51 | struct device *dev; | ||
52 | unsigned int power; | ||
53 | unsigned int id; | ||
54 | unsigned int gamma; | ||
55 | unsigned int acl_enable; | ||
56 | unsigned int cur_acl; | ||
57 | |||
58 | struct lcd_device *ld; | ||
59 | struct backlight_device *bd; | ||
60 | |||
61 | struct mipi_dsim_lcd_device *dsim_dev; | ||
62 | struct lcd_platform_data *ddi_pd; | ||
63 | struct mutex lock; | ||
64 | bool enabled; | ||
65 | }; | ||
66 | |||
67 | |||
68 | static struct regulator_bulk_data supplies[] = { | ||
69 | { .supply = "vdd3", }, | ||
70 | { .supply = "vci", }, | ||
71 | }; | ||
72 | |||
73 | static void s6e8ax0_regulator_enable(struct s6e8ax0 *lcd) | ||
74 | { | ||
75 | int ret = 0; | ||
76 | struct lcd_platform_data *pd = NULL; | ||
77 | |||
78 | pd = lcd->ddi_pd; | ||
79 | mutex_lock(&lcd->lock); | ||
80 | if (!lcd->enabled) { | ||
81 | ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies); | ||
82 | if (ret) | ||
83 | goto out; | ||
84 | |||
85 | lcd->enabled = true; | ||
86 | } | ||
87 | msleep(pd->power_on_delay); | ||
88 | out: | ||
89 | mutex_unlock(&lcd->lock); | ||
90 | } | ||
91 | |||
92 | static void s6e8ax0_regulator_disable(struct s6e8ax0 *lcd) | ||
93 | { | ||
94 | int ret = 0; | ||
95 | |||
96 | mutex_lock(&lcd->lock); | ||
97 | if (lcd->enabled) { | ||
98 | ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies); | ||
99 | if (ret) | ||
100 | goto out; | ||
101 | |||
102 | lcd->enabled = false; | ||
103 | } | ||
104 | out: | ||
105 | mutex_unlock(&lcd->lock); | ||
106 | } | ||
107 | |||
108 | static const unsigned char s6e8ax0_22_gamma_30[] = { | ||
109 | 0xfa, 0x01, 0x60, 0x10, 0x60, 0xf5, 0x00, 0xff, 0xad, 0xaf, | ||
110 | 0xbA, 0xc3, 0xd8, 0xc5, 0x9f, 0xc6, 0x9e, 0xc1, 0xdc, 0xc0, | ||
111 | 0x00, 0x61, 0x00, 0x5a, 0x00, 0x74, | ||
112 | }; | ||
113 | |||
114 | static const unsigned char s6e8ax0_22_gamma_50[] = { | ||
115 | 0xfa, 0x01, 0x60, 0x10, 0x60, 0xe8, 0x1f, 0xf7, 0xad, 0xc0, | ||
116 | 0xb5, 0xc4, 0xdc, 0xc4, 0x9e, 0xc6, 0x9c, 0xbb, 0xd8, 0xbb, | ||
117 | 0x00, 0x70, 0x00, 0x68, 0x00, 0x86, | ||
118 | }; | ||
119 | |||
120 | static const unsigned char s6e8ax0_22_gamma_60[] = { | ||
121 | 0xfa, 0x01, 0x60, 0x10, 0x60, 0xde, 0x1f, 0xef, 0xad, 0xc4, | ||
122 | 0xb3, 0xc3, 0xdd, 0xc4, 0x9e, 0xc6, 0x9c, 0xbc, 0xd6, 0xba, | ||
123 | 0x00, 0x75, 0x00, 0x6e, 0x00, 0x8d, | ||
124 | }; | ||
125 | |||
126 | static const unsigned char s6e8ax0_22_gamma_70[] = { | ||
127 | 0xfa, 0x01, 0x60, 0x10, 0x60, 0xd8, 0x1f, 0xe7, 0xaf, 0xc8, | ||
128 | 0xb4, 0xc4, 0xdd, 0xc3, 0x9d, 0xc6, 0x9c, 0xbb, 0xd6, 0xb9, | ||
129 | 0x00, 0x7a, 0x00, 0x72, 0x00, 0x93, | ||
130 | }; | ||
131 | |||
132 | static const unsigned char s6e8ax0_22_gamma_80[] = { | ||
133 | 0xfa, 0x01, 0x60, 0x10, 0x60, 0xc9, 0x1f, 0xde, 0xae, 0xc9, | ||
134 | 0xb1, 0xc3, 0xdd, 0xc2, 0x9d, 0xc5, 0x9b, 0xbc, 0xd6, 0xbb, | ||
135 | 0x00, 0x7f, 0x00, 0x77, 0x00, 0x99, | ||
136 | }; | ||
137 | |||
138 | static const unsigned char s6e8ax0_22_gamma_90[] = { | ||
139 | 0xfa, 0x01, 0x60, 0x10, 0x60, 0xc7, 0x1f, 0xd9, 0xb0, 0xcc, | ||
140 | 0xb2, 0xc3, 0xdc, 0xc1, 0x9c, 0xc6, 0x9c, 0xbc, 0xd4, 0xb9, | ||
141 | 0x00, 0x83, 0x00, 0x7b, 0x00, 0x9e, | ||
142 | }; | ||
143 | |||
144 | static const unsigned char s6e8ax0_22_gamma_100[] = { | ||
145 | 0xfa, 0x01, 0x60, 0x10, 0x60, 0xbd, 0x80, 0xcd, 0xba, 0xce, | ||
146 | 0xb3, 0xc4, 0xde, 0xc3, 0x9c, 0xc4, 0x9, 0xb8, 0xd3, 0xb6, | ||
147 | 0x00, 0x88, 0x00, 0x80, 0x00, 0xa5, | ||
148 | }; | ||
149 | |||
150 | static const unsigned char s6e8ax0_22_gamma_120[] = { | ||
151 | 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb9, 0x95, 0xc8, 0xb1, 0xcf, | ||
152 | 0xb2, 0xc6, 0xdf, 0xc5, 0x9b, 0xc3, 0x99, 0xb6, 0xd2, 0xb6, | ||
153 | 0x00, 0x8f, 0x00, 0x86, 0x00, 0xac, | ||
154 | }; | ||
155 | |||
156 | static const unsigned char s6e8ax0_22_gamma_130[] = { | ||
157 | 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb7, 0xa0, 0xc7, 0xb1, 0xd0, | ||
158 | 0xb2, 0xc4, 0xdd, 0xc3, 0x9a, 0xc3, 0x98, 0xb6, 0xd0, 0xb4, | ||
159 | 0x00, 0x92, 0x00, 0x8a, 0x00, 0xb1, | ||
160 | }; | ||
161 | |||
162 | static const unsigned char s6e8ax0_22_gamma_140[] = { | ||
163 | 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb7, 0xa0, 0xc5, 0xb2, 0xd0, | ||
164 | 0xb3, 0xc3, 0xde, 0xc3, 0x9b, 0xc2, 0x98, 0xb6, 0xd0, 0xb4, | ||
165 | 0x00, 0x95, 0x00, 0x8d, 0x00, 0xb5, | ||
166 | }; | ||
167 | |||
168 | static const unsigned char s6e8ax0_22_gamma_150[] = { | ||
169 | 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb3, 0xa0, 0xc2, 0xb2, 0xd0, | ||
170 | 0xb2, 0xc1, 0xdd, 0xc2, 0x9b, 0xc2, 0x98, 0xb4, 0xcf, 0xb1, | ||
171 | 0x00, 0x99, 0x00, 0x90, 0x00, 0xba, | ||
172 | }; | ||
173 | |||
174 | static const unsigned char s6e8ax0_22_gamma_160[] = { | ||
175 | 0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xa5, 0xbf, 0xb0, 0xd0, | ||
176 | 0xb1, 0xc3, 0xde, 0xc2, 0x99, 0xc1, 0x97, 0xb4, 0xce, 0xb1, | ||
177 | 0x00, 0x9c, 0x00, 0x93, 0x00, 0xbe, | ||
178 | }; | ||
179 | |||
180 | static const unsigned char s6e8ax0_22_gamma_170[] = { | ||
181 | 0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb5, 0xbf, 0xb1, 0xd1, | ||
182 | 0xb1, 0xc3, 0xde, 0xc3, 0x99, 0xc0, 0x96, 0xb4, 0xce, 0xb1, | ||
183 | 0x00, 0x9f, 0x00, 0x96, 0x00, 0xc2, | ||
184 | }; | ||
185 | |||
186 | static const unsigned char s6e8ax0_22_gamma_180[] = { | ||
187 | 0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb7, 0xbe, 0xb3, 0xd2, | ||
188 | 0xb3, 0xc3, 0xde, 0xc2, 0x97, 0xbf, 0x95, 0xb4, 0xcd, 0xb1, | ||
189 | 0x00, 0xa2, 0x00, 0x99, 0x00, 0xc5, | ||
190 | }; | ||
191 | |||
192 | static const unsigned char s6e8ax0_22_gamma_190[] = { | ||
193 | 0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb9, 0xbe, 0xb2, 0xd2, | ||
194 | 0xb2, 0xc3, 0xdd, 0xc3, 0x98, 0xbf, 0x95, 0xb2, 0xcc, 0xaf, | ||
195 | 0x00, 0xa5, 0x00, 0x9c, 0x00, 0xc9, | ||
196 | }; | ||
197 | |||
198 | static const unsigned char s6e8ax0_22_gamma_200[] = { | ||
199 | 0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb9, 0xbc, 0xb2, 0xd2, | ||
200 | 0xb1, 0xc4, 0xdd, 0xc3, 0x97, 0xbe, 0x95, 0xb1, 0xcb, 0xae, | ||
201 | 0x00, 0xa8, 0x00, 0x9f, 0x00, 0xcd, | ||
202 | }; | ||
203 | |||
204 | static const unsigned char s6e8ax0_22_gamma_210[] = { | ||
205 | 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xc1, 0xbd, 0xb1, 0xd1, | ||
206 | 0xb1, 0xc2, 0xde, 0xc2, 0x97, 0xbe, 0x94, 0xB0, 0xc9, 0xad, | ||
207 | 0x00, 0xae, 0x00, 0xa4, 0x00, 0xd4, | ||
208 | }; | ||
209 | |||
210 | static const unsigned char s6e8ax0_22_gamma_220[] = { | ||
211 | 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xc7, 0xbd, 0xb1, 0xd1, | ||
212 | 0xb1, 0xc2, 0xdd, 0xc2, 0x97, 0xbd, 0x94, 0xb0, 0xc9, 0xad, | ||
213 | 0x00, 0xad, 0x00, 0xa2, 0x00, 0xd3, | ||
214 | }; | ||
215 | |||
216 | static const unsigned char s6e8ax0_22_gamma_230[] = { | ||
217 | 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xc3, 0xbd, 0xb2, 0xd1, | ||
218 | 0xb1, 0xc3, 0xdd, 0xc1, 0x96, 0xbd, 0x94, 0xb0, 0xc9, 0xad, | ||
219 | 0x00, 0xb0, 0x00, 0xa7, 0x00, 0xd7, | ||
220 | }; | ||
221 | |||
222 | static const unsigned char s6e8ax0_22_gamma_240[] = { | ||
223 | 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xcb, 0xbd, 0xb1, 0xd2, | ||
224 | 0xb1, 0xc3, 0xdD, 0xc2, 0x95, 0xbd, 0x93, 0xaf, 0xc8, 0xab, | ||
225 | 0x00, 0xb3, 0x00, 0xa9, 0x00, 0xdb, | ||
226 | }; | ||
227 | |||
228 | static const unsigned char s6e8ax0_22_gamma_250[] = { | ||
229 | 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb3, 0xcc, 0xbe, 0xb0, 0xd2, | ||
230 | 0xb0, 0xc3, 0xdD, 0xc2, 0x94, 0xbc, 0x92, 0xae, 0xc8, 0xab, | ||
231 | 0x00, 0xb6, 0x00, 0xab, 0x00, 0xde, | ||
232 | }; | ||
233 | |||
234 | static const unsigned char s6e8ax0_22_gamma_260[] = { | ||
235 | 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb3, 0xd0, 0xbe, 0xaf, 0xd1, | ||
236 | 0xaf, 0xc2, 0xdd, 0xc1, 0x96, 0xbc, 0x93, 0xaf, 0xc8, 0xac, | ||
237 | 0x00, 0xb7, 0x00, 0xad, 0x00, 0xe0, | ||
238 | }; | ||
239 | |||
240 | static const unsigned char s6e8ax0_22_gamma_270[] = { | ||
241 | 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb2, 0xcF, 0xbd, 0xb0, 0xd2, | ||
242 | 0xaf, 0xc2, 0xdc, 0xc1, 0x95, 0xbd, 0x93, 0xae, 0xc6, 0xaa, | ||
243 | 0x00, 0xba, 0x00, 0xb0, 0x00, 0xe4, | ||
244 | }; | ||
245 | |||
246 | static const unsigned char s6e8ax0_22_gamma_280[] = { | ||
247 | 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb2, 0xd0, 0xbd, 0xaf, 0xd0, | ||
248 | 0xad, 0xc4, 0xdd, 0xc3, 0x95, 0xbd, 0x93, 0xac, 0xc5, 0xa9, | ||
249 | 0x00, 0xbd, 0x00, 0xb2, 0x00, 0xe7, | ||
250 | }; | ||
251 | |||
252 | static const unsigned char s6e8ax0_22_gamma_300[] = { | ||
253 | 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb5, 0xd3, 0xbd, 0xb1, 0xd2, | ||
254 | 0xb0, 0xc0, 0xdc, 0xc0, 0x94, 0xba, 0x91, 0xac, 0xc5, 0xa9, | ||
255 | 0x00, 0xc2, 0x00, 0xb7, 0x00, 0xed, | ||
256 | }; | ||
257 | |||
258 | static const unsigned char *s6e8ax0_22_gamma_table[] = { | ||
259 | s6e8ax0_22_gamma_30, | ||
260 | s6e8ax0_22_gamma_50, | ||
261 | s6e8ax0_22_gamma_60, | ||
262 | s6e8ax0_22_gamma_70, | ||
263 | s6e8ax0_22_gamma_80, | ||
264 | s6e8ax0_22_gamma_90, | ||
265 | s6e8ax0_22_gamma_100, | ||
266 | s6e8ax0_22_gamma_120, | ||
267 | s6e8ax0_22_gamma_130, | ||
268 | s6e8ax0_22_gamma_140, | ||
269 | s6e8ax0_22_gamma_150, | ||
270 | s6e8ax0_22_gamma_160, | ||
271 | s6e8ax0_22_gamma_170, | ||
272 | s6e8ax0_22_gamma_180, | ||
273 | s6e8ax0_22_gamma_190, | ||
274 | s6e8ax0_22_gamma_200, | ||
275 | s6e8ax0_22_gamma_210, | ||
276 | s6e8ax0_22_gamma_220, | ||
277 | s6e8ax0_22_gamma_230, | ||
278 | s6e8ax0_22_gamma_240, | ||
279 | s6e8ax0_22_gamma_250, | ||
280 | s6e8ax0_22_gamma_260, | ||
281 | s6e8ax0_22_gamma_270, | ||
282 | s6e8ax0_22_gamma_280, | ||
283 | s6e8ax0_22_gamma_300, | ||
284 | }; | ||
285 | |||
286 | static void s6e8ax0_panel_cond(struct s6e8ax0 *lcd) | ||
287 | { | ||
288 | struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd); | ||
289 | |||
290 | static const unsigned char data_to_send[] = { | ||
291 | 0xf8, 0x3d, 0x35, 0x00, 0x00, 0x00, 0x93, 0x00, 0x3c, 0x7d, | ||
292 | 0x08, 0x27, 0x7d, 0x3f, 0x00, 0x00, 0x00, 0x20, 0x04, 0x08, | ||
293 | 0x6e, 0x00, 0x00, 0x00, 0x02, 0x08, 0x08, 0x23, 0x23, 0xc0, | ||
294 | 0xc8, 0x08, 0x48, 0xc1, 0x00, 0xc1, 0xff, 0xff, 0xc8 | ||
295 | }; | ||
296 | |||
297 | ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE, | ||
298 | data_to_send, ARRAY_SIZE(data_to_send)); | ||
299 | } | ||
300 | |||
301 | static void s6e8ax0_display_cond(struct s6e8ax0 *lcd) | ||
302 | { | ||
303 | struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd); | ||
304 | static const unsigned char data_to_send[] = { | ||
305 | 0xf2, 0x80, 0x03, 0x0d | ||
306 | }; | ||
307 | |||
308 | ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE, | ||
309 | data_to_send, ARRAY_SIZE(data_to_send)); | ||
310 | } | ||
311 | |||
312 | /* Gamma 2.2 Setting (200cd, 7500K, 10MPCD) */ | ||
313 | static void s6e8ax0_gamma_cond(struct s6e8ax0 *lcd) | ||
314 | { | ||
315 | struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd); | ||
316 | unsigned int gamma = lcd->bd->props.brightness; | ||
317 | |||
318 | ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE, | ||
319 | s6e8ax0_22_gamma_table[gamma], | ||
320 | GAMMA_TABLE_COUNT); | ||
321 | } | ||
322 | |||
323 | static void s6e8ax0_gamma_update(struct s6e8ax0 *lcd) | ||
324 | { | ||
325 | struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd); | ||
326 | static const unsigned char data_to_send[] = { | ||
327 | 0xf7, 0x03 | ||
328 | }; | ||
329 | |||
330 | ops->cmd_write(lcd_to_master(lcd), | ||
331 | MIPI_DSI_DCS_SHORT_WRITE_PARAM, data_to_send, | ||
332 | ARRAY_SIZE(data_to_send)); | ||
333 | } | ||
334 | |||
335 | static void s6e8ax0_etc_cond1(struct s6e8ax0 *lcd) | ||
336 | { | ||
337 | struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd); | ||
338 | static const unsigned char data_to_send[] = { | ||
339 | 0xd1, 0xfe, 0x80, 0x00, 0x01, 0x0b, 0x00, 0x00, 0x40, | ||
340 | 0x0d, 0x00, 0x00 | ||
341 | }; | ||
342 | |||
343 | ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE, | ||
344 | data_to_send, ARRAY_SIZE(data_to_send)); | ||
345 | } | ||
346 | |||
347 | static void s6e8ax0_etc_cond2(struct s6e8ax0 *lcd) | ||
348 | { | ||
349 | struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd); | ||
350 | static const unsigned char data_to_send[] = { | ||
351 | 0xb6, 0x0c, 0x02, 0x03, 0x32, 0xff, 0x44, 0x44, 0xc0, | ||
352 | 0x00 | ||
353 | }; | ||
354 | |||
355 | ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE, | ||
356 | data_to_send, ARRAY_SIZE(data_to_send)); | ||
357 | } | ||
358 | |||
359 | static void s6e8ax0_etc_cond3(struct s6e8ax0 *lcd) | ||
360 | { | ||
361 | struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd); | ||
362 | static const unsigned char data_to_send[] = { | ||
363 | 0xe1, 0x10, 0x1c, 0x17, 0x08, 0x1d | ||
364 | }; | ||
365 | |||
366 | ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE, | ||
367 | data_to_send, ARRAY_SIZE(data_to_send)); | ||
368 | } | ||
369 | |||
370 | static void s6e8ax0_etc_cond4(struct s6e8ax0 *lcd) | ||
371 | { | ||
372 | struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd); | ||
373 | static const unsigned char data_to_send[] = { | ||
374 | 0xe2, 0xed, 0x07, 0xc3, 0x13, 0x0d, 0x03 | ||
375 | }; | ||
376 | |||
377 | ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE, | ||
378 | data_to_send, ARRAY_SIZE(data_to_send)); | ||
379 | } | ||
380 | |||
381 | static void s6e8ax0_etc_cond5(struct s6e8ax0 *lcd) | ||
382 | { | ||
383 | struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd); | ||
384 | static const unsigned char data_to_send[] = { | ||
385 | 0xf4, 0xcf, 0x0a, 0x12, 0x10, 0x19, 0x33, 0x02 | ||
386 | }; | ||
387 | |||
388 | ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE, | ||
389 | data_to_send, ARRAY_SIZE(data_to_send)); | ||
390 | } | ||
391 | static void s6e8ax0_etc_cond6(struct s6e8ax0 *lcd) | ||
392 | { | ||
393 | struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd); | ||
394 | static const unsigned char data_to_send[] = { | ||
395 | 0xe3, 0x40 | ||
396 | }; | ||
397 | |||
398 | ops->cmd_write(lcd_to_master(lcd), | ||
399 | MIPI_DSI_DCS_SHORT_WRITE_PARAM, | ||
400 | data_to_send, ARRAY_SIZE(data_to_send)); | ||
401 | } | ||
402 | |||
403 | static void s6e8ax0_etc_cond7(struct s6e8ax0 *lcd) | ||
404 | { | ||
405 | struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd); | ||
406 | static const unsigned char data_to_send[] = { | ||
407 | 0xe4, 0x00, 0x00, 0x14, 0x80, 0x00, 0x00, 0x00 | ||
408 | }; | ||
409 | |||
410 | ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE, | ||
411 | data_to_send, ARRAY_SIZE(data_to_send)); | ||
412 | } | ||
413 | |||
414 | static void s6e8ax0_elvss_set(struct s6e8ax0 *lcd) | ||
415 | { | ||
416 | struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd); | ||
417 | static const unsigned char data_to_send[] = { | ||
418 | 0xb1, 0x04, 0x00 | ||
419 | }; | ||
420 | |||
421 | ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE, | ||
422 | data_to_send, ARRAY_SIZE(data_to_send)); | ||
423 | } | ||
424 | |||
425 | static void s6e8ax0_elvss_nvm_set(struct s6e8ax0 *lcd) | ||
426 | { | ||
427 | struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd); | ||
428 | static const unsigned char data_to_send[] = { | ||
429 | 0xd9, 0x5c, 0x20, 0x0c, 0x0f, 0x41, 0x00, 0x10, 0x11, | ||
430 | 0x12, 0xd1, 0x00, 0x00, 0x00, 0x00, 0x80, 0xcb, 0xed, | ||
431 | 0x64, 0xaf | ||
432 | }; | ||
433 | |||
434 | ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE, | ||
435 | data_to_send, ARRAY_SIZE(data_to_send)); | ||
436 | } | ||
437 | |||
438 | static void s6e8ax0_sleep_in(struct s6e8ax0 *lcd) | ||
439 | { | ||
440 | struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd); | ||
441 | static const unsigned char data_to_send[] = { | ||
442 | 0x10, 0x00 | ||
443 | }; | ||
444 | |||
445 | ops->cmd_write(lcd_to_master(lcd), | ||
446 | MIPI_DSI_DCS_SHORT_WRITE, | ||
447 | data_to_send, ARRAY_SIZE(data_to_send)); | ||
448 | } | ||
449 | |||
450 | static void s6e8ax0_sleep_out(struct s6e8ax0 *lcd) | ||
451 | { | ||
452 | struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd); | ||
453 | static const unsigned char data_to_send[] = { | ||
454 | 0x11, 0x00 | ||
455 | }; | ||
456 | |||
457 | ops->cmd_write(lcd_to_master(lcd), | ||
458 | MIPI_DSI_DCS_SHORT_WRITE, | ||
459 | data_to_send, ARRAY_SIZE(data_to_send)); | ||
460 | } | ||
461 | |||
462 | static void s6e8ax0_display_on(struct s6e8ax0 *lcd) | ||
463 | { | ||
464 | struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd); | ||
465 | static const unsigned char data_to_send[] = { | ||
466 | 0x29, 0x00 | ||
467 | }; | ||
468 | |||
469 | ops->cmd_write(lcd_to_master(lcd), | ||
470 | MIPI_DSI_DCS_SHORT_WRITE, | ||
471 | data_to_send, ARRAY_SIZE(data_to_send)); | ||
472 | } | ||
473 | |||
474 | static void s6e8ax0_display_off(struct s6e8ax0 *lcd) | ||
475 | { | ||
476 | struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd); | ||
477 | static const unsigned char data_to_send[] = { | ||
478 | 0x28, 0x00 | ||
479 | }; | ||
480 | |||
481 | ops->cmd_write(lcd_to_master(lcd), | ||
482 | MIPI_DSI_DCS_SHORT_WRITE, | ||
483 | data_to_send, ARRAY_SIZE(data_to_send)); | ||
484 | } | ||
485 | |||
486 | static void s6e8ax0_apply_level2_key(struct s6e8ax0 *lcd) | ||
487 | { | ||
488 | struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd); | ||
489 | static const unsigned char data_to_send[] = { | ||
490 | 0xf0, 0x5a, 0x5a | ||
491 | }; | ||
492 | |||
493 | ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE, | ||
494 | data_to_send, ARRAY_SIZE(data_to_send)); | ||
495 | } | ||
496 | |||
497 | static void s6e8ax0_acl_on(struct s6e8ax0 *lcd) | ||
498 | { | ||
499 | struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd); | ||
500 | static const unsigned char data_to_send[] = { | ||
501 | 0xc0, 0x01 | ||
502 | }; | ||
503 | |||
504 | ops->cmd_write(lcd_to_master(lcd), | ||
505 | MIPI_DSI_DCS_SHORT_WRITE, | ||
506 | data_to_send, ARRAY_SIZE(data_to_send)); | ||
507 | } | ||
508 | |||
509 | static void s6e8ax0_acl_off(struct s6e8ax0 *lcd) | ||
510 | { | ||
511 | struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd); | ||
512 | static const unsigned char data_to_send[] = { | ||
513 | 0xc0, 0x00 | ||
514 | }; | ||
515 | |||
516 | ops->cmd_write(lcd_to_master(lcd), | ||
517 | MIPI_DSI_DCS_SHORT_WRITE, | ||
518 | data_to_send, ARRAY_SIZE(data_to_send)); | ||
519 | } | ||
520 | |||
521 | /* Full white 50% reducing setting */ | ||
522 | static void s6e8ax0_acl_ctrl_set(struct s6e8ax0 *lcd) | ||
523 | { | ||
524 | struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd); | ||
525 | /* Full white 50% reducing setting */ | ||
526 | static const unsigned char cutoff_50[] = { | ||
527 | 0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf, | ||
528 | 0x00, 0x00, 0x04, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
529 | 0x01, 0x08, 0x0f, 0x16, 0x1d, 0x24, 0x2a, 0x31, 0x38, | ||
530 | 0x3f, 0x46 | ||
531 | }; | ||
532 | /* Full white 45% reducing setting */ | ||
533 | static const unsigned char cutoff_45[] = { | ||
534 | 0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf, | ||
535 | 0x00, 0x00, 0x04, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
536 | 0x01, 0x07, 0x0d, 0x13, 0x19, 0x1f, 0x25, 0x2b, 0x31, | ||
537 | 0x37, 0x3d | ||
538 | }; | ||
539 | /* Full white 40% reducing setting */ | ||
540 | static const unsigned char cutoff_40[] = { | ||
541 | 0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf, | ||
542 | 0x00, 0x00, 0x04, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
543 | 0x01, 0x06, 0x0c, 0x11, 0x16, 0x1c, 0x21, 0x26, 0x2b, | ||
544 | 0x31, 0x36 | ||
545 | }; | ||
546 | |||
547 | if (lcd->acl_enable) { | ||
548 | if (lcd->cur_acl == 0) { | ||
549 | if (lcd->gamma == 0 || lcd->gamma == 1) { | ||
550 | s6e8ax0_acl_off(lcd); | ||
551 | dev_dbg(&lcd->ld->dev, | ||
552 | "cur_acl=%d\n", lcd->cur_acl); | ||
553 | } else | ||
554 | s6e8ax0_acl_on(lcd); | ||
555 | } | ||
556 | switch (lcd->gamma) { | ||
557 | case 0: /* 30cd */ | ||
558 | s6e8ax0_acl_off(lcd); | ||
559 | lcd->cur_acl = 0; | ||
560 | break; | ||
561 | case 1 ... 3: /* 50cd ~ 90cd */ | ||
562 | ops->cmd_write(lcd_to_master(lcd), | ||
563 | MIPI_DSI_DCS_LONG_WRITE, | ||
564 | cutoff_40, | ||
565 | ARRAY_SIZE(cutoff_40)); | ||
566 | lcd->cur_acl = 40; | ||
567 | break; | ||
568 | case 4 ... 7: /* 120cd ~ 210cd */ | ||
569 | ops->cmd_write(lcd_to_master(lcd), | ||
570 | MIPI_DSI_DCS_LONG_WRITE, | ||
571 | cutoff_45, | ||
572 | ARRAY_SIZE(cutoff_45)); | ||
573 | lcd->cur_acl = 45; | ||
574 | break; | ||
575 | case 8 ... 10: /* 220cd ~ 300cd */ | ||
576 | ops->cmd_write(lcd_to_master(lcd), | ||
577 | MIPI_DSI_DCS_LONG_WRITE, | ||
578 | cutoff_50, | ||
579 | ARRAY_SIZE(cutoff_50)); | ||
580 | lcd->cur_acl = 50; | ||
581 | break; | ||
582 | default: | ||
583 | break; | ||
584 | } | ||
585 | } else { | ||
586 | s6e8ax0_acl_off(lcd); | ||
587 | lcd->cur_acl = 0; | ||
588 | dev_dbg(&lcd->ld->dev, "cur_acl = %d\n", lcd->cur_acl); | ||
589 | } | ||
590 | } | ||
591 | |||
592 | static void s6e8ax0_read_id(struct s6e8ax0 *lcd, u8 *mtp_id) | ||
593 | { | ||
594 | unsigned int ret; | ||
595 | unsigned int addr = 0xd1; /* MTP ID */ | ||
596 | struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd); | ||
597 | |||
598 | ret = ops->cmd_read(lcd_to_master(lcd), | ||
599 | MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM, | ||
600 | addr, 3, mtp_id); | ||
601 | } | ||
602 | |||
603 | static int s6e8ax0_panel_init(struct s6e8ax0 *lcd) | ||
604 | { | ||
605 | s6e8ax0_apply_level2_key(lcd); | ||
606 | s6e8ax0_sleep_out(lcd); | ||
607 | msleep(1); | ||
608 | s6e8ax0_panel_cond(lcd); | ||
609 | s6e8ax0_display_cond(lcd); | ||
610 | s6e8ax0_gamma_cond(lcd); | ||
611 | s6e8ax0_gamma_update(lcd); | ||
612 | |||
613 | s6e8ax0_etc_cond1(lcd); | ||
614 | s6e8ax0_etc_cond2(lcd); | ||
615 | s6e8ax0_etc_cond3(lcd); | ||
616 | s6e8ax0_etc_cond4(lcd); | ||
617 | s6e8ax0_etc_cond5(lcd); | ||
618 | s6e8ax0_etc_cond6(lcd); | ||
619 | s6e8ax0_etc_cond7(lcd); | ||
620 | |||
621 | s6e8ax0_elvss_nvm_set(lcd); | ||
622 | s6e8ax0_elvss_set(lcd); | ||
623 | |||
624 | s6e8ax0_acl_ctrl_set(lcd); | ||
625 | s6e8ax0_acl_on(lcd); | ||
626 | |||
627 | /* if ID3 value is not 33h, branch private elvss mode */ | ||
628 | msleep(lcd->ddi_pd->power_on_delay); | ||
629 | |||
630 | return 0; | ||
631 | } | ||
632 | |||
633 | static int s6e8ax0_update_gamma_ctrl(struct s6e8ax0 *lcd, int brightness) | ||
634 | { | ||
635 | struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd); | ||
636 | |||
637 | ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE, | ||
638 | s6e8ax0_22_gamma_table[brightness], | ||
639 | ARRAY_SIZE(s6e8ax0_22_gamma_table)); | ||
640 | |||
641 | /* update gamma table. */ | ||
642 | s6e8ax0_gamma_update(lcd); | ||
643 | lcd->gamma = brightness; | ||
644 | |||
645 | return 0; | ||
646 | } | ||
647 | |||
648 | static int s6e8ax0_gamma_ctrl(struct s6e8ax0 *lcd, int gamma) | ||
649 | { | ||
650 | s6e8ax0_update_gamma_ctrl(lcd, gamma); | ||
651 | |||
652 | return 0; | ||
653 | } | ||
654 | |||
655 | static int s6e8ax0_set_power(struct lcd_device *ld, int power) | ||
656 | { | ||
657 | struct s6e8ax0 *lcd = lcd_get_data(ld); | ||
658 | struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd); | ||
659 | int ret = 0; | ||
660 | |||
661 | if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN && | ||
662 | power != FB_BLANK_NORMAL) { | ||
663 | dev_err(lcd->dev, "power value should be 0, 1 or 4.\n"); | ||
664 | return -EINVAL; | ||
665 | } | ||
666 | |||
667 | if ((power == FB_BLANK_UNBLANK) && ops->set_blank_mode) { | ||
668 | /* LCD power on */ | ||
669 | if ((POWER_IS_ON(power) && POWER_IS_OFF(lcd->power)) | ||
670 | || (POWER_IS_ON(power) && POWER_IS_NRM(lcd->power))) { | ||
671 | ret = ops->set_blank_mode(lcd_to_master(lcd), power); | ||
672 | if (!ret && lcd->power != power) | ||
673 | lcd->power = power; | ||
674 | } | ||
675 | } else if ((power == FB_BLANK_POWERDOWN) && ops->set_early_blank_mode) { | ||
676 | /* LCD power off */ | ||
677 | if ((POWER_IS_OFF(power) && POWER_IS_ON(lcd->power)) || | ||
678 | (POWER_IS_ON(lcd->power) && POWER_IS_NRM(power))) { | ||
679 | ret = ops->set_early_blank_mode(lcd_to_master(lcd), | ||
680 | power); | ||
681 | if (!ret && lcd->power != power) | ||
682 | lcd->power = power; | ||
683 | } | ||
684 | } | ||
685 | |||
686 | return ret; | ||
687 | } | ||
688 | |||
689 | static int s6e8ax0_get_power(struct lcd_device *ld) | ||
690 | { | ||
691 | struct s6e8ax0 *lcd = lcd_get_data(ld); | ||
692 | |||
693 | return lcd->power; | ||
694 | } | ||
695 | |||
696 | static int s6e8ax0_get_brightness(struct backlight_device *bd) | ||
697 | { | ||
698 | return bd->props.brightness; | ||
699 | } | ||
700 | |||
701 | static int s6e8ax0_set_brightness(struct backlight_device *bd) | ||
702 | { | ||
703 | int ret = 0, brightness = bd->props.brightness; | ||
704 | struct s6e8ax0 *lcd = bl_get_data(bd); | ||
705 | |||
706 | if (brightness < MIN_BRIGHTNESS || | ||
707 | brightness > bd->props.max_brightness) { | ||
708 | dev_err(lcd->dev, "lcd brightness should be %d to %d.\n", | ||
709 | MIN_BRIGHTNESS, MAX_BRIGHTNESS); | ||
710 | return -EINVAL; | ||
711 | } | ||
712 | |||
713 | ret = s6e8ax0_gamma_ctrl(lcd, brightness); | ||
714 | if (ret) { | ||
715 | dev_err(&bd->dev, "lcd brightness setting failed.\n"); | ||
716 | return -EIO; | ||
717 | } | ||
718 | |||
719 | return ret; | ||
720 | } | ||
721 | |||
722 | static struct lcd_ops s6e8ax0_lcd_ops = { | ||
723 | .set_power = s6e8ax0_set_power, | ||
724 | .get_power = s6e8ax0_get_power, | ||
725 | }; | ||
726 | |||
727 | static const struct backlight_ops s6e8ax0_backlight_ops = { | ||
728 | .get_brightness = s6e8ax0_get_brightness, | ||
729 | .update_status = s6e8ax0_set_brightness, | ||
730 | }; | ||
731 | |||
732 | static void s6e8ax0_power_on(struct mipi_dsim_lcd_device *dsim_dev, int power) | ||
733 | { | ||
734 | struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev); | ||
735 | |||
736 | msleep(lcd->ddi_pd->power_on_delay); | ||
737 | |||
738 | /* lcd power on */ | ||
739 | if (power) | ||
740 | s6e8ax0_regulator_enable(lcd); | ||
741 | else | ||
742 | s6e8ax0_regulator_disable(lcd); | ||
743 | |||
744 | msleep(lcd->ddi_pd->reset_delay); | ||
745 | |||
746 | /* lcd reset */ | ||
747 | if (lcd->ddi_pd->reset) | ||
748 | lcd->ddi_pd->reset(lcd->ld); | ||
749 | msleep(5); | ||
750 | } | ||
751 | |||
752 | static void s6e8ax0_set_sequence(struct mipi_dsim_lcd_device *dsim_dev) | ||
753 | { | ||
754 | struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev); | ||
755 | |||
756 | s6e8ax0_panel_init(lcd); | ||
757 | s6e8ax0_display_on(lcd); | ||
758 | |||
759 | lcd->power = FB_BLANK_UNBLANK; | ||
760 | } | ||
761 | |||
762 | static int s6e8ax0_probe(struct mipi_dsim_lcd_device *dsim_dev) | ||
763 | { | ||
764 | struct s6e8ax0 *lcd; | ||
765 | int ret; | ||
766 | u8 mtp_id[3] = {0, }; | ||
767 | |||
768 | lcd = kzalloc(sizeof(struct s6e8ax0), GFP_KERNEL); | ||
769 | if (!lcd) { | ||
770 | dev_err(&dsim_dev->dev, "failed to allocate s6e8ax0 structure.\n"); | ||
771 | return -ENOMEM; | ||
772 | } | ||
773 | |||
774 | lcd->dsim_dev = dsim_dev; | ||
775 | lcd->ddi_pd = (struct lcd_platform_data *)dsim_dev->platform_data; | ||
776 | lcd->dev = &dsim_dev->dev; | ||
777 | |||
778 | mutex_init(&lcd->lock); | ||
779 | |||
780 | ret = regulator_bulk_get(lcd->dev, ARRAY_SIZE(supplies), supplies); | ||
781 | if (ret) { | ||
782 | dev_err(lcd->dev, "Failed to get regulators: %d\n", ret); | ||
783 | goto err_lcd_register; | ||
784 | } | ||
785 | |||
786 | lcd->ld = lcd_device_register("s6e8ax0", lcd->dev, lcd, | ||
787 | &s6e8ax0_lcd_ops); | ||
788 | if (IS_ERR(lcd->ld)) { | ||
789 | dev_err(lcd->dev, "failed to register lcd ops.\n"); | ||
790 | ret = PTR_ERR(lcd->ld); | ||
791 | goto err_lcd_register; | ||
792 | } | ||
793 | |||
794 | lcd->bd = backlight_device_register("s6e8ax0-bl", lcd->dev, lcd, | ||
795 | &s6e8ax0_backlight_ops, NULL); | ||
796 | if (IS_ERR(lcd->bd)) { | ||
797 | dev_err(lcd->dev, "failed to register backlight ops.\n"); | ||
798 | ret = PTR_ERR(lcd->bd); | ||
799 | goto err_backlight_register; | ||
800 | } | ||
801 | |||
802 | lcd->bd->props.max_brightness = MAX_BRIGHTNESS; | ||
803 | lcd->bd->props.brightness = MAX_BRIGHTNESS; | ||
804 | |||
805 | s6e8ax0_read_id(lcd, mtp_id); | ||
806 | if (mtp_id[0] == 0x00) | ||
807 | dev_err(lcd->dev, "read id failed\n"); | ||
808 | |||
809 | dev_info(lcd->dev, "Read ID : %x, %x, %x\n", | ||
810 | mtp_id[0], mtp_id[1], mtp_id[2]); | ||
811 | |||
812 | if (mtp_id[2] == 0x33) | ||
813 | dev_info(lcd->dev, | ||
814 | "ID-3 is 0xff does not support dynamic elvss\n"); | ||
815 | else | ||
816 | dev_info(lcd->dev, | ||
817 | "ID-3 is 0x%x support dynamic elvss\n", mtp_id[2]); | ||
818 | |||
819 | lcd->acl_enable = 1; | ||
820 | lcd->cur_acl = 0; | ||
821 | |||
822 | dev_set_drvdata(&dsim_dev->dev, lcd); | ||
823 | |||
824 | dev_dbg(lcd->dev, "probed s6e8ax0 panel driver.\n"); | ||
825 | |||
826 | return 0; | ||
827 | |||
828 | err_backlight_register: | ||
829 | lcd_device_unregister(lcd->ld); | ||
830 | |||
831 | err_lcd_register: | ||
832 | regulator_bulk_free(ARRAY_SIZE(supplies), supplies); | ||
833 | kfree(lcd); | ||
834 | |||
835 | return ret; | ||
836 | } | ||
837 | |||
838 | #ifdef CONFIG_PM | ||
839 | static int s6e8ax0_suspend(struct mipi_dsim_lcd_device *dsim_dev) | ||
840 | { | ||
841 | struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev); | ||
842 | |||
843 | s6e8ax0_sleep_in(lcd); | ||
844 | msleep(lcd->ddi_pd->power_off_delay); | ||
845 | s6e8ax0_display_off(lcd); | ||
846 | |||
847 | s6e8ax0_regulator_disable(lcd); | ||
848 | |||
849 | return 0; | ||
850 | } | ||
851 | |||
852 | static int s6e8ax0_resume(struct mipi_dsim_lcd_device *dsim_dev) | ||
853 | { | ||
854 | struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev); | ||
855 | |||
856 | s6e8ax0_sleep_out(lcd); | ||
857 | msleep(lcd->ddi_pd->power_on_delay); | ||
858 | |||
859 | s6e8ax0_regulator_enable(lcd); | ||
860 | s6e8ax0_set_sequence(dsim_dev); | ||
861 | |||
862 | return 0; | ||
863 | } | ||
864 | #else | ||
865 | #define s6e8ax0_suspend NULL | ||
866 | #define s6e8ax0_resume NULL | ||
867 | #endif | ||
868 | |||
869 | static struct mipi_dsim_lcd_driver s6e8ax0_dsim_ddi_driver = { | ||
870 | .name = "s6e8ax0", | ||
871 | .id = -1, | ||
872 | |||
873 | .power_on = s6e8ax0_power_on, | ||
874 | .set_sequence = s6e8ax0_set_sequence, | ||
875 | .probe = s6e8ax0_probe, | ||
876 | .suspend = s6e8ax0_suspend, | ||
877 | .resume = s6e8ax0_resume, | ||
878 | }; | ||
879 | |||
880 | static int s6e8ax0_init(void) | ||
881 | { | ||
882 | exynos_mipi_dsi_register_lcd_driver(&s6e8ax0_dsim_ddi_driver); | ||
883 | |||
884 | return 0; | ||
885 | } | ||
886 | |||
887 | static void s6e8ax0_exit(void) | ||
888 | { | ||
889 | return; | ||
890 | } | ||
891 | |||
892 | module_init(s6e8ax0_init); | ||
893 | module_exit(s6e8ax0_exit); | ||
894 | |||
895 | MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>"); | ||
896 | MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>"); | ||
897 | MODULE_DESCRIPTION("MIPI-DSI based s6e8ax0 AMOLED LCD Panel Driver"); | ||
898 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/exynos/s6e8ax0.h b/drivers/video/exynos/s6e8ax0.h new file mode 100644 index 000000000000..1f1b270484b0 --- /dev/null +++ b/drivers/video/exynos/s6e8ax0.h | |||
@@ -0,0 +1,21 @@ | |||
1 | /* linux/drivers/video/backlight/s6e8ax0.h | ||
2 | * | ||
3 | * MIPI-DSI based s6e8ax0 AMOLED LCD Panel definitions. | ||
4 | * | ||
5 | * Copyright (c) 2011 Samsung Electronics | ||
6 | * | ||
7 | * Inki Dae, <inki.dae@samsung.com> | ||
8 | * Donghwa Lee <dh09.lee@samsung.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #ifndef _S6E8AX0_H | ||
16 | #define _S6E8AX0_H | ||
17 | |||
18 | extern void s6e8ax0_init(void); | ||
19 | |||
20 | #endif | ||
21 | |||
diff --git a/drivers/video/i740_reg.h b/drivers/video/i740_reg.h new file mode 100644 index 000000000000..91bac76549d7 --- /dev/null +++ b/drivers/video/i740_reg.h | |||
@@ -0,0 +1,309 @@ | |||
1 | /************************************************************************** | ||
2 | |||
3 | Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. | ||
4 | All Rights Reserved. | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a | ||
7 | copy of this software and associated documentation files (the | ||
8 | "Software"), to deal in the Software without restriction, including | ||
9 | without limitation the rights to use, copy, modify, merge, publish, | ||
10 | distribute, sub license, and/or sell copies of the Software, and to | ||
11 | permit persons to whom the Software is furnished to do so, subject to | ||
12 | the following conditions: | ||
13 | |||
14 | The above copyright notice and this permission notice (including the | ||
15 | next paragraph) shall be included in all copies or substantial portions | ||
16 | of the Software. | ||
17 | |||
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
19 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. | ||
21 | IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR | ||
22 | ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
23 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
24 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
25 | |||
26 | **************************************************************************/ | ||
27 | |||
28 | /* | ||
29 | * Authors: | ||
30 | * Kevin E. Martin <kevin@precisioninsight.com> | ||
31 | */ | ||
32 | |||
33 | /* I/O register offsets */ | ||
34 | #define SRX VGA_SEQ_I | ||
35 | #define GRX VGA_GFX_I | ||
36 | #define ARX VGA_ATT_IW | ||
37 | #define XRX 0x3D6 | ||
38 | #define MRX 0x3D2 | ||
39 | |||
40 | /* VGA Color Palette Registers */ | ||
41 | #define DACMASK 0x3C6 | ||
42 | #define DACSTATE 0x3C7 | ||
43 | #define DACRX 0x3C7 | ||
44 | #define DACWX 0x3C8 | ||
45 | #define DACDATA 0x3C9 | ||
46 | |||
47 | /* CRT Controller Registers (CRX) */ | ||
48 | #define START_ADDR_HI 0x0C | ||
49 | #define START_ADDR_LO 0x0D | ||
50 | #define VERT_SYNC_END 0x11 | ||
51 | #define EXT_VERT_TOTAL 0x30 | ||
52 | #define EXT_VERT_DISPLAY 0x31 | ||
53 | #define EXT_VERT_SYNC_START 0x32 | ||
54 | #define EXT_VERT_BLANK_START 0x33 | ||
55 | #define EXT_HORIZ_TOTAL 0x35 | ||
56 | #define EXT_HORIZ_BLANK 0x39 | ||
57 | #define EXT_START_ADDR 0x40 | ||
58 | #define EXT_START_ADDR_ENABLE 0x80 | ||
59 | #define EXT_OFFSET 0x41 | ||
60 | #define EXT_START_ADDR_HI 0x42 | ||
61 | #define INTERLACE_CNTL 0x70 | ||
62 | #define INTERLACE_ENABLE 0x80 | ||
63 | #define INTERLACE_DISABLE 0x00 | ||
64 | |||
65 | /* Miscellaneous Output Register */ | ||
66 | #define MSR_R 0x3CC | ||
67 | #define MSR_W 0x3C2 | ||
68 | #define IO_ADDR_SELECT 0x01 | ||
69 | |||
70 | #define MDA_BASE 0x3B0 | ||
71 | #define CGA_BASE 0x3D0 | ||
72 | |||
73 | /* System Configuration Extension Registers (XRX) */ | ||
74 | #define IO_CTNL 0x09 | ||
75 | #define EXTENDED_ATTR_CNTL 0x02 | ||
76 | #define EXTENDED_CRTC_CNTL 0x01 | ||
77 | |||
78 | #define ADDRESS_MAPPING 0x0A | ||
79 | #define PACKED_MODE_ENABLE 0x04 | ||
80 | #define LINEAR_MODE_ENABLE 0x02 | ||
81 | #define PAGE_MAPPING_ENABLE 0x01 | ||
82 | |||
83 | #define BITBLT_CNTL 0x20 | ||
84 | #define COLEXP_MODE 0x30 | ||
85 | #define COLEXP_8BPP 0x00 | ||
86 | #define COLEXP_16BPP 0x10 | ||
87 | #define COLEXP_24BPP 0x20 | ||
88 | #define COLEXP_RESERVED 0x30 | ||
89 | #define CHIP_RESET 0x02 | ||
90 | #define BITBLT_STATUS 0x01 | ||
91 | |||
92 | #define DISPLAY_CNTL 0x40 | ||
93 | #define VGA_WRAP_MODE 0x02 | ||
94 | #define VGA_WRAP_AT_256KB 0x00 | ||
95 | #define VGA_NO_WRAP 0x02 | ||
96 | #define GUI_MODE 0x01 | ||
97 | #define STANDARD_VGA_MODE 0x00 | ||
98 | #define HIRES_MODE 0x01 | ||
99 | |||
100 | #define DRAM_ROW_TYPE 0x50 | ||
101 | #define DRAM_ROW_0 0x07 | ||
102 | #define DRAM_ROW_0_SDRAM 0x00 | ||
103 | #define DRAM_ROW_0_EMPTY 0x07 | ||
104 | #define DRAM_ROW_1 0x38 | ||
105 | #define DRAM_ROW_1_SDRAM 0x00 | ||
106 | #define DRAM_ROW_1_EMPTY 0x38 | ||
107 | #define DRAM_ROW_CNTL_LO 0x51 | ||
108 | #define DRAM_CAS_LATENCY 0x10 | ||
109 | #define DRAM_RAS_TIMING 0x08 | ||
110 | #define DRAM_RAS_PRECHARGE 0x04 | ||
111 | #define DRAM_ROW_CNTL_HI 0x52 | ||
112 | #define DRAM_EXT_CNTL 0x53 | ||
113 | #define DRAM_REFRESH_RATE 0x03 | ||
114 | #define DRAM_REFRESH_DISABLE 0x00 | ||
115 | #define DRAM_REFRESH_60HZ 0x01 | ||
116 | #define DRAM_REFRESH_FAST_TEST 0x02 | ||
117 | #define DRAM_REFRESH_RESERVED 0x03 | ||
118 | #define DRAM_TIMING 0x54 | ||
119 | #define DRAM_ROW_BNDRY_0 0x55 | ||
120 | #define DRAM_ROW_BNDRY_1 0x56 | ||
121 | |||
122 | #define DPMS_SYNC_SELECT 0x61 | ||
123 | #define VSYNC_CNTL 0x08 | ||
124 | #define VSYNC_ON 0x00 | ||
125 | #define VSYNC_OFF 0x08 | ||
126 | #define HSYNC_CNTL 0x02 | ||
127 | #define HSYNC_ON 0x00 | ||
128 | #define HSYNC_OFF 0x02 | ||
129 | |||
130 | #define PIXPIPE_CONFIG_0 0x80 | ||
131 | #define DAC_8_BIT 0x80 | ||
132 | #define DAC_6_BIT 0x00 | ||
133 | #define HW_CURSOR_ENABLE 0x10 | ||
134 | #define EXTENDED_PALETTE 0x01 | ||
135 | |||
136 | #define PIXPIPE_CONFIG_1 0x81 | ||
137 | #define DISPLAY_COLOR_MODE 0x0F | ||
138 | #define DISPLAY_VGA_MODE 0x00 | ||
139 | #define DISPLAY_8BPP_MODE 0x02 | ||
140 | #define DISPLAY_15BPP_MODE 0x04 | ||
141 | #define DISPLAY_16BPP_MODE 0x05 | ||
142 | #define DISPLAY_24BPP_MODE 0x06 | ||
143 | #define DISPLAY_32BPP_MODE 0x07 | ||
144 | |||
145 | #define PIXPIPE_CONFIG_2 0x82 | ||
146 | #define DISPLAY_GAMMA_ENABLE 0x08 | ||
147 | #define DISPLAY_GAMMA_DISABLE 0x00 | ||
148 | #define OVERLAY_GAMMA_ENABLE 0x04 | ||
149 | #define OVERLAY_GAMMA_DISABLE 0x00 | ||
150 | |||
151 | #define CURSOR_CONTROL 0xA0 | ||
152 | #define CURSOR_ORIGIN_SCREEN 0x00 | ||
153 | #define CURSOR_ORIGIN_DISPLAY 0x10 | ||
154 | #define CURSOR_MODE 0x07 | ||
155 | #define CURSOR_MODE_DISABLE 0x00 | ||
156 | #define CURSOR_MODE_32_4C_AX 0x01 | ||
157 | #define CURSOR_MODE_128_2C 0x02 | ||
158 | #define CURSOR_MODE_128_1C 0x03 | ||
159 | #define CURSOR_MODE_64_3C 0x04 | ||
160 | #define CURSOR_MODE_64_4C_AX 0x05 | ||
161 | #define CURSOR_MODE_64_4C 0x06 | ||
162 | #define CURSOR_MODE_RESERVED 0x07 | ||
163 | #define CURSOR_BASEADDR_LO 0xA2 | ||
164 | #define CURSOR_BASEADDR_HI 0xA3 | ||
165 | #define CURSOR_X_LO 0xA4 | ||
166 | #define CURSOR_X_HI 0xA5 | ||
167 | #define CURSOR_X_POS 0x00 | ||
168 | #define CURSOR_X_NEG 0x80 | ||
169 | #define CURSOR_Y_LO 0xA6 | ||
170 | #define CURSOR_Y_HI 0xA7 | ||
171 | #define CURSOR_Y_POS 0x00 | ||
172 | #define CURSOR_Y_NEG 0x80 | ||
173 | |||
174 | #define VCLK2_VCO_M 0xC8 | ||
175 | #define VCLK2_VCO_N 0xC9 | ||
176 | #define VCLK2_VCO_MN_MSBS 0xCA | ||
177 | #define VCO_N_MSBS 0x30 | ||
178 | #define VCO_M_MSBS 0x03 | ||
179 | #define VCLK2_VCO_DIV_SEL 0xCB | ||
180 | #define POST_DIV_SELECT 0x70 | ||
181 | #define POST_DIV_1 0x00 | ||
182 | #define POST_DIV_2 0x10 | ||
183 | #define POST_DIV_4 0x20 | ||
184 | #define POST_DIV_8 0x30 | ||
185 | #define POST_DIV_16 0x40 | ||
186 | #define POST_DIV_32 0x50 | ||
187 | #define VCO_LOOP_DIV_BY_4M 0x00 | ||
188 | #define VCO_LOOP_DIV_BY_16M 0x04 | ||
189 | #define REF_CLK_DIV_BY_5 0x02 | ||
190 | #define REF_DIV_4 0x00 | ||
191 | #define REF_DIV_1 0x01 | ||
192 | |||
193 | #define PLL_CNTL 0xCE | ||
194 | #define PLL_MEMCLK_SEL 0x03 | ||
195 | #define PLL_MEMCLK__66667KHZ 0x00 | ||
196 | #define PLL_MEMCLK__75000KHZ 0x01 | ||
197 | #define PLL_MEMCLK__88889KHZ 0x02 | ||
198 | #define PLL_MEMCLK_100000KHZ 0x03 | ||
199 | |||
200 | /* Multimedia Extension Registers (MRX) */ | ||
201 | #define ACQ_CNTL_1 0x02 | ||
202 | #define ACQ_CNTL_2 0x03 | ||
203 | #define FRAME_CAP_MODE 0x01 | ||
204 | #define CONT_CAP_MODE 0x00 | ||
205 | #define SINGLE_CAP_MODE 0x01 | ||
206 | #define ACQ_CNTL_3 0x04 | ||
207 | #define COL_KEY_CNTL_1 0x3C | ||
208 | #define BLANK_DISP_OVERLAY 0x20 | ||
209 | |||
210 | /* FIFOs */ | ||
211 | #define LP_FIFO 0x1000 | ||
212 | #define HP_FIFO 0x2000 | ||
213 | #define INSTPNT 0x3040 | ||
214 | #define LP_FIFO_COUNT 0x3040 | ||
215 | #define HP_FIFO_COUNT 0x3041 | ||
216 | |||
217 | /* FIFO Commands */ | ||
218 | #define CLIENT 0xE0000000 | ||
219 | #define CLIENT_2D 0x60000000 | ||
220 | |||
221 | /* Command Parser Mode Register */ | ||
222 | #define COMPARS 0x3038 | ||
223 | #define TWO_D_INST_DISABLE 0x08 | ||
224 | #define THREE_D_INST_DISABLE 0x04 | ||
225 | #define STATE_VAR_UPDATE_DISABLE 0x02 | ||
226 | #define PAL_STIP_DISABLE 0x01 | ||
227 | |||
228 | /* Interrupt Control Registers */ | ||
229 | #define IER 0x3030 | ||
230 | #define IIR 0x3032 | ||
231 | #define IMR 0x3034 | ||
232 | #define ISR 0x3036 | ||
233 | #define VMIINTB_EVENT 0x2000 | ||
234 | #define GPIO4_INT 0x1000 | ||
235 | #define DISP_FLIP_EVENT 0x0800 | ||
236 | #define DVD_PORT_DMA 0x0400 | ||
237 | #define DISP_VBLANK 0x0200 | ||
238 | #define FIFO_EMPTY_DMA_DONE 0x0100 | ||
239 | #define INST_PARSER_ERROR 0x0080 | ||
240 | #define USER_DEFINED 0x0040 | ||
241 | #define BREAKPOINT 0x0020 | ||
242 | #define DISP_HORIZ_COUNT 0x0010 | ||
243 | #define DISP_VSYNC 0x0008 | ||
244 | #define CAPTURE_HORIZ_COUNT 0x0004 | ||
245 | #define CAPTURE_VSYNC 0x0002 | ||
246 | #define THREE_D_PIPE_FLUSHED 0x0001 | ||
247 | |||
248 | /* FIFO Watermark and Burst Length Control Register */ | ||
249 | #define FWATER_BLC 0x00006000 | ||
250 | #define LMI_BURST_LENGTH 0x7F000000 | ||
251 | #define LMI_FIFO_WATERMARK 0x003F0000 | ||
252 | #define AGP_BURST_LENGTH 0x00007F00 | ||
253 | #define AGP_FIFO_WATERMARK 0x0000003F | ||
254 | |||
255 | /* BitBLT Registers */ | ||
256 | #define SRC_DST_PITCH 0x00040000 | ||
257 | #define DST_PITCH 0x1FFF0000 | ||
258 | #define SRC_PITCH 0x00001FFF | ||
259 | #define COLEXP_BG_COLOR 0x00040004 | ||
260 | #define COLEXP_FG_COLOR 0x00040008 | ||
261 | #define MONO_SRC_CNTL 0x0004000C | ||
262 | #define MONO_USE_COLEXP 0x00000000 | ||
263 | #define MONO_USE_SRCEXP 0x08000000 | ||
264 | #define MONO_DATA_ALIGN 0x07000000 | ||
265 | #define MONO_BIT_ALIGN 0x01000000 | ||
266 | #define MONO_BYTE_ALIGN 0x02000000 | ||
267 | #define MONO_WORD_ALIGN 0x03000000 | ||
268 | #define MONO_DWORD_ALIGN 0x04000000 | ||
269 | #define MONO_QWORD_ALIGN 0x05000000 | ||
270 | #define MONO_SRC_INIT_DSCRD 0x003F0000 | ||
271 | #define MONO_SRC_RIGHT_CLIP 0x00003F00 | ||
272 | #define MONO_SRC_LEFT_CLIP 0x0000003F | ||
273 | #define BITBLT_CONTROL 0x00040010 | ||
274 | #define BLTR_STATUS 0x80000000 | ||
275 | #define DYN_DEPTH 0x03000000 | ||
276 | #define DYN_DEPTH_8BPP 0x00000000 | ||
277 | #define DYN_DEPTH_16BPP 0x01000000 | ||
278 | #define DYN_DEPTH_24BPP 0x02000000 | ||
279 | #define DYN_DEPTH_32BPP 0x03000000 /* Unimplemented on the i740 */ | ||
280 | #define DYN_DEPTH_ENABLE 0x00800000 | ||
281 | #define PAT_VERT_ALIGN 0x00700000 | ||
282 | #define SOLID_PAT_SELECT 0x00080000 | ||
283 | #define PAT_IS_IN_COLOR 0x00000000 | ||
284 | #define PAT_IS_MONO 0x00040000 | ||
285 | #define MONO_PAT_TRANSP 0x00020000 | ||
286 | #define COLOR_TRANSP_ROP 0x00000000 | ||
287 | #define COLOR_TRANSP_DST 0x00008000 | ||
288 | #define COLOR_TRANSP_EQ 0x00000000 | ||
289 | #define COLOR_TRANSP_NOT_EQ 0x00010000 | ||
290 | #define COLOR_TRANSP_ENABLE 0x00004000 | ||
291 | #define MONO_SRC_TRANSP 0x00002000 | ||
292 | #define SRC_IS_IN_COLOR 0x00000000 | ||
293 | #define SRC_IS_MONO 0x00001000 | ||
294 | #define SRC_USE_SRC_ADDR 0x00000000 | ||
295 | #define SRC_USE_BLTDATA 0x00000400 | ||
296 | #define BLT_TOP_TO_BOT 0x00000000 | ||
297 | #define BLT_BOT_TO_TOP 0x00000200 | ||
298 | #define BLT_LEFT_TO_RIGHT 0x00000000 | ||
299 | #define BLT_RIGHT_TO_LEFT 0x00000100 | ||
300 | #define BLT_ROP 0x000000FF | ||
301 | #define BLT_PAT_ADDR 0x00040014 | ||
302 | #define BLT_SRC_ADDR 0x00040018 | ||
303 | #define BLT_DST_ADDR 0x0004001C | ||
304 | #define BLT_DST_H_W 0x00040020 | ||
305 | #define BLT_DST_HEIGHT 0x1FFF0000 | ||
306 | #define BLT_DST_WIDTH 0x00001FFF | ||
307 | #define SRCEXP_BG_COLOR 0x00040024 | ||
308 | #define SRCEXP_FG_COLOR 0x00040028 | ||
309 | #define BLTDATA 0x00050000 | ||
diff --git a/drivers/video/i740fb.c b/drivers/video/i740fb.c new file mode 100644 index 000000000000..fe574d84ed99 --- /dev/null +++ b/drivers/video/i740fb.c | |||
@@ -0,0 +1,1337 @@ | |||
1 | /* | ||
2 | * i740fb - framebuffer driver for Intel740 | ||
3 | * Copyright (c) 2011 Ondrej Zary | ||
4 | * | ||
5 | * Based on old i740fb driver (c) 2001-2002 Andrey Ulanov <drey@rt.mipt.ru> | ||
6 | * which was partially based on: | ||
7 | * VGA 16-color framebuffer driver (c) 1999 Ben Pfaff <pfaffben@debian.org> | ||
8 | * and Petr Vandrovec <VANDROVE@vc.cvut.cz> | ||
9 | * i740 driver from XFree86 (c) 1998-1999 Precision Insight, Inc., Cedar Park, | ||
10 | * Texas. | ||
11 | * i740fb by Patrick LERDA, v0.9 | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/string.h> | ||
18 | #include <linux/mm.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/fb.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/pci.h> | ||
24 | #include <linux/pci_ids.h> | ||
25 | #include <linux/i2c.h> | ||
26 | #include <linux/i2c-algo-bit.h> | ||
27 | #include <linux/console.h> | ||
28 | #include <video/vga.h> | ||
29 | |||
30 | #ifdef CONFIG_MTRR | ||
31 | #include <asm/mtrr.h> | ||
32 | #endif | ||
33 | |||
34 | #include "i740_reg.h" | ||
35 | |||
36 | static char *mode_option __devinitdata; | ||
37 | |||
38 | #ifdef CONFIG_MTRR | ||
39 | static int mtrr __devinitdata = 1; | ||
40 | #endif | ||
41 | |||
42 | struct i740fb_par { | ||
43 | unsigned char __iomem *regs; | ||
44 | bool has_sgram; | ||
45 | #ifdef CONFIG_MTRR | ||
46 | int mtrr_reg; | ||
47 | #endif | ||
48 | bool ddc_registered; | ||
49 | struct i2c_adapter ddc_adapter; | ||
50 | struct i2c_algo_bit_data ddc_algo; | ||
51 | u32 pseudo_palette[16]; | ||
52 | struct mutex open_lock; | ||
53 | unsigned int ref_count; | ||
54 | |||
55 | u8 crtc[VGA_CRT_C]; | ||
56 | u8 atc[VGA_ATT_C]; | ||
57 | u8 gdc[VGA_GFX_C]; | ||
58 | u8 seq[VGA_SEQ_C]; | ||
59 | u8 misc; | ||
60 | u8 vss; | ||
61 | |||
62 | /* i740 specific registers */ | ||
63 | u8 display_cntl; | ||
64 | u8 pixelpipe_cfg0; | ||
65 | u8 pixelpipe_cfg1; | ||
66 | u8 pixelpipe_cfg2; | ||
67 | u8 video_clk2_m; | ||
68 | u8 video_clk2_n; | ||
69 | u8 video_clk2_mn_msbs; | ||
70 | u8 video_clk2_div_sel; | ||
71 | u8 pll_cntl; | ||
72 | u8 address_mapping; | ||
73 | u8 io_cntl; | ||
74 | u8 bitblt_cntl; | ||
75 | u8 ext_vert_total; | ||
76 | u8 ext_vert_disp_end; | ||
77 | u8 ext_vert_sync_start; | ||
78 | u8 ext_vert_blank_start; | ||
79 | u8 ext_horiz_total; | ||
80 | u8 ext_horiz_blank; | ||
81 | u8 ext_offset; | ||
82 | u8 interlace_cntl; | ||
83 | u32 lmi_fifo_watermark; | ||
84 | u8 ext_start_addr; | ||
85 | u8 ext_start_addr_hi; | ||
86 | }; | ||
87 | |||
88 | #define DACSPEED8 203 | ||
89 | #define DACSPEED16 163 | ||
90 | #define DACSPEED24_SG 136 | ||
91 | #define DACSPEED24_SD 128 | ||
92 | #define DACSPEED32 86 | ||
93 | |||
94 | static struct fb_fix_screeninfo i740fb_fix __devinitdata = { | ||
95 | .id = "i740fb", | ||
96 | .type = FB_TYPE_PACKED_PIXELS, | ||
97 | .visual = FB_VISUAL_TRUECOLOR, | ||
98 | .xpanstep = 8, | ||
99 | .ypanstep = 1, | ||
100 | .accel = FB_ACCEL_NONE, | ||
101 | }; | ||
102 | |||
103 | static inline void i740outb(struct i740fb_par *par, u16 port, u8 val) | ||
104 | { | ||
105 | vga_mm_w(par->regs, port, val); | ||
106 | } | ||
107 | static inline u8 i740inb(struct i740fb_par *par, u16 port) | ||
108 | { | ||
109 | return vga_mm_r(par->regs, port); | ||
110 | } | ||
111 | static inline void i740outreg(struct i740fb_par *par, u16 port, u8 reg, u8 val) | ||
112 | { | ||
113 | vga_mm_w_fast(par->regs, port, reg, val); | ||
114 | } | ||
115 | static inline u8 i740inreg(struct i740fb_par *par, u16 port, u8 reg) | ||
116 | { | ||
117 | vga_mm_w(par->regs, port, reg); | ||
118 | return vga_mm_r(par->regs, port+1); | ||
119 | } | ||
120 | static inline void i740outreg_mask(struct i740fb_par *par, u16 port, u8 reg, | ||
121 | u8 val, u8 mask) | ||
122 | { | ||
123 | vga_mm_w_fast(par->regs, port, reg, (val & mask) | ||
124 | | (i740inreg(par, port, reg) & ~mask)); | ||
125 | } | ||
126 | |||
127 | #define REG_DDC_DRIVE 0x62 | ||
128 | #define REG_DDC_STATE 0x63 | ||
129 | #define DDC_SCL (1 << 3) | ||
130 | #define DDC_SDA (1 << 2) | ||
131 | |||
132 | static void i740fb_ddc_setscl(void *data, int val) | ||
133 | { | ||
134 | struct i740fb_par *par = data; | ||
135 | |||
136 | i740outreg_mask(par, XRX, REG_DDC_DRIVE, DDC_SCL, DDC_SCL); | ||
137 | i740outreg_mask(par, XRX, REG_DDC_STATE, val ? DDC_SCL : 0, DDC_SCL); | ||
138 | } | ||
139 | |||
140 | static void i740fb_ddc_setsda(void *data, int val) | ||
141 | { | ||
142 | struct i740fb_par *par = data; | ||
143 | |||
144 | i740outreg_mask(par, XRX, REG_DDC_DRIVE, DDC_SDA, DDC_SDA); | ||
145 | i740outreg_mask(par, XRX, REG_DDC_STATE, val ? DDC_SDA : 0, DDC_SDA); | ||
146 | } | ||
147 | |||
148 | static int i740fb_ddc_getscl(void *data) | ||
149 | { | ||
150 | struct i740fb_par *par = data; | ||
151 | |||
152 | i740outreg_mask(par, XRX, REG_DDC_DRIVE, 0, DDC_SCL); | ||
153 | |||
154 | return !!(i740inreg(par, XRX, REG_DDC_STATE) & DDC_SCL); | ||
155 | } | ||
156 | |||
157 | static int i740fb_ddc_getsda(void *data) | ||
158 | { | ||
159 | struct i740fb_par *par = data; | ||
160 | |||
161 | i740outreg_mask(par, XRX, REG_DDC_DRIVE, 0, DDC_SDA); | ||
162 | |||
163 | return !!(i740inreg(par, XRX, REG_DDC_STATE) & DDC_SDA); | ||
164 | } | ||
165 | |||
166 | static int __devinit i740fb_setup_ddc_bus(struct fb_info *info) | ||
167 | { | ||
168 | struct i740fb_par *par = info->par; | ||
169 | |||
170 | strlcpy(par->ddc_adapter.name, info->fix.id, | ||
171 | sizeof(par->ddc_adapter.name)); | ||
172 | par->ddc_adapter.owner = THIS_MODULE; | ||
173 | par->ddc_adapter.class = I2C_CLASS_DDC; | ||
174 | par->ddc_adapter.algo_data = &par->ddc_algo; | ||
175 | par->ddc_adapter.dev.parent = info->device; | ||
176 | par->ddc_algo.setsda = i740fb_ddc_setsda; | ||
177 | par->ddc_algo.setscl = i740fb_ddc_setscl; | ||
178 | par->ddc_algo.getsda = i740fb_ddc_getsda; | ||
179 | par->ddc_algo.getscl = i740fb_ddc_getscl; | ||
180 | par->ddc_algo.udelay = 10; | ||
181 | par->ddc_algo.timeout = 20; | ||
182 | par->ddc_algo.data = par; | ||
183 | |||
184 | i2c_set_adapdata(&par->ddc_adapter, par); | ||
185 | |||
186 | return i2c_bit_add_bus(&par->ddc_adapter); | ||
187 | } | ||
188 | |||
189 | static int i740fb_open(struct fb_info *info, int user) | ||
190 | { | ||
191 | struct i740fb_par *par = info->par; | ||
192 | |||
193 | mutex_lock(&(par->open_lock)); | ||
194 | par->ref_count++; | ||
195 | mutex_unlock(&(par->open_lock)); | ||
196 | |||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | static int i740fb_release(struct fb_info *info, int user) | ||
201 | { | ||
202 | struct i740fb_par *par = info->par; | ||
203 | |||
204 | mutex_lock(&(par->open_lock)); | ||
205 | if (par->ref_count == 0) { | ||
206 | printk(KERN_ERR "fb%d: release called with zero refcount\n", | ||
207 | info->node); | ||
208 | mutex_unlock(&(par->open_lock)); | ||
209 | return -EINVAL; | ||
210 | } | ||
211 | |||
212 | par->ref_count--; | ||
213 | mutex_unlock(&(par->open_lock)); | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static u32 i740_calc_fifo(struct i740fb_par *par, u32 freq, int bpp) | ||
219 | { | ||
220 | /* | ||
221 | * Would like to calculate these values automatically, but a generic | ||
222 | * algorithm does not seem possible. Note: These FIFO water mark | ||
223 | * values were tested on several cards and seem to eliminate the | ||
224 | * all of the snow and vertical banding, but fine adjustments will | ||
225 | * probably be required for other cards. | ||
226 | */ | ||
227 | |||
228 | u32 wm; | ||
229 | |||
230 | switch (bpp) { | ||
231 | case 8: | ||
232 | if (freq > 200) | ||
233 | wm = 0x18120000; | ||
234 | else if (freq > 175) | ||
235 | wm = 0x16110000; | ||
236 | else if (freq > 135) | ||
237 | wm = 0x120E0000; | ||
238 | else | ||
239 | wm = 0x100D0000; | ||
240 | break; | ||
241 | case 15: | ||
242 | case 16: | ||
243 | if (par->has_sgram) { | ||
244 | if (freq > 140) | ||
245 | wm = 0x2C1D0000; | ||
246 | else if (freq > 120) | ||
247 | wm = 0x2C180000; | ||
248 | else if (freq > 100) | ||
249 | wm = 0x24160000; | ||
250 | else if (freq > 90) | ||
251 | wm = 0x18120000; | ||
252 | else if (freq > 50) | ||
253 | wm = 0x16110000; | ||
254 | else if (freq > 32) | ||
255 | wm = 0x13100000; | ||
256 | else | ||
257 | wm = 0x120E0000; | ||
258 | } else { | ||
259 | if (freq > 160) | ||
260 | wm = 0x28200000; | ||
261 | else if (freq > 140) | ||
262 | wm = 0x2A1E0000; | ||
263 | else if (freq > 130) | ||
264 | wm = 0x2B1A0000; | ||
265 | else if (freq > 120) | ||
266 | wm = 0x2C180000; | ||
267 | else if (freq > 100) | ||
268 | wm = 0x24180000; | ||
269 | else if (freq > 90) | ||
270 | wm = 0x18120000; | ||
271 | else if (freq > 50) | ||
272 | wm = 0x16110000; | ||
273 | else if (freq > 32) | ||
274 | wm = 0x13100000; | ||
275 | else | ||
276 | wm = 0x120E0000; | ||
277 | } | ||
278 | break; | ||
279 | case 24: | ||
280 | if (par->has_sgram) { | ||
281 | if (freq > 130) | ||
282 | wm = 0x31200000; | ||
283 | else if (freq > 120) | ||
284 | wm = 0x2E200000; | ||
285 | else if (freq > 100) | ||
286 | wm = 0x2C1D0000; | ||
287 | else if (freq > 80) | ||
288 | wm = 0x25180000; | ||
289 | else if (freq > 64) | ||
290 | wm = 0x24160000; | ||
291 | else if (freq > 49) | ||
292 | wm = 0x18120000; | ||
293 | else if (freq > 32) | ||
294 | wm = 0x16110000; | ||
295 | else | ||
296 | wm = 0x13100000; | ||
297 | } else { | ||
298 | if (freq > 120) | ||
299 | wm = 0x311F0000; | ||
300 | else if (freq > 100) | ||
301 | wm = 0x2C1D0000; | ||
302 | else if (freq > 80) | ||
303 | wm = 0x25180000; | ||
304 | else if (freq > 64) | ||
305 | wm = 0x24160000; | ||
306 | else if (freq > 49) | ||
307 | wm = 0x18120000; | ||
308 | else if (freq > 32) | ||
309 | wm = 0x16110000; | ||
310 | else | ||
311 | wm = 0x13100000; | ||
312 | } | ||
313 | break; | ||
314 | case 32: | ||
315 | if (par->has_sgram) { | ||
316 | if (freq > 80) | ||
317 | wm = 0x2A200000; | ||
318 | else if (freq > 60) | ||
319 | wm = 0x281A0000; | ||
320 | else if (freq > 49) | ||
321 | wm = 0x25180000; | ||
322 | else if (freq > 32) | ||
323 | wm = 0x18120000; | ||
324 | else | ||
325 | wm = 0x16110000; | ||
326 | } else { | ||
327 | if (freq > 80) | ||
328 | wm = 0x29200000; | ||
329 | else if (freq > 60) | ||
330 | wm = 0x281A0000; | ||
331 | else if (freq > 49) | ||
332 | wm = 0x25180000; | ||
333 | else if (freq > 32) | ||
334 | wm = 0x18120000; | ||
335 | else | ||
336 | wm = 0x16110000; | ||
337 | } | ||
338 | break; | ||
339 | } | ||
340 | |||
341 | return wm; | ||
342 | } | ||
343 | |||
344 | /* clock calculation from i740fb by Patrick LERDA */ | ||
345 | |||
346 | #define I740_RFREQ 1000000 | ||
347 | #define TARGET_MAX_N 30 | ||
348 | #define I740_FFIX (1 << 8) | ||
349 | #define I740_RFREQ_FIX (I740_RFREQ / I740_FFIX) | ||
350 | #define I740_REF_FREQ (6667 * I740_FFIX / 100) /* 66.67 MHz */ | ||
351 | #define I740_MAX_VCO_FREQ (450 * I740_FFIX) /* 450 MHz */ | ||
352 | |||
353 | static void i740_calc_vclk(u32 freq, struct i740fb_par *par) | ||
354 | { | ||
355 | const u32 err_max = freq / (200 * I740_RFREQ / I740_FFIX); | ||
356 | const u32 err_target = freq / (1000 * I740_RFREQ / I740_FFIX); | ||
357 | u32 err_best = 512 * I740_FFIX; | ||
358 | u32 f_err, f_vco; | ||
359 | int m_best = 0, n_best = 0, p_best = 0, d_best = 0; | ||
360 | int m, n; | ||
361 | |||
362 | p_best = min(15, ilog2(I740_MAX_VCO_FREQ / (freq / I740_RFREQ_FIX))); | ||
363 | d_best = 0; | ||
364 | f_vco = (freq * (1 << p_best)) / I740_RFREQ_FIX; | ||
365 | freq = freq / I740_RFREQ_FIX; | ||
366 | |||
367 | n = 2; | ||
368 | do { | ||
369 | n++; | ||
370 | m = ((f_vco * n) / I740_REF_FREQ + 2) / 4; | ||
371 | |||
372 | if (m < 3) | ||
373 | m = 3; | ||
374 | |||
375 | { | ||
376 | u32 f_out = (((m * I740_REF_FREQ * (4 << 2 * d_best)) | ||
377 | / n) + ((1 << p_best) / 2)) / (1 << p_best); | ||
378 | |||
379 | f_err = (freq - f_out); | ||
380 | |||
381 | if (abs(f_err) < err_max) { | ||
382 | m_best = m; | ||
383 | n_best = n; | ||
384 | err_best = f_err; | ||
385 | } | ||
386 | } | ||
387 | } while ((abs(f_err) >= err_target) && | ||
388 | ((n <= TARGET_MAX_N) || (abs(err_best) > err_max))); | ||
389 | |||
390 | if (abs(f_err) < err_target) { | ||
391 | m_best = m; | ||
392 | n_best = n; | ||
393 | } | ||
394 | |||
395 | par->video_clk2_m = (m_best - 2) & 0xFF; | ||
396 | par->video_clk2_n = (n_best - 2) & 0xFF; | ||
397 | par->video_clk2_mn_msbs = ((((n_best - 2) >> 4) & VCO_N_MSBS) | ||
398 | | (((m_best - 2) >> 8) & VCO_M_MSBS)); | ||
399 | par->video_clk2_div_sel = | ||
400 | ((p_best << 4) | (d_best ? 4 : 0) | REF_DIV_1); | ||
401 | } | ||
402 | |||
403 | static int i740fb_decode_var(const struct fb_var_screeninfo *var, | ||
404 | struct i740fb_par *par, struct fb_info *info) | ||
405 | { | ||
406 | /* | ||
407 | * Get the video params out of 'var'. | ||
408 | * If a value doesn't fit, round it up, if it's too big, return -EINVAL. | ||
409 | */ | ||
410 | |||
411 | u32 xres, right, hslen, left, xtotal; | ||
412 | u32 yres, lower, vslen, upper, ytotal; | ||
413 | u32 vxres, xoffset, vyres, yoffset; | ||
414 | u32 bpp, base, dacspeed24, mem; | ||
415 | u8 r7; | ||
416 | int i; | ||
417 | |||
418 | dev_dbg(info->device, "decode_var: xres: %i, yres: %i, xres_v: %i, xres_v: %i\n", | ||
419 | var->xres, var->yres, var->xres_virtual, var->xres_virtual); | ||
420 | dev_dbg(info->device, " xoff: %i, yoff: %i, bpp: %i, graysc: %i\n", | ||
421 | var->xoffset, var->yoffset, var->bits_per_pixel, | ||
422 | var->grayscale); | ||
423 | dev_dbg(info->device, " activate: %i, nonstd: %i, vmode: %i\n", | ||
424 | var->activate, var->nonstd, var->vmode); | ||
425 | dev_dbg(info->device, " pixclock: %i, hsynclen:%i, vsynclen:%i\n", | ||
426 | var->pixclock, var->hsync_len, var->vsync_len); | ||
427 | dev_dbg(info->device, " left: %i, right: %i, up:%i, lower:%i\n", | ||
428 | var->left_margin, var->right_margin, var->upper_margin, | ||
429 | var->lower_margin); | ||
430 | |||
431 | |||
432 | bpp = var->bits_per_pixel; | ||
433 | switch (bpp) { | ||
434 | case 1 ... 8: | ||
435 | bpp = 8; | ||
436 | if ((1000000 / var->pixclock) > DACSPEED8) { | ||
437 | dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 8bpp)\n", | ||
438 | 1000000 / var->pixclock, DACSPEED8); | ||
439 | return -EINVAL; | ||
440 | } | ||
441 | break; | ||
442 | case 9 ... 15: | ||
443 | bpp = 15; | ||
444 | case 16: | ||
445 | if ((1000000 / var->pixclock) > DACSPEED16) { | ||
446 | dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 15/16bpp)\n", | ||
447 | 1000000 / var->pixclock, DACSPEED16); | ||
448 | return -EINVAL; | ||
449 | } | ||
450 | break; | ||
451 | case 17 ... 24: | ||
452 | bpp = 24; | ||
453 | dacspeed24 = par->has_sgram ? DACSPEED24_SG : DACSPEED24_SD; | ||
454 | if ((1000000 / var->pixclock) > dacspeed24) { | ||
455 | dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 24bpp)\n", | ||
456 | 1000000 / var->pixclock, dacspeed24); | ||
457 | return -EINVAL; | ||
458 | } | ||
459 | break; | ||
460 | case 25 ... 32: | ||
461 | bpp = 32; | ||
462 | if ((1000000 / var->pixclock) > DACSPEED32) { | ||
463 | dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 32bpp)\n", | ||
464 | 1000000 / var->pixclock, DACSPEED32); | ||
465 | return -EINVAL; | ||
466 | } | ||
467 | break; | ||
468 | default: | ||
469 | return -EINVAL; | ||
470 | } | ||
471 | |||
472 | xres = ALIGN(var->xres, 8); | ||
473 | vxres = ALIGN(var->xres_virtual, 16); | ||
474 | if (vxres < xres) | ||
475 | vxres = xres; | ||
476 | |||
477 | xoffset = ALIGN(var->xoffset, 8); | ||
478 | if (xres + xoffset > vxres) | ||
479 | xoffset = vxres - xres; | ||
480 | |||
481 | left = ALIGN(var->left_margin, 8); | ||
482 | right = ALIGN(var->right_margin, 8); | ||
483 | hslen = ALIGN(var->hsync_len, 8); | ||
484 | |||
485 | yres = var->yres; | ||
486 | vyres = var->yres_virtual; | ||
487 | if (yres > vyres) | ||
488 | vyres = yres; | ||
489 | |||
490 | yoffset = var->yoffset; | ||
491 | if (yres + yoffset > vyres) | ||
492 | yoffset = vyres - yres; | ||
493 | |||
494 | lower = var->lower_margin; | ||
495 | vslen = var->vsync_len; | ||
496 | upper = var->upper_margin; | ||
497 | |||
498 | mem = vxres * vyres * ((bpp + 1) / 8); | ||
499 | if (mem > info->screen_size) { | ||
500 | dev_err(info->device, "not enough video memory (%d KB requested, %ld KB avaliable)\n", | ||
501 | mem >> 10, info->screen_size >> 10); | ||
502 | return -ENOMEM; | ||
503 | } | ||
504 | |||
505 | if (yoffset + yres > vyres) | ||
506 | yoffset = vyres - yres; | ||
507 | |||
508 | xtotal = xres + right + hslen + left; | ||
509 | ytotal = yres + lower + vslen + upper; | ||
510 | |||
511 | par->crtc[VGA_CRTC_H_TOTAL] = (xtotal >> 3) - 5; | ||
512 | par->crtc[VGA_CRTC_H_DISP] = (xres >> 3) - 1; | ||
513 | par->crtc[VGA_CRTC_H_BLANK_START] = ((xres + right) >> 3) - 1; | ||
514 | par->crtc[VGA_CRTC_H_SYNC_START] = (xres + right) >> 3; | ||
515 | par->crtc[VGA_CRTC_H_SYNC_END] = (((xres + right + hslen) >> 3) & 0x1F) | ||
516 | | ((((xres + right + hslen) >> 3) & 0x20) << 2); | ||
517 | par->crtc[VGA_CRTC_H_BLANK_END] = ((xres + right + hslen) >> 3 & 0x1F) | ||
518 | | 0x80; | ||
519 | |||
520 | par->crtc[VGA_CRTC_V_TOTAL] = ytotal - 2; | ||
521 | |||
522 | r7 = 0x10; /* disable linecompare */ | ||
523 | if (ytotal & 0x100) | ||
524 | r7 |= 0x01; | ||
525 | if (ytotal & 0x200) | ||
526 | r7 |= 0x20; | ||
527 | |||
528 | par->crtc[VGA_CRTC_PRESET_ROW] = 0; | ||
529 | par->crtc[VGA_CRTC_MAX_SCAN] = 0x40; /* 1 scanline, no linecmp */ | ||
530 | if (var->vmode & FB_VMODE_DOUBLE) | ||
531 | par->crtc[VGA_CRTC_MAX_SCAN] |= 0x80; | ||
532 | par->crtc[VGA_CRTC_CURSOR_START] = 0x00; | ||
533 | par->crtc[VGA_CRTC_CURSOR_END] = 0x00; | ||
534 | par->crtc[VGA_CRTC_CURSOR_HI] = 0x00; | ||
535 | par->crtc[VGA_CRTC_CURSOR_LO] = 0x00; | ||
536 | par->crtc[VGA_CRTC_V_DISP_END] = yres-1; | ||
537 | if ((yres-1) & 0x100) | ||
538 | r7 |= 0x02; | ||
539 | if ((yres-1) & 0x200) | ||
540 | r7 |= 0x40; | ||
541 | |||
542 | par->crtc[VGA_CRTC_V_BLANK_START] = yres + lower - 1; | ||
543 | par->crtc[VGA_CRTC_V_SYNC_START] = yres + lower - 1; | ||
544 | if ((yres + lower - 1) & 0x100) | ||
545 | r7 |= 0x0C; | ||
546 | if ((yres + lower - 1) & 0x200) { | ||
547 | par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20; | ||
548 | r7 |= 0x80; | ||
549 | } | ||
550 | |||
551 | /* disabled IRQ */ | ||
552 | par->crtc[VGA_CRTC_V_SYNC_END] = | ||
553 | ((yres + lower - 1 + vslen) & 0x0F) & ~0x10; | ||
554 | /* 0x7F for VGA, but some SVGA chips require all 8 bits to be set */ | ||
555 | par->crtc[VGA_CRTC_V_BLANK_END] = (yres + lower - 1 + vslen) & 0xFF; | ||
556 | |||
557 | par->crtc[VGA_CRTC_UNDERLINE] = 0x00; | ||
558 | par->crtc[VGA_CRTC_MODE] = 0xC3 ; | ||
559 | par->crtc[VGA_CRTC_LINE_COMPARE] = 0xFF; | ||
560 | par->crtc[VGA_CRTC_OVERFLOW] = r7; | ||
561 | |||
562 | par->vss = 0x00; /* 3DA */ | ||
563 | |||
564 | for (i = 0x00; i < 0x10; i++) | ||
565 | par->atc[i] = i; | ||
566 | par->atc[VGA_ATC_MODE] = 0x81; | ||
567 | par->atc[VGA_ATC_OVERSCAN] = 0x00; /* 0 for EGA, 0xFF for VGA */ | ||
568 | par->atc[VGA_ATC_PLANE_ENABLE] = 0x0F; | ||
569 | par->atc[VGA_ATC_COLOR_PAGE] = 0x00; | ||
570 | |||
571 | par->misc = 0xC3; | ||
572 | if (var->sync & FB_SYNC_HOR_HIGH_ACT) | ||
573 | par->misc &= ~0x40; | ||
574 | if (var->sync & FB_SYNC_VERT_HIGH_ACT) | ||
575 | par->misc &= ~0x80; | ||
576 | |||
577 | par->seq[VGA_SEQ_CLOCK_MODE] = 0x01; | ||
578 | par->seq[VGA_SEQ_PLANE_WRITE] = 0x0F; | ||
579 | par->seq[VGA_SEQ_CHARACTER_MAP] = 0x00; | ||
580 | par->seq[VGA_SEQ_MEMORY_MODE] = 0x06; | ||
581 | |||
582 | par->gdc[VGA_GFX_SR_VALUE] = 0x00; | ||
583 | par->gdc[VGA_GFX_SR_ENABLE] = 0x00; | ||
584 | par->gdc[VGA_GFX_COMPARE_VALUE] = 0x00; | ||
585 | par->gdc[VGA_GFX_DATA_ROTATE] = 0x00; | ||
586 | par->gdc[VGA_GFX_PLANE_READ] = 0; | ||
587 | par->gdc[VGA_GFX_MODE] = 0x02; | ||
588 | par->gdc[VGA_GFX_MISC] = 0x05; | ||
589 | par->gdc[VGA_GFX_COMPARE_MASK] = 0x0F; | ||
590 | par->gdc[VGA_GFX_BIT_MASK] = 0xFF; | ||
591 | |||
592 | base = (yoffset * vxres + (xoffset & ~7)) >> 2; | ||
593 | switch (bpp) { | ||
594 | case 8: | ||
595 | par->crtc[VGA_CRTC_OFFSET] = vxres >> 3; | ||
596 | par->ext_offset = vxres >> 11; | ||
597 | par->pixelpipe_cfg1 = DISPLAY_8BPP_MODE; | ||
598 | par->bitblt_cntl = COLEXP_8BPP; | ||
599 | break; | ||
600 | case 15: /* 0rrrrrgg gggbbbbb */ | ||
601 | case 16: /* rrrrrggg gggbbbbb */ | ||
602 | par->pixelpipe_cfg1 = (var->green.length == 6) ? | ||
603 | DISPLAY_16BPP_MODE : DISPLAY_15BPP_MODE; | ||
604 | par->crtc[VGA_CRTC_OFFSET] = vxres >> 2; | ||
605 | par->ext_offset = vxres >> 10; | ||
606 | par->bitblt_cntl = COLEXP_16BPP; | ||
607 | base *= 2; | ||
608 | break; | ||
609 | case 24: | ||
610 | par->crtc[VGA_CRTC_OFFSET] = (vxres * 3) >> 3; | ||
611 | par->ext_offset = (vxres * 3) >> 11; | ||
612 | par->pixelpipe_cfg1 = DISPLAY_24BPP_MODE; | ||
613 | par->bitblt_cntl = COLEXP_24BPP; | ||
614 | base &= 0xFFFFFFFE; /* ...ignore the last bit. */ | ||
615 | base *= 3; | ||
616 | break; | ||
617 | case 32: | ||
618 | par->crtc[VGA_CRTC_OFFSET] = vxres >> 1; | ||
619 | par->ext_offset = vxres >> 9; | ||
620 | par->pixelpipe_cfg1 = DISPLAY_32BPP_MODE; | ||
621 | par->bitblt_cntl = COLEXP_RESERVED; /* Unimplemented on i740 */ | ||
622 | base *= 4; | ||
623 | break; | ||
624 | } | ||
625 | |||
626 | par->crtc[VGA_CRTC_START_LO] = base & 0x000000FF; | ||
627 | par->crtc[VGA_CRTC_START_HI] = (base & 0x0000FF00) >> 8; | ||
628 | par->ext_start_addr = | ||
629 | ((base & 0x003F0000) >> 16) | EXT_START_ADDR_ENABLE; | ||
630 | par->ext_start_addr_hi = (base & 0x3FC00000) >> 22; | ||
631 | |||
632 | par->pixelpipe_cfg0 = DAC_8_BIT; | ||
633 | |||
634 | par->pixelpipe_cfg2 = DISPLAY_GAMMA_ENABLE | OVERLAY_GAMMA_ENABLE; | ||
635 | par->io_cntl = EXTENDED_CRTC_CNTL; | ||
636 | par->address_mapping = LINEAR_MODE_ENABLE | PAGE_MAPPING_ENABLE; | ||
637 | par->display_cntl = HIRES_MODE; | ||
638 | |||
639 | /* Set the MCLK freq */ | ||
640 | par->pll_cntl = PLL_MEMCLK_100000KHZ; /* 100 MHz -- use as default */ | ||
641 | |||
642 | /* Calculate the extended CRTC regs */ | ||
643 | par->ext_vert_total = (ytotal - 2) >> 8; | ||
644 | par->ext_vert_disp_end = (yres - 1) >> 8; | ||
645 | par->ext_vert_sync_start = (yres + lower) >> 8; | ||
646 | par->ext_vert_blank_start = (yres + lower) >> 8; | ||
647 | par->ext_horiz_total = ((xtotal >> 3) - 5) >> 8; | ||
648 | par->ext_horiz_blank = (((xres + right) >> 3) & 0x40) >> 6; | ||
649 | |||
650 | par->interlace_cntl = INTERLACE_DISABLE; | ||
651 | |||
652 | /* Set the overscan color to 0. (NOTE: This only affects >8bpp mode) */ | ||
653 | par->atc[VGA_ATC_OVERSCAN] = 0; | ||
654 | |||
655 | /* Calculate VCLK that most closely matches the requested dot clock */ | ||
656 | i740_calc_vclk((((u32)1e9) / var->pixclock) * (u32)(1e3), par); | ||
657 | |||
658 | /* Since we program the clocks ourselves, always use VCLK2. */ | ||
659 | par->misc |= 0x0C; | ||
660 | |||
661 | /* Calculate the FIFO Watermark and Burst Length. */ | ||
662 | par->lmi_fifo_watermark = | ||
663 | i740_calc_fifo(par, 1000000 / var->pixclock, bpp); | ||
664 | |||
665 | return 0; | ||
666 | } | ||
667 | |||
668 | static int i740fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | ||
669 | { | ||
670 | switch (var->bits_per_pixel) { | ||
671 | case 8: | ||
672 | var->red.offset = var->green.offset = var->blue.offset = 0; | ||
673 | var->red.length = var->green.length = var->blue.length = 8; | ||
674 | break; | ||
675 | case 16: | ||
676 | switch (var->green.length) { | ||
677 | default: | ||
678 | case 5: | ||
679 | var->red.offset = 10; | ||
680 | var->green.offset = 5; | ||
681 | var->blue.offset = 0; | ||
682 | var->red.length = 5; | ||
683 | var->green.length = 5; | ||
684 | var->blue.length = 5; | ||
685 | break; | ||
686 | case 6: | ||
687 | var->red.offset = 11; | ||
688 | var->green.offset = 5; | ||
689 | var->blue.offset = 0; | ||
690 | var->red.length = var->blue.length = 5; | ||
691 | break; | ||
692 | } | ||
693 | break; | ||
694 | case 24: | ||
695 | var->red.offset = 16; | ||
696 | var->green.offset = 8; | ||
697 | var->blue.offset = 0; | ||
698 | var->red.length = var->green.length = var->blue.length = 8; | ||
699 | break; | ||
700 | case 32: | ||
701 | var->transp.offset = 24; | ||
702 | var->red.offset = 16; | ||
703 | var->green.offset = 8; | ||
704 | var->blue.offset = 0; | ||
705 | var->transp.length = 8; | ||
706 | var->red.length = var->green.length = var->blue.length = 8; | ||
707 | break; | ||
708 | default: | ||
709 | return -EINVAL; | ||
710 | } | ||
711 | |||
712 | if (var->xres > var->xres_virtual) | ||
713 | var->xres_virtual = var->xres; | ||
714 | |||
715 | if (var->yres > var->yres_virtual) | ||
716 | var->yres_virtual = var->yres; | ||
717 | |||
718 | if (info->monspecs.hfmax && info->monspecs.vfmax && | ||
719 | info->monspecs.dclkmax && fb_validate_mode(var, info) < 0) | ||
720 | return -EINVAL; | ||
721 | |||
722 | return 0; | ||
723 | } | ||
724 | |||
725 | static void vga_protect(struct i740fb_par *par) | ||
726 | { | ||
727 | /* disable the display */ | ||
728 | i740outreg_mask(par, VGA_SEQ_I, VGA_SEQ_CLOCK_MODE, 0x20, 0x20); | ||
729 | |||
730 | i740inb(par, 0x3DA); | ||
731 | i740outb(par, VGA_ATT_W, 0x00); /* enable pallete access */ | ||
732 | } | ||
733 | |||
734 | static void vga_unprotect(struct i740fb_par *par) | ||
735 | { | ||
736 | /* reenable display */ | ||
737 | i740outreg_mask(par, VGA_SEQ_I, VGA_SEQ_CLOCK_MODE, 0, 0x20); | ||
738 | |||
739 | i740inb(par, 0x3DA); | ||
740 | i740outb(par, VGA_ATT_W, 0x20); /* disable pallete access */ | ||
741 | } | ||
742 | |||
743 | static int i740fb_set_par(struct fb_info *info) | ||
744 | { | ||
745 | struct i740fb_par *par = info->par; | ||
746 | u32 itemp; | ||
747 | int i; | ||
748 | |||
749 | i = i740fb_decode_var(&info->var, par, info); | ||
750 | if (i) | ||
751 | return i; | ||
752 | |||
753 | memset(info->screen_base, 0, info->screen_size); | ||
754 | |||
755 | vga_protect(par); | ||
756 | |||
757 | i740outreg(par, XRX, DRAM_EXT_CNTL, DRAM_REFRESH_DISABLE); | ||
758 | |||
759 | mdelay(1); | ||
760 | |||
761 | i740outreg(par, XRX, VCLK2_VCO_M, par->video_clk2_m); | ||
762 | i740outreg(par, XRX, VCLK2_VCO_N, par->video_clk2_n); | ||
763 | i740outreg(par, XRX, VCLK2_VCO_MN_MSBS, par->video_clk2_mn_msbs); | ||
764 | i740outreg(par, XRX, VCLK2_VCO_DIV_SEL, par->video_clk2_div_sel); | ||
765 | |||
766 | i740outreg_mask(par, XRX, PIXPIPE_CONFIG_0, | ||
767 | par->pixelpipe_cfg0 & DAC_8_BIT, 0x80); | ||
768 | |||
769 | i740inb(par, 0x3DA); | ||
770 | i740outb(par, 0x3C0, 0x00); | ||
771 | |||
772 | /* update misc output register */ | ||
773 | i740outb(par, VGA_MIS_W, par->misc | 0x01); | ||
774 | |||
775 | /* synchronous reset on */ | ||
776 | i740outreg(par, VGA_SEQ_I, VGA_SEQ_RESET, 0x01); | ||
777 | /* write sequencer registers */ | ||
778 | i740outreg(par, VGA_SEQ_I, VGA_SEQ_CLOCK_MODE, | ||
779 | par->seq[VGA_SEQ_CLOCK_MODE] | 0x20); | ||
780 | for (i = 2; i < VGA_SEQ_C; i++) | ||
781 | i740outreg(par, VGA_SEQ_I, i, par->seq[i]); | ||
782 | |||
783 | /* synchronous reset off */ | ||
784 | i740outreg(par, VGA_SEQ_I, VGA_SEQ_RESET, 0x03); | ||
785 | |||
786 | /* deprotect CRT registers 0-7 */ | ||
787 | i740outreg(par, VGA_CRT_IC, VGA_CRTC_V_SYNC_END, | ||
788 | par->crtc[VGA_CRTC_V_SYNC_END]); | ||
789 | |||
790 | /* write CRT registers */ | ||
791 | for (i = 0; i < VGA_CRT_C; i++) | ||
792 | i740outreg(par, VGA_CRT_IC, i, par->crtc[i]); | ||
793 | |||
794 | /* write graphics controller registers */ | ||
795 | for (i = 0; i < VGA_GFX_C; i++) | ||
796 | i740outreg(par, VGA_GFX_I, i, par->gdc[i]); | ||
797 | |||
798 | /* write attribute controller registers */ | ||
799 | for (i = 0; i < VGA_ATT_C; i++) { | ||
800 | i740inb(par, VGA_IS1_RC); /* reset flip-flop */ | ||
801 | i740outb(par, VGA_ATT_IW, i); | ||
802 | i740outb(par, VGA_ATT_IW, par->atc[i]); | ||
803 | } | ||
804 | |||
805 | i740inb(par, VGA_IS1_RC); | ||
806 | i740outb(par, VGA_ATT_IW, 0x20); | ||
807 | |||
808 | i740outreg(par, VGA_CRT_IC, EXT_VERT_TOTAL, par->ext_vert_total); | ||
809 | i740outreg(par, VGA_CRT_IC, EXT_VERT_DISPLAY, par->ext_vert_disp_end); | ||
810 | i740outreg(par, VGA_CRT_IC, EXT_VERT_SYNC_START, | ||
811 | par->ext_vert_sync_start); | ||
812 | i740outreg(par, VGA_CRT_IC, EXT_VERT_BLANK_START, | ||
813 | par->ext_vert_blank_start); | ||
814 | i740outreg(par, VGA_CRT_IC, EXT_HORIZ_TOTAL, par->ext_horiz_total); | ||
815 | i740outreg(par, VGA_CRT_IC, EXT_HORIZ_BLANK, par->ext_horiz_blank); | ||
816 | i740outreg(par, VGA_CRT_IC, EXT_OFFSET, par->ext_offset); | ||
817 | i740outreg(par, VGA_CRT_IC, EXT_START_ADDR_HI, par->ext_start_addr_hi); | ||
818 | i740outreg(par, VGA_CRT_IC, EXT_START_ADDR, par->ext_start_addr); | ||
819 | |||
820 | i740outreg_mask(par, VGA_CRT_IC, INTERLACE_CNTL, | ||
821 | par->interlace_cntl, INTERLACE_ENABLE); | ||
822 | i740outreg_mask(par, XRX, ADDRESS_MAPPING, par->address_mapping, 0x1F); | ||
823 | i740outreg_mask(par, XRX, BITBLT_CNTL, par->bitblt_cntl, COLEXP_MODE); | ||
824 | i740outreg_mask(par, XRX, DISPLAY_CNTL, | ||
825 | par->display_cntl, VGA_WRAP_MODE | GUI_MODE); | ||
826 | i740outreg_mask(par, XRX, PIXPIPE_CONFIG_0, par->pixelpipe_cfg0, 0x9B); | ||
827 | i740outreg_mask(par, XRX, PIXPIPE_CONFIG_2, par->pixelpipe_cfg2, 0x0C); | ||
828 | |||
829 | i740outreg(par, XRX, PLL_CNTL, par->pll_cntl); | ||
830 | |||
831 | i740outreg_mask(par, XRX, PIXPIPE_CONFIG_1, | ||
832 | par->pixelpipe_cfg1, DISPLAY_COLOR_MODE); | ||
833 | |||
834 | itemp = readl(par->regs + FWATER_BLC); | ||
835 | itemp &= ~(LMI_BURST_LENGTH | LMI_FIFO_WATERMARK); | ||
836 | itemp |= par->lmi_fifo_watermark; | ||
837 | writel(itemp, par->regs + FWATER_BLC); | ||
838 | |||
839 | i740outreg(par, XRX, DRAM_EXT_CNTL, DRAM_REFRESH_60HZ); | ||
840 | |||
841 | i740outreg_mask(par, MRX, COL_KEY_CNTL_1, 0, BLANK_DISP_OVERLAY); | ||
842 | i740outreg_mask(par, XRX, IO_CTNL, | ||
843 | par->io_cntl, EXTENDED_ATTR_CNTL | EXTENDED_CRTC_CNTL); | ||
844 | |||
845 | if (par->pixelpipe_cfg1 != DISPLAY_8BPP_MODE) { | ||
846 | i740outb(par, VGA_PEL_MSK, 0xFF); | ||
847 | i740outb(par, VGA_PEL_IW, 0x00); | ||
848 | for (i = 0; i < 256; i++) { | ||
849 | itemp = (par->pixelpipe_cfg0 & DAC_8_BIT) ? i : i >> 2; | ||
850 | i740outb(par, VGA_PEL_D, itemp); | ||
851 | i740outb(par, VGA_PEL_D, itemp); | ||
852 | i740outb(par, VGA_PEL_D, itemp); | ||
853 | } | ||
854 | } | ||
855 | |||
856 | /* Wait for screen to stabilize. */ | ||
857 | mdelay(50); | ||
858 | vga_unprotect(par); | ||
859 | |||
860 | info->fix.line_length = | ||
861 | info->var.xres_virtual * info->var.bits_per_pixel / 8; | ||
862 | if (info->var.bits_per_pixel == 8) | ||
863 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; | ||
864 | else | ||
865 | info->fix.visual = FB_VISUAL_TRUECOLOR; | ||
866 | |||
867 | return 0; | ||
868 | } | ||
869 | |||
870 | static int i740fb_setcolreg(unsigned regno, unsigned red, unsigned green, | ||
871 | unsigned blue, unsigned transp, | ||
872 | struct fb_info *info) | ||
873 | { | ||
874 | u32 r, g, b; | ||
875 | |||
876 | dev_dbg(info->device, "setcolreg: regno: %i, red=%d, green=%d, blue=%d, transp=%d, bpp=%d\n", | ||
877 | regno, red, green, blue, transp, info->var.bits_per_pixel); | ||
878 | |||
879 | switch (info->fix.visual) { | ||
880 | case FB_VISUAL_PSEUDOCOLOR: | ||
881 | if (regno >= 256) | ||
882 | return -EINVAL; | ||
883 | i740outb(info->par, VGA_PEL_IW, regno); | ||
884 | i740outb(info->par, VGA_PEL_D, red >> 8); | ||
885 | i740outb(info->par, VGA_PEL_D, green >> 8); | ||
886 | i740outb(info->par, VGA_PEL_D, blue >> 8); | ||
887 | break; | ||
888 | case FB_VISUAL_TRUECOLOR: | ||
889 | if (regno >= 16) | ||
890 | return -EINVAL; | ||
891 | r = (red >> (16 - info->var.red.length)) | ||
892 | << info->var.red.offset; | ||
893 | b = (blue >> (16 - info->var.blue.length)) | ||
894 | << info->var.blue.offset; | ||
895 | g = (green >> (16 - info->var.green.length)) | ||
896 | << info->var.green.offset; | ||
897 | ((u32 *) info->pseudo_palette)[regno] = r | g | b; | ||
898 | break; | ||
899 | default: | ||
900 | return -EINVAL; | ||
901 | } | ||
902 | |||
903 | return 0; | ||
904 | } | ||
905 | |||
906 | static int i740fb_pan_display(struct fb_var_screeninfo *var, | ||
907 | struct fb_info *info) | ||
908 | { | ||
909 | struct i740fb_par *par = info->par; | ||
910 | u32 base = (var->yoffset * info->var.xres_virtual | ||
911 | + (var->xoffset & ~7)) >> 2; | ||
912 | |||
913 | dev_dbg(info->device, "pan_display: xoffset: %i yoffset: %i base: %i\n", | ||
914 | var->xoffset, var->yoffset, base); | ||
915 | |||
916 | switch (info->var.bits_per_pixel) { | ||
917 | case 8: | ||
918 | break; | ||
919 | case 15: | ||
920 | case 16: | ||
921 | base *= 2; | ||
922 | break; | ||
923 | case 24: | ||
924 | /* | ||
925 | * The last bit does not seem to have any effect on the start | ||
926 | * address register in 24bpp mode, so... | ||
927 | */ | ||
928 | base &= 0xFFFFFFFE; /* ...ignore the last bit. */ | ||
929 | base *= 3; | ||
930 | break; | ||
931 | case 32: | ||
932 | base *= 4; | ||
933 | break; | ||
934 | } | ||
935 | |||
936 | par->crtc[VGA_CRTC_START_LO] = base & 0x000000FF; | ||
937 | par->crtc[VGA_CRTC_START_HI] = (base & 0x0000FF00) >> 8; | ||
938 | par->ext_start_addr_hi = (base & 0x3FC00000) >> 22; | ||
939 | par->ext_start_addr = | ||
940 | ((base & 0x003F0000) >> 16) | EXT_START_ADDR_ENABLE; | ||
941 | |||
942 | i740outreg(par, VGA_CRT_IC, VGA_CRTC_START_LO, base & 0x000000FF); | ||
943 | i740outreg(par, VGA_CRT_IC, VGA_CRTC_START_HI, | ||
944 | (base & 0x0000FF00) >> 8); | ||
945 | i740outreg(par, VGA_CRT_IC, EXT_START_ADDR_HI, | ||
946 | (base & 0x3FC00000) >> 22); | ||
947 | i740outreg(par, VGA_CRT_IC, EXT_START_ADDR, | ||
948 | ((base & 0x003F0000) >> 16) | EXT_START_ADDR_ENABLE); | ||
949 | |||
950 | return 0; | ||
951 | } | ||
952 | |||
953 | static int i740fb_blank(int blank_mode, struct fb_info *info) | ||
954 | { | ||
955 | struct i740fb_par *par = info->par; | ||
956 | |||
957 | unsigned char SEQ01; | ||
958 | int DPMSSyncSelect; | ||
959 | |||
960 | switch (blank_mode) { | ||
961 | case FB_BLANK_UNBLANK: | ||
962 | case FB_BLANK_NORMAL: | ||
963 | SEQ01 = 0x00; | ||
964 | DPMSSyncSelect = HSYNC_ON | VSYNC_ON; | ||
965 | break; | ||
966 | case FB_BLANK_VSYNC_SUSPEND: | ||
967 | SEQ01 = 0x20; | ||
968 | DPMSSyncSelect = HSYNC_ON | VSYNC_OFF; | ||
969 | break; | ||
970 | case FB_BLANK_HSYNC_SUSPEND: | ||
971 | SEQ01 = 0x20; | ||
972 | DPMSSyncSelect = HSYNC_OFF | VSYNC_ON; | ||
973 | break; | ||
974 | case FB_BLANK_POWERDOWN: | ||
975 | SEQ01 = 0x20; | ||
976 | DPMSSyncSelect = HSYNC_OFF | VSYNC_OFF; | ||
977 | break; | ||
978 | default: | ||
979 | return -EINVAL; | ||
980 | } | ||
981 | /* Turn the screen on/off */ | ||
982 | i740outb(par, SRX, 0x01); | ||
983 | SEQ01 |= i740inb(par, SRX + 1) & ~0x20; | ||
984 | i740outb(par, SRX, 0x01); | ||
985 | i740outb(par, SRX + 1, SEQ01); | ||
986 | |||
987 | /* Set the DPMS mode */ | ||
988 | i740outreg(par, XRX, DPMS_SYNC_SELECT, DPMSSyncSelect); | ||
989 | |||
990 | /* Let fbcon do a soft blank for us */ | ||
991 | return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0; | ||
992 | } | ||
993 | |||
994 | static struct fb_ops i740fb_ops = { | ||
995 | .owner = THIS_MODULE, | ||
996 | .fb_open = i740fb_open, | ||
997 | .fb_release = i740fb_release, | ||
998 | .fb_check_var = i740fb_check_var, | ||
999 | .fb_set_par = i740fb_set_par, | ||
1000 | .fb_setcolreg = i740fb_setcolreg, | ||
1001 | .fb_blank = i740fb_blank, | ||
1002 | .fb_pan_display = i740fb_pan_display, | ||
1003 | .fb_fillrect = cfb_fillrect, | ||
1004 | .fb_copyarea = cfb_copyarea, | ||
1005 | .fb_imageblit = cfb_imageblit, | ||
1006 | }; | ||
1007 | |||
1008 | /* ------------------------------------------------------------------------- */ | ||
1009 | |||
1010 | static int __devinit i740fb_probe(struct pci_dev *dev, | ||
1011 | const struct pci_device_id *ent) | ||
1012 | { | ||
1013 | struct fb_info *info; | ||
1014 | struct i740fb_par *par; | ||
1015 | int ret, tmp; | ||
1016 | bool found = false; | ||
1017 | u8 *edid; | ||
1018 | |||
1019 | info = framebuffer_alloc(sizeof(struct i740fb_par), &(dev->dev)); | ||
1020 | if (!info) { | ||
1021 | dev_err(&(dev->dev), "cannot allocate framebuffer\n"); | ||
1022 | return -ENOMEM; | ||
1023 | } | ||
1024 | |||
1025 | par = info->par; | ||
1026 | mutex_init(&par->open_lock); | ||
1027 | |||
1028 | info->var.activate = FB_ACTIVATE_NOW; | ||
1029 | info->var.bits_per_pixel = 8; | ||
1030 | info->fbops = &i740fb_ops; | ||
1031 | info->pseudo_palette = par->pseudo_palette; | ||
1032 | |||
1033 | ret = pci_enable_device(dev); | ||
1034 | if (ret) { | ||
1035 | dev_err(info->device, "cannot enable PCI device\n"); | ||
1036 | goto err_enable_device; | ||
1037 | } | ||
1038 | |||
1039 | ret = pci_request_regions(dev, info->fix.id); | ||
1040 | if (ret) { | ||
1041 | dev_err(info->device, "error requesting regions\n"); | ||
1042 | goto err_request_regions; | ||
1043 | } | ||
1044 | |||
1045 | info->screen_base = pci_ioremap_bar(dev, 0); | ||
1046 | if (!info->screen_base) { | ||
1047 | dev_err(info->device, "error remapping base\n"); | ||
1048 | ret = -ENOMEM; | ||
1049 | goto err_ioremap_1; | ||
1050 | } | ||
1051 | |||
1052 | par->regs = pci_ioremap_bar(dev, 1); | ||
1053 | if (!par->regs) { | ||
1054 | dev_err(info->device, "error remapping MMIO\n"); | ||
1055 | ret = -ENOMEM; | ||
1056 | goto err_ioremap_2; | ||
1057 | } | ||
1058 | |||
1059 | /* detect memory size */ | ||
1060 | if ((i740inreg(par, XRX, DRAM_ROW_TYPE) & DRAM_ROW_1) | ||
1061 | == DRAM_ROW_1_SDRAM) | ||
1062 | i740outb(par, XRX, DRAM_ROW_BNDRY_1); | ||
1063 | else | ||
1064 | i740outb(par, XRX, DRAM_ROW_BNDRY_0); | ||
1065 | info->screen_size = i740inb(par, XRX + 1) * 1024 * 1024; | ||
1066 | /* detect memory type */ | ||
1067 | tmp = i740inreg(par, XRX, DRAM_ROW_CNTL_LO); | ||
1068 | par->has_sgram = !((tmp & DRAM_RAS_TIMING) || | ||
1069 | (tmp & DRAM_RAS_PRECHARGE)); | ||
1070 | |||
1071 | printk(KERN_INFO "fb%d: Intel740 on %s, %ld KB %s\n", info->node, | ||
1072 | pci_name(dev), info->screen_size >> 10, | ||
1073 | par->has_sgram ? "SGRAM" : "SDRAM"); | ||
1074 | |||
1075 | info->fix = i740fb_fix; | ||
1076 | info->fix.mmio_start = pci_resource_start(dev, 1); | ||
1077 | info->fix.mmio_len = pci_resource_len(dev, 1); | ||
1078 | info->fix.smem_start = pci_resource_start(dev, 0); | ||
1079 | info->fix.smem_len = info->screen_size; | ||
1080 | info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; | ||
1081 | |||
1082 | if (i740fb_setup_ddc_bus(info) == 0) { | ||
1083 | par->ddc_registered = true; | ||
1084 | edid = fb_ddc_read(&par->ddc_adapter); | ||
1085 | if (edid) { | ||
1086 | fb_edid_to_monspecs(edid, &info->monspecs); | ||
1087 | kfree(edid); | ||
1088 | if (!info->monspecs.modedb) | ||
1089 | dev_err(info->device, | ||
1090 | "error getting mode database\n"); | ||
1091 | else { | ||
1092 | const struct fb_videomode *m; | ||
1093 | |||
1094 | fb_videomode_to_modelist( | ||
1095 | info->monspecs.modedb, | ||
1096 | info->monspecs.modedb_len, | ||
1097 | &info->modelist); | ||
1098 | m = fb_find_best_display(&info->monspecs, | ||
1099 | &info->modelist); | ||
1100 | if (m) { | ||
1101 | fb_videomode_to_var(&info->var, m); | ||
1102 | /* fill all other info->var's fields */ | ||
1103 | if (!i740fb_check_var(&info->var, info)) | ||
1104 | found = true; | ||
1105 | } | ||
1106 | } | ||
1107 | } | ||
1108 | } | ||
1109 | |||
1110 | if (!mode_option && !found) | ||
1111 | mode_option = "640x480-8@60"; | ||
1112 | |||
1113 | if (mode_option) { | ||
1114 | ret = fb_find_mode(&info->var, info, mode_option, | ||
1115 | info->monspecs.modedb, | ||
1116 | info->monspecs.modedb_len, | ||
1117 | NULL, info->var.bits_per_pixel); | ||
1118 | if (!ret || ret == 4) { | ||
1119 | dev_err(info->device, "mode %s not found\n", | ||
1120 | mode_option); | ||
1121 | ret = -EINVAL; | ||
1122 | } | ||
1123 | } | ||
1124 | |||
1125 | fb_destroy_modedb(info->monspecs.modedb); | ||
1126 | info->monspecs.modedb = NULL; | ||
1127 | |||
1128 | /* maximize virtual vertical size for fast scrolling */ | ||
1129 | info->var.yres_virtual = info->fix.smem_len * 8 / | ||
1130 | (info->var.bits_per_pixel * info->var.xres_virtual); | ||
1131 | |||
1132 | if (ret == -EINVAL) | ||
1133 | goto err_find_mode; | ||
1134 | |||
1135 | ret = fb_alloc_cmap(&info->cmap, 256, 0); | ||
1136 | if (ret) { | ||
1137 | dev_err(info->device, "cannot allocate colormap\n"); | ||
1138 | goto err_alloc_cmap; | ||
1139 | } | ||
1140 | |||
1141 | ret = register_framebuffer(info); | ||
1142 | if (ret) { | ||
1143 | dev_err(info->device, "error registering framebuffer\n"); | ||
1144 | goto err_reg_framebuffer; | ||
1145 | } | ||
1146 | |||
1147 | printk(KERN_INFO "fb%d: %s frame buffer device\n", | ||
1148 | info->node, info->fix.id); | ||
1149 | pci_set_drvdata(dev, info); | ||
1150 | #ifdef CONFIG_MTRR | ||
1151 | if (mtrr) { | ||
1152 | par->mtrr_reg = -1; | ||
1153 | par->mtrr_reg = mtrr_add(info->fix.smem_start, | ||
1154 | info->fix.smem_len, MTRR_TYPE_WRCOMB, 1); | ||
1155 | } | ||
1156 | #endif | ||
1157 | return 0; | ||
1158 | |||
1159 | err_reg_framebuffer: | ||
1160 | fb_dealloc_cmap(&info->cmap); | ||
1161 | err_alloc_cmap: | ||
1162 | err_find_mode: | ||
1163 | if (par->ddc_registered) | ||
1164 | i2c_del_adapter(&par->ddc_adapter); | ||
1165 | pci_iounmap(dev, par->regs); | ||
1166 | err_ioremap_2: | ||
1167 | pci_iounmap(dev, info->screen_base); | ||
1168 | err_ioremap_1: | ||
1169 | pci_release_regions(dev); | ||
1170 | err_request_regions: | ||
1171 | /* pci_disable_device(dev); */ | ||
1172 | err_enable_device: | ||
1173 | framebuffer_release(info); | ||
1174 | return ret; | ||
1175 | } | ||
1176 | |||
1177 | static void __devexit i740fb_remove(struct pci_dev *dev) | ||
1178 | { | ||
1179 | struct fb_info *info = pci_get_drvdata(dev); | ||
1180 | |||
1181 | if (info) { | ||
1182 | struct i740fb_par *par = info->par; | ||
1183 | |||
1184 | #ifdef CONFIG_MTRR | ||
1185 | if (par->mtrr_reg >= 0) { | ||
1186 | mtrr_del(par->mtrr_reg, 0, 0); | ||
1187 | par->mtrr_reg = -1; | ||
1188 | } | ||
1189 | #endif | ||
1190 | unregister_framebuffer(info); | ||
1191 | fb_dealloc_cmap(&info->cmap); | ||
1192 | if (par->ddc_registered) | ||
1193 | i2c_del_adapter(&par->ddc_adapter); | ||
1194 | pci_iounmap(dev, par->regs); | ||
1195 | pci_iounmap(dev, info->screen_base); | ||
1196 | pci_release_regions(dev); | ||
1197 | /* pci_disable_device(dev); */ | ||
1198 | pci_set_drvdata(dev, NULL); | ||
1199 | framebuffer_release(info); | ||
1200 | } | ||
1201 | } | ||
1202 | |||
1203 | #ifdef CONFIG_PM | ||
1204 | static int i740fb_suspend(struct pci_dev *dev, pm_message_t state) | ||
1205 | { | ||
1206 | struct fb_info *info = pci_get_drvdata(dev); | ||
1207 | struct i740fb_par *par = info->par; | ||
1208 | |||
1209 | /* don't disable console during hibernation and wakeup from it */ | ||
1210 | if (state.event == PM_EVENT_FREEZE || state.event == PM_EVENT_PRETHAW) | ||
1211 | return 0; | ||
1212 | |||
1213 | console_lock(); | ||
1214 | mutex_lock(&(par->open_lock)); | ||
1215 | |||
1216 | /* do nothing if framebuffer is not active */ | ||
1217 | if (par->ref_count == 0) { | ||
1218 | mutex_unlock(&(par->open_lock)); | ||
1219 | console_unlock(); | ||
1220 | return 0; | ||
1221 | } | ||
1222 | |||
1223 | fb_set_suspend(info, 1); | ||
1224 | |||
1225 | pci_save_state(dev); | ||
1226 | pci_disable_device(dev); | ||
1227 | pci_set_power_state(dev, pci_choose_state(dev, state)); | ||
1228 | |||
1229 | mutex_unlock(&(par->open_lock)); | ||
1230 | console_unlock(); | ||
1231 | |||
1232 | return 0; | ||
1233 | } | ||
1234 | |||
1235 | static int i740fb_resume(struct pci_dev *dev) | ||
1236 | { | ||
1237 | struct fb_info *info = pci_get_drvdata(dev); | ||
1238 | struct i740fb_par *par = info->par; | ||
1239 | |||
1240 | console_lock(); | ||
1241 | mutex_lock(&(par->open_lock)); | ||
1242 | |||
1243 | if (par->ref_count == 0) | ||
1244 | goto fail; | ||
1245 | |||
1246 | pci_set_power_state(dev, PCI_D0); | ||
1247 | pci_restore_state(dev); | ||
1248 | if (pci_enable_device(dev)) | ||
1249 | goto fail; | ||
1250 | |||
1251 | i740fb_set_par(info); | ||
1252 | fb_set_suspend(info, 0); | ||
1253 | |||
1254 | fail: | ||
1255 | mutex_unlock(&(par->open_lock)); | ||
1256 | console_unlock(); | ||
1257 | return 0; | ||
1258 | } | ||
1259 | #else | ||
1260 | #define i740fb_suspend NULL | ||
1261 | #define i740fb_resume NULL | ||
1262 | #endif /* CONFIG_PM */ | ||
1263 | |||
1264 | #define I740_ID_PCI 0x00d1 | ||
1265 | #define I740_ID_AGP 0x7800 | ||
1266 | |||
1267 | static DEFINE_PCI_DEVICE_TABLE(i740fb_id_table) = { | ||
1268 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, I740_ID_PCI) }, | ||
1269 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, I740_ID_AGP) }, | ||
1270 | { 0 } | ||
1271 | }; | ||
1272 | MODULE_DEVICE_TABLE(pci, i740fb_id_table); | ||
1273 | |||
1274 | static struct pci_driver i740fb_driver = { | ||
1275 | .name = "i740fb", | ||
1276 | .id_table = i740fb_id_table, | ||
1277 | .probe = i740fb_probe, | ||
1278 | .remove = __devexit_p(i740fb_remove), | ||
1279 | .suspend = i740fb_suspend, | ||
1280 | .resume = i740fb_resume, | ||
1281 | }; | ||
1282 | |||
1283 | #ifndef MODULE | ||
1284 | static int __init i740fb_setup(char *options) | ||
1285 | { | ||
1286 | char *opt; | ||
1287 | |||
1288 | if (!options || !*options) | ||
1289 | return 0; | ||
1290 | |||
1291 | while ((opt = strsep(&options, ",")) != NULL) { | ||
1292 | if (!*opt) | ||
1293 | continue; | ||
1294 | #ifdef CONFIG_MTRR | ||
1295 | else if (!strncmp(opt, "mtrr:", 5)) | ||
1296 | mtrr = simple_strtoul(opt + 5, NULL, 0); | ||
1297 | #endif | ||
1298 | else | ||
1299 | mode_option = opt; | ||
1300 | } | ||
1301 | |||
1302 | return 0; | ||
1303 | } | ||
1304 | #endif | ||
1305 | |||
1306 | int __init i740fb_init(void) | ||
1307 | { | ||
1308 | #ifndef MODULE | ||
1309 | char *option = NULL; | ||
1310 | |||
1311 | if (fb_get_options("i740fb", &option)) | ||
1312 | return -ENODEV; | ||
1313 | i740fb_setup(option); | ||
1314 | #endif | ||
1315 | |||
1316 | return pci_register_driver(&i740fb_driver); | ||
1317 | } | ||
1318 | |||
1319 | static void __exit i740fb_exit(void) | ||
1320 | { | ||
1321 | pci_unregister_driver(&i740fb_driver); | ||
1322 | } | ||
1323 | |||
1324 | module_init(i740fb_init); | ||
1325 | module_exit(i740fb_exit); | ||
1326 | |||
1327 | MODULE_AUTHOR("(c) 2011 Ondrej Zary <linux@rainbow-software.org>"); | ||
1328 | MODULE_LICENSE("GPL"); | ||
1329 | MODULE_DESCRIPTION("fbdev driver for Intel740"); | ||
1330 | |||
1331 | module_param(mode_option, charp, 0444); | ||
1332 | MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)"); | ||
1333 | |||
1334 | #ifdef CONFIG_MTRR | ||
1335 | module_param(mtrr, int, 0444); | ||
1336 | MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)"); | ||
1337 | #endif | ||
diff --git a/drivers/video/msm/mddi_client_nt35399.c b/drivers/video/msm/mddi_client_nt35399.c index f239f4a25e01..7fcd67e132bf 100644 --- a/drivers/video/msm/mddi_client_nt35399.c +++ b/drivers/video/msm/mddi_client_nt35399.c | |||
@@ -155,14 +155,10 @@ static int setup_vsync(struct panel_info *panel, int init) | |||
155 | ret = 0; | 155 | ret = 0; |
156 | goto uninit; | 156 | goto uninit; |
157 | } | 157 | } |
158 | ret = gpio_request(gpio, "vsync"); | 158 | ret = gpio_request_one(gpio, GPIOF_IN, "vsync"); |
159 | if (ret) | 159 | if (ret) |
160 | goto err_request_gpio_failed; | 160 | goto err_request_gpio_failed; |
161 | 161 | ||
162 | ret = gpio_direction_input(gpio); | ||
163 | if (ret) | ||
164 | goto err_gpio_direction_input_failed; | ||
165 | |||
166 | ret = irq = gpio_to_irq(gpio); | 162 | ret = irq = gpio_to_irq(gpio); |
167 | if (ret < 0) | 163 | if (ret < 0) |
168 | goto err_get_irq_num_failed; | 164 | goto err_get_irq_num_failed; |
@@ -180,7 +176,6 @@ uninit: | |||
180 | free_irq(gpio_to_irq(gpio), panel->client_data); | 176 | free_irq(gpio_to_irq(gpio), panel->client_data); |
181 | err_request_irq_failed: | 177 | err_request_irq_failed: |
182 | err_get_irq_num_failed: | 178 | err_get_irq_num_failed: |
183 | err_gpio_direction_input_failed: | ||
184 | gpio_free(gpio); | 179 | gpio_free(gpio); |
185 | err_request_gpio_failed: | 180 | err_request_gpio_failed: |
186 | return ret; | 181 | return ret; |
diff --git a/drivers/video/msm/mddi_client_toshiba.c b/drivers/video/msm/mddi_client_toshiba.c index f9bc932ac46b..053eb6877330 100644 --- a/drivers/video/msm/mddi_client_toshiba.c +++ b/drivers/video/msm/mddi_client_toshiba.c | |||
@@ -186,14 +186,10 @@ static int setup_vsync(struct panel_info *panel, | |||
186 | ret = 0; | 186 | ret = 0; |
187 | goto uninit; | 187 | goto uninit; |
188 | } | 188 | } |
189 | ret = gpio_request(gpio, "vsync"); | 189 | ret = gpio_request_one(gpio, GPIOF_IN, "vsync"); |
190 | if (ret) | 190 | if (ret) |
191 | goto err_request_gpio_failed; | 191 | goto err_request_gpio_failed; |
192 | 192 | ||
193 | ret = gpio_direction_input(gpio); | ||
194 | if (ret) | ||
195 | goto err_gpio_direction_input_failed; | ||
196 | |||
197 | ret = irq = gpio_to_irq(gpio); | 193 | ret = irq = gpio_to_irq(gpio); |
198 | if (ret < 0) | 194 | if (ret < 0) |
199 | goto err_get_irq_num_failed; | 195 | goto err_get_irq_num_failed; |
@@ -210,7 +206,6 @@ uninit: | |||
210 | free_irq(gpio_to_irq(gpio), panel); | 206 | free_irq(gpio_to_irq(gpio), panel); |
211 | err_request_irq_failed: | 207 | err_request_irq_failed: |
212 | err_get_irq_num_failed: | 208 | err_get_irq_num_failed: |
213 | err_gpio_direction_input_failed: | ||
214 | gpio_free(gpio); | 209 | gpio_free(gpio); |
215 | err_request_gpio_failed: | 210 | err_request_gpio_failed: |
216 | return ret; | 211 | return ret; |
diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig index 84ff23208c25..1e7536d9a8fc 100644 --- a/drivers/video/omap/Kconfig +++ b/drivers/video/omap/Kconfig | |||
@@ -1,11 +1,10 @@ | |||
1 | config FB_OMAP | 1 | config FB_OMAP |
2 | tristate "OMAP frame buffer support (EXPERIMENTAL)" | 2 | tristate "OMAP frame buffer support (EXPERIMENTAL)" |
3 | depends on FB && (OMAP2_DSS = "n") | 3 | depends on FB |
4 | depends on ARCH_OMAP1 || ARCH_OMAP2 || ARCH_OMAP3 | 4 | depends on ARCH_OMAP1 |
5 | select FB_CFB_FILLRECT | 5 | select FB_CFB_FILLRECT |
6 | select FB_CFB_COPYAREA | 6 | select FB_CFB_COPYAREA |
7 | select FB_CFB_IMAGEBLIT | 7 | select FB_CFB_IMAGEBLIT |
8 | select TWL4030_CORE if MACH_OMAP_2430SDP | ||
9 | help | 8 | help |
10 | Frame buffer driver for OMAP based boards. | 9 | Frame buffer driver for OMAP based boards. |
11 | 10 | ||
@@ -23,13 +22,6 @@ config FB_OMAP_LCDC_HWA742 | |||
23 | Say Y here if you want to have support for the external | 22 | Say Y here if you want to have support for the external |
24 | Epson HWA742 LCD controller. | 23 | Epson HWA742 LCD controller. |
25 | 24 | ||
26 | config FB_OMAP_LCDC_BLIZZARD | ||
27 | bool "Epson Blizzard LCD controller support" | ||
28 | depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL | ||
29 | help | ||
30 | Say Y here if you want to have support for the external | ||
31 | Epson Blizzard LCD controller. | ||
32 | |||
33 | config FB_OMAP_MANUAL_UPDATE | 25 | config FB_OMAP_MANUAL_UPDATE |
34 | bool "Default to manual update mode" | 26 | bool "Default to manual update mode" |
35 | depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL | 27 | depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL |
@@ -49,7 +41,7 @@ config FB_OMAP_LCD_MIPID | |||
49 | 41 | ||
50 | config FB_OMAP_BOOTLOADER_INIT | 42 | config FB_OMAP_BOOTLOADER_INIT |
51 | bool "Check bootloader initialization" | 43 | bool "Check bootloader initialization" |
52 | depends on FB_OMAP || FB_OMAP2 | 44 | depends on FB_OMAP |
53 | help | 45 | help |
54 | Say Y here if you want to enable checking if the bootloader has | 46 | Say Y here if you want to enable checking if the bootloader has |
55 | already initialized the display controller. In this case the | 47 | already initialized the display controller. In this case the |
@@ -68,7 +60,7 @@ config FB_OMAP_CONSISTENT_DMA_SIZE | |||
68 | 60 | ||
69 | config FB_OMAP_DMA_TUNE | 61 | config FB_OMAP_DMA_TUNE |
70 | bool "Set DMA SDRAM access priority high" | 62 | bool "Set DMA SDRAM access priority high" |
71 | depends on FB_OMAP && ARCH_OMAP1 | 63 | depends on FB_OMAP |
72 | help | 64 | help |
73 | On systems in which video memory is in system memory | 65 | On systems in which video memory is in system memory |
74 | (SDRAM) this will speed up graphics DMA operations. | 66 | (SDRAM) this will speed up graphics DMA operations. |
diff --git a/drivers/video/omap/Makefile b/drivers/video/omap/Makefile index ef78550917ff..1927faffb5bc 100644 --- a/drivers/video/omap/Makefile +++ b/drivers/video/omap/Makefile | |||
@@ -1,20 +1,14 @@ | |||
1 | # | 1 | # |
2 | # Makefile for the new OMAP framebuffer device driver | 2 | # Makefile for the OMAP1 framebuffer device driver |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_FB_OMAP) += omapfb.o | 5 | obj-$(CONFIG_FB_OMAP) += omapfb.o |
6 | 6 | ||
7 | objs-yy := omapfb_main.o | 7 | objs-yy := omapfb_main.o lcdc.o |
8 | 8 | ||
9 | objs-y$(CONFIG_ARCH_OMAP1) += lcdc.o | 9 | objs-y$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += sossi.o |
10 | objs-y$(CONFIG_ARCH_OMAP2) += dispc.o | ||
11 | objs-y$(CONFIG_ARCH_OMAP3) += dispc.o | ||
12 | |||
13 | objs-$(CONFIG_ARCH_OMAP1)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += sossi.o | ||
14 | objs-$(CONFIG_ARCH_OMAP2)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += rfbi.o | ||
15 | 10 | ||
16 | objs-y$(CONFIG_FB_OMAP_LCDC_HWA742) += hwa742.o | 11 | objs-y$(CONFIG_FB_OMAP_LCDC_HWA742) += hwa742.o |
17 | objs-y$(CONFIG_FB_OMAP_LCDC_BLIZZARD) += blizzard.o | ||
18 | 12 | ||
19 | objs-y$(CONFIG_MACH_AMS_DELTA) += lcd_ams_delta.o | 13 | objs-y$(CONFIG_MACH_AMS_DELTA) += lcd_ams_delta.o |
20 | objs-y$(CONFIG_MACH_OMAP_H3) += lcd_h3.o | 14 | objs-y$(CONFIG_MACH_OMAP_H3) += lcd_h3.o |
diff --git a/drivers/video/omap/blizzard.c b/drivers/video/omap/blizzard.c deleted file mode 100644 index c0504a8a5079..000000000000 --- a/drivers/video/omap/blizzard.c +++ /dev/null | |||
@@ -1,1648 +0,0 @@ | |||
1 | /* | ||
2 | * Epson Blizzard LCD controller driver | ||
3 | * | ||
4 | * Copyright (C) 2004-2005 Nokia Corporation | ||
5 | * Authors: Juha Yrjola <juha.yrjola@nokia.com> | ||
6 | * Imre Deak <imre.deak@nokia.com> | ||
7 | * YUV support: Jussi Laako <jussi.laako@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along | ||
20 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
22 | */ | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/mm.h> | ||
25 | #include <linux/fb.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/clk.h> | ||
28 | |||
29 | #include <plat/dma.h> | ||
30 | #include <plat/blizzard.h> | ||
31 | |||
32 | #include "omapfb.h" | ||
33 | #include "dispc.h" | ||
34 | |||
35 | #define MODULE_NAME "blizzard" | ||
36 | |||
37 | #define BLIZZARD_REV_CODE 0x00 | ||
38 | #define BLIZZARD_CONFIG 0x02 | ||
39 | #define BLIZZARD_PLL_DIV 0x04 | ||
40 | #define BLIZZARD_PLL_LOCK_RANGE 0x06 | ||
41 | #define BLIZZARD_PLL_CLOCK_SYNTH_0 0x08 | ||
42 | #define BLIZZARD_PLL_CLOCK_SYNTH_1 0x0a | ||
43 | #define BLIZZARD_PLL_MODE 0x0c | ||
44 | #define BLIZZARD_CLK_SRC 0x0e | ||
45 | #define BLIZZARD_MEM_BANK0_ACTIVATE 0x10 | ||
46 | #define BLIZZARD_MEM_BANK0_STATUS 0x14 | ||
47 | #define BLIZZARD_PANEL_CONFIGURATION 0x28 | ||
48 | #define BLIZZARD_HDISP 0x2a | ||
49 | #define BLIZZARD_HNDP 0x2c | ||
50 | #define BLIZZARD_VDISP0 0x2e | ||
51 | #define BLIZZARD_VDISP1 0x30 | ||
52 | #define BLIZZARD_VNDP 0x32 | ||
53 | #define BLIZZARD_HSW 0x34 | ||
54 | #define BLIZZARD_VSW 0x38 | ||
55 | #define BLIZZARD_DISPLAY_MODE 0x68 | ||
56 | #define BLIZZARD_INPUT_WIN_X_START_0 0x6c | ||
57 | #define BLIZZARD_DATA_SOURCE_SELECT 0x8e | ||
58 | #define BLIZZARD_DISP_MEM_DATA_PORT 0x90 | ||
59 | #define BLIZZARD_DISP_MEM_READ_ADDR0 0x92 | ||
60 | #define BLIZZARD_POWER_SAVE 0xE6 | ||
61 | #define BLIZZARD_NDISP_CTRL_STATUS 0xE8 | ||
62 | |||
63 | /* Data source select */ | ||
64 | /* For S1D13745 */ | ||
65 | #define BLIZZARD_SRC_WRITE_LCD_BACKGROUND 0x00 | ||
66 | #define BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE 0x01 | ||
67 | #define BLIZZARD_SRC_WRITE_OVERLAY_ENABLE 0x04 | ||
68 | #define BLIZZARD_SRC_DISABLE_OVERLAY 0x05 | ||
69 | /* For S1D13744 */ | ||
70 | #define BLIZZARD_SRC_WRITE_LCD 0x00 | ||
71 | #define BLIZZARD_SRC_BLT_LCD 0x06 | ||
72 | |||
73 | #define BLIZZARD_COLOR_RGB565 0x01 | ||
74 | #define BLIZZARD_COLOR_YUV420 0x09 | ||
75 | |||
76 | #define BLIZZARD_VERSION_S1D13745 0x01 /* Hailstorm */ | ||
77 | #define BLIZZARD_VERSION_S1D13744 0x02 /* Blizzard */ | ||
78 | |||
79 | #define BLIZZARD_AUTO_UPDATE_TIME (HZ / 20) | ||
80 | |||
81 | /* Reserve 4 request slots for requests in irq context */ | ||
82 | #define REQ_POOL_SIZE 24 | ||
83 | #define IRQ_REQ_POOL_SIZE 4 | ||
84 | |||
85 | #define REQ_FROM_IRQ_POOL 0x01 | ||
86 | |||
87 | #define REQ_COMPLETE 0 | ||
88 | #define REQ_PENDING 1 | ||
89 | |||
90 | struct blizzard_reg_list { | ||
91 | int start; | ||
92 | int end; | ||
93 | }; | ||
94 | |||
95 | /* These need to be saved / restored separately from the rest. */ | ||
96 | static const struct blizzard_reg_list blizzard_pll_regs[] = { | ||
97 | { | ||
98 | .start = 0x04, /* Don't save PLL ctrl (0x0C) */ | ||
99 | .end = 0x0a, | ||
100 | }, | ||
101 | { | ||
102 | .start = 0x0e, /* Clock configuration */ | ||
103 | .end = 0x0e, | ||
104 | }, | ||
105 | }; | ||
106 | |||
107 | static const struct blizzard_reg_list blizzard_gen_regs[] = { | ||
108 | { | ||
109 | .start = 0x18, /* SDRAM control */ | ||
110 | .end = 0x20, | ||
111 | }, | ||
112 | { | ||
113 | .start = 0x28, /* LCD Panel configuration */ | ||
114 | .end = 0x5a, /* HSSI interface, TV configuration */ | ||
115 | }, | ||
116 | }; | ||
117 | |||
118 | static u8 blizzard_reg_cache[0x5a / 2]; | ||
119 | |||
120 | struct update_param { | ||
121 | int plane; | ||
122 | int x, y, width, height; | ||
123 | int out_x, out_y; | ||
124 | int out_width, out_height; | ||
125 | int color_mode; | ||
126 | int bpp; | ||
127 | int flags; | ||
128 | }; | ||
129 | |||
130 | struct blizzard_request { | ||
131 | struct list_head entry; | ||
132 | unsigned int flags; | ||
133 | |||
134 | int (*handler)(struct blizzard_request *req); | ||
135 | void (*complete)(void *data); | ||
136 | void *complete_data; | ||
137 | |||
138 | union { | ||
139 | struct update_param update; | ||
140 | struct completion *sync; | ||
141 | } par; | ||
142 | }; | ||
143 | |||
144 | struct plane_info { | ||
145 | unsigned long offset; | ||
146 | int pos_x, pos_y; | ||
147 | int width, height; | ||
148 | int out_width, out_height; | ||
149 | int scr_width; | ||
150 | int color_mode; | ||
151 | int bpp; | ||
152 | }; | ||
153 | |||
154 | struct blizzard_struct { | ||
155 | enum omapfb_update_mode update_mode; | ||
156 | enum omapfb_update_mode update_mode_before_suspend; | ||
157 | |||
158 | struct timer_list auto_update_timer; | ||
159 | int stop_auto_update; | ||
160 | struct omapfb_update_window auto_update_window; | ||
161 | int enabled_planes; | ||
162 | int vid_nonstd_color; | ||
163 | int vid_scaled; | ||
164 | int last_color_mode; | ||
165 | int zoom_on; | ||
166 | int zoom_area_gx1; | ||
167 | int zoom_area_gx2; | ||
168 | int zoom_area_gy1; | ||
169 | int zoom_area_gy2; | ||
170 | int screen_width; | ||
171 | int screen_height; | ||
172 | unsigned te_connected:1; | ||
173 | unsigned vsync_only:1; | ||
174 | |||
175 | struct plane_info plane[OMAPFB_PLANE_NUM]; | ||
176 | |||
177 | struct blizzard_request req_pool[REQ_POOL_SIZE]; | ||
178 | struct list_head pending_req_list; | ||
179 | struct list_head free_req_list; | ||
180 | struct semaphore req_sema; | ||
181 | spinlock_t req_lock; | ||
182 | |||
183 | unsigned long sys_ck_rate; | ||
184 | struct extif_timings reg_timings, lut_timings; | ||
185 | |||
186 | u32 max_transmit_size; | ||
187 | u32 extif_clk_period; | ||
188 | int extif_clk_div; | ||
189 | unsigned long pix_tx_time; | ||
190 | unsigned long line_upd_time; | ||
191 | |||
192 | struct omapfb_device *fbdev; | ||
193 | struct lcd_ctrl_extif *extif; | ||
194 | const struct lcd_ctrl *int_ctrl; | ||
195 | |||
196 | void (*power_up)(struct device *dev); | ||
197 | void (*power_down)(struct device *dev); | ||
198 | |||
199 | int version; | ||
200 | } blizzard; | ||
201 | |||
202 | struct lcd_ctrl blizzard_ctrl; | ||
203 | |||
204 | static u8 blizzard_read_reg(u8 reg) | ||
205 | { | ||
206 | u8 data; | ||
207 | |||
208 | blizzard.extif->set_bits_per_cycle(8); | ||
209 | blizzard.extif->write_command(®, 1); | ||
210 | blizzard.extif->read_data(&data, 1); | ||
211 | |||
212 | return data; | ||
213 | } | ||
214 | |||
215 | static void blizzard_write_reg(u8 reg, u8 val) | ||
216 | { | ||
217 | blizzard.extif->set_bits_per_cycle(8); | ||
218 | blizzard.extif->write_command(®, 1); | ||
219 | blizzard.extif->write_data(&val, 1); | ||
220 | } | ||
221 | |||
222 | static void blizzard_restart_sdram(void) | ||
223 | { | ||
224 | unsigned long tmo; | ||
225 | |||
226 | blizzard_write_reg(BLIZZARD_MEM_BANK0_ACTIVATE, 0); | ||
227 | udelay(50); | ||
228 | blizzard_write_reg(BLIZZARD_MEM_BANK0_ACTIVATE, 1); | ||
229 | tmo = jiffies + msecs_to_jiffies(200); | ||
230 | while (!(blizzard_read_reg(BLIZZARD_MEM_BANK0_STATUS) & 0x01)) { | ||
231 | if (time_after(jiffies, tmo)) { | ||
232 | dev_err(blizzard.fbdev->dev, | ||
233 | "s1d1374x: SDRAM not ready\n"); | ||
234 | break; | ||
235 | } | ||
236 | msleep(1); | ||
237 | } | ||
238 | } | ||
239 | |||
240 | static void blizzard_stop_sdram(void) | ||
241 | { | ||
242 | blizzard_write_reg(BLIZZARD_MEM_BANK0_ACTIVATE, 0); | ||
243 | } | ||
244 | |||
245 | /* Wait until the last window was completely written into the controllers | ||
246 | * SDRAM and we can start transferring the next window. | ||
247 | */ | ||
248 | static void blizzard_wait_line_buffer(void) | ||
249 | { | ||
250 | unsigned long tmo = jiffies + msecs_to_jiffies(30); | ||
251 | |||
252 | while (blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS) & (1 << 7)) { | ||
253 | if (time_after(jiffies, tmo)) { | ||
254 | if (printk_ratelimit()) | ||
255 | dev_err(blizzard.fbdev->dev, | ||
256 | "s1d1374x: line buffer not ready\n"); | ||
257 | break; | ||
258 | } | ||
259 | } | ||
260 | } | ||
261 | |||
262 | /* Wait until the YYC color space converter is idle. */ | ||
263 | static void blizzard_wait_yyc(void) | ||
264 | { | ||
265 | unsigned long tmo = jiffies + msecs_to_jiffies(30); | ||
266 | |||
267 | while (blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS) & (1 << 4)) { | ||
268 | if (time_after(jiffies, tmo)) { | ||
269 | if (printk_ratelimit()) | ||
270 | dev_err(blizzard.fbdev->dev, | ||
271 | "s1d1374x: YYC not ready\n"); | ||
272 | break; | ||
273 | } | ||
274 | } | ||
275 | } | ||
276 | |||
277 | static void disable_overlay(void) | ||
278 | { | ||
279 | blizzard_write_reg(BLIZZARD_DATA_SOURCE_SELECT, | ||
280 | BLIZZARD_SRC_DISABLE_OVERLAY); | ||
281 | } | ||
282 | |||
283 | static void set_window_regs(int x_start, int y_start, int x_end, int y_end, | ||
284 | int x_out_start, int y_out_start, | ||
285 | int x_out_end, int y_out_end, int color_mode, | ||
286 | int zoom_off, int flags) | ||
287 | { | ||
288 | u8 tmp[18]; | ||
289 | u8 cmd; | ||
290 | |||
291 | x_end--; | ||
292 | y_end--; | ||
293 | tmp[0] = x_start; | ||
294 | tmp[1] = x_start >> 8; | ||
295 | tmp[2] = y_start; | ||
296 | tmp[3] = y_start >> 8; | ||
297 | tmp[4] = x_end; | ||
298 | tmp[5] = x_end >> 8; | ||
299 | tmp[6] = y_end; | ||
300 | tmp[7] = y_end >> 8; | ||
301 | |||
302 | x_out_end--; | ||
303 | y_out_end--; | ||
304 | tmp[8] = x_out_start; | ||
305 | tmp[9] = x_out_start >> 8; | ||
306 | tmp[10] = y_out_start; | ||
307 | tmp[11] = y_out_start >> 8; | ||
308 | tmp[12] = x_out_end; | ||
309 | tmp[13] = x_out_end >> 8; | ||
310 | tmp[14] = y_out_end; | ||
311 | tmp[15] = y_out_end >> 8; | ||
312 | |||
313 | tmp[16] = color_mode; | ||
314 | if (zoom_off && blizzard.version == BLIZZARD_VERSION_S1D13745) | ||
315 | tmp[17] = BLIZZARD_SRC_WRITE_LCD_BACKGROUND; | ||
316 | else if (flags & OMAPFB_FORMAT_FLAG_ENABLE_OVERLAY) | ||
317 | tmp[17] = BLIZZARD_SRC_WRITE_OVERLAY_ENABLE; | ||
318 | else | ||
319 | tmp[17] = blizzard.version == BLIZZARD_VERSION_S1D13744 ? | ||
320 | BLIZZARD_SRC_WRITE_LCD : | ||
321 | BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE; | ||
322 | |||
323 | blizzard.extif->set_bits_per_cycle(8); | ||
324 | cmd = BLIZZARD_INPUT_WIN_X_START_0; | ||
325 | blizzard.extif->write_command(&cmd, 1); | ||
326 | blizzard.extif->write_data(tmp, 18); | ||
327 | } | ||
328 | |||
329 | static void enable_tearsync(int y, int width, int height, int screen_height, | ||
330 | int out_height, int force_vsync) | ||
331 | { | ||
332 | u8 b; | ||
333 | |||
334 | b = blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS); | ||
335 | b |= 1 << 3; | ||
336 | blizzard_write_reg(BLIZZARD_NDISP_CTRL_STATUS, b); | ||
337 | |||
338 | if (likely(blizzard.vsync_only || force_vsync)) { | ||
339 | blizzard.extif->enable_tearsync(1, 0); | ||
340 | return; | ||
341 | } | ||
342 | |||
343 | if (width * blizzard.pix_tx_time < blizzard.line_upd_time) { | ||
344 | blizzard.extif->enable_tearsync(1, 0); | ||
345 | return; | ||
346 | } | ||
347 | |||
348 | if ((width * blizzard.pix_tx_time / 1000) * height < | ||
349 | (y + out_height) * (blizzard.line_upd_time / 1000)) { | ||
350 | blizzard.extif->enable_tearsync(1, 0); | ||
351 | return; | ||
352 | } | ||
353 | |||
354 | blizzard.extif->enable_tearsync(1, y + 1); | ||
355 | } | ||
356 | |||
357 | static void disable_tearsync(void) | ||
358 | { | ||
359 | u8 b; | ||
360 | |||
361 | blizzard.extif->enable_tearsync(0, 0); | ||
362 | b = blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS); | ||
363 | b &= ~(1 << 3); | ||
364 | blizzard_write_reg(BLIZZARD_NDISP_CTRL_STATUS, b); | ||
365 | b = blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS); | ||
366 | } | ||
367 | |||
368 | static inline void set_extif_timings(const struct extif_timings *t); | ||
369 | |||
370 | static inline struct blizzard_request *alloc_req(void) | ||
371 | { | ||
372 | unsigned long flags; | ||
373 | struct blizzard_request *req; | ||
374 | int req_flags = 0; | ||
375 | |||
376 | if (!in_interrupt()) | ||
377 | down(&blizzard.req_sema); | ||
378 | else | ||
379 | req_flags = REQ_FROM_IRQ_POOL; | ||
380 | |||
381 | spin_lock_irqsave(&blizzard.req_lock, flags); | ||
382 | BUG_ON(list_empty(&blizzard.free_req_list)); | ||
383 | req = list_entry(blizzard.free_req_list.next, | ||
384 | struct blizzard_request, entry); | ||
385 | list_del(&req->entry); | ||
386 | spin_unlock_irqrestore(&blizzard.req_lock, flags); | ||
387 | |||
388 | INIT_LIST_HEAD(&req->entry); | ||
389 | req->flags = req_flags; | ||
390 | |||
391 | return req; | ||
392 | } | ||
393 | |||
394 | static inline void free_req(struct blizzard_request *req) | ||
395 | { | ||
396 | unsigned long flags; | ||
397 | |||
398 | spin_lock_irqsave(&blizzard.req_lock, flags); | ||
399 | |||
400 | list_move(&req->entry, &blizzard.free_req_list); | ||
401 | if (!(req->flags & REQ_FROM_IRQ_POOL)) | ||
402 | up(&blizzard.req_sema); | ||
403 | |||
404 | spin_unlock_irqrestore(&blizzard.req_lock, flags); | ||
405 | } | ||
406 | |||
407 | static void process_pending_requests(void) | ||
408 | { | ||
409 | unsigned long flags; | ||
410 | |||
411 | spin_lock_irqsave(&blizzard.req_lock, flags); | ||
412 | |||
413 | while (!list_empty(&blizzard.pending_req_list)) { | ||
414 | struct blizzard_request *req; | ||
415 | void (*complete)(void *); | ||
416 | void *complete_data; | ||
417 | |||
418 | req = list_entry(blizzard.pending_req_list.next, | ||
419 | struct blizzard_request, entry); | ||
420 | spin_unlock_irqrestore(&blizzard.req_lock, flags); | ||
421 | |||
422 | if (req->handler(req) == REQ_PENDING) | ||
423 | return; | ||
424 | |||
425 | complete = req->complete; | ||
426 | complete_data = req->complete_data; | ||
427 | free_req(req); | ||
428 | |||
429 | if (complete) | ||
430 | complete(complete_data); | ||
431 | |||
432 | spin_lock_irqsave(&blizzard.req_lock, flags); | ||
433 | } | ||
434 | |||
435 | spin_unlock_irqrestore(&blizzard.req_lock, flags); | ||
436 | } | ||
437 | |||
438 | static void submit_req_list(struct list_head *head) | ||
439 | { | ||
440 | unsigned long flags; | ||
441 | int process = 1; | ||
442 | |||
443 | spin_lock_irqsave(&blizzard.req_lock, flags); | ||
444 | if (likely(!list_empty(&blizzard.pending_req_list))) | ||
445 | process = 0; | ||
446 | list_splice_init(head, blizzard.pending_req_list.prev); | ||
447 | spin_unlock_irqrestore(&blizzard.req_lock, flags); | ||
448 | |||
449 | if (process) | ||
450 | process_pending_requests(); | ||
451 | } | ||
452 | |||
453 | static void request_complete(void *data) | ||
454 | { | ||
455 | struct blizzard_request *req = (struct blizzard_request *)data; | ||
456 | void (*complete)(void *); | ||
457 | void *complete_data; | ||
458 | |||
459 | complete = req->complete; | ||
460 | complete_data = req->complete_data; | ||
461 | |||
462 | free_req(req); | ||
463 | |||
464 | if (complete) | ||
465 | complete(complete_data); | ||
466 | |||
467 | process_pending_requests(); | ||
468 | } | ||
469 | |||
470 | |||
471 | static int do_full_screen_update(struct blizzard_request *req) | ||
472 | { | ||
473 | int i; | ||
474 | int flags; | ||
475 | |||
476 | for (i = 0; i < 3; i++) { | ||
477 | struct plane_info *p = &blizzard.plane[i]; | ||
478 | if (!(blizzard.enabled_planes & (1 << i))) { | ||
479 | blizzard.int_ctrl->enable_plane(i, 0); | ||
480 | continue; | ||
481 | } | ||
482 | dev_dbg(blizzard.fbdev->dev, "pw %d ph %d\n", | ||
483 | p->width, p->height); | ||
484 | blizzard.int_ctrl->setup_plane(i, | ||
485 | OMAPFB_CHANNEL_OUT_LCD, p->offset, | ||
486 | p->scr_width, p->pos_x, p->pos_y, | ||
487 | p->width, p->height, | ||
488 | p->color_mode); | ||
489 | blizzard.int_ctrl->enable_plane(i, 1); | ||
490 | } | ||
491 | |||
492 | dev_dbg(blizzard.fbdev->dev, "sw %d sh %d\n", | ||
493 | blizzard.screen_width, blizzard.screen_height); | ||
494 | blizzard_wait_line_buffer(); | ||
495 | flags = req->par.update.flags; | ||
496 | if (flags & OMAPFB_FORMAT_FLAG_TEARSYNC) | ||
497 | enable_tearsync(0, blizzard.screen_width, | ||
498 | blizzard.screen_height, | ||
499 | blizzard.screen_height, | ||
500 | blizzard.screen_height, | ||
501 | flags & OMAPFB_FORMAT_FLAG_FORCE_VSYNC); | ||
502 | else | ||
503 | disable_tearsync(); | ||
504 | |||
505 | set_window_regs(0, 0, blizzard.screen_width, blizzard.screen_height, | ||
506 | 0, 0, blizzard.screen_width, blizzard.screen_height, | ||
507 | BLIZZARD_COLOR_RGB565, blizzard.zoom_on, flags); | ||
508 | blizzard.zoom_on = 0; | ||
509 | |||
510 | blizzard.extif->set_bits_per_cycle(16); | ||
511 | /* set_window_regs has left the register index at the right | ||
512 | * place, so no need to set it here. | ||
513 | */ | ||
514 | blizzard.extif->transfer_area(blizzard.screen_width, | ||
515 | blizzard.screen_height, | ||
516 | request_complete, req); | ||
517 | return REQ_PENDING; | ||
518 | } | ||
519 | |||
520 | static int check_1d_intersect(int a1, int a2, int b1, int b2) | ||
521 | { | ||
522 | if (a2 <= b1 || b2 <= a1) | ||
523 | return 0; | ||
524 | return 1; | ||
525 | } | ||
526 | |||
527 | /* Setup all planes with an overlapping area with the update window. */ | ||
528 | static int do_partial_update(struct blizzard_request *req, int plane, | ||
529 | int x, int y, int w, int h, | ||
530 | int x_out, int y_out, int w_out, int h_out, | ||
531 | int wnd_color_mode, int bpp) | ||
532 | { | ||
533 | int i; | ||
534 | int gx1, gy1, gx2, gy2; | ||
535 | int gx1_out, gy1_out, gx2_out, gy2_out; | ||
536 | int color_mode; | ||
537 | int flags; | ||
538 | int zoom_off; | ||
539 | int have_zoom_for_this_update = 0; | ||
540 | |||
541 | /* Global coordinates, relative to pixel 0,0 of the LCD */ | ||
542 | gx1 = x + blizzard.plane[plane].pos_x; | ||
543 | gy1 = y + blizzard.plane[plane].pos_y; | ||
544 | gx2 = gx1 + w; | ||
545 | gy2 = gy1 + h; | ||
546 | |||
547 | flags = req->par.update.flags; | ||
548 | if (flags & OMAPFB_FORMAT_FLAG_DOUBLE) { | ||
549 | gx1_out = gx1; | ||
550 | gy1_out = gy1; | ||
551 | gx2_out = gx1 + w * 2; | ||
552 | gy2_out = gy1 + h * 2; | ||
553 | } else { | ||
554 | gx1_out = x_out + blizzard.plane[plane].pos_x; | ||
555 | gy1_out = y_out + blizzard.plane[plane].pos_y; | ||
556 | gx2_out = gx1_out + w_out; | ||
557 | gy2_out = gy1_out + h_out; | ||
558 | } | ||
559 | |||
560 | for (i = 0; i < OMAPFB_PLANE_NUM; i++) { | ||
561 | struct plane_info *p = &blizzard.plane[i]; | ||
562 | int px1, py1; | ||
563 | int px2, py2; | ||
564 | int pw, ph; | ||
565 | int pposx, pposy; | ||
566 | unsigned long offset; | ||
567 | |||
568 | if (!(blizzard.enabled_planes & (1 << i)) || | ||
569 | (wnd_color_mode && i != plane)) { | ||
570 | blizzard.int_ctrl->enable_plane(i, 0); | ||
571 | continue; | ||
572 | } | ||
573 | /* Plane coordinates */ | ||
574 | if (i == plane) { | ||
575 | /* Plane in which we are doing the update. | ||
576 | * Local coordinates are the one in the update | ||
577 | * request. | ||
578 | */ | ||
579 | px1 = x; | ||
580 | py1 = y; | ||
581 | px2 = x + w; | ||
582 | py2 = y + h; | ||
583 | pposx = 0; | ||
584 | pposy = 0; | ||
585 | } else { | ||
586 | /* Check if this plane has an overlapping part */ | ||
587 | px1 = gx1 - p->pos_x; | ||
588 | py1 = gy1 - p->pos_y; | ||
589 | px2 = gx2 - p->pos_x; | ||
590 | py2 = gy2 - p->pos_y; | ||
591 | if (px1 >= p->width || py1 >= p->height || | ||
592 | px2 <= 0 || py2 <= 0) { | ||
593 | blizzard.int_ctrl->enable_plane(i, 0); | ||
594 | continue; | ||
595 | } | ||
596 | /* Calculate the coordinates for the overlapping | ||
597 | * part in the plane's local coordinates. | ||
598 | */ | ||
599 | pposx = -px1; | ||
600 | pposy = -py1; | ||
601 | if (px1 < 0) | ||
602 | px1 = 0; | ||
603 | if (py1 < 0) | ||
604 | py1 = 0; | ||
605 | if (px2 > p->width) | ||
606 | px2 = p->width; | ||
607 | if (py2 > p->height) | ||
608 | py2 = p->height; | ||
609 | if (pposx < 0) | ||
610 | pposx = 0; | ||
611 | if (pposy < 0) | ||
612 | pposy = 0; | ||
613 | } | ||
614 | pw = px2 - px1; | ||
615 | ph = py2 - py1; | ||
616 | offset = p->offset + (p->scr_width * py1 + px1) * p->bpp / 8; | ||
617 | if (wnd_color_mode) | ||
618 | /* Window embedded in the plane with a differing | ||
619 | * color mode / bpp. Calculate the number of DMA | ||
620 | * transfer elements in terms of the plane's bpp. | ||
621 | */ | ||
622 | pw = (pw + 1) * bpp / p->bpp; | ||
623 | #ifdef VERBOSE | ||
624 | dev_dbg(blizzard.fbdev->dev, | ||
625 | "plane %d offset %#08lx pposx %d pposy %d " | ||
626 | "px1 %d py1 %d pw %d ph %d\n", | ||
627 | i, offset, pposx, pposy, px1, py1, pw, ph); | ||
628 | #endif | ||
629 | blizzard.int_ctrl->setup_plane(i, | ||
630 | OMAPFB_CHANNEL_OUT_LCD, offset, | ||
631 | p->scr_width, | ||
632 | pposx, pposy, pw, ph, | ||
633 | p->color_mode); | ||
634 | |||
635 | blizzard.int_ctrl->enable_plane(i, 1); | ||
636 | } | ||
637 | |||
638 | switch (wnd_color_mode) { | ||
639 | case OMAPFB_COLOR_YUV420: | ||
640 | color_mode = BLIZZARD_COLOR_YUV420; | ||
641 | /* Currently only the 16 bits/pixel cycle format is | ||
642 | * supported on the external interface. Adjust the number | ||
643 | * of transfer elements per line for 12bpp format. | ||
644 | */ | ||
645 | w = (w + 1) * 3 / 4; | ||
646 | break; | ||
647 | default: | ||
648 | color_mode = BLIZZARD_COLOR_RGB565; | ||
649 | break; | ||
650 | } | ||
651 | |||
652 | blizzard_wait_line_buffer(); | ||
653 | if (blizzard.last_color_mode == BLIZZARD_COLOR_YUV420) | ||
654 | blizzard_wait_yyc(); | ||
655 | blizzard.last_color_mode = color_mode; | ||
656 | if (flags & OMAPFB_FORMAT_FLAG_TEARSYNC) | ||
657 | enable_tearsync(gy1, w, h, | ||
658 | blizzard.screen_height, | ||
659 | h_out, | ||
660 | flags & OMAPFB_FORMAT_FLAG_FORCE_VSYNC); | ||
661 | else | ||
662 | disable_tearsync(); | ||
663 | |||
664 | if ((gx2_out - gx1_out) != (gx2 - gx1) || | ||
665 | (gy2_out - gy1_out) != (gy2 - gy1)) | ||
666 | have_zoom_for_this_update = 1; | ||
667 | |||
668 | /* 'background' type of screen update (as opposed to 'destructive') | ||
669 | can be used to disable scaling if scaling is active */ | ||
670 | zoom_off = blizzard.zoom_on && !have_zoom_for_this_update && | ||
671 | (gx1_out == 0) && (gx2_out == blizzard.screen_width) && | ||
672 | (gy1_out == 0) && (gy2_out == blizzard.screen_height) && | ||
673 | (gx1 == 0) && (gy1 == 0); | ||
674 | |||
675 | if (blizzard.zoom_on && !have_zoom_for_this_update && !zoom_off && | ||
676 | check_1d_intersect(blizzard.zoom_area_gx1, blizzard.zoom_area_gx2, | ||
677 | gx1_out, gx2_out) && | ||
678 | check_1d_intersect(blizzard.zoom_area_gy1, blizzard.zoom_area_gy2, | ||
679 | gy1_out, gy2_out)) { | ||
680 | /* Previous screen update was using scaling, current update | ||
681 | * is not using it. Additionally, current screen update is | ||
682 | * going to overlap with the scaled area. Scaling needs to be | ||
683 | * disabled in order to avoid 'magnifying glass' effect. | ||
684 | * Dummy setup of background window can be used for this. | ||
685 | */ | ||
686 | set_window_regs(0, 0, blizzard.screen_width, | ||
687 | blizzard.screen_height, | ||
688 | 0, 0, blizzard.screen_width, | ||
689 | blizzard.screen_height, | ||
690 | BLIZZARD_COLOR_RGB565, 1, flags); | ||
691 | blizzard.zoom_on = 0; | ||
692 | } | ||
693 | |||
694 | /* remember scaling settings if we have scaled update */ | ||
695 | if (have_zoom_for_this_update) { | ||
696 | blizzard.zoom_on = 1; | ||
697 | blizzard.zoom_area_gx1 = gx1_out; | ||
698 | blizzard.zoom_area_gx2 = gx2_out; | ||
699 | blizzard.zoom_area_gy1 = gy1_out; | ||
700 | blizzard.zoom_area_gy2 = gy2_out; | ||
701 | } | ||
702 | |||
703 | set_window_regs(gx1, gy1, gx2, gy2, gx1_out, gy1_out, gx2_out, gy2_out, | ||
704 | color_mode, zoom_off, flags); | ||
705 | if (zoom_off) | ||
706 | blizzard.zoom_on = 0; | ||
707 | |||
708 | blizzard.extif->set_bits_per_cycle(16); | ||
709 | /* set_window_regs has left the register index at the right | ||
710 | * place, so no need to set it here. | ||
711 | */ | ||
712 | blizzard.extif->transfer_area(w, h, request_complete, req); | ||
713 | |||
714 | return REQ_PENDING; | ||
715 | } | ||
716 | |||
717 | static int send_frame_handler(struct blizzard_request *req) | ||
718 | { | ||
719 | struct update_param *par = &req->par.update; | ||
720 | int plane = par->plane; | ||
721 | |||
722 | #ifdef VERBOSE | ||
723 | dev_dbg(blizzard.fbdev->dev, | ||
724 | "send_frame: x %d y %d w %d h %d " | ||
725 | "x_out %d y_out %d w_out %d h_out %d " | ||
726 | "color_mode %04x flags %04x planes %01x\n", | ||
727 | par->x, par->y, par->width, par->height, | ||
728 | par->out_x, par->out_y, par->out_width, par->out_height, | ||
729 | par->color_mode, par->flags, blizzard.enabled_planes); | ||
730 | #endif | ||
731 | if (par->flags & OMAPFB_FORMAT_FLAG_DISABLE_OVERLAY) | ||
732 | disable_overlay(); | ||
733 | |||
734 | if ((blizzard.enabled_planes & blizzard.vid_nonstd_color) || | ||
735 | (blizzard.enabled_planes & blizzard.vid_scaled)) | ||
736 | return do_full_screen_update(req); | ||
737 | |||
738 | return do_partial_update(req, plane, par->x, par->y, | ||
739 | par->width, par->height, | ||
740 | par->out_x, par->out_y, | ||
741 | par->out_width, par->out_height, | ||
742 | par->color_mode, par->bpp); | ||
743 | } | ||
744 | |||
745 | static void send_frame_complete(void *data) | ||
746 | { | ||
747 | } | ||
748 | |||
749 | #define ADD_PREQ(_x, _y, _w, _h, _x_out, _y_out, _w_out, _h_out) do { \ | ||
750 | req = alloc_req(); \ | ||
751 | req->handler = send_frame_handler; \ | ||
752 | req->complete = send_frame_complete; \ | ||
753 | req->par.update.plane = plane_idx; \ | ||
754 | req->par.update.x = _x; \ | ||
755 | req->par.update.y = _y; \ | ||
756 | req->par.update.width = _w; \ | ||
757 | req->par.update.height = _h; \ | ||
758 | req->par.update.out_x = _x_out; \ | ||
759 | req->par.update.out_y = _y_out; \ | ||
760 | req->par.update.out_width = _w_out; \ | ||
761 | req->par.update.out_height = _h_out; \ | ||
762 | req->par.update.bpp = bpp; \ | ||
763 | req->par.update.color_mode = color_mode;\ | ||
764 | req->par.update.flags = flags; \ | ||
765 | list_add_tail(&req->entry, req_head); \ | ||
766 | } while(0) | ||
767 | |||
768 | static void create_req_list(int plane_idx, | ||
769 | struct omapfb_update_window *win, | ||
770 | struct list_head *req_head) | ||
771 | { | ||
772 | struct blizzard_request *req; | ||
773 | int x = win->x; | ||
774 | int y = win->y; | ||
775 | int width = win->width; | ||
776 | int height = win->height; | ||
777 | int x_out = win->out_x; | ||
778 | int y_out = win->out_y; | ||
779 | int width_out = win->out_width; | ||
780 | int height_out = win->out_height; | ||
781 | int color_mode; | ||
782 | int bpp; | ||
783 | int flags; | ||
784 | unsigned int ystart = y; | ||
785 | unsigned int yspan = height; | ||
786 | unsigned int ystart_out = y_out; | ||
787 | unsigned int yspan_out = height_out; | ||
788 | |||
789 | flags = win->format & ~OMAPFB_FORMAT_MASK; | ||
790 | color_mode = win->format & OMAPFB_FORMAT_MASK; | ||
791 | switch (color_mode) { | ||
792 | case OMAPFB_COLOR_YUV420: | ||
793 | /* Embedded window with different color mode */ | ||
794 | bpp = 12; | ||
795 | /* X, Y, height must be aligned at 2, width at 4 pixels */ | ||
796 | x &= ~1; | ||
797 | y &= ~1; | ||
798 | height = yspan = height & ~1; | ||
799 | width = width & ~3; | ||
800 | break; | ||
801 | default: | ||
802 | /* Same as the plane color mode */ | ||
803 | bpp = blizzard.plane[plane_idx].bpp; | ||
804 | break; | ||
805 | } | ||
806 | if (width * height * bpp / 8 > blizzard.max_transmit_size) { | ||
807 | yspan = blizzard.max_transmit_size / (width * bpp / 8); | ||
808 | yspan_out = yspan * height_out / height; | ||
809 | ADD_PREQ(x, ystart, width, yspan, x_out, ystart_out, | ||
810 | width_out, yspan_out); | ||
811 | ystart += yspan; | ||
812 | ystart_out += yspan_out; | ||
813 | yspan = height - yspan; | ||
814 | yspan_out = height_out - yspan_out; | ||
815 | flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC; | ||
816 | } | ||
817 | |||
818 | ADD_PREQ(x, ystart, width, yspan, x_out, ystart_out, | ||
819 | width_out, yspan_out); | ||
820 | } | ||
821 | |||
822 | static void auto_update_complete(void *data) | ||
823 | { | ||
824 | if (!blizzard.stop_auto_update) | ||
825 | mod_timer(&blizzard.auto_update_timer, | ||
826 | jiffies + BLIZZARD_AUTO_UPDATE_TIME); | ||
827 | } | ||
828 | |||
829 | static void blizzard_update_window_auto(unsigned long arg) | ||
830 | { | ||
831 | LIST_HEAD(req_list); | ||
832 | struct blizzard_request *last; | ||
833 | struct omapfb_plane_struct *plane; | ||
834 | |||
835 | plane = blizzard.fbdev->fb_info[0]->par; | ||
836 | create_req_list(plane->idx, | ||
837 | &blizzard.auto_update_window, &req_list); | ||
838 | last = list_entry(req_list.prev, struct blizzard_request, entry); | ||
839 | |||
840 | last->complete = auto_update_complete; | ||
841 | last->complete_data = NULL; | ||
842 | |||
843 | submit_req_list(&req_list); | ||
844 | } | ||
845 | |||
846 | int blizzard_update_window_async(struct fb_info *fbi, | ||
847 | struct omapfb_update_window *win, | ||
848 | void (*complete_callback)(void *arg), | ||
849 | void *complete_callback_data) | ||
850 | { | ||
851 | LIST_HEAD(req_list); | ||
852 | struct blizzard_request *last; | ||
853 | struct omapfb_plane_struct *plane = fbi->par; | ||
854 | |||
855 | if (unlikely(blizzard.update_mode != OMAPFB_MANUAL_UPDATE)) | ||
856 | return -EINVAL; | ||
857 | if (unlikely(!blizzard.te_connected && | ||
858 | (win->format & OMAPFB_FORMAT_FLAG_TEARSYNC))) | ||
859 | return -EINVAL; | ||
860 | |||
861 | create_req_list(plane->idx, win, &req_list); | ||
862 | last = list_entry(req_list.prev, struct blizzard_request, entry); | ||
863 | |||
864 | last->complete = complete_callback; | ||
865 | last->complete_data = (void *)complete_callback_data; | ||
866 | |||
867 | submit_req_list(&req_list); | ||
868 | |||
869 | return 0; | ||
870 | } | ||
871 | EXPORT_SYMBOL(blizzard_update_window_async); | ||
872 | |||
873 | static int update_full_screen(void) | ||
874 | { | ||
875 | return blizzard_update_window_async(blizzard.fbdev->fb_info[0], | ||
876 | &blizzard.auto_update_window, NULL, NULL); | ||
877 | |||
878 | } | ||
879 | |||
880 | static int blizzard_setup_plane(int plane, int channel_out, | ||
881 | unsigned long offset, int screen_width, | ||
882 | int pos_x, int pos_y, int width, int height, | ||
883 | int color_mode) | ||
884 | { | ||
885 | struct plane_info *p; | ||
886 | |||
887 | #ifdef VERBOSE | ||
888 | dev_dbg(blizzard.fbdev->dev, | ||
889 | "plane %d ch_out %d offset %#08lx scr_width %d " | ||
890 | "pos_x %d pos_y %d width %d height %d color_mode %d\n", | ||
891 | plane, channel_out, offset, screen_width, | ||
892 | pos_x, pos_y, width, height, color_mode); | ||
893 | #endif | ||
894 | if ((unsigned)plane > OMAPFB_PLANE_NUM) | ||
895 | return -EINVAL; | ||
896 | p = &blizzard.plane[plane]; | ||
897 | |||
898 | switch (color_mode) { | ||
899 | case OMAPFB_COLOR_YUV422: | ||
900 | case OMAPFB_COLOR_YUY422: | ||
901 | p->bpp = 16; | ||
902 | blizzard.vid_nonstd_color &= ~(1 << plane); | ||
903 | break; | ||
904 | case OMAPFB_COLOR_YUV420: | ||
905 | p->bpp = 12; | ||
906 | blizzard.vid_nonstd_color |= 1 << plane; | ||
907 | break; | ||
908 | case OMAPFB_COLOR_RGB565: | ||
909 | p->bpp = 16; | ||
910 | blizzard.vid_nonstd_color &= ~(1 << plane); | ||
911 | break; | ||
912 | default: | ||
913 | return -EINVAL; | ||
914 | } | ||
915 | |||
916 | p->offset = offset; | ||
917 | p->pos_x = pos_x; | ||
918 | p->pos_y = pos_y; | ||
919 | p->width = width; | ||
920 | p->height = height; | ||
921 | p->scr_width = screen_width; | ||
922 | if (!p->out_width) | ||
923 | p->out_width = width; | ||
924 | if (!p->out_height) | ||
925 | p->out_height = height; | ||
926 | |||
927 | p->color_mode = color_mode; | ||
928 | |||
929 | return 0; | ||
930 | } | ||
931 | |||
932 | static int blizzard_set_scale(int plane, int orig_w, int orig_h, | ||
933 | int out_w, int out_h) | ||
934 | { | ||
935 | struct plane_info *p = &blizzard.plane[plane]; | ||
936 | int r; | ||
937 | |||
938 | dev_dbg(blizzard.fbdev->dev, | ||
939 | "plane %d orig_w %d orig_h %d out_w %d out_h %d\n", | ||
940 | plane, orig_w, orig_h, out_w, out_h); | ||
941 | if ((unsigned)plane > OMAPFB_PLANE_NUM) | ||
942 | return -ENODEV; | ||
943 | |||
944 | r = blizzard.int_ctrl->set_scale(plane, orig_w, orig_h, out_w, out_h); | ||
945 | if (r < 0) | ||
946 | return r; | ||
947 | |||
948 | p->width = orig_w; | ||
949 | p->height = orig_h; | ||
950 | p->out_width = out_w; | ||
951 | p->out_height = out_h; | ||
952 | if (orig_w == out_w && orig_h == out_h) | ||
953 | blizzard.vid_scaled &= ~(1 << plane); | ||
954 | else | ||
955 | blizzard.vid_scaled |= 1 << plane; | ||
956 | |||
957 | return 0; | ||
958 | } | ||
959 | |||
960 | static int blizzard_set_rotate(int angle) | ||
961 | { | ||
962 | u32 l; | ||
963 | |||
964 | l = blizzard_read_reg(BLIZZARD_PANEL_CONFIGURATION); | ||
965 | l &= ~0x03; | ||
966 | |||
967 | switch (angle) { | ||
968 | case 0: | ||
969 | l = l | 0x00; | ||
970 | break; | ||
971 | case 90: | ||
972 | l = l | 0x03; | ||
973 | break; | ||
974 | case 180: | ||
975 | l = l | 0x02; | ||
976 | break; | ||
977 | case 270: | ||
978 | l = l | 0x01; | ||
979 | break; | ||
980 | default: | ||
981 | return -EINVAL; | ||
982 | } | ||
983 | |||
984 | blizzard_write_reg(BLIZZARD_PANEL_CONFIGURATION, l); | ||
985 | |||
986 | return 0; | ||
987 | } | ||
988 | |||
989 | static int blizzard_enable_plane(int plane, int enable) | ||
990 | { | ||
991 | if (enable) | ||
992 | blizzard.enabled_planes |= 1 << plane; | ||
993 | else | ||
994 | blizzard.enabled_planes &= ~(1 << plane); | ||
995 | |||
996 | return 0; | ||
997 | } | ||
998 | |||
999 | static int sync_handler(struct blizzard_request *req) | ||
1000 | { | ||
1001 | complete(req->par.sync); | ||
1002 | return REQ_COMPLETE; | ||
1003 | } | ||
1004 | |||
1005 | static void blizzard_sync(void) | ||
1006 | { | ||
1007 | LIST_HEAD(req_list); | ||
1008 | struct blizzard_request *req; | ||
1009 | struct completion comp; | ||
1010 | |||
1011 | req = alloc_req(); | ||
1012 | |||
1013 | req->handler = sync_handler; | ||
1014 | req->complete = NULL; | ||
1015 | init_completion(&comp); | ||
1016 | req->par.sync = ∁ | ||
1017 | |||
1018 | list_add(&req->entry, &req_list); | ||
1019 | submit_req_list(&req_list); | ||
1020 | |||
1021 | wait_for_completion(&comp); | ||
1022 | } | ||
1023 | |||
1024 | |||
1025 | static void blizzard_bind_client(struct omapfb_notifier_block *nb) | ||
1026 | { | ||
1027 | if (blizzard.update_mode == OMAPFB_MANUAL_UPDATE) { | ||
1028 | omapfb_notify_clients(blizzard.fbdev, OMAPFB_EVENT_READY); | ||
1029 | } | ||
1030 | } | ||
1031 | |||
1032 | static int blizzard_set_update_mode(enum omapfb_update_mode mode) | ||
1033 | { | ||
1034 | if (unlikely(mode != OMAPFB_MANUAL_UPDATE && | ||
1035 | mode != OMAPFB_AUTO_UPDATE && | ||
1036 | mode != OMAPFB_UPDATE_DISABLED)) | ||
1037 | return -EINVAL; | ||
1038 | |||
1039 | if (mode == blizzard.update_mode) | ||
1040 | return 0; | ||
1041 | |||
1042 | dev_info(blizzard.fbdev->dev, "s1d1374x: setting update mode to %s\n", | ||
1043 | mode == OMAPFB_UPDATE_DISABLED ? "disabled" : | ||
1044 | (mode == OMAPFB_AUTO_UPDATE ? "auto" : "manual")); | ||
1045 | |||
1046 | switch (blizzard.update_mode) { | ||
1047 | case OMAPFB_MANUAL_UPDATE: | ||
1048 | omapfb_notify_clients(blizzard.fbdev, OMAPFB_EVENT_DISABLED); | ||
1049 | break; | ||
1050 | case OMAPFB_AUTO_UPDATE: | ||
1051 | blizzard.stop_auto_update = 1; | ||
1052 | del_timer_sync(&blizzard.auto_update_timer); | ||
1053 | break; | ||
1054 | case OMAPFB_UPDATE_DISABLED: | ||
1055 | break; | ||
1056 | } | ||
1057 | |||
1058 | blizzard.update_mode = mode; | ||
1059 | blizzard_sync(); | ||
1060 | blizzard.stop_auto_update = 0; | ||
1061 | |||
1062 | switch (mode) { | ||
1063 | case OMAPFB_MANUAL_UPDATE: | ||
1064 | omapfb_notify_clients(blizzard.fbdev, OMAPFB_EVENT_READY); | ||
1065 | break; | ||
1066 | case OMAPFB_AUTO_UPDATE: | ||
1067 | blizzard_update_window_auto(0); | ||
1068 | break; | ||
1069 | case OMAPFB_UPDATE_DISABLED: | ||
1070 | break; | ||
1071 | } | ||
1072 | |||
1073 | return 0; | ||
1074 | } | ||
1075 | |||
1076 | static enum omapfb_update_mode blizzard_get_update_mode(void) | ||
1077 | { | ||
1078 | return blizzard.update_mode; | ||
1079 | } | ||
1080 | |||
1081 | static inline void set_extif_timings(const struct extif_timings *t) | ||
1082 | { | ||
1083 | blizzard.extif->set_timings(t); | ||
1084 | } | ||
1085 | |||
1086 | static inline unsigned long round_to_extif_ticks(unsigned long ps, int div) | ||
1087 | { | ||
1088 | int bus_tick = blizzard.extif_clk_period * div; | ||
1089 | return (ps + bus_tick - 1) / bus_tick * bus_tick; | ||
1090 | } | ||
1091 | |||
1092 | static int calc_reg_timing(unsigned long sysclk, int div) | ||
1093 | { | ||
1094 | struct extif_timings *t; | ||
1095 | unsigned long systim; | ||
1096 | |||
1097 | /* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns, | ||
1098 | * AccessTime 2 ns + 12.2 ns (regs), | ||
1099 | * WEOffTime = WEOnTime + 1 ns, | ||
1100 | * REOffTime = REOnTime + 12 ns (regs), | ||
1101 | * CSOffTime = REOffTime + 1 ns | ||
1102 | * ReadCycle = 2ns + 2*SYSCLK (regs), | ||
1103 | * WriteCycle = 2*SYSCLK + 2 ns, | ||
1104 | * CSPulseWidth = 10 ns */ | ||
1105 | |||
1106 | systim = 1000000000 / (sysclk / 1000); | ||
1107 | dev_dbg(blizzard.fbdev->dev, | ||
1108 | "Blizzard systim %lu ps extif_clk_period %u div %d\n", | ||
1109 | systim, blizzard.extif_clk_period, div); | ||
1110 | |||
1111 | t = &blizzard.reg_timings; | ||
1112 | memset(t, 0, sizeof(*t)); | ||
1113 | |||
1114 | t->clk_div = div; | ||
1115 | |||
1116 | t->cs_on_time = 0; | ||
1117 | t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
1118 | t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
1119 | t->access_time = round_to_extif_ticks(t->re_on_time + 12200, div); | ||
1120 | t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div); | ||
1121 | t->re_off_time = round_to_extif_ticks(t->re_on_time + 13000, div); | ||
1122 | t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div); | ||
1123 | t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div); | ||
1124 | if (t->we_cycle_time < t->we_off_time) | ||
1125 | t->we_cycle_time = t->we_off_time; | ||
1126 | t->re_cycle_time = round_to_extif_ticks(2 * systim + 2000, div); | ||
1127 | if (t->re_cycle_time < t->re_off_time) | ||
1128 | t->re_cycle_time = t->re_off_time; | ||
1129 | t->cs_pulse_width = 0; | ||
1130 | |||
1131 | dev_dbg(blizzard.fbdev->dev, "[reg]cson %d csoff %d reon %d reoff %d\n", | ||
1132 | t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time); | ||
1133 | dev_dbg(blizzard.fbdev->dev, "[reg]weon %d weoff %d recyc %d wecyc %d\n", | ||
1134 | t->we_on_time, t->we_off_time, t->re_cycle_time, | ||
1135 | t->we_cycle_time); | ||
1136 | dev_dbg(blizzard.fbdev->dev, "[reg]rdaccess %d cspulse %d\n", | ||
1137 | t->access_time, t->cs_pulse_width); | ||
1138 | |||
1139 | return blizzard.extif->convert_timings(t); | ||
1140 | } | ||
1141 | |||
1142 | static int calc_lut_timing(unsigned long sysclk, int div) | ||
1143 | { | ||
1144 | struct extif_timings *t; | ||
1145 | unsigned long systim; | ||
1146 | |||
1147 | /* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns, | ||
1148 | * AccessTime 2 ns + 4 * SYSCLK + 26 (lut), | ||
1149 | * WEOffTime = WEOnTime + 1 ns, | ||
1150 | * REOffTime = REOnTime + 4*SYSCLK + 26 ns (lut), | ||
1151 | * CSOffTime = REOffTime + 1 ns | ||
1152 | * ReadCycle = 2ns + 4*SYSCLK + 26 ns (lut), | ||
1153 | * WriteCycle = 2*SYSCLK + 2 ns, | ||
1154 | * CSPulseWidth = 10 ns */ | ||
1155 | |||
1156 | systim = 1000000000 / (sysclk / 1000); | ||
1157 | dev_dbg(blizzard.fbdev->dev, | ||
1158 | "Blizzard systim %lu ps extif_clk_period %u div %d\n", | ||
1159 | systim, blizzard.extif_clk_period, div); | ||
1160 | |||
1161 | t = &blizzard.lut_timings; | ||
1162 | memset(t, 0, sizeof(*t)); | ||
1163 | |||
1164 | t->clk_div = div; | ||
1165 | |||
1166 | t->cs_on_time = 0; | ||
1167 | t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
1168 | t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
1169 | t->access_time = round_to_extif_ticks(t->re_on_time + 4 * systim + | ||
1170 | 26000, div); | ||
1171 | t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div); | ||
1172 | t->re_off_time = round_to_extif_ticks(t->re_on_time + 4 * systim + | ||
1173 | 26000, div); | ||
1174 | t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div); | ||
1175 | t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div); | ||
1176 | if (t->we_cycle_time < t->we_off_time) | ||
1177 | t->we_cycle_time = t->we_off_time; | ||
1178 | t->re_cycle_time = round_to_extif_ticks(2000 + 4 * systim + 26000, div); | ||
1179 | if (t->re_cycle_time < t->re_off_time) | ||
1180 | t->re_cycle_time = t->re_off_time; | ||
1181 | t->cs_pulse_width = 0; | ||
1182 | |||
1183 | dev_dbg(blizzard.fbdev->dev, | ||
1184 | "[lut]cson %d csoff %d reon %d reoff %d\n", | ||
1185 | t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time); | ||
1186 | dev_dbg(blizzard.fbdev->dev, | ||
1187 | "[lut]weon %d weoff %d recyc %d wecyc %d\n", | ||
1188 | t->we_on_time, t->we_off_time, t->re_cycle_time, | ||
1189 | t->we_cycle_time); | ||
1190 | dev_dbg(blizzard.fbdev->dev, "[lut]rdaccess %d cspulse %d\n", | ||
1191 | t->access_time, t->cs_pulse_width); | ||
1192 | |||
1193 | return blizzard.extif->convert_timings(t); | ||
1194 | } | ||
1195 | |||
1196 | static int calc_extif_timings(unsigned long sysclk, int *extif_mem_div) | ||
1197 | { | ||
1198 | int max_clk_div; | ||
1199 | int div; | ||
1200 | |||
1201 | blizzard.extif->get_clk_info(&blizzard.extif_clk_period, &max_clk_div); | ||
1202 | for (div = 1; div <= max_clk_div; div++) { | ||
1203 | if (calc_reg_timing(sysclk, div) == 0) | ||
1204 | break; | ||
1205 | } | ||
1206 | if (div > max_clk_div) { | ||
1207 | dev_dbg(blizzard.fbdev->dev, "reg timing failed\n"); | ||
1208 | goto err; | ||
1209 | } | ||
1210 | *extif_mem_div = div; | ||
1211 | |||
1212 | for (div = 1; div <= max_clk_div; div++) { | ||
1213 | if (calc_lut_timing(sysclk, div) == 0) | ||
1214 | break; | ||
1215 | } | ||
1216 | |||
1217 | if (div > max_clk_div) | ||
1218 | goto err; | ||
1219 | |||
1220 | blizzard.extif_clk_div = div; | ||
1221 | |||
1222 | return 0; | ||
1223 | err: | ||
1224 | dev_err(blizzard.fbdev->dev, "can't setup timings\n"); | ||
1225 | return -1; | ||
1226 | } | ||
1227 | |||
1228 | static void calc_blizzard_clk_rates(unsigned long ext_clk, | ||
1229 | unsigned long *sys_clk, unsigned long *pix_clk) | ||
1230 | { | ||
1231 | int pix_clk_src; | ||
1232 | int sys_div = 0, sys_mul = 0; | ||
1233 | int pix_div; | ||
1234 | |||
1235 | pix_clk_src = blizzard_read_reg(BLIZZARD_CLK_SRC); | ||
1236 | pix_div = ((pix_clk_src >> 3) & 0x1f) + 1; | ||
1237 | if ((pix_clk_src & (0x3 << 1)) == 0) { | ||
1238 | /* Source is the PLL */ | ||
1239 | sys_div = (blizzard_read_reg(BLIZZARD_PLL_DIV) & 0x3f) + 1; | ||
1240 | sys_mul = blizzard_read_reg(BLIZZARD_PLL_CLOCK_SYNTH_0); | ||
1241 | sys_mul |= ((blizzard_read_reg(BLIZZARD_PLL_CLOCK_SYNTH_1) | ||
1242 | & 0x0f) << 11); | ||
1243 | *sys_clk = ext_clk * sys_mul / sys_div; | ||
1244 | } else /* else source is ext clk, or oscillator */ | ||
1245 | *sys_clk = ext_clk; | ||
1246 | |||
1247 | *pix_clk = *sys_clk / pix_div; /* HZ */ | ||
1248 | dev_dbg(blizzard.fbdev->dev, | ||
1249 | "ext_clk %ld pix_src %d pix_div %d sys_div %d sys_mul %d\n", | ||
1250 | ext_clk, pix_clk_src & (0x3 << 1), pix_div, sys_div, sys_mul); | ||
1251 | dev_dbg(blizzard.fbdev->dev, "sys_clk %ld pix_clk %ld\n", | ||
1252 | *sys_clk, *pix_clk); | ||
1253 | } | ||
1254 | |||
1255 | static int setup_tearsync(unsigned long pix_clk, int extif_div) | ||
1256 | { | ||
1257 | int hdisp, vdisp; | ||
1258 | int hndp, vndp; | ||
1259 | int hsw, vsw; | ||
1260 | int hs, vs; | ||
1261 | int hs_pol_inv, vs_pol_inv; | ||
1262 | int use_hsvs, use_ndp; | ||
1263 | u8 b; | ||
1264 | |||
1265 | hsw = blizzard_read_reg(BLIZZARD_HSW); | ||
1266 | vsw = blizzard_read_reg(BLIZZARD_VSW); | ||
1267 | hs_pol_inv = !(hsw & 0x80); | ||
1268 | vs_pol_inv = !(vsw & 0x80); | ||
1269 | hsw = hsw & 0x7f; | ||
1270 | vsw = vsw & 0x3f; | ||
1271 | |||
1272 | hdisp = blizzard_read_reg(BLIZZARD_HDISP) * 8; | ||
1273 | vdisp = blizzard_read_reg(BLIZZARD_VDISP0) + | ||
1274 | ((blizzard_read_reg(BLIZZARD_VDISP1) & 0x3) << 8); | ||
1275 | |||
1276 | hndp = blizzard_read_reg(BLIZZARD_HNDP) & 0x3f; | ||
1277 | vndp = blizzard_read_reg(BLIZZARD_VNDP); | ||
1278 | |||
1279 | /* time to transfer one pixel (16bpp) in ps */ | ||
1280 | blizzard.pix_tx_time = blizzard.reg_timings.we_cycle_time; | ||
1281 | if (blizzard.extif->get_max_tx_rate != NULL) { | ||
1282 | /* The external interface might have a rate limitation, | ||
1283 | * if so, we have to maximize our transfer rate. | ||
1284 | */ | ||
1285 | unsigned long min_tx_time; | ||
1286 | unsigned long max_tx_rate = blizzard.extif->get_max_tx_rate(); | ||
1287 | |||
1288 | dev_dbg(blizzard.fbdev->dev, "max_tx_rate %ld HZ\n", | ||
1289 | max_tx_rate); | ||
1290 | min_tx_time = 1000000000 / (max_tx_rate / 1000); /* ps */ | ||
1291 | if (blizzard.pix_tx_time < min_tx_time) | ||
1292 | blizzard.pix_tx_time = min_tx_time; | ||
1293 | } | ||
1294 | |||
1295 | /* time to update one line in ps */ | ||
1296 | blizzard.line_upd_time = (hdisp + hndp) * 1000000 / (pix_clk / 1000); | ||
1297 | blizzard.line_upd_time *= 1000; | ||
1298 | if (hdisp * blizzard.pix_tx_time > blizzard.line_upd_time) | ||
1299 | /* transfer speed too low, we might have to use both | ||
1300 | * HS and VS */ | ||
1301 | use_hsvs = 1; | ||
1302 | else | ||
1303 | /* decent transfer speed, we'll always use only VS */ | ||
1304 | use_hsvs = 0; | ||
1305 | |||
1306 | if (use_hsvs && (hs_pol_inv || vs_pol_inv)) { | ||
1307 | /* HS or'ed with VS doesn't work, use the active high | ||
1308 | * TE signal based on HNDP / VNDP */ | ||
1309 | use_ndp = 1; | ||
1310 | hs_pol_inv = 0; | ||
1311 | vs_pol_inv = 0; | ||
1312 | hs = hndp; | ||
1313 | vs = vndp; | ||
1314 | } else { | ||
1315 | /* Use HS or'ed with VS as a TE signal if both are needed | ||
1316 | * or VNDP if only vsync is needed. */ | ||
1317 | use_ndp = 0; | ||
1318 | hs = hsw; | ||
1319 | vs = vsw; | ||
1320 | if (!use_hsvs) { | ||
1321 | hs_pol_inv = 0; | ||
1322 | vs_pol_inv = 0; | ||
1323 | } | ||
1324 | } | ||
1325 | |||
1326 | hs = hs * 1000000 / (pix_clk / 1000); /* ps */ | ||
1327 | hs *= 1000; | ||
1328 | |||
1329 | vs = vs * (hdisp + hndp) * 1000000 / (pix_clk / 1000); /* ps */ | ||
1330 | vs *= 1000; | ||
1331 | |||
1332 | if (vs <= hs) | ||
1333 | return -EDOM; | ||
1334 | /* set VS to 120% of HS to minimize VS detection time */ | ||
1335 | vs = hs * 12 / 10; | ||
1336 | /* minimize HS too */ | ||
1337 | if (hs > 10000) | ||
1338 | hs = 10000; | ||
1339 | |||
1340 | b = blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS); | ||
1341 | b &= ~0x3; | ||
1342 | b |= use_hsvs ? 1 : 0; | ||
1343 | b |= (use_ndp && use_hsvs) ? 0 : 2; | ||
1344 | blizzard_write_reg(BLIZZARD_NDISP_CTRL_STATUS, b); | ||
1345 | |||
1346 | blizzard.vsync_only = !use_hsvs; | ||
1347 | |||
1348 | dev_dbg(blizzard.fbdev->dev, | ||
1349 | "pix_clk %ld HZ pix_tx_time %ld ps line_upd_time %ld ps\n", | ||
1350 | pix_clk, blizzard.pix_tx_time, blizzard.line_upd_time); | ||
1351 | dev_dbg(blizzard.fbdev->dev, | ||
1352 | "hs %d ps vs %d ps mode %d vsync_only %d\n", | ||
1353 | hs, vs, b & 0x3, !use_hsvs); | ||
1354 | |||
1355 | return blizzard.extif->setup_tearsync(1, hs, vs, | ||
1356 | hs_pol_inv, vs_pol_inv, | ||
1357 | extif_div); | ||
1358 | } | ||
1359 | |||
1360 | static void blizzard_get_caps(int plane, struct omapfb_caps *caps) | ||
1361 | { | ||
1362 | blizzard.int_ctrl->get_caps(plane, caps); | ||
1363 | caps->ctrl |= OMAPFB_CAPS_MANUAL_UPDATE | | ||
1364 | OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE | | ||
1365 | OMAPFB_CAPS_WINDOW_SCALE | | ||
1366 | OMAPFB_CAPS_WINDOW_OVERLAY | | ||
1367 | OMAPFB_CAPS_WINDOW_ROTATE; | ||
1368 | if (blizzard.te_connected) | ||
1369 | caps->ctrl |= OMAPFB_CAPS_TEARSYNC; | ||
1370 | caps->wnd_color |= (1 << OMAPFB_COLOR_RGB565) | | ||
1371 | (1 << OMAPFB_COLOR_YUV420); | ||
1372 | } | ||
1373 | |||
1374 | static void _save_regs(const struct blizzard_reg_list *list, int cnt) | ||
1375 | { | ||
1376 | int i; | ||
1377 | |||
1378 | for (i = 0; i < cnt; i++, list++) { | ||
1379 | int reg; | ||
1380 | for (reg = list->start; reg <= list->end; reg += 2) | ||
1381 | blizzard_reg_cache[reg / 2] = blizzard_read_reg(reg); | ||
1382 | } | ||
1383 | } | ||
1384 | |||
1385 | static void _restore_regs(const struct blizzard_reg_list *list, int cnt) | ||
1386 | { | ||
1387 | int i; | ||
1388 | |||
1389 | for (i = 0; i < cnt; i++, list++) { | ||
1390 | int reg; | ||
1391 | for (reg = list->start; reg <= list->end; reg += 2) | ||
1392 | blizzard_write_reg(reg, blizzard_reg_cache[reg / 2]); | ||
1393 | } | ||
1394 | } | ||
1395 | |||
1396 | static void blizzard_save_all_regs(void) | ||
1397 | { | ||
1398 | _save_regs(blizzard_pll_regs, ARRAY_SIZE(blizzard_pll_regs)); | ||
1399 | _save_regs(blizzard_gen_regs, ARRAY_SIZE(blizzard_gen_regs)); | ||
1400 | } | ||
1401 | |||
1402 | static void blizzard_restore_pll_regs(void) | ||
1403 | { | ||
1404 | _restore_regs(blizzard_pll_regs, ARRAY_SIZE(blizzard_pll_regs)); | ||
1405 | } | ||
1406 | |||
1407 | static void blizzard_restore_gen_regs(void) | ||
1408 | { | ||
1409 | _restore_regs(blizzard_gen_regs, ARRAY_SIZE(blizzard_gen_regs)); | ||
1410 | } | ||
1411 | |||
1412 | static void blizzard_suspend(void) | ||
1413 | { | ||
1414 | u32 l; | ||
1415 | unsigned long tmo; | ||
1416 | |||
1417 | if (blizzard.last_color_mode) { | ||
1418 | update_full_screen(); | ||
1419 | blizzard_sync(); | ||
1420 | } | ||
1421 | blizzard.update_mode_before_suspend = blizzard.update_mode; | ||
1422 | /* the following will disable clocks as well */ | ||
1423 | blizzard_set_update_mode(OMAPFB_UPDATE_DISABLED); | ||
1424 | |||
1425 | blizzard_save_all_regs(); | ||
1426 | |||
1427 | blizzard_stop_sdram(); | ||
1428 | |||
1429 | l = blizzard_read_reg(BLIZZARD_POWER_SAVE); | ||
1430 | /* Standby, Sleep. We assume we use an external clock. */ | ||
1431 | l |= 0x03; | ||
1432 | blizzard_write_reg(BLIZZARD_POWER_SAVE, l); | ||
1433 | |||
1434 | tmo = jiffies + msecs_to_jiffies(100); | ||
1435 | while (!(blizzard_read_reg(BLIZZARD_PLL_MODE) & (1 << 1))) { | ||
1436 | if (time_after(jiffies, tmo)) { | ||
1437 | dev_err(blizzard.fbdev->dev, | ||
1438 | "s1d1374x: sleep timeout, stopping PLL manually\n"); | ||
1439 | l = blizzard_read_reg(BLIZZARD_PLL_MODE); | ||
1440 | l &= ~0x03; | ||
1441 | /* Disable PLL, counter function */ | ||
1442 | l |= 0x2; | ||
1443 | blizzard_write_reg(BLIZZARD_PLL_MODE, l); | ||
1444 | break; | ||
1445 | } | ||
1446 | msleep(1); | ||
1447 | } | ||
1448 | |||
1449 | if (blizzard.power_down != NULL) | ||
1450 | blizzard.power_down(blizzard.fbdev->dev); | ||
1451 | } | ||
1452 | |||
1453 | static void blizzard_resume(void) | ||
1454 | { | ||
1455 | u32 l; | ||
1456 | |||
1457 | if (blizzard.power_up != NULL) | ||
1458 | blizzard.power_up(blizzard.fbdev->dev); | ||
1459 | |||
1460 | l = blizzard_read_reg(BLIZZARD_POWER_SAVE); | ||
1461 | /* Standby, Sleep */ | ||
1462 | l &= ~0x03; | ||
1463 | blizzard_write_reg(BLIZZARD_POWER_SAVE, l); | ||
1464 | |||
1465 | blizzard_restore_pll_regs(); | ||
1466 | l = blizzard_read_reg(BLIZZARD_PLL_MODE); | ||
1467 | l &= ~0x03; | ||
1468 | /* Enable PLL, counter function */ | ||
1469 | l |= 0x1; | ||
1470 | blizzard_write_reg(BLIZZARD_PLL_MODE, l); | ||
1471 | |||
1472 | while (!(blizzard_read_reg(BLIZZARD_PLL_DIV) & (1 << 7))) | ||
1473 | msleep(1); | ||
1474 | |||
1475 | blizzard_restart_sdram(); | ||
1476 | |||
1477 | blizzard_restore_gen_regs(); | ||
1478 | |||
1479 | /* Enable display */ | ||
1480 | blizzard_write_reg(BLIZZARD_DISPLAY_MODE, 0x01); | ||
1481 | |||
1482 | /* the following will enable clocks as necessary */ | ||
1483 | blizzard_set_update_mode(blizzard.update_mode_before_suspend); | ||
1484 | |||
1485 | /* Force a background update */ | ||
1486 | blizzard.zoom_on = 1; | ||
1487 | update_full_screen(); | ||
1488 | blizzard_sync(); | ||
1489 | } | ||
1490 | |||
1491 | static int blizzard_init(struct omapfb_device *fbdev, int ext_mode, | ||
1492 | struct omapfb_mem_desc *req_vram) | ||
1493 | { | ||
1494 | int r = 0, i; | ||
1495 | u8 rev, conf; | ||
1496 | unsigned long ext_clk; | ||
1497 | int extif_div; | ||
1498 | unsigned long sys_clk, pix_clk; | ||
1499 | struct omapfb_platform_data *omapfb_conf; | ||
1500 | struct blizzard_platform_data *ctrl_conf; | ||
1501 | |||
1502 | blizzard.fbdev = fbdev; | ||
1503 | |||
1504 | BUG_ON(!fbdev->ext_if || !fbdev->int_ctrl); | ||
1505 | |||
1506 | blizzard.fbdev = fbdev; | ||
1507 | blizzard.extif = fbdev->ext_if; | ||
1508 | blizzard.int_ctrl = fbdev->int_ctrl; | ||
1509 | |||
1510 | omapfb_conf = fbdev->dev->platform_data; | ||
1511 | ctrl_conf = omapfb_conf->ctrl_platform_data; | ||
1512 | if (ctrl_conf == NULL || ctrl_conf->get_clock_rate == NULL) { | ||
1513 | dev_err(fbdev->dev, "s1d1374x: missing platform data\n"); | ||
1514 | r = -ENOENT; | ||
1515 | goto err1; | ||
1516 | } | ||
1517 | |||
1518 | blizzard.power_down = ctrl_conf->power_down; | ||
1519 | blizzard.power_up = ctrl_conf->power_up; | ||
1520 | |||
1521 | spin_lock_init(&blizzard.req_lock); | ||
1522 | |||
1523 | if ((r = blizzard.int_ctrl->init(fbdev, 1, req_vram)) < 0) | ||
1524 | goto err1; | ||
1525 | |||
1526 | if ((r = blizzard.extif->init(fbdev)) < 0) | ||
1527 | goto err2; | ||
1528 | |||
1529 | blizzard_ctrl.set_color_key = blizzard.int_ctrl->set_color_key; | ||
1530 | blizzard_ctrl.get_color_key = blizzard.int_ctrl->get_color_key; | ||
1531 | blizzard_ctrl.setup_mem = blizzard.int_ctrl->setup_mem; | ||
1532 | blizzard_ctrl.mmap = blizzard.int_ctrl->mmap; | ||
1533 | |||
1534 | ext_clk = ctrl_conf->get_clock_rate(fbdev->dev); | ||
1535 | if ((r = calc_extif_timings(ext_clk, &extif_div)) < 0) | ||
1536 | goto err3; | ||
1537 | |||
1538 | set_extif_timings(&blizzard.reg_timings); | ||
1539 | |||
1540 | if (blizzard.power_up != NULL) | ||
1541 | blizzard.power_up(fbdev->dev); | ||
1542 | |||
1543 | calc_blizzard_clk_rates(ext_clk, &sys_clk, &pix_clk); | ||
1544 | |||
1545 | if ((r = calc_extif_timings(sys_clk, &extif_div)) < 0) | ||
1546 | goto err3; | ||
1547 | set_extif_timings(&blizzard.reg_timings); | ||
1548 | |||
1549 | if (!(blizzard_read_reg(BLIZZARD_PLL_DIV) & 0x80)) { | ||
1550 | dev_err(fbdev->dev, | ||
1551 | "controller not initialized by the bootloader\n"); | ||
1552 | r = -ENODEV; | ||
1553 | goto err3; | ||
1554 | } | ||
1555 | |||
1556 | if (ctrl_conf->te_connected) { | ||
1557 | if ((r = setup_tearsync(pix_clk, extif_div)) < 0) | ||
1558 | goto err3; | ||
1559 | blizzard.te_connected = 1; | ||
1560 | } | ||
1561 | |||
1562 | rev = blizzard_read_reg(BLIZZARD_REV_CODE); | ||
1563 | conf = blizzard_read_reg(BLIZZARD_CONFIG); | ||
1564 | |||
1565 | switch (rev & 0xfc) { | ||
1566 | case 0x9c: | ||
1567 | blizzard.version = BLIZZARD_VERSION_S1D13744; | ||
1568 | pr_info("omapfb: s1d13744 LCD controller rev %d " | ||
1569 | "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07); | ||
1570 | break; | ||
1571 | case 0xa4: | ||
1572 | blizzard.version = BLIZZARD_VERSION_S1D13745; | ||
1573 | pr_info("omapfb: s1d13745 LCD controller rev %d " | ||
1574 | "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07); | ||
1575 | break; | ||
1576 | default: | ||
1577 | dev_err(fbdev->dev, "invalid s1d1374x revision %02x\n", | ||
1578 | rev); | ||
1579 | r = -ENODEV; | ||
1580 | goto err3; | ||
1581 | } | ||
1582 | |||
1583 | blizzard.max_transmit_size = blizzard.extif->max_transmit_size; | ||
1584 | |||
1585 | blizzard.update_mode = OMAPFB_UPDATE_DISABLED; | ||
1586 | |||
1587 | blizzard.auto_update_window.x = 0; | ||
1588 | blizzard.auto_update_window.y = 0; | ||
1589 | blizzard.auto_update_window.width = fbdev->panel->x_res; | ||
1590 | blizzard.auto_update_window.height = fbdev->panel->y_res; | ||
1591 | blizzard.auto_update_window.out_x = 0; | ||
1592 | blizzard.auto_update_window.out_y = 0; | ||
1593 | blizzard.auto_update_window.out_width = fbdev->panel->x_res; | ||
1594 | blizzard.auto_update_window.out_height = fbdev->panel->y_res; | ||
1595 | blizzard.auto_update_window.format = 0; | ||
1596 | |||
1597 | blizzard.screen_width = fbdev->panel->x_res; | ||
1598 | blizzard.screen_height = fbdev->panel->y_res; | ||
1599 | |||
1600 | init_timer(&blizzard.auto_update_timer); | ||
1601 | blizzard.auto_update_timer.function = blizzard_update_window_auto; | ||
1602 | blizzard.auto_update_timer.data = 0; | ||
1603 | |||
1604 | INIT_LIST_HEAD(&blizzard.free_req_list); | ||
1605 | INIT_LIST_HEAD(&blizzard.pending_req_list); | ||
1606 | for (i = 0; i < ARRAY_SIZE(blizzard.req_pool); i++) | ||
1607 | list_add(&blizzard.req_pool[i].entry, &blizzard.free_req_list); | ||
1608 | BUG_ON(i <= IRQ_REQ_POOL_SIZE); | ||
1609 | sema_init(&blizzard.req_sema, i - IRQ_REQ_POOL_SIZE); | ||
1610 | |||
1611 | return 0; | ||
1612 | err3: | ||
1613 | if (blizzard.power_down != NULL) | ||
1614 | blizzard.power_down(fbdev->dev); | ||
1615 | blizzard.extif->cleanup(); | ||
1616 | err2: | ||
1617 | blizzard.int_ctrl->cleanup(); | ||
1618 | err1: | ||
1619 | return r; | ||
1620 | } | ||
1621 | |||
1622 | static void blizzard_cleanup(void) | ||
1623 | { | ||
1624 | blizzard_set_update_mode(OMAPFB_UPDATE_DISABLED); | ||
1625 | blizzard.extif->cleanup(); | ||
1626 | blizzard.int_ctrl->cleanup(); | ||
1627 | if (blizzard.power_down != NULL) | ||
1628 | blizzard.power_down(blizzard.fbdev->dev); | ||
1629 | } | ||
1630 | |||
1631 | struct lcd_ctrl blizzard_ctrl = { | ||
1632 | .name = "blizzard", | ||
1633 | .init = blizzard_init, | ||
1634 | .cleanup = blizzard_cleanup, | ||
1635 | .bind_client = blizzard_bind_client, | ||
1636 | .get_caps = blizzard_get_caps, | ||
1637 | .set_update_mode = blizzard_set_update_mode, | ||
1638 | .get_update_mode = blizzard_get_update_mode, | ||
1639 | .setup_plane = blizzard_setup_plane, | ||
1640 | .set_scale = blizzard_set_scale, | ||
1641 | .enable_plane = blizzard_enable_plane, | ||
1642 | .set_rotate = blizzard_set_rotate, | ||
1643 | .update_window = blizzard_update_window_async, | ||
1644 | .sync = blizzard_sync, | ||
1645 | .suspend = blizzard_suspend, | ||
1646 | .resume = blizzard_resume, | ||
1647 | }; | ||
1648 | |||
diff --git a/drivers/video/omap/dispc.c b/drivers/video/omap/dispc.c deleted file mode 100644 index 6f61e781f15a..000000000000 --- a/drivers/video/omap/dispc.c +++ /dev/null | |||
@@ -1,1547 +0,0 @@ | |||
1 | /* | ||
2 | * OMAP2 display controller support | ||
3 | * | ||
4 | * Copyright (C) 2005 Nokia Corporation | ||
5 | * Author: Imre Deak <imre.deak@nokia.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | */ | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/dma-mapping.h> | ||
24 | #include <linux/mm.h> | ||
25 | #include <linux/vmalloc.h> | ||
26 | #include <linux/clk.h> | ||
27 | #include <linux/io.h> | ||
28 | #include <linux/platform_device.h> | ||
29 | #include <linux/slab.h> | ||
30 | |||
31 | #include <plat/sram.h> | ||
32 | #include <plat/board.h> | ||
33 | |||
34 | #include "omapfb.h" | ||
35 | #include "dispc.h" | ||
36 | |||
37 | #define MODULE_NAME "dispc" | ||
38 | |||
39 | #define DSS_BASE 0x48050000 | ||
40 | #define DSS_SYSCONFIG 0x0010 | ||
41 | |||
42 | #define DISPC_BASE 0x48050400 | ||
43 | |||
44 | /* DISPC common */ | ||
45 | #define DISPC_REVISION 0x0000 | ||
46 | #define DISPC_SYSCONFIG 0x0010 | ||
47 | #define DISPC_SYSSTATUS 0x0014 | ||
48 | #define DISPC_IRQSTATUS 0x0018 | ||
49 | #define DISPC_IRQENABLE 0x001C | ||
50 | #define DISPC_CONTROL 0x0040 | ||
51 | #define DISPC_CONFIG 0x0044 | ||
52 | #define DISPC_CAPABLE 0x0048 | ||
53 | #define DISPC_DEFAULT_COLOR0 0x004C | ||
54 | #define DISPC_DEFAULT_COLOR1 0x0050 | ||
55 | #define DISPC_TRANS_COLOR0 0x0054 | ||
56 | #define DISPC_TRANS_COLOR1 0x0058 | ||
57 | #define DISPC_LINE_STATUS 0x005C | ||
58 | #define DISPC_LINE_NUMBER 0x0060 | ||
59 | #define DISPC_TIMING_H 0x0064 | ||
60 | #define DISPC_TIMING_V 0x0068 | ||
61 | #define DISPC_POL_FREQ 0x006C | ||
62 | #define DISPC_DIVISOR 0x0070 | ||
63 | #define DISPC_SIZE_DIG 0x0078 | ||
64 | #define DISPC_SIZE_LCD 0x007C | ||
65 | |||
66 | #define DISPC_DATA_CYCLE1 0x01D4 | ||
67 | #define DISPC_DATA_CYCLE2 0x01D8 | ||
68 | #define DISPC_DATA_CYCLE3 0x01DC | ||
69 | |||
70 | /* DISPC GFX plane */ | ||
71 | #define DISPC_GFX_BA0 0x0080 | ||
72 | #define DISPC_GFX_BA1 0x0084 | ||
73 | #define DISPC_GFX_POSITION 0x0088 | ||
74 | #define DISPC_GFX_SIZE 0x008C | ||
75 | #define DISPC_GFX_ATTRIBUTES 0x00A0 | ||
76 | #define DISPC_GFX_FIFO_THRESHOLD 0x00A4 | ||
77 | #define DISPC_GFX_FIFO_SIZE_STATUS 0x00A8 | ||
78 | #define DISPC_GFX_ROW_INC 0x00AC | ||
79 | #define DISPC_GFX_PIXEL_INC 0x00B0 | ||
80 | #define DISPC_GFX_WINDOW_SKIP 0x00B4 | ||
81 | #define DISPC_GFX_TABLE_BA 0x00B8 | ||
82 | |||
83 | /* DISPC Video plane 1/2 */ | ||
84 | #define DISPC_VID1_BASE 0x00BC | ||
85 | #define DISPC_VID2_BASE 0x014C | ||
86 | |||
87 | /* Offsets into DISPC_VID1/2_BASE */ | ||
88 | #define DISPC_VID_BA0 0x0000 | ||
89 | #define DISPC_VID_BA1 0x0004 | ||
90 | #define DISPC_VID_POSITION 0x0008 | ||
91 | #define DISPC_VID_SIZE 0x000C | ||
92 | #define DISPC_VID_ATTRIBUTES 0x0010 | ||
93 | #define DISPC_VID_FIFO_THRESHOLD 0x0014 | ||
94 | #define DISPC_VID_FIFO_SIZE_STATUS 0x0018 | ||
95 | #define DISPC_VID_ROW_INC 0x001C | ||
96 | #define DISPC_VID_PIXEL_INC 0x0020 | ||
97 | #define DISPC_VID_FIR 0x0024 | ||
98 | #define DISPC_VID_PICTURE_SIZE 0x0028 | ||
99 | #define DISPC_VID_ACCU0 0x002C | ||
100 | #define DISPC_VID_ACCU1 0x0030 | ||
101 | |||
102 | /* 8 elements in 8 byte increments */ | ||
103 | #define DISPC_VID_FIR_COEF_H0 0x0034 | ||
104 | /* 8 elements in 8 byte increments */ | ||
105 | #define DISPC_VID_FIR_COEF_HV0 0x0038 | ||
106 | /* 5 elements in 4 byte increments */ | ||
107 | #define DISPC_VID_CONV_COEF0 0x0074 | ||
108 | |||
109 | #define DISPC_IRQ_FRAMEMASK 0x0001 | ||
110 | #define DISPC_IRQ_VSYNC 0x0002 | ||
111 | #define DISPC_IRQ_EVSYNC_EVEN 0x0004 | ||
112 | #define DISPC_IRQ_EVSYNC_ODD 0x0008 | ||
113 | #define DISPC_IRQ_ACBIAS_COUNT_STAT 0x0010 | ||
114 | #define DISPC_IRQ_PROG_LINE_NUM 0x0020 | ||
115 | #define DISPC_IRQ_GFX_FIFO_UNDERFLOW 0x0040 | ||
116 | #define DISPC_IRQ_GFX_END_WIN 0x0080 | ||
117 | #define DISPC_IRQ_PAL_GAMMA_MASK 0x0100 | ||
118 | #define DISPC_IRQ_OCP_ERR 0x0200 | ||
119 | #define DISPC_IRQ_VID1_FIFO_UNDERFLOW 0x0400 | ||
120 | #define DISPC_IRQ_VID1_END_WIN 0x0800 | ||
121 | #define DISPC_IRQ_VID2_FIFO_UNDERFLOW 0x1000 | ||
122 | #define DISPC_IRQ_VID2_END_WIN 0x2000 | ||
123 | #define DISPC_IRQ_SYNC_LOST 0x4000 | ||
124 | |||
125 | #define DISPC_IRQ_MASK_ALL 0x7fff | ||
126 | |||
127 | #define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \ | ||
128 | DISPC_IRQ_VID1_FIFO_UNDERFLOW | \ | ||
129 | DISPC_IRQ_VID2_FIFO_UNDERFLOW | \ | ||
130 | DISPC_IRQ_SYNC_LOST) | ||
131 | |||
132 | #define RFBI_CONTROL 0x48050040 | ||
133 | |||
134 | #define MAX_PALETTE_SIZE (256 * 16) | ||
135 | |||
136 | #define FLD_MASK(pos, len) (((1 << len) - 1) << pos) | ||
137 | |||
138 | #define MOD_REG_FLD(reg, mask, val) \ | ||
139 | dispc_write_reg((reg), (dispc_read_reg(reg) & ~(mask)) | (val)); | ||
140 | |||
141 | #define OMAP2_SRAM_START 0x40200000 | ||
142 | /* Maximum size, in reality this is smaller if SRAM is partially locked. */ | ||
143 | #define OMAP2_SRAM_SIZE 0xa0000 /* 640k */ | ||
144 | |||
145 | /* We support the SDRAM / SRAM types. See OMAPFB_PLANE_MEMTYPE_* in omapfb.h */ | ||
146 | #define DISPC_MEMTYPE_NUM 2 | ||
147 | |||
148 | #define RESMAP_SIZE(_page_cnt) \ | ||
149 | ((_page_cnt + (sizeof(unsigned long) * 8) - 1) / 8) | ||
150 | #define RESMAP_PTR(_res_map, _page_nr) \ | ||
151 | (((_res_map)->map) + (_page_nr) / (sizeof(unsigned long) * 8)) | ||
152 | #define RESMAP_MASK(_page_nr) \ | ||
153 | (1 << ((_page_nr) & (sizeof(unsigned long) * 8 - 1))) | ||
154 | |||
155 | struct resmap { | ||
156 | unsigned long start; | ||
157 | unsigned page_cnt; | ||
158 | unsigned long *map; | ||
159 | }; | ||
160 | |||
161 | #define MAX_IRQ_HANDLERS 4 | ||
162 | |||
163 | static struct { | ||
164 | void __iomem *base; | ||
165 | |||
166 | struct omapfb_mem_desc mem_desc; | ||
167 | struct resmap *res_map[DISPC_MEMTYPE_NUM]; | ||
168 | atomic_t map_count[OMAPFB_PLANE_NUM]; | ||
169 | |||
170 | dma_addr_t palette_paddr; | ||
171 | void *palette_vaddr; | ||
172 | |||
173 | int ext_mode; | ||
174 | |||
175 | struct { | ||
176 | u32 irq_mask; | ||
177 | void (*callback)(void *); | ||
178 | void *data; | ||
179 | } irq_handlers[MAX_IRQ_HANDLERS]; | ||
180 | struct completion frame_done; | ||
181 | |||
182 | int fir_hinc[OMAPFB_PLANE_NUM]; | ||
183 | int fir_vinc[OMAPFB_PLANE_NUM]; | ||
184 | |||
185 | struct clk *dss_ick, *dss1_fck; | ||
186 | struct clk *dss_54m_fck; | ||
187 | |||
188 | enum omapfb_update_mode update_mode; | ||
189 | struct omapfb_device *fbdev; | ||
190 | |||
191 | struct omapfb_color_key color_key; | ||
192 | } dispc; | ||
193 | |||
194 | static void enable_lcd_clocks(int enable); | ||
195 | |||
196 | static void inline dispc_write_reg(int idx, u32 val) | ||
197 | { | ||
198 | __raw_writel(val, dispc.base + idx); | ||
199 | } | ||
200 | |||
201 | static u32 inline dispc_read_reg(int idx) | ||
202 | { | ||
203 | u32 l = __raw_readl(dispc.base + idx); | ||
204 | return l; | ||
205 | } | ||
206 | |||
207 | /* Select RFBI or bypass mode */ | ||
208 | static void enable_rfbi_mode(int enable) | ||
209 | { | ||
210 | void __iomem *rfbi_control; | ||
211 | u32 l; | ||
212 | |||
213 | l = dispc_read_reg(DISPC_CONTROL); | ||
214 | /* Enable RFBI, GPIO0/1 */ | ||
215 | l &= ~((1 << 11) | (1 << 15) | (1 << 16)); | ||
216 | l |= enable ? (1 << 11) : 0; | ||
217 | /* RFBI En: GPIO0/1=10 RFBI Dis: GPIO0/1=11 */ | ||
218 | l |= 1 << 15; | ||
219 | l |= enable ? 0 : (1 << 16); | ||
220 | dispc_write_reg(DISPC_CONTROL, l); | ||
221 | |||
222 | /* Set bypass mode in RFBI module */ | ||
223 | rfbi_control = ioremap(RFBI_CONTROL, SZ_1K); | ||
224 | if (!rfbi_control) { | ||
225 | pr_err("Unable to ioremap rfbi_control\n"); | ||
226 | return; | ||
227 | } | ||
228 | l = __raw_readl(rfbi_control); | ||
229 | l |= enable ? 0 : (1 << 1); | ||
230 | __raw_writel(l, rfbi_control); | ||
231 | iounmap(rfbi_control); | ||
232 | } | ||
233 | |||
234 | static void set_lcd_data_lines(int data_lines) | ||
235 | { | ||
236 | u32 l; | ||
237 | int code = 0; | ||
238 | |||
239 | switch (data_lines) { | ||
240 | case 12: | ||
241 | code = 0; | ||
242 | break; | ||
243 | case 16: | ||
244 | code = 1; | ||
245 | break; | ||
246 | case 18: | ||
247 | code = 2; | ||
248 | break; | ||
249 | case 24: | ||
250 | code = 3; | ||
251 | break; | ||
252 | default: | ||
253 | BUG(); | ||
254 | } | ||
255 | |||
256 | l = dispc_read_reg(DISPC_CONTROL); | ||
257 | l &= ~(0x03 << 8); | ||
258 | l |= code << 8; | ||
259 | dispc_write_reg(DISPC_CONTROL, l); | ||
260 | } | ||
261 | |||
262 | static void set_load_mode(int mode) | ||
263 | { | ||
264 | BUG_ON(mode & ~(DISPC_LOAD_CLUT_ONLY | DISPC_LOAD_FRAME_ONLY | | ||
265 | DISPC_LOAD_CLUT_ONCE_FRAME)); | ||
266 | MOD_REG_FLD(DISPC_CONFIG, 0x03 << 1, mode << 1); | ||
267 | } | ||
268 | |||
269 | void omap_dispc_set_lcd_size(int x, int y) | ||
270 | { | ||
271 | BUG_ON((x > (1 << 11)) || (y > (1 << 11))); | ||
272 | enable_lcd_clocks(1); | ||
273 | MOD_REG_FLD(DISPC_SIZE_LCD, FLD_MASK(16, 11) | FLD_MASK(0, 11), | ||
274 | ((y - 1) << 16) | (x - 1)); | ||
275 | enable_lcd_clocks(0); | ||
276 | } | ||
277 | EXPORT_SYMBOL(omap_dispc_set_lcd_size); | ||
278 | |||
279 | void omap_dispc_set_digit_size(int x, int y) | ||
280 | { | ||
281 | BUG_ON((x > (1 << 11)) || (y > (1 << 11))); | ||
282 | enable_lcd_clocks(1); | ||
283 | MOD_REG_FLD(DISPC_SIZE_DIG, FLD_MASK(16, 11) | FLD_MASK(0, 11), | ||
284 | ((y - 1) << 16) | (x - 1)); | ||
285 | enable_lcd_clocks(0); | ||
286 | } | ||
287 | EXPORT_SYMBOL(omap_dispc_set_digit_size); | ||
288 | |||
289 | static void setup_plane_fifo(int plane, int ext_mode) | ||
290 | { | ||
291 | const u32 ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD, | ||
292 | DISPC_VID1_BASE + DISPC_VID_FIFO_THRESHOLD, | ||
293 | DISPC_VID2_BASE + DISPC_VID_FIFO_THRESHOLD }; | ||
294 | const u32 fsz_reg[] = { DISPC_GFX_FIFO_SIZE_STATUS, | ||
295 | DISPC_VID1_BASE + DISPC_VID_FIFO_SIZE_STATUS, | ||
296 | DISPC_VID2_BASE + DISPC_VID_FIFO_SIZE_STATUS }; | ||
297 | int low, high; | ||
298 | u32 l; | ||
299 | |||
300 | BUG_ON(plane > 2); | ||
301 | |||
302 | l = dispc_read_reg(fsz_reg[plane]); | ||
303 | l &= FLD_MASK(0, 11); | ||
304 | if (ext_mode) { | ||
305 | low = l * 3 / 4; | ||
306 | high = l; | ||
307 | } else { | ||
308 | low = l / 4; | ||
309 | high = l * 3 / 4; | ||
310 | } | ||
311 | MOD_REG_FLD(ftrs_reg[plane], FLD_MASK(16, 12) | FLD_MASK(0, 12), | ||
312 | (high << 16) | low); | ||
313 | } | ||
314 | |||
315 | void omap_dispc_enable_lcd_out(int enable) | ||
316 | { | ||
317 | enable_lcd_clocks(1); | ||
318 | MOD_REG_FLD(DISPC_CONTROL, 1, enable ? 1 : 0); | ||
319 | enable_lcd_clocks(0); | ||
320 | } | ||
321 | EXPORT_SYMBOL(omap_dispc_enable_lcd_out); | ||
322 | |||
323 | void omap_dispc_enable_digit_out(int enable) | ||
324 | { | ||
325 | enable_lcd_clocks(1); | ||
326 | MOD_REG_FLD(DISPC_CONTROL, 1 << 1, enable ? 1 << 1 : 0); | ||
327 | enable_lcd_clocks(0); | ||
328 | } | ||
329 | EXPORT_SYMBOL(omap_dispc_enable_digit_out); | ||
330 | |||
331 | static inline int _setup_plane(int plane, int channel_out, | ||
332 | u32 paddr, int screen_width, | ||
333 | int pos_x, int pos_y, int width, int height, | ||
334 | int color_mode) | ||
335 | { | ||
336 | const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES, | ||
337 | DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES, | ||
338 | DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES }; | ||
339 | const u32 ba_reg[] = { DISPC_GFX_BA0, DISPC_VID1_BASE + DISPC_VID_BA0, | ||
340 | DISPC_VID2_BASE + DISPC_VID_BA0 }; | ||
341 | const u32 ps_reg[] = { DISPC_GFX_POSITION, | ||
342 | DISPC_VID1_BASE + DISPC_VID_POSITION, | ||
343 | DISPC_VID2_BASE + DISPC_VID_POSITION }; | ||
344 | const u32 sz_reg[] = { DISPC_GFX_SIZE, | ||
345 | DISPC_VID1_BASE + DISPC_VID_PICTURE_SIZE, | ||
346 | DISPC_VID2_BASE + DISPC_VID_PICTURE_SIZE }; | ||
347 | const u32 ri_reg[] = { DISPC_GFX_ROW_INC, | ||
348 | DISPC_VID1_BASE + DISPC_VID_ROW_INC, | ||
349 | DISPC_VID2_BASE + DISPC_VID_ROW_INC }; | ||
350 | const u32 vs_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_SIZE, | ||
351 | DISPC_VID2_BASE + DISPC_VID_SIZE }; | ||
352 | |||
353 | int chout_shift, burst_shift; | ||
354 | int chout_val; | ||
355 | int color_code; | ||
356 | int bpp; | ||
357 | int cconv_en; | ||
358 | int set_vsize; | ||
359 | u32 l; | ||
360 | |||
361 | #ifdef VERBOSE | ||
362 | dev_dbg(dispc.fbdev->dev, "plane %d channel %d paddr %#08x scr_width %d" | ||
363 | " pos_x %d pos_y %d width %d height %d color_mode %d\n", | ||
364 | plane, channel_out, paddr, screen_width, pos_x, pos_y, | ||
365 | width, height, color_mode); | ||
366 | #endif | ||
367 | |||
368 | set_vsize = 0; | ||
369 | switch (plane) { | ||
370 | case OMAPFB_PLANE_GFX: | ||
371 | burst_shift = 6; | ||
372 | chout_shift = 8; | ||
373 | break; | ||
374 | case OMAPFB_PLANE_VID1: | ||
375 | case OMAPFB_PLANE_VID2: | ||
376 | burst_shift = 14; | ||
377 | chout_shift = 16; | ||
378 | set_vsize = 1; | ||
379 | break; | ||
380 | default: | ||
381 | return -EINVAL; | ||
382 | } | ||
383 | |||
384 | switch (channel_out) { | ||
385 | case OMAPFB_CHANNEL_OUT_LCD: | ||
386 | chout_val = 0; | ||
387 | break; | ||
388 | case OMAPFB_CHANNEL_OUT_DIGIT: | ||
389 | chout_val = 1; | ||
390 | break; | ||
391 | default: | ||
392 | return -EINVAL; | ||
393 | } | ||
394 | |||
395 | cconv_en = 0; | ||
396 | switch (color_mode) { | ||
397 | case OMAPFB_COLOR_RGB565: | ||
398 | color_code = DISPC_RGB_16_BPP; | ||
399 | bpp = 16; | ||
400 | break; | ||
401 | case OMAPFB_COLOR_YUV422: | ||
402 | if (plane == 0) | ||
403 | return -EINVAL; | ||
404 | color_code = DISPC_UYVY_422; | ||
405 | cconv_en = 1; | ||
406 | bpp = 16; | ||
407 | break; | ||
408 | case OMAPFB_COLOR_YUY422: | ||
409 | if (plane == 0) | ||
410 | return -EINVAL; | ||
411 | color_code = DISPC_YUV2_422; | ||
412 | cconv_en = 1; | ||
413 | bpp = 16; | ||
414 | break; | ||
415 | default: | ||
416 | return -EINVAL; | ||
417 | } | ||
418 | |||
419 | l = dispc_read_reg(at_reg[plane]); | ||
420 | |||
421 | l &= ~(0x0f << 1); | ||
422 | l |= color_code << 1; | ||
423 | l &= ~(1 << 9); | ||
424 | l |= cconv_en << 9; | ||
425 | |||
426 | l &= ~(0x03 << burst_shift); | ||
427 | l |= DISPC_BURST_8x32 << burst_shift; | ||
428 | |||
429 | l &= ~(1 << chout_shift); | ||
430 | l |= chout_val << chout_shift; | ||
431 | |||
432 | dispc_write_reg(at_reg[plane], l); | ||
433 | |||
434 | dispc_write_reg(ba_reg[plane], paddr); | ||
435 | MOD_REG_FLD(ps_reg[plane], | ||
436 | FLD_MASK(16, 11) | FLD_MASK(0, 11), (pos_y << 16) | pos_x); | ||
437 | |||
438 | MOD_REG_FLD(sz_reg[plane], FLD_MASK(16, 11) | FLD_MASK(0, 11), | ||
439 | ((height - 1) << 16) | (width - 1)); | ||
440 | |||
441 | if (set_vsize) { | ||
442 | /* Set video size if set_scale hasn't set it */ | ||
443 | if (!dispc.fir_vinc[plane]) | ||
444 | MOD_REG_FLD(vs_reg[plane], | ||
445 | FLD_MASK(16, 11), (height - 1) << 16); | ||
446 | if (!dispc.fir_hinc[plane]) | ||
447 | MOD_REG_FLD(vs_reg[plane], | ||
448 | FLD_MASK(0, 11), width - 1); | ||
449 | } | ||
450 | |||
451 | dispc_write_reg(ri_reg[plane], (screen_width - width) * bpp / 8 + 1); | ||
452 | |||
453 | return height * screen_width * bpp / 8; | ||
454 | } | ||
455 | |||
456 | static int omap_dispc_setup_plane(int plane, int channel_out, | ||
457 | unsigned long offset, | ||
458 | int screen_width, | ||
459 | int pos_x, int pos_y, int width, int height, | ||
460 | int color_mode) | ||
461 | { | ||
462 | u32 paddr; | ||
463 | int r; | ||
464 | |||
465 | if ((unsigned)plane > dispc.mem_desc.region_cnt) | ||
466 | return -EINVAL; | ||
467 | paddr = dispc.mem_desc.region[plane].paddr + offset; | ||
468 | enable_lcd_clocks(1); | ||
469 | r = _setup_plane(plane, channel_out, paddr, | ||
470 | screen_width, | ||
471 | pos_x, pos_y, width, height, color_mode); | ||
472 | enable_lcd_clocks(0); | ||
473 | return r; | ||
474 | } | ||
475 | |||
476 | static void write_firh_reg(int plane, int reg, u32 value) | ||
477 | { | ||
478 | u32 base; | ||
479 | |||
480 | if (plane == 1) | ||
481 | base = DISPC_VID1_BASE + DISPC_VID_FIR_COEF_H0; | ||
482 | else | ||
483 | base = DISPC_VID2_BASE + DISPC_VID_FIR_COEF_H0; | ||
484 | dispc_write_reg(base + reg * 8, value); | ||
485 | } | ||
486 | |||
487 | static void write_firhv_reg(int plane, int reg, u32 value) | ||
488 | { | ||
489 | u32 base; | ||
490 | |||
491 | if (plane == 1) | ||
492 | base = DISPC_VID1_BASE + DISPC_VID_FIR_COEF_HV0; | ||
493 | else | ||
494 | base = DISPC_VID2_BASE + DISPC_VID_FIR_COEF_HV0; | ||
495 | dispc_write_reg(base + reg * 8, value); | ||
496 | } | ||
497 | |||
498 | static void set_upsampling_coef_table(int plane) | ||
499 | { | ||
500 | const u32 coef[][2] = { | ||
501 | { 0x00800000, 0x00800000 }, | ||
502 | { 0x0D7CF800, 0x037B02FF }, | ||
503 | { 0x1E70F5FF, 0x0C6F05FE }, | ||
504 | { 0x335FF5FE, 0x205907FB }, | ||
505 | { 0xF74949F7, 0x00404000 }, | ||
506 | { 0xF55F33FB, 0x075920FE }, | ||
507 | { 0xF5701EFE, 0x056F0CFF }, | ||
508 | { 0xF87C0DFF, 0x027B0300 }, | ||
509 | }; | ||
510 | int i; | ||
511 | |||
512 | for (i = 0; i < 8; i++) { | ||
513 | write_firh_reg(plane, i, coef[i][0]); | ||
514 | write_firhv_reg(plane, i, coef[i][1]); | ||
515 | } | ||
516 | } | ||
517 | |||
518 | static int omap_dispc_set_scale(int plane, | ||
519 | int orig_width, int orig_height, | ||
520 | int out_width, int out_height) | ||
521 | { | ||
522 | const u32 at_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES, | ||
523 | DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES }; | ||
524 | const u32 vs_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_SIZE, | ||
525 | DISPC_VID2_BASE + DISPC_VID_SIZE }; | ||
526 | const u32 fir_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_FIR, | ||
527 | DISPC_VID2_BASE + DISPC_VID_FIR }; | ||
528 | |||
529 | u32 l; | ||
530 | int fir_hinc; | ||
531 | int fir_vinc; | ||
532 | |||
533 | if ((unsigned)plane > OMAPFB_PLANE_NUM) | ||
534 | return -ENODEV; | ||
535 | |||
536 | if (plane == OMAPFB_PLANE_GFX && | ||
537 | (out_width != orig_width || out_height != orig_height)) | ||
538 | return -EINVAL; | ||
539 | |||
540 | enable_lcd_clocks(1); | ||
541 | if (orig_width < out_width) { | ||
542 | /* | ||
543 | * Upsampling. | ||
544 | * Currently you can only scale both dimensions in one way. | ||
545 | */ | ||
546 | if (orig_height > out_height || | ||
547 | orig_width * 8 < out_width || | ||
548 | orig_height * 8 < out_height) { | ||
549 | enable_lcd_clocks(0); | ||
550 | return -EINVAL; | ||
551 | } | ||
552 | set_upsampling_coef_table(plane); | ||
553 | } else if (orig_width > out_width) { | ||
554 | /* Downsampling not yet supported | ||
555 | */ | ||
556 | |||
557 | enable_lcd_clocks(0); | ||
558 | return -EINVAL; | ||
559 | } | ||
560 | if (!orig_width || orig_width == out_width) | ||
561 | fir_hinc = 0; | ||
562 | else | ||
563 | fir_hinc = 1024 * orig_width / out_width; | ||
564 | if (!orig_height || orig_height == out_height) | ||
565 | fir_vinc = 0; | ||
566 | else | ||
567 | fir_vinc = 1024 * orig_height / out_height; | ||
568 | dispc.fir_hinc[plane] = fir_hinc; | ||
569 | dispc.fir_vinc[plane] = fir_vinc; | ||
570 | |||
571 | MOD_REG_FLD(fir_reg[plane], | ||
572 | FLD_MASK(16, 12) | FLD_MASK(0, 12), | ||
573 | ((fir_vinc & 4095) << 16) | | ||
574 | (fir_hinc & 4095)); | ||
575 | |||
576 | dev_dbg(dispc.fbdev->dev, "out_width %d out_height %d orig_width %d " | ||
577 | "orig_height %d fir_hinc %d fir_vinc %d\n", | ||
578 | out_width, out_height, orig_width, orig_height, | ||
579 | fir_hinc, fir_vinc); | ||
580 | |||
581 | MOD_REG_FLD(vs_reg[plane], | ||
582 | FLD_MASK(16, 11) | FLD_MASK(0, 11), | ||
583 | ((out_height - 1) << 16) | (out_width - 1)); | ||
584 | |||
585 | l = dispc_read_reg(at_reg[plane]); | ||
586 | l &= ~(0x03 << 5); | ||
587 | l |= fir_hinc ? (1 << 5) : 0; | ||
588 | l |= fir_vinc ? (1 << 6) : 0; | ||
589 | dispc_write_reg(at_reg[plane], l); | ||
590 | |||
591 | enable_lcd_clocks(0); | ||
592 | return 0; | ||
593 | } | ||
594 | |||
595 | static int omap_dispc_enable_plane(int plane, int enable) | ||
596 | { | ||
597 | const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES, | ||
598 | DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES, | ||
599 | DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES }; | ||
600 | if ((unsigned int)plane > dispc.mem_desc.region_cnt) | ||
601 | return -EINVAL; | ||
602 | |||
603 | enable_lcd_clocks(1); | ||
604 | MOD_REG_FLD(at_reg[plane], 1, enable ? 1 : 0); | ||
605 | enable_lcd_clocks(0); | ||
606 | |||
607 | return 0; | ||
608 | } | ||
609 | |||
610 | static int omap_dispc_set_color_key(struct omapfb_color_key *ck) | ||
611 | { | ||
612 | u32 df_reg, tr_reg; | ||
613 | int shift, val; | ||
614 | |||
615 | switch (ck->channel_out) { | ||
616 | case OMAPFB_CHANNEL_OUT_LCD: | ||
617 | df_reg = DISPC_DEFAULT_COLOR0; | ||
618 | tr_reg = DISPC_TRANS_COLOR0; | ||
619 | shift = 10; | ||
620 | break; | ||
621 | case OMAPFB_CHANNEL_OUT_DIGIT: | ||
622 | df_reg = DISPC_DEFAULT_COLOR1; | ||
623 | tr_reg = DISPC_TRANS_COLOR1; | ||
624 | shift = 12; | ||
625 | break; | ||
626 | default: | ||
627 | return -EINVAL; | ||
628 | } | ||
629 | switch (ck->key_type) { | ||
630 | case OMAPFB_COLOR_KEY_DISABLED: | ||
631 | val = 0; | ||
632 | break; | ||
633 | case OMAPFB_COLOR_KEY_GFX_DST: | ||
634 | val = 1; | ||
635 | break; | ||
636 | case OMAPFB_COLOR_KEY_VID_SRC: | ||
637 | val = 3; | ||
638 | break; | ||
639 | default: | ||
640 | return -EINVAL; | ||
641 | } | ||
642 | enable_lcd_clocks(1); | ||
643 | MOD_REG_FLD(DISPC_CONFIG, FLD_MASK(shift, 2), val << shift); | ||
644 | |||
645 | if (val != 0) | ||
646 | dispc_write_reg(tr_reg, ck->trans_key); | ||
647 | dispc_write_reg(df_reg, ck->background); | ||
648 | enable_lcd_clocks(0); | ||
649 | |||
650 | dispc.color_key = *ck; | ||
651 | |||
652 | return 0; | ||
653 | } | ||
654 | |||
655 | static int omap_dispc_get_color_key(struct omapfb_color_key *ck) | ||
656 | { | ||
657 | *ck = dispc.color_key; | ||
658 | return 0; | ||
659 | } | ||
660 | |||
661 | static void load_palette(void) | ||
662 | { | ||
663 | } | ||
664 | |||
665 | static int omap_dispc_set_update_mode(enum omapfb_update_mode mode) | ||
666 | { | ||
667 | int r = 0; | ||
668 | |||
669 | if (mode != dispc.update_mode) { | ||
670 | switch (mode) { | ||
671 | case OMAPFB_AUTO_UPDATE: | ||
672 | case OMAPFB_MANUAL_UPDATE: | ||
673 | enable_lcd_clocks(1); | ||
674 | omap_dispc_enable_lcd_out(1); | ||
675 | dispc.update_mode = mode; | ||
676 | break; | ||
677 | case OMAPFB_UPDATE_DISABLED: | ||
678 | init_completion(&dispc.frame_done); | ||
679 | omap_dispc_enable_lcd_out(0); | ||
680 | if (!wait_for_completion_timeout(&dispc.frame_done, | ||
681 | msecs_to_jiffies(500))) { | ||
682 | dev_err(dispc.fbdev->dev, | ||
683 | "timeout waiting for FRAME DONE\n"); | ||
684 | } | ||
685 | dispc.update_mode = mode; | ||
686 | enable_lcd_clocks(0); | ||
687 | break; | ||
688 | default: | ||
689 | r = -EINVAL; | ||
690 | } | ||
691 | } | ||
692 | |||
693 | return r; | ||
694 | } | ||
695 | |||
696 | static void omap_dispc_get_caps(int plane, struct omapfb_caps *caps) | ||
697 | { | ||
698 | caps->ctrl |= OMAPFB_CAPS_PLANE_RELOCATE_MEM; | ||
699 | if (plane > 0) | ||
700 | caps->ctrl |= OMAPFB_CAPS_PLANE_SCALE; | ||
701 | caps->plane_color |= (1 << OMAPFB_COLOR_RGB565) | | ||
702 | (1 << OMAPFB_COLOR_YUV422) | | ||
703 | (1 << OMAPFB_COLOR_YUY422); | ||
704 | if (plane == 0) | ||
705 | caps->plane_color |= (1 << OMAPFB_COLOR_CLUT_8BPP) | | ||
706 | (1 << OMAPFB_COLOR_CLUT_4BPP) | | ||
707 | (1 << OMAPFB_COLOR_CLUT_2BPP) | | ||
708 | (1 << OMAPFB_COLOR_CLUT_1BPP) | | ||
709 | (1 << OMAPFB_COLOR_RGB444); | ||
710 | } | ||
711 | |||
712 | static enum omapfb_update_mode omap_dispc_get_update_mode(void) | ||
713 | { | ||
714 | return dispc.update_mode; | ||
715 | } | ||
716 | |||
717 | static void setup_color_conv_coef(void) | ||
718 | { | ||
719 | u32 mask = FLD_MASK(16, 11) | FLD_MASK(0, 11); | ||
720 | int cf1_reg = DISPC_VID1_BASE + DISPC_VID_CONV_COEF0; | ||
721 | int cf2_reg = DISPC_VID2_BASE + DISPC_VID_CONV_COEF0; | ||
722 | int at1_reg = DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES; | ||
723 | int at2_reg = DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES; | ||
724 | const struct color_conv_coef { | ||
725 | int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb; | ||
726 | int full_range; | ||
727 | } ctbl_bt601_5 = { | ||
728 | 298, 409, 0, 298, -208, -100, 298, 0, 517, 0, | ||
729 | }; | ||
730 | const struct color_conv_coef *ct; | ||
731 | #define CVAL(x, y) (((x & 2047) << 16) | (y & 2047)) | ||
732 | |||
733 | ct = &ctbl_bt601_5; | ||
734 | |||
735 | MOD_REG_FLD(cf1_reg, mask, CVAL(ct->rcr, ct->ry)); | ||
736 | MOD_REG_FLD(cf1_reg + 4, mask, CVAL(ct->gy, ct->rcb)); | ||
737 | MOD_REG_FLD(cf1_reg + 8, mask, CVAL(ct->gcb, ct->gcr)); | ||
738 | MOD_REG_FLD(cf1_reg + 12, mask, CVAL(ct->bcr, ct->by)); | ||
739 | MOD_REG_FLD(cf1_reg + 16, mask, CVAL(0, ct->bcb)); | ||
740 | |||
741 | MOD_REG_FLD(cf2_reg, mask, CVAL(ct->rcr, ct->ry)); | ||
742 | MOD_REG_FLD(cf2_reg + 4, mask, CVAL(ct->gy, ct->rcb)); | ||
743 | MOD_REG_FLD(cf2_reg + 8, mask, CVAL(ct->gcb, ct->gcr)); | ||
744 | MOD_REG_FLD(cf2_reg + 12, mask, CVAL(ct->bcr, ct->by)); | ||
745 | MOD_REG_FLD(cf2_reg + 16, mask, CVAL(0, ct->bcb)); | ||
746 | #undef CVAL | ||
747 | |||
748 | MOD_REG_FLD(at1_reg, (1 << 11), ct->full_range); | ||
749 | MOD_REG_FLD(at2_reg, (1 << 11), ct->full_range); | ||
750 | } | ||
751 | |||
752 | static void calc_ck_div(int is_tft, int pck, int *lck_div, int *pck_div) | ||
753 | { | ||
754 | unsigned long fck, lck; | ||
755 | |||
756 | *lck_div = 1; | ||
757 | pck = max(1, pck); | ||
758 | fck = clk_get_rate(dispc.dss1_fck); | ||
759 | lck = fck; | ||
760 | *pck_div = (lck + pck - 1) / pck; | ||
761 | if (is_tft) | ||
762 | *pck_div = max(2, *pck_div); | ||
763 | else | ||
764 | *pck_div = max(3, *pck_div); | ||
765 | if (*pck_div > 255) { | ||
766 | *pck_div = 255; | ||
767 | lck = pck * *pck_div; | ||
768 | *lck_div = fck / lck; | ||
769 | BUG_ON(*lck_div < 1); | ||
770 | if (*lck_div > 255) { | ||
771 | *lck_div = 255; | ||
772 | dev_warn(dispc.fbdev->dev, "pixclock %d kHz too low.\n", | ||
773 | pck / 1000); | ||
774 | } | ||
775 | } | ||
776 | } | ||
777 | |||
778 | static void set_lcd_tft_mode(int enable) | ||
779 | { | ||
780 | u32 mask; | ||
781 | |||
782 | mask = 1 << 3; | ||
783 | MOD_REG_FLD(DISPC_CONTROL, mask, enable ? mask : 0); | ||
784 | } | ||
785 | |||
786 | static void set_lcd_timings(void) | ||
787 | { | ||
788 | u32 l; | ||
789 | int lck_div, pck_div; | ||
790 | struct lcd_panel *panel = dispc.fbdev->panel; | ||
791 | int is_tft = panel->config & OMAP_LCDC_PANEL_TFT; | ||
792 | unsigned long fck; | ||
793 | |||
794 | l = dispc_read_reg(DISPC_TIMING_H); | ||
795 | l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8)); | ||
796 | l |= ( max(1, (min(64, panel->hsw))) - 1 ) << 0; | ||
797 | l |= ( max(1, (min(256, panel->hfp))) - 1 ) << 8; | ||
798 | l |= ( max(1, (min(256, panel->hbp))) - 1 ) << 20; | ||
799 | dispc_write_reg(DISPC_TIMING_H, l); | ||
800 | |||
801 | l = dispc_read_reg(DISPC_TIMING_V); | ||
802 | l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8)); | ||
803 | l |= ( max(1, (min(64, panel->vsw))) - 1 ) << 0; | ||
804 | l |= ( max(0, (min(255, panel->vfp))) - 0 ) << 8; | ||
805 | l |= ( max(0, (min(255, panel->vbp))) - 0 ) << 20; | ||
806 | dispc_write_reg(DISPC_TIMING_V, l); | ||
807 | |||
808 | l = dispc_read_reg(DISPC_POL_FREQ); | ||
809 | l &= ~FLD_MASK(12, 6); | ||
810 | l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 12; | ||
811 | l |= panel->acb & 0xff; | ||
812 | dispc_write_reg(DISPC_POL_FREQ, l); | ||
813 | |||
814 | calc_ck_div(is_tft, panel->pixel_clock * 1000, &lck_div, &pck_div); | ||
815 | |||
816 | l = dispc_read_reg(DISPC_DIVISOR); | ||
817 | l &= ~(FLD_MASK(16, 8) | FLD_MASK(0, 8)); | ||
818 | l |= (lck_div << 16) | (pck_div << 0); | ||
819 | dispc_write_reg(DISPC_DIVISOR, l); | ||
820 | |||
821 | /* update panel info with the exact clock */ | ||
822 | fck = clk_get_rate(dispc.dss1_fck); | ||
823 | panel->pixel_clock = fck / lck_div / pck_div / 1000; | ||
824 | } | ||
825 | |||
826 | static void recalc_irq_mask(void) | ||
827 | { | ||
828 | int i; | ||
829 | unsigned long irq_mask = DISPC_IRQ_MASK_ERROR; | ||
830 | |||
831 | for (i = 0; i < MAX_IRQ_HANDLERS; i++) { | ||
832 | if (!dispc.irq_handlers[i].callback) | ||
833 | continue; | ||
834 | |||
835 | irq_mask |= dispc.irq_handlers[i].irq_mask; | ||
836 | } | ||
837 | |||
838 | enable_lcd_clocks(1); | ||
839 | MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask); | ||
840 | enable_lcd_clocks(0); | ||
841 | } | ||
842 | |||
843 | int omap_dispc_request_irq(unsigned long irq_mask, void (*callback)(void *data), | ||
844 | void *data) | ||
845 | { | ||
846 | int i; | ||
847 | |||
848 | BUG_ON(callback == NULL); | ||
849 | |||
850 | for (i = 0; i < MAX_IRQ_HANDLERS; i++) { | ||
851 | if (dispc.irq_handlers[i].callback) | ||
852 | continue; | ||
853 | |||
854 | dispc.irq_handlers[i].irq_mask = irq_mask; | ||
855 | dispc.irq_handlers[i].callback = callback; | ||
856 | dispc.irq_handlers[i].data = data; | ||
857 | recalc_irq_mask(); | ||
858 | |||
859 | return 0; | ||
860 | } | ||
861 | |||
862 | return -EBUSY; | ||
863 | } | ||
864 | EXPORT_SYMBOL(omap_dispc_request_irq); | ||
865 | |||
866 | void omap_dispc_free_irq(unsigned long irq_mask, void (*callback)(void *data), | ||
867 | void *data) | ||
868 | { | ||
869 | int i; | ||
870 | |||
871 | for (i = 0; i < MAX_IRQ_HANDLERS; i++) { | ||
872 | if (dispc.irq_handlers[i].callback == callback && | ||
873 | dispc.irq_handlers[i].data == data) { | ||
874 | dispc.irq_handlers[i].irq_mask = 0; | ||
875 | dispc.irq_handlers[i].callback = NULL; | ||
876 | dispc.irq_handlers[i].data = NULL; | ||
877 | recalc_irq_mask(); | ||
878 | return; | ||
879 | } | ||
880 | } | ||
881 | |||
882 | BUG(); | ||
883 | } | ||
884 | EXPORT_SYMBOL(omap_dispc_free_irq); | ||
885 | |||
886 | static irqreturn_t omap_dispc_irq_handler(int irq, void *dev) | ||
887 | { | ||
888 | u32 stat; | ||
889 | int i = 0; | ||
890 | |||
891 | enable_lcd_clocks(1); | ||
892 | |||
893 | stat = dispc_read_reg(DISPC_IRQSTATUS); | ||
894 | if (stat & DISPC_IRQ_FRAMEMASK) | ||
895 | complete(&dispc.frame_done); | ||
896 | |||
897 | if (stat & DISPC_IRQ_MASK_ERROR) { | ||
898 | if (printk_ratelimit()) { | ||
899 | dev_err(dispc.fbdev->dev, "irq error status %04x\n", | ||
900 | stat & 0x7fff); | ||
901 | } | ||
902 | } | ||
903 | |||
904 | for (i = 0; i < MAX_IRQ_HANDLERS; i++) { | ||
905 | if (unlikely(dispc.irq_handlers[i].callback && | ||
906 | (stat & dispc.irq_handlers[i].irq_mask))) | ||
907 | dispc.irq_handlers[i].callback( | ||
908 | dispc.irq_handlers[i].data); | ||
909 | } | ||
910 | |||
911 | dispc_write_reg(DISPC_IRQSTATUS, stat); | ||
912 | |||
913 | enable_lcd_clocks(0); | ||
914 | |||
915 | return IRQ_HANDLED; | ||
916 | } | ||
917 | |||
918 | static int get_dss_clocks(void) | ||
919 | { | ||
920 | dispc.dss_ick = clk_get(&dispc.fbdev->dssdev->dev, "ick"); | ||
921 | if (IS_ERR(dispc.dss_ick)) { | ||
922 | dev_err(dispc.fbdev->dev, "can't get ick\n"); | ||
923 | return PTR_ERR(dispc.dss_ick); | ||
924 | } | ||
925 | |||
926 | dispc.dss1_fck = clk_get(&dispc.fbdev->dssdev->dev, "fck"); | ||
927 | if (IS_ERR(dispc.dss1_fck)) { | ||
928 | dev_err(dispc.fbdev->dev, "can't get dss1_fck\n"); | ||
929 | clk_put(dispc.dss_ick); | ||
930 | return PTR_ERR(dispc.dss1_fck); | ||
931 | } | ||
932 | |||
933 | dispc.dss_54m_fck = clk_get(&dispc.fbdev->dssdev->dev, "tv_clk"); | ||
934 | if (IS_ERR(dispc.dss_54m_fck)) { | ||
935 | dev_err(dispc.fbdev->dev, "can't get tv_fck\n"); | ||
936 | clk_put(dispc.dss_ick); | ||
937 | clk_put(dispc.dss1_fck); | ||
938 | return PTR_ERR(dispc.dss_54m_fck); | ||
939 | } | ||
940 | |||
941 | return 0; | ||
942 | } | ||
943 | |||
944 | static void put_dss_clocks(void) | ||
945 | { | ||
946 | clk_put(dispc.dss_54m_fck); | ||
947 | clk_put(dispc.dss1_fck); | ||
948 | clk_put(dispc.dss_ick); | ||
949 | } | ||
950 | |||
951 | static void enable_lcd_clocks(int enable) | ||
952 | { | ||
953 | if (enable) { | ||
954 | clk_enable(dispc.dss_ick); | ||
955 | clk_enable(dispc.dss1_fck); | ||
956 | } else { | ||
957 | clk_disable(dispc.dss1_fck); | ||
958 | clk_disable(dispc.dss_ick); | ||
959 | } | ||
960 | } | ||
961 | |||
962 | static void enable_digit_clocks(int enable) | ||
963 | { | ||
964 | if (enable) | ||
965 | clk_enable(dispc.dss_54m_fck); | ||
966 | else | ||
967 | clk_disable(dispc.dss_54m_fck); | ||
968 | } | ||
969 | |||
970 | static void omap_dispc_suspend(void) | ||
971 | { | ||
972 | if (dispc.update_mode == OMAPFB_AUTO_UPDATE) { | ||
973 | init_completion(&dispc.frame_done); | ||
974 | omap_dispc_enable_lcd_out(0); | ||
975 | if (!wait_for_completion_timeout(&dispc.frame_done, | ||
976 | msecs_to_jiffies(500))) { | ||
977 | dev_err(dispc.fbdev->dev, | ||
978 | "timeout waiting for FRAME DONE\n"); | ||
979 | } | ||
980 | enable_lcd_clocks(0); | ||
981 | } | ||
982 | } | ||
983 | |||
984 | static void omap_dispc_resume(void) | ||
985 | { | ||
986 | if (dispc.update_mode == OMAPFB_AUTO_UPDATE) { | ||
987 | enable_lcd_clocks(1); | ||
988 | if (!dispc.ext_mode) { | ||
989 | set_lcd_timings(); | ||
990 | load_palette(); | ||
991 | } | ||
992 | omap_dispc_enable_lcd_out(1); | ||
993 | } | ||
994 | } | ||
995 | |||
996 | |||
997 | static int omap_dispc_update_window(struct fb_info *fbi, | ||
998 | struct omapfb_update_window *win, | ||
999 | void (*complete_callback)(void *arg), | ||
1000 | void *complete_callback_data) | ||
1001 | { | ||
1002 | return dispc.update_mode == OMAPFB_UPDATE_DISABLED ? -ENODEV : 0; | ||
1003 | } | ||
1004 | |||
1005 | static int mmap_kern(struct omapfb_mem_region *region) | ||
1006 | { | ||
1007 | struct vm_struct *kvma; | ||
1008 | struct vm_area_struct vma; | ||
1009 | pgprot_t pgprot; | ||
1010 | unsigned long vaddr; | ||
1011 | |||
1012 | kvma = get_vm_area(region->size, VM_IOREMAP); | ||
1013 | if (kvma == NULL) { | ||
1014 | dev_err(dispc.fbdev->dev, "can't get kernel vm area\n"); | ||
1015 | return -ENOMEM; | ||
1016 | } | ||
1017 | vma.vm_mm = &init_mm; | ||
1018 | |||
1019 | vaddr = (unsigned long)kvma->addr; | ||
1020 | |||
1021 | pgprot = pgprot_writecombine(pgprot_kernel); | ||
1022 | vma.vm_start = vaddr; | ||
1023 | vma.vm_end = vaddr + region->size; | ||
1024 | if (io_remap_pfn_range(&vma, vaddr, region->paddr >> PAGE_SHIFT, | ||
1025 | region->size, pgprot) < 0) { | ||
1026 | dev_err(dispc.fbdev->dev, "kernel mmap for FBMEM failed\n"); | ||
1027 | return -EAGAIN; | ||
1028 | } | ||
1029 | region->vaddr = (void *)vaddr; | ||
1030 | |||
1031 | return 0; | ||
1032 | } | ||
1033 | |||
1034 | static void mmap_user_open(struct vm_area_struct *vma) | ||
1035 | { | ||
1036 | int plane = (int)vma->vm_private_data; | ||
1037 | |||
1038 | atomic_inc(&dispc.map_count[plane]); | ||
1039 | } | ||
1040 | |||
1041 | static void mmap_user_close(struct vm_area_struct *vma) | ||
1042 | { | ||
1043 | int plane = (int)vma->vm_private_data; | ||
1044 | |||
1045 | atomic_dec(&dispc.map_count[plane]); | ||
1046 | } | ||
1047 | |||
1048 | static const struct vm_operations_struct mmap_user_ops = { | ||
1049 | .open = mmap_user_open, | ||
1050 | .close = mmap_user_close, | ||
1051 | }; | ||
1052 | |||
1053 | static int omap_dispc_mmap_user(struct fb_info *info, | ||
1054 | struct vm_area_struct *vma) | ||
1055 | { | ||
1056 | struct omapfb_plane_struct *plane = info->par; | ||
1057 | unsigned long off; | ||
1058 | unsigned long start; | ||
1059 | u32 len; | ||
1060 | |||
1061 | if (vma->vm_end - vma->vm_start == 0) | ||
1062 | return 0; | ||
1063 | if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) | ||
1064 | return -EINVAL; | ||
1065 | off = vma->vm_pgoff << PAGE_SHIFT; | ||
1066 | |||
1067 | start = info->fix.smem_start; | ||
1068 | len = info->fix.smem_len; | ||
1069 | if (off >= len) | ||
1070 | return -EINVAL; | ||
1071 | if ((vma->vm_end - vma->vm_start + off) > len) | ||
1072 | return -EINVAL; | ||
1073 | off += start; | ||
1074 | vma->vm_pgoff = off >> PAGE_SHIFT; | ||
1075 | vma->vm_flags |= VM_IO | VM_RESERVED; | ||
1076 | vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); | ||
1077 | vma->vm_ops = &mmap_user_ops; | ||
1078 | vma->vm_private_data = (void *)plane->idx; | ||
1079 | if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, | ||
1080 | vma->vm_end - vma->vm_start, vma->vm_page_prot)) | ||
1081 | return -EAGAIN; | ||
1082 | /* vm_ops.open won't be called for mmap itself. */ | ||
1083 | atomic_inc(&dispc.map_count[plane->idx]); | ||
1084 | return 0; | ||
1085 | } | ||
1086 | |||
1087 | static void unmap_kern(struct omapfb_mem_region *region) | ||
1088 | { | ||
1089 | vunmap(region->vaddr); | ||
1090 | } | ||
1091 | |||
1092 | static int alloc_palette_ram(void) | ||
1093 | { | ||
1094 | dispc.palette_vaddr = dma_alloc_writecombine(dispc.fbdev->dev, | ||
1095 | MAX_PALETTE_SIZE, &dispc.palette_paddr, GFP_KERNEL); | ||
1096 | if (dispc.palette_vaddr == NULL) { | ||
1097 | dev_err(dispc.fbdev->dev, "failed to alloc palette memory\n"); | ||
1098 | return -ENOMEM; | ||
1099 | } | ||
1100 | |||
1101 | return 0; | ||
1102 | } | ||
1103 | |||
1104 | static void free_palette_ram(void) | ||
1105 | { | ||
1106 | dma_free_writecombine(dispc.fbdev->dev, MAX_PALETTE_SIZE, | ||
1107 | dispc.palette_vaddr, dispc.palette_paddr); | ||
1108 | } | ||
1109 | |||
1110 | static int alloc_fbmem(struct omapfb_mem_region *region) | ||
1111 | { | ||
1112 | region->vaddr = dma_alloc_writecombine(dispc.fbdev->dev, | ||
1113 | region->size, ®ion->paddr, GFP_KERNEL); | ||
1114 | |||
1115 | if (region->vaddr == NULL) { | ||
1116 | dev_err(dispc.fbdev->dev, "unable to allocate FB DMA memory\n"); | ||
1117 | return -ENOMEM; | ||
1118 | } | ||
1119 | |||
1120 | return 0; | ||
1121 | } | ||
1122 | |||
1123 | static void free_fbmem(struct omapfb_mem_region *region) | ||
1124 | { | ||
1125 | dma_free_writecombine(dispc.fbdev->dev, region->size, | ||
1126 | region->vaddr, region->paddr); | ||
1127 | } | ||
1128 | |||
1129 | static struct resmap *init_resmap(unsigned long start, size_t size) | ||
1130 | { | ||
1131 | unsigned page_cnt; | ||
1132 | struct resmap *res_map; | ||
1133 | |||
1134 | page_cnt = PAGE_ALIGN(size) / PAGE_SIZE; | ||
1135 | res_map = | ||
1136 | kzalloc(sizeof(struct resmap) + RESMAP_SIZE(page_cnt), GFP_KERNEL); | ||
1137 | if (res_map == NULL) | ||
1138 | return NULL; | ||
1139 | res_map->start = start; | ||
1140 | res_map->page_cnt = page_cnt; | ||
1141 | res_map->map = (unsigned long *)(res_map + 1); | ||
1142 | return res_map; | ||
1143 | } | ||
1144 | |||
1145 | static void cleanup_resmap(struct resmap *res_map) | ||
1146 | { | ||
1147 | kfree(res_map); | ||
1148 | } | ||
1149 | |||
1150 | static inline int resmap_mem_type(unsigned long start) | ||
1151 | { | ||
1152 | if (start >= OMAP2_SRAM_START && | ||
1153 | start < OMAP2_SRAM_START + OMAP2_SRAM_SIZE) | ||
1154 | return OMAPFB_MEMTYPE_SRAM; | ||
1155 | else | ||
1156 | return OMAPFB_MEMTYPE_SDRAM; | ||
1157 | } | ||
1158 | |||
1159 | static inline int resmap_page_reserved(struct resmap *res_map, unsigned page_nr) | ||
1160 | { | ||
1161 | return *RESMAP_PTR(res_map, page_nr) & RESMAP_MASK(page_nr) ? 1 : 0; | ||
1162 | } | ||
1163 | |||
1164 | static inline void resmap_reserve_page(struct resmap *res_map, unsigned page_nr) | ||
1165 | { | ||
1166 | BUG_ON(resmap_page_reserved(res_map, page_nr)); | ||
1167 | *RESMAP_PTR(res_map, page_nr) |= RESMAP_MASK(page_nr); | ||
1168 | } | ||
1169 | |||
1170 | static inline void resmap_free_page(struct resmap *res_map, unsigned page_nr) | ||
1171 | { | ||
1172 | BUG_ON(!resmap_page_reserved(res_map, page_nr)); | ||
1173 | *RESMAP_PTR(res_map, page_nr) &= ~RESMAP_MASK(page_nr); | ||
1174 | } | ||
1175 | |||
1176 | static void resmap_reserve_region(unsigned long start, size_t size) | ||
1177 | { | ||
1178 | |||
1179 | struct resmap *res_map; | ||
1180 | unsigned start_page; | ||
1181 | unsigned end_page; | ||
1182 | int mtype; | ||
1183 | unsigned i; | ||
1184 | |||
1185 | mtype = resmap_mem_type(start); | ||
1186 | res_map = dispc.res_map[mtype]; | ||
1187 | dev_dbg(dispc.fbdev->dev, "reserve mem type %d start %08lx size %d\n", | ||
1188 | mtype, start, size); | ||
1189 | start_page = (start - res_map->start) / PAGE_SIZE; | ||
1190 | end_page = start_page + PAGE_ALIGN(size) / PAGE_SIZE; | ||
1191 | for (i = start_page; i < end_page; i++) | ||
1192 | resmap_reserve_page(res_map, i); | ||
1193 | } | ||
1194 | |||
1195 | static void resmap_free_region(unsigned long start, size_t size) | ||
1196 | { | ||
1197 | struct resmap *res_map; | ||
1198 | unsigned start_page; | ||
1199 | unsigned end_page; | ||
1200 | unsigned i; | ||
1201 | int mtype; | ||
1202 | |||
1203 | mtype = resmap_mem_type(start); | ||
1204 | res_map = dispc.res_map[mtype]; | ||
1205 | dev_dbg(dispc.fbdev->dev, "free mem type %d start %08lx size %d\n", | ||
1206 | mtype, start, size); | ||
1207 | start_page = (start - res_map->start) / PAGE_SIZE; | ||
1208 | end_page = start_page + PAGE_ALIGN(size) / PAGE_SIZE; | ||
1209 | for (i = start_page; i < end_page; i++) | ||
1210 | resmap_free_page(res_map, i); | ||
1211 | } | ||
1212 | |||
1213 | static unsigned long resmap_alloc_region(int mtype, size_t size) | ||
1214 | { | ||
1215 | unsigned i; | ||
1216 | unsigned total; | ||
1217 | unsigned start_page; | ||
1218 | unsigned long start; | ||
1219 | struct resmap *res_map = dispc.res_map[mtype]; | ||
1220 | |||
1221 | BUG_ON(mtype >= DISPC_MEMTYPE_NUM || res_map == NULL || !size); | ||
1222 | |||
1223 | size = PAGE_ALIGN(size) / PAGE_SIZE; | ||
1224 | start_page = 0; | ||
1225 | total = 0; | ||
1226 | for (i = 0; i < res_map->page_cnt; i++) { | ||
1227 | if (resmap_page_reserved(res_map, i)) { | ||
1228 | start_page = i + 1; | ||
1229 | total = 0; | ||
1230 | } else if (++total == size) | ||
1231 | break; | ||
1232 | } | ||
1233 | if (total < size) | ||
1234 | return 0; | ||
1235 | |||
1236 | start = res_map->start + start_page * PAGE_SIZE; | ||
1237 | resmap_reserve_region(start, size * PAGE_SIZE); | ||
1238 | |||
1239 | return start; | ||
1240 | } | ||
1241 | |||
1242 | /* Note that this will only work for user mappings, we don't deal with | ||
1243 | * kernel mappings here, so fbcon will keep using the old region. | ||
1244 | */ | ||
1245 | static int omap_dispc_setup_mem(int plane, size_t size, int mem_type, | ||
1246 | unsigned long *paddr) | ||
1247 | { | ||
1248 | struct omapfb_mem_region *rg; | ||
1249 | unsigned long new_addr = 0; | ||
1250 | |||
1251 | if ((unsigned)plane > dispc.mem_desc.region_cnt) | ||
1252 | return -EINVAL; | ||
1253 | if (mem_type >= DISPC_MEMTYPE_NUM) | ||
1254 | return -EINVAL; | ||
1255 | if (dispc.res_map[mem_type] == NULL) | ||
1256 | return -ENOMEM; | ||
1257 | rg = &dispc.mem_desc.region[plane]; | ||
1258 | if (size == rg->size && mem_type == rg->type) | ||
1259 | return 0; | ||
1260 | if (atomic_read(&dispc.map_count[plane])) | ||
1261 | return -EBUSY; | ||
1262 | if (rg->size != 0) | ||
1263 | resmap_free_region(rg->paddr, rg->size); | ||
1264 | if (size != 0) { | ||
1265 | new_addr = resmap_alloc_region(mem_type, size); | ||
1266 | if (!new_addr) { | ||
1267 | /* Reallocate old region. */ | ||
1268 | resmap_reserve_region(rg->paddr, rg->size); | ||
1269 | return -ENOMEM; | ||
1270 | } | ||
1271 | } | ||
1272 | rg->paddr = new_addr; | ||
1273 | rg->size = size; | ||
1274 | rg->type = mem_type; | ||
1275 | |||
1276 | *paddr = new_addr; | ||
1277 | |||
1278 | return 0; | ||
1279 | } | ||
1280 | |||
1281 | static int setup_fbmem(struct omapfb_mem_desc *req_md) | ||
1282 | { | ||
1283 | struct omapfb_mem_region *rg; | ||
1284 | int i; | ||
1285 | int r; | ||
1286 | unsigned long mem_start[DISPC_MEMTYPE_NUM]; | ||
1287 | unsigned long mem_end[DISPC_MEMTYPE_NUM]; | ||
1288 | |||
1289 | if (!req_md->region_cnt) { | ||
1290 | dev_err(dispc.fbdev->dev, "no memory regions defined\n"); | ||
1291 | return -ENOENT; | ||
1292 | } | ||
1293 | |||
1294 | rg = &req_md->region[0]; | ||
1295 | memset(mem_start, 0xff, sizeof(mem_start)); | ||
1296 | memset(mem_end, 0, sizeof(mem_end)); | ||
1297 | |||
1298 | for (i = 0; i < req_md->region_cnt; i++, rg++) { | ||
1299 | int mtype; | ||
1300 | if (rg->paddr) { | ||
1301 | rg->alloc = 0; | ||
1302 | if (rg->vaddr == NULL) { | ||
1303 | rg->map = 1; | ||
1304 | if ((r = mmap_kern(rg)) < 0) | ||
1305 | return r; | ||
1306 | } | ||
1307 | } else { | ||
1308 | if (rg->type != OMAPFB_MEMTYPE_SDRAM) { | ||
1309 | dev_err(dispc.fbdev->dev, | ||
1310 | "unsupported memory type\n"); | ||
1311 | return -EINVAL; | ||
1312 | } | ||
1313 | rg->alloc = rg->map = 1; | ||
1314 | if ((r = alloc_fbmem(rg)) < 0) | ||
1315 | return r; | ||
1316 | } | ||
1317 | mtype = rg->type; | ||
1318 | |||
1319 | if (rg->paddr < mem_start[mtype]) | ||
1320 | mem_start[mtype] = rg->paddr; | ||
1321 | if (rg->paddr + rg->size > mem_end[mtype]) | ||
1322 | mem_end[mtype] = rg->paddr + rg->size; | ||
1323 | } | ||
1324 | |||
1325 | for (i = 0; i < DISPC_MEMTYPE_NUM; i++) { | ||
1326 | unsigned long start; | ||
1327 | size_t size; | ||
1328 | if (mem_end[i] == 0) | ||
1329 | continue; | ||
1330 | start = mem_start[i]; | ||
1331 | size = mem_end[i] - start; | ||
1332 | dispc.res_map[i] = init_resmap(start, size); | ||
1333 | r = -ENOMEM; | ||
1334 | if (dispc.res_map[i] == NULL) | ||
1335 | goto fail; | ||
1336 | /* Initial state is that everything is reserved. This | ||
1337 | * includes possible holes as well, which will never be | ||
1338 | * freed. | ||
1339 | */ | ||
1340 | resmap_reserve_region(start, size); | ||
1341 | } | ||
1342 | |||
1343 | dispc.mem_desc = *req_md; | ||
1344 | |||
1345 | return 0; | ||
1346 | fail: | ||
1347 | for (i = 0; i < DISPC_MEMTYPE_NUM; i++) { | ||
1348 | if (dispc.res_map[i] != NULL) | ||
1349 | cleanup_resmap(dispc.res_map[i]); | ||
1350 | } | ||
1351 | return r; | ||
1352 | } | ||
1353 | |||
1354 | static void cleanup_fbmem(void) | ||
1355 | { | ||
1356 | struct omapfb_mem_region *rg; | ||
1357 | int i; | ||
1358 | |||
1359 | for (i = 0; i < DISPC_MEMTYPE_NUM; i++) { | ||
1360 | if (dispc.res_map[i] != NULL) | ||
1361 | cleanup_resmap(dispc.res_map[i]); | ||
1362 | } | ||
1363 | rg = &dispc.mem_desc.region[0]; | ||
1364 | for (i = 0; i < dispc.mem_desc.region_cnt; i++, rg++) { | ||
1365 | if (rg->alloc) | ||
1366 | free_fbmem(rg); | ||
1367 | else { | ||
1368 | if (rg->map) | ||
1369 | unmap_kern(rg); | ||
1370 | } | ||
1371 | } | ||
1372 | } | ||
1373 | |||
1374 | static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode, | ||
1375 | struct omapfb_mem_desc *req_vram) | ||
1376 | { | ||
1377 | int r; | ||
1378 | u32 l; | ||
1379 | struct lcd_panel *panel = fbdev->panel; | ||
1380 | void __iomem *ram_fw_base; | ||
1381 | int tmo = 10000; | ||
1382 | int skip_init = 0; | ||
1383 | int i; | ||
1384 | |||
1385 | memset(&dispc, 0, sizeof(dispc)); | ||
1386 | |||
1387 | dispc.base = ioremap(DISPC_BASE, SZ_1K); | ||
1388 | if (!dispc.base) { | ||
1389 | dev_err(fbdev->dev, "can't ioremap DISPC\n"); | ||
1390 | return -ENOMEM; | ||
1391 | } | ||
1392 | |||
1393 | dispc.fbdev = fbdev; | ||
1394 | dispc.ext_mode = ext_mode; | ||
1395 | |||
1396 | init_completion(&dispc.frame_done); | ||
1397 | |||
1398 | if ((r = get_dss_clocks()) < 0) | ||
1399 | goto fail0; | ||
1400 | |||
1401 | enable_lcd_clocks(1); | ||
1402 | |||
1403 | #ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT | ||
1404 | l = dispc_read_reg(DISPC_CONTROL); | ||
1405 | /* LCD enabled ? */ | ||
1406 | if (l & 1) { | ||
1407 | pr_info("omapfb: skipping hardware initialization\n"); | ||
1408 | skip_init = 1; | ||
1409 | } | ||
1410 | #endif | ||
1411 | |||
1412 | if (!skip_init) { | ||
1413 | /* Reset monitoring works only w/ the 54M clk */ | ||
1414 | enable_digit_clocks(1); | ||
1415 | |||
1416 | /* Soft reset */ | ||
1417 | MOD_REG_FLD(DISPC_SYSCONFIG, 1 << 1, 1 << 1); | ||
1418 | |||
1419 | while (!(dispc_read_reg(DISPC_SYSSTATUS) & 1)) { | ||
1420 | if (!--tmo) { | ||
1421 | dev_err(dispc.fbdev->dev, "soft reset failed\n"); | ||
1422 | r = -ENODEV; | ||
1423 | enable_digit_clocks(0); | ||
1424 | goto fail1; | ||
1425 | } | ||
1426 | } | ||
1427 | |||
1428 | enable_digit_clocks(0); | ||
1429 | } | ||
1430 | |||
1431 | /* Enable smart standby/idle, autoidle and wakeup */ | ||
1432 | l = dispc_read_reg(DISPC_SYSCONFIG); | ||
1433 | l &= ~((3 << 12) | (3 << 3)); | ||
1434 | l |= (2 << 12) | (2 << 3) | (1 << 2) | (1 << 0); | ||
1435 | dispc_write_reg(DISPC_SYSCONFIG, l); | ||
1436 | omap_writel(1 << 0, DSS_BASE + DSS_SYSCONFIG); | ||
1437 | |||
1438 | /* Set functional clock autogating */ | ||
1439 | l = dispc_read_reg(DISPC_CONFIG); | ||
1440 | l |= 1 << 9; | ||
1441 | dispc_write_reg(DISPC_CONFIG, l); | ||
1442 | |||
1443 | l = dispc_read_reg(DISPC_IRQSTATUS); | ||
1444 | dispc_write_reg(DISPC_IRQSTATUS, l); | ||
1445 | |||
1446 | recalc_irq_mask(); | ||
1447 | |||
1448 | if ((r = request_irq(INT_24XX_DSS_IRQ, omap_dispc_irq_handler, | ||
1449 | 0, MODULE_NAME, fbdev)) < 0) { | ||
1450 | dev_err(dispc.fbdev->dev, "can't get DSS IRQ\n"); | ||
1451 | goto fail1; | ||
1452 | } | ||
1453 | |||
1454 | /* L3 firewall setting: enable access to OCM RAM */ | ||
1455 | ram_fw_base = ioremap(0x68005000, SZ_1K); | ||
1456 | if (!ram_fw_base) { | ||
1457 | dev_err(dispc.fbdev->dev, "Cannot ioremap to enable OCM RAM\n"); | ||
1458 | goto fail1; | ||
1459 | } | ||
1460 | __raw_writel(0x402000b0, ram_fw_base + 0xa0); | ||
1461 | iounmap(ram_fw_base); | ||
1462 | |||
1463 | if ((r = alloc_palette_ram()) < 0) | ||
1464 | goto fail2; | ||
1465 | |||
1466 | if ((r = setup_fbmem(req_vram)) < 0) | ||
1467 | goto fail3; | ||
1468 | |||
1469 | if (!skip_init) { | ||
1470 | for (i = 0; i < dispc.mem_desc.region_cnt; i++) { | ||
1471 | memset(dispc.mem_desc.region[i].vaddr, 0, | ||
1472 | dispc.mem_desc.region[i].size); | ||
1473 | } | ||
1474 | |||
1475 | /* Set logic clock to fck, pixel clock to fck/2 for now */ | ||
1476 | MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(16, 8), 1 << 16); | ||
1477 | MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(0, 8), 2 << 0); | ||
1478 | |||
1479 | setup_plane_fifo(0, ext_mode); | ||
1480 | setup_plane_fifo(1, ext_mode); | ||
1481 | setup_plane_fifo(2, ext_mode); | ||
1482 | |||
1483 | setup_color_conv_coef(); | ||
1484 | |||
1485 | set_lcd_tft_mode(panel->config & OMAP_LCDC_PANEL_TFT); | ||
1486 | set_load_mode(DISPC_LOAD_FRAME_ONLY); | ||
1487 | |||
1488 | if (!ext_mode) { | ||
1489 | set_lcd_data_lines(panel->data_lines); | ||
1490 | omap_dispc_set_lcd_size(panel->x_res, panel->y_res); | ||
1491 | set_lcd_timings(); | ||
1492 | } else | ||
1493 | set_lcd_data_lines(panel->bpp); | ||
1494 | enable_rfbi_mode(ext_mode); | ||
1495 | } | ||
1496 | |||
1497 | l = dispc_read_reg(DISPC_REVISION); | ||
1498 | pr_info("omapfb: DISPC version %d.%d initialized\n", | ||
1499 | l >> 4 & 0x0f, l & 0x0f); | ||
1500 | enable_lcd_clocks(0); | ||
1501 | |||
1502 | return 0; | ||
1503 | fail3: | ||
1504 | free_palette_ram(); | ||
1505 | fail2: | ||
1506 | free_irq(INT_24XX_DSS_IRQ, fbdev); | ||
1507 | fail1: | ||
1508 | enable_lcd_clocks(0); | ||
1509 | put_dss_clocks(); | ||
1510 | fail0: | ||
1511 | iounmap(dispc.base); | ||
1512 | return r; | ||
1513 | } | ||
1514 | |||
1515 | static void omap_dispc_cleanup(void) | ||
1516 | { | ||
1517 | int i; | ||
1518 | |||
1519 | omap_dispc_set_update_mode(OMAPFB_UPDATE_DISABLED); | ||
1520 | /* This will also disable clocks that are on */ | ||
1521 | for (i = 0; i < dispc.mem_desc.region_cnt; i++) | ||
1522 | omap_dispc_enable_plane(i, 0); | ||
1523 | cleanup_fbmem(); | ||
1524 | free_palette_ram(); | ||
1525 | free_irq(INT_24XX_DSS_IRQ, dispc.fbdev); | ||
1526 | put_dss_clocks(); | ||
1527 | iounmap(dispc.base); | ||
1528 | } | ||
1529 | |||
1530 | const struct lcd_ctrl omap2_int_ctrl = { | ||
1531 | .name = "internal", | ||
1532 | .init = omap_dispc_init, | ||
1533 | .cleanup = omap_dispc_cleanup, | ||
1534 | .get_caps = omap_dispc_get_caps, | ||
1535 | .set_update_mode = omap_dispc_set_update_mode, | ||
1536 | .get_update_mode = omap_dispc_get_update_mode, | ||
1537 | .update_window = omap_dispc_update_window, | ||
1538 | .suspend = omap_dispc_suspend, | ||
1539 | .resume = omap_dispc_resume, | ||
1540 | .setup_plane = omap_dispc_setup_plane, | ||
1541 | .setup_mem = omap_dispc_setup_mem, | ||
1542 | .set_scale = omap_dispc_set_scale, | ||
1543 | .enable_plane = omap_dispc_enable_plane, | ||
1544 | .set_color_key = omap_dispc_set_color_key, | ||
1545 | .get_color_key = omap_dispc_get_color_key, | ||
1546 | .mmap = omap_dispc_mmap_user, | ||
1547 | }; | ||
diff --git a/drivers/video/omap/dispc.h b/drivers/video/omap/dispc.h deleted file mode 100644 index c15ea77f0604..000000000000 --- a/drivers/video/omap/dispc.h +++ /dev/null | |||
@@ -1,46 +0,0 @@ | |||
1 | #ifndef _DISPC_H | ||
2 | #define _DISPC_H | ||
3 | |||
4 | #include <linux/interrupt.h> | ||
5 | |||
6 | #define DISPC_PLANE_GFX 0 | ||
7 | #define DISPC_PLANE_VID1 1 | ||
8 | #define DISPC_PLANE_VID2 2 | ||
9 | |||
10 | #define DISPC_RGB_1_BPP 0x00 | ||
11 | #define DISPC_RGB_2_BPP 0x01 | ||
12 | #define DISPC_RGB_4_BPP 0x02 | ||
13 | #define DISPC_RGB_8_BPP 0x03 | ||
14 | #define DISPC_RGB_12_BPP 0x04 | ||
15 | #define DISPC_RGB_16_BPP 0x06 | ||
16 | #define DISPC_RGB_24_BPP 0x08 | ||
17 | #define DISPC_RGB_24_BPP_UNPACK_32 0x09 | ||
18 | #define DISPC_YUV2_422 0x0a | ||
19 | #define DISPC_UYVY_422 0x0b | ||
20 | |||
21 | #define DISPC_BURST_4x32 0 | ||
22 | #define DISPC_BURST_8x32 1 | ||
23 | #define DISPC_BURST_16x32 2 | ||
24 | |||
25 | #define DISPC_LOAD_CLUT_AND_FRAME 0x00 | ||
26 | #define DISPC_LOAD_CLUT_ONLY 0x01 | ||
27 | #define DISPC_LOAD_FRAME_ONLY 0x02 | ||
28 | #define DISPC_LOAD_CLUT_ONCE_FRAME 0x03 | ||
29 | |||
30 | #define DISPC_TFT_DATA_LINES_12 0 | ||
31 | #define DISPC_TFT_DATA_LINES_16 1 | ||
32 | #define DISPC_TFT_DATA_LINES_18 2 | ||
33 | #define DISPC_TFT_DATA_LINES_24 3 | ||
34 | |||
35 | extern void omap_dispc_set_lcd_size(int width, int height); | ||
36 | |||
37 | extern void omap_dispc_enable_lcd_out(int enable); | ||
38 | extern void omap_dispc_enable_digit_out(int enable); | ||
39 | |||
40 | extern int omap_dispc_request_irq(unsigned long irq_mask, | ||
41 | void (*callback)(void *data), void *data); | ||
42 | extern void omap_dispc_free_irq(unsigned long irq_mask, | ||
43 | void (*callback)(void *data), void *data); | ||
44 | |||
45 | extern const struct lcd_ctrl omap2_int_ctrl; | ||
46 | #endif | ||
diff --git a/drivers/video/omap/hwa742.c b/drivers/video/omap/hwa742.c index 084aa0ac562b..9f1d23c319cb 100644 --- a/drivers/video/omap/hwa742.c +++ b/drivers/video/omap/hwa742.c | |||
@@ -28,7 +28,6 @@ | |||
28 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
29 | 29 | ||
30 | #include <plat/dma.h> | 30 | #include <plat/dma.h> |
31 | #include <plat/hwa742.h> | ||
32 | #include "omapfb.h" | 31 | #include "omapfb.h" |
33 | 32 | ||
34 | #define HWA742_REV_CODE_REG 0x0 | 33 | #define HWA742_REV_CODE_REG 0x0 |
@@ -942,7 +941,6 @@ static int hwa742_init(struct omapfb_device *fbdev, int ext_mode, | |||
942 | unsigned long sys_clk, pix_clk; | 941 | unsigned long sys_clk, pix_clk; |
943 | int extif_mem_div; | 942 | int extif_mem_div; |
944 | struct omapfb_platform_data *omapfb_conf; | 943 | struct omapfb_platform_data *omapfb_conf; |
945 | struct hwa742_platform_data *ctrl_conf; | ||
946 | 944 | ||
947 | BUG_ON(!fbdev->ext_if || !fbdev->int_ctrl); | 945 | BUG_ON(!fbdev->ext_if || !fbdev->int_ctrl); |
948 | 946 | ||
@@ -951,13 +949,6 @@ static int hwa742_init(struct omapfb_device *fbdev, int ext_mode, | |||
951 | hwa742.int_ctrl = fbdev->int_ctrl; | 949 | hwa742.int_ctrl = fbdev->int_ctrl; |
952 | 950 | ||
953 | omapfb_conf = fbdev->dev->platform_data; | 951 | omapfb_conf = fbdev->dev->platform_data; |
954 | ctrl_conf = omapfb_conf->ctrl_platform_data; | ||
955 | |||
956 | if (ctrl_conf == NULL) { | ||
957 | dev_err(fbdev->dev, "HWA742: missing platform data\n"); | ||
958 | r = -ENOENT; | ||
959 | goto err1; | ||
960 | } | ||
961 | 952 | ||
962 | hwa742.sys_ck = clk_get(NULL, "hwa_sys_ck"); | 953 | hwa742.sys_ck = clk_get(NULL, "hwa_sys_ck"); |
963 | 954 | ||
@@ -995,14 +986,12 @@ static int hwa742_init(struct omapfb_device *fbdev, int ext_mode, | |||
995 | goto err4; | 986 | goto err4; |
996 | } | 987 | } |
997 | 988 | ||
998 | if (ctrl_conf->te_connected) { | 989 | if ((r = setup_tearsync(pix_clk, extif_mem_div)) < 0) { |
999 | if ((r = setup_tearsync(pix_clk, extif_mem_div)) < 0) { | 990 | dev_err(hwa742.fbdev->dev, |
1000 | dev_err(hwa742.fbdev->dev, | 991 | "HWA742: can't setup tearing synchronization\n"); |
1001 | "HWA742: can't setup tearing synchronization\n"); | 992 | goto err4; |
1002 | goto err4; | ||
1003 | } | ||
1004 | hwa742.te_connected = 1; | ||
1005 | } | 993 | } |
994 | hwa742.te_connected = 1; | ||
1006 | 995 | ||
1007 | hwa742.max_transmit_size = hwa742.extif->max_transmit_size; | 996 | hwa742.max_transmit_size = hwa742.extif->max_transmit_size; |
1008 | 997 | ||
diff --git a/drivers/video/omap/lcd_inn1610.c b/drivers/video/omap/lcd_inn1610.c index 7e8bd8e08a98..e3d3d135aa48 100644 --- a/drivers/video/omap/lcd_inn1610.c +++ b/drivers/video/omap/lcd_inn1610.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
23 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
24 | 24 | ||
25 | #include <asm/gpio.h> | 25 | #include <linux/gpio.h> |
26 | #include "omapfb.h" | 26 | #include "omapfb.h" |
27 | 27 | ||
28 | #define MODULE_NAME "omapfb-lcd_h3" | 28 | #define MODULE_NAME "omapfb-lcd_h3" |
@@ -32,20 +32,18 @@ static int innovator1610_panel_init(struct lcd_panel *panel, | |||
32 | { | 32 | { |
33 | int r = 0; | 33 | int r = 0; |
34 | 34 | ||
35 | if (gpio_request(14, "lcd_en0")) { | 35 | /* configure GPIO(14, 15) as outputs */ |
36 | if (gpio_request_one(14, GPIOF_OUT_INIT_LOW, "lcd_en0")) { | ||
36 | pr_err(MODULE_NAME ": can't request GPIO 14\n"); | 37 | pr_err(MODULE_NAME ": can't request GPIO 14\n"); |
37 | r = -1; | 38 | r = -1; |
38 | goto exit; | 39 | goto exit; |
39 | } | 40 | } |
40 | if (gpio_request(15, "lcd_en1")) { | 41 | if (gpio_request_one(15, GPIOF_OUT_INIT_LOW, "lcd_en1")) { |
41 | pr_err(MODULE_NAME ": can't request GPIO 15\n"); | 42 | pr_err(MODULE_NAME ": can't request GPIO 15\n"); |
42 | gpio_free(14); | 43 | gpio_free(14); |
43 | r = -1; | 44 | r = -1; |
44 | goto exit; | 45 | goto exit; |
45 | } | 46 | } |
46 | /* configure GPIO(14, 15) as outputs */ | ||
47 | gpio_direction_output(14, 0); | ||
48 | gpio_direction_output(15, 0); | ||
49 | exit: | 47 | exit: |
50 | return r; | 48 | return r; |
51 | } | 49 | } |
diff --git a/drivers/video/omap/lcd_mipid.c b/drivers/video/omap/lcd_mipid.c index 8d546dd55e81..e3880c4a0bb1 100644 --- a/drivers/video/omap/lcd_mipid.c +++ b/drivers/video/omap/lcd_mipid.c | |||
@@ -609,19 +609,7 @@ static struct spi_driver mipid_spi_driver = { | |||
609 | .remove = __devexit_p(mipid_spi_remove), | 609 | .remove = __devexit_p(mipid_spi_remove), |
610 | }; | 610 | }; |
611 | 611 | ||
612 | static int __init mipid_drv_init(void) | 612 | module_spi_driver(mipid_spi_driver); |
613 | { | ||
614 | spi_register_driver(&mipid_spi_driver); | ||
615 | |||
616 | return 0; | ||
617 | } | ||
618 | module_init(mipid_drv_init); | ||
619 | |||
620 | static void __exit mipid_drv_cleanup(void) | ||
621 | { | ||
622 | spi_unregister_driver(&mipid_spi_driver); | ||
623 | } | ||
624 | module_exit(mipid_drv_cleanup); | ||
625 | 613 | ||
626 | MODULE_DESCRIPTION("MIPI display driver"); | 614 | MODULE_DESCRIPTION("MIPI display driver"); |
627 | MODULE_LICENSE("GPL"); | 615 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/video/omap/omapfb.h b/drivers/video/omap/omapfb.h index af3c9e571ec3..2921d20e4fba 100644 --- a/drivers/video/omap/omapfb.h +++ b/drivers/video/omap/omapfb.h | |||
@@ -47,6 +47,27 @@ | |||
47 | 47 | ||
48 | struct omapfb_device; | 48 | struct omapfb_device; |
49 | 49 | ||
50 | #define OMAPFB_PLANE_NUM 1 | ||
51 | |||
52 | struct omapfb_mem_region { | ||
53 | u32 paddr; | ||
54 | void __iomem *vaddr; | ||
55 | unsigned long size; | ||
56 | u8 type; /* OMAPFB_PLANE_MEM_* */ | ||
57 | enum omapfb_color_format format;/* OMAPFB_COLOR_* */ | ||
58 | unsigned format_used:1; /* Must be set when format is set. | ||
59 | * Needed b/c of the badly chosen 0 | ||
60 | * base for OMAPFB_COLOR_* values | ||
61 | */ | ||
62 | unsigned alloc:1; /* allocated by the driver */ | ||
63 | unsigned map:1; /* kernel mapped by the driver */ | ||
64 | }; | ||
65 | |||
66 | struct omapfb_mem_desc { | ||
67 | int region_cnt; | ||
68 | struct omapfb_mem_region region[OMAPFB_PLANE_NUM]; | ||
69 | }; | ||
70 | |||
50 | struct lcd_panel { | 71 | struct lcd_panel { |
51 | const char *name; | 72 | const char *name; |
52 | int config; /* TFT/STN, signal inversion */ | 73 | int config; /* TFT/STN, signal inversion */ |
@@ -207,11 +228,7 @@ struct omapfb_device { | |||
207 | struct platform_device *dssdev; /* dummy dev for clocks */ | 228 | struct platform_device *dssdev; /* dummy dev for clocks */ |
208 | }; | 229 | }; |
209 | 230 | ||
210 | #ifdef CONFIG_ARCH_OMAP1 | ||
211 | extern struct lcd_ctrl omap1_lcd_ctrl; | 231 | extern struct lcd_ctrl omap1_lcd_ctrl; |
212 | #else | ||
213 | extern struct lcd_ctrl omap2_disp_ctrl; | ||
214 | #endif | ||
215 | 232 | ||
216 | extern void omapfb_register_panel(struct lcd_panel *panel); | 233 | extern void omapfb_register_panel(struct lcd_panel *panel); |
217 | extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval); | 234 | extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval); |
diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c index b291bfaac80e..f54b463709e9 100644 --- a/drivers/video/omap/omapfb_main.c +++ b/drivers/video/omap/omapfb_main.c | |||
@@ -34,7 +34,6 @@ | |||
34 | 34 | ||
35 | #include "omapfb.h" | 35 | #include "omapfb.h" |
36 | #include "lcdc.h" | 36 | #include "lcdc.h" |
37 | #include "dispc.h" | ||
38 | 37 | ||
39 | #define MODULE_NAME "omapfb" | 38 | #define MODULE_NAME "omapfb" |
40 | 39 | ||
@@ -104,29 +103,17 @@ static struct platform_device omapdss_device = { | |||
104 | * --------------------------------------------------------------------------- | 103 | * --------------------------------------------------------------------------- |
105 | */ | 104 | */ |
106 | extern struct lcd_ctrl hwa742_ctrl; | 105 | extern struct lcd_ctrl hwa742_ctrl; |
107 | extern struct lcd_ctrl blizzard_ctrl; | ||
108 | 106 | ||
109 | static const struct lcd_ctrl *ctrls[] = { | 107 | static const struct lcd_ctrl *ctrls[] = { |
110 | #ifdef CONFIG_ARCH_OMAP1 | ||
111 | &omap1_int_ctrl, | 108 | &omap1_int_ctrl, |
112 | #else | ||
113 | &omap2_int_ctrl, | ||
114 | #endif | ||
115 | 109 | ||
116 | #ifdef CONFIG_FB_OMAP_LCDC_HWA742 | 110 | #ifdef CONFIG_FB_OMAP_LCDC_HWA742 |
117 | &hwa742_ctrl, | 111 | &hwa742_ctrl, |
118 | #endif | 112 | #endif |
119 | #ifdef CONFIG_FB_OMAP_LCDC_BLIZZARD | ||
120 | &blizzard_ctrl, | ||
121 | #endif | ||
122 | }; | 113 | }; |
123 | 114 | ||
124 | #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL | 115 | #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL |
125 | #ifdef CONFIG_ARCH_OMAP1 | ||
126 | extern struct lcd_ctrl_extif omap1_ext_if; | 116 | extern struct lcd_ctrl_extif omap1_ext_if; |
127 | #else | ||
128 | extern struct lcd_ctrl_extif omap2_ext_if; | ||
129 | #endif | ||
130 | #endif | 117 | #endif |
131 | 118 | ||
132 | static void omapfb_rqueue_lock(struct omapfb_device *fbdev) | 119 | static void omapfb_rqueue_lock(struct omapfb_device *fbdev) |
@@ -170,11 +157,6 @@ static int ctrl_init(struct omapfb_device *fbdev) | |||
170 | fbdev->mem_desc.region[i].size = | 157 | fbdev->mem_desc.region[i].size = |
171 | PAGE_ALIGN(def_vram[i]); | 158 | PAGE_ALIGN(def_vram[i]); |
172 | fbdev->mem_desc.region_cnt = i; | 159 | fbdev->mem_desc.region_cnt = i; |
173 | } else { | ||
174 | struct omapfb_platform_data *conf; | ||
175 | |||
176 | conf = fbdev->dev->platform_data; | ||
177 | fbdev->mem_desc = conf->mem_desc; | ||
178 | } | 160 | } |
179 | 161 | ||
180 | if (!fbdev->mem_desc.region_cnt) { | 162 | if (!fbdev->mem_desc.region_cnt) { |
@@ -880,7 +862,7 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | |||
880 | 862 | ||
881 | if (fbdev->ctrl->setup_mem == NULL) | 863 | if (fbdev->ctrl->setup_mem == NULL) |
882 | return -ENODEV; | 864 | return -ENODEV; |
883 | if (mi->type > OMAPFB_MEMTYPE_MAX) | 865 | if (mi->type != OMAPFB_MEMTYPE_SDRAM) |
884 | return -EINVAL; | 866 | return -EINVAL; |
885 | 867 | ||
886 | size = PAGE_ALIGN(mi->size); | 868 | size = PAGE_ALIGN(mi->size); |
@@ -1721,17 +1703,10 @@ static int omapfb_do_probe(struct platform_device *pdev, | |||
1721 | 1703 | ||
1722 | mutex_init(&fbdev->rqueue_mutex); | 1704 | mutex_init(&fbdev->rqueue_mutex); |
1723 | 1705 | ||
1724 | #ifdef CONFIG_ARCH_OMAP1 | ||
1725 | fbdev->int_ctrl = &omap1_int_ctrl; | 1706 | fbdev->int_ctrl = &omap1_int_ctrl; |
1726 | #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL | 1707 | #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL |
1727 | fbdev->ext_if = &omap1_ext_if; | 1708 | fbdev->ext_if = &omap1_ext_if; |
1728 | #endif | 1709 | #endif |
1729 | #else /* OMAP2 */ | ||
1730 | fbdev->int_ctrl = &omap2_int_ctrl; | ||
1731 | #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL | ||
1732 | fbdev->ext_if = &omap2_ext_if; | ||
1733 | #endif | ||
1734 | #endif | ||
1735 | if (omapfb_find_ctrl(fbdev) < 0) { | 1710 | if (omapfb_find_ctrl(fbdev) < 0) { |
1736 | dev_err(fbdev->dev, | 1711 | dev_err(fbdev->dev, |
1737 | "LCD controller not found, board not supported\n"); | 1712 | "LCD controller not found, board not supported\n"); |
@@ -1766,8 +1741,7 @@ static int omapfb_do_probe(struct platform_device *pdev, | |||
1766 | 1741 | ||
1767 | #ifdef CONFIG_FB_OMAP_DMA_TUNE | 1742 | #ifdef CONFIG_FB_OMAP_DMA_TUNE |
1768 | /* Set DMA priority for EMIFF access to highest */ | 1743 | /* Set DMA priority for EMIFF access to highest */ |
1769 | if (cpu_class_is_omap1()) | 1744 | omap_set_dma_priority(0, OMAP_DMA_PORT_EMIFF, 15); |
1770 | omap_set_dma_priority(0, OMAP_DMA_PORT_EMIFF, 15); | ||
1771 | #endif | 1745 | #endif |
1772 | 1746 | ||
1773 | r = ctrl_change_mode(fbdev->fb_info[0]); | 1747 | r = ctrl_change_mode(fbdev->fb_info[0]); |
diff --git a/drivers/video/omap/rfbi.c b/drivers/video/omap/rfbi.c deleted file mode 100644 index 2c1a3402bef0..000000000000 --- a/drivers/video/omap/rfbi.c +++ /dev/null | |||
@@ -1,598 +0,0 @@ | |||
1 | /* | ||
2 | * OMAP2 Remote Frame Buffer Interface support | ||
3 | * | ||
4 | * Copyright (C) 2005 Nokia Corporation | ||
5 | * Author: Juha Yrjölä <juha.yrjola@nokia.com> | ||
6 | * Imre Deak <imre.deak@nokia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
21 | */ | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/i2c.h> | ||
25 | #include <linux/err.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/clk.h> | ||
28 | #include <linux/io.h> | ||
29 | #include <linux/platform_device.h> | ||
30 | |||
31 | #include "omapfb.h" | ||
32 | #include "dispc.h" | ||
33 | |||
34 | /* To work around an RFBI transfer rate limitation */ | ||
35 | #define OMAP_RFBI_RATE_LIMIT 1 | ||
36 | |||
37 | #define RFBI_BASE 0x48050800 | ||
38 | #define RFBI_REVISION 0x0000 | ||
39 | #define RFBI_SYSCONFIG 0x0010 | ||
40 | #define RFBI_SYSSTATUS 0x0014 | ||
41 | #define RFBI_CONTROL 0x0040 | ||
42 | #define RFBI_PIXEL_CNT 0x0044 | ||
43 | #define RFBI_LINE_NUMBER 0x0048 | ||
44 | #define RFBI_CMD 0x004c | ||
45 | #define RFBI_PARAM 0x0050 | ||
46 | #define RFBI_DATA 0x0054 | ||
47 | #define RFBI_READ 0x0058 | ||
48 | #define RFBI_STATUS 0x005c | ||
49 | #define RFBI_CONFIG0 0x0060 | ||
50 | #define RFBI_ONOFF_TIME0 0x0064 | ||
51 | #define RFBI_CYCLE_TIME0 0x0068 | ||
52 | #define RFBI_DATA_CYCLE1_0 0x006c | ||
53 | #define RFBI_DATA_CYCLE2_0 0x0070 | ||
54 | #define RFBI_DATA_CYCLE3_0 0x0074 | ||
55 | #define RFBI_VSYNC_WIDTH 0x0090 | ||
56 | #define RFBI_HSYNC_WIDTH 0x0094 | ||
57 | |||
58 | #define DISPC_BASE 0x48050400 | ||
59 | #define DISPC_CONTROL 0x0040 | ||
60 | #define DISPC_IRQ_FRAMEMASK 0x0001 | ||
61 | |||
62 | static struct { | ||
63 | void __iomem *base; | ||
64 | void (*lcdc_callback)(void *data); | ||
65 | void *lcdc_callback_data; | ||
66 | unsigned long l4_khz; | ||
67 | int bits_per_cycle; | ||
68 | struct omapfb_device *fbdev; | ||
69 | struct clk *dss_ick; | ||
70 | struct clk *dss1_fck; | ||
71 | unsigned tearsync_pin_cnt; | ||
72 | unsigned tearsync_mode; | ||
73 | } rfbi; | ||
74 | |||
75 | static inline void rfbi_write_reg(int idx, u32 val) | ||
76 | { | ||
77 | __raw_writel(val, rfbi.base + idx); | ||
78 | } | ||
79 | |||
80 | static inline u32 rfbi_read_reg(int idx) | ||
81 | { | ||
82 | return __raw_readl(rfbi.base + idx); | ||
83 | } | ||
84 | |||
85 | static int rfbi_get_clocks(void) | ||
86 | { | ||
87 | rfbi.dss_ick = clk_get(&rfbi.fbdev->dssdev->dev, "ick"); | ||
88 | if (IS_ERR(rfbi.dss_ick)) { | ||
89 | dev_err(rfbi.fbdev->dev, "can't get ick\n"); | ||
90 | return PTR_ERR(rfbi.dss_ick); | ||
91 | } | ||
92 | |||
93 | rfbi.dss1_fck = clk_get(&rfbi.fbdev->dssdev->dev, "fck"); | ||
94 | if (IS_ERR(rfbi.dss1_fck)) { | ||
95 | dev_err(rfbi.fbdev->dev, "can't get dss1_fck\n"); | ||
96 | clk_put(rfbi.dss_ick); | ||
97 | return PTR_ERR(rfbi.dss1_fck); | ||
98 | } | ||
99 | |||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static void rfbi_put_clocks(void) | ||
104 | { | ||
105 | clk_put(rfbi.dss1_fck); | ||
106 | clk_put(rfbi.dss_ick); | ||
107 | } | ||
108 | |||
109 | static void rfbi_enable_clocks(int enable) | ||
110 | { | ||
111 | if (enable) { | ||
112 | clk_enable(rfbi.dss_ick); | ||
113 | clk_enable(rfbi.dss1_fck); | ||
114 | } else { | ||
115 | clk_disable(rfbi.dss1_fck); | ||
116 | clk_disable(rfbi.dss_ick); | ||
117 | } | ||
118 | } | ||
119 | |||
120 | |||
121 | #ifdef VERBOSE | ||
122 | static void rfbi_print_timings(void) | ||
123 | { | ||
124 | u32 l; | ||
125 | u32 time; | ||
126 | |||
127 | l = rfbi_read_reg(RFBI_CONFIG0); | ||
128 | time = 1000000000 / rfbi.l4_khz; | ||
129 | if (l & (1 << 4)) | ||
130 | time *= 2; | ||
131 | |||
132 | dev_dbg(rfbi.fbdev->dev, "Tick time %u ps\n", time); | ||
133 | l = rfbi_read_reg(RFBI_ONOFF_TIME0); | ||
134 | dev_dbg(rfbi.fbdev->dev, | ||
135 | "CSONTIME %d, CSOFFTIME %d, WEONTIME %d, WEOFFTIME %d, " | ||
136 | "REONTIME %d, REOFFTIME %d\n", | ||
137 | l & 0x0f, (l >> 4) & 0x3f, (l >> 10) & 0x0f, (l >> 14) & 0x3f, | ||
138 | (l >> 20) & 0x0f, (l >> 24) & 0x3f); | ||
139 | |||
140 | l = rfbi_read_reg(RFBI_CYCLE_TIME0); | ||
141 | dev_dbg(rfbi.fbdev->dev, | ||
142 | "WECYCLETIME %d, RECYCLETIME %d, CSPULSEWIDTH %d, " | ||
143 | "ACCESSTIME %d\n", | ||
144 | (l & 0x3f), (l >> 6) & 0x3f, (l >> 12) & 0x3f, | ||
145 | (l >> 22) & 0x3f); | ||
146 | } | ||
147 | #else | ||
148 | static void rfbi_print_timings(void) {} | ||
149 | #endif | ||
150 | |||
151 | static void rfbi_set_timings(const struct extif_timings *t) | ||
152 | { | ||
153 | u32 l; | ||
154 | |||
155 | BUG_ON(!t->converted); | ||
156 | |||
157 | rfbi_enable_clocks(1); | ||
158 | rfbi_write_reg(RFBI_ONOFF_TIME0, t->tim[0]); | ||
159 | rfbi_write_reg(RFBI_CYCLE_TIME0, t->tim[1]); | ||
160 | |||
161 | l = rfbi_read_reg(RFBI_CONFIG0); | ||
162 | l &= ~(1 << 4); | ||
163 | l |= (t->tim[2] ? 1 : 0) << 4; | ||
164 | rfbi_write_reg(RFBI_CONFIG0, l); | ||
165 | |||
166 | rfbi_print_timings(); | ||
167 | rfbi_enable_clocks(0); | ||
168 | } | ||
169 | |||
170 | static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div) | ||
171 | { | ||
172 | *clk_period = 1000000000 / rfbi.l4_khz; | ||
173 | *max_clk_div = 2; | ||
174 | } | ||
175 | |||
176 | static int ps_to_rfbi_ticks(int time, int div) | ||
177 | { | ||
178 | unsigned long tick_ps; | ||
179 | int ret; | ||
180 | |||
181 | /* Calculate in picosecs to yield more exact results */ | ||
182 | tick_ps = 1000000000 / (rfbi.l4_khz) * div; | ||
183 | |||
184 | ret = (time + tick_ps - 1) / tick_ps; | ||
185 | |||
186 | return ret; | ||
187 | } | ||
188 | |||
189 | #ifdef OMAP_RFBI_RATE_LIMIT | ||
190 | static unsigned long rfbi_get_max_tx_rate(void) | ||
191 | { | ||
192 | unsigned long l4_rate, dss1_rate; | ||
193 | int min_l4_ticks = 0; | ||
194 | int i; | ||
195 | |||
196 | /* According to TI this can't be calculated so make the | ||
197 | * adjustments for a couple of known frequencies and warn for | ||
198 | * others. | ||
199 | */ | ||
200 | static const struct { | ||
201 | unsigned long l4_clk; /* HZ */ | ||
202 | unsigned long dss1_clk; /* HZ */ | ||
203 | unsigned long min_l4_ticks; | ||
204 | } ftab[] = { | ||
205 | { 55, 132, 7, }, /* 7.86 MPix/s */ | ||
206 | { 110, 110, 12, }, /* 9.16 MPix/s */ | ||
207 | { 110, 132, 10, }, /* 11 Mpix/s */ | ||
208 | { 120, 120, 10, }, /* 12 Mpix/s */ | ||
209 | { 133, 133, 10, }, /* 13.3 Mpix/s */ | ||
210 | }; | ||
211 | |||
212 | l4_rate = rfbi.l4_khz / 1000; | ||
213 | dss1_rate = clk_get_rate(rfbi.dss1_fck) / 1000000; | ||
214 | |||
215 | for (i = 0; i < ARRAY_SIZE(ftab); i++) { | ||
216 | /* Use a window instead of an exact match, to account | ||
217 | * for different DPLL multiplier / divider pairs. | ||
218 | */ | ||
219 | if (abs(ftab[i].l4_clk - l4_rate) < 3 && | ||
220 | abs(ftab[i].dss1_clk - dss1_rate) < 3) { | ||
221 | min_l4_ticks = ftab[i].min_l4_ticks; | ||
222 | break; | ||
223 | } | ||
224 | } | ||
225 | if (i == ARRAY_SIZE(ftab)) { | ||
226 | /* Can't be sure, return anyway the maximum not | ||
227 | * rate-limited. This might cause a problem only for the | ||
228 | * tearing synchronisation. | ||
229 | */ | ||
230 | dev_err(rfbi.fbdev->dev, | ||
231 | "can't determine maximum RFBI transfer rate\n"); | ||
232 | return rfbi.l4_khz * 1000; | ||
233 | } | ||
234 | return rfbi.l4_khz * 1000 / min_l4_ticks; | ||
235 | } | ||
236 | #else | ||
237 | static int rfbi_get_max_tx_rate(void) | ||
238 | { | ||
239 | return rfbi.l4_khz * 1000; | ||
240 | } | ||
241 | #endif | ||
242 | |||
243 | |||
244 | static int rfbi_convert_timings(struct extif_timings *t) | ||
245 | { | ||
246 | u32 l; | ||
247 | int reon, reoff, weon, weoff, cson, csoff, cs_pulse; | ||
248 | int actim, recyc, wecyc; | ||
249 | int div = t->clk_div; | ||
250 | |||
251 | if (div <= 0 || div > 2) | ||
252 | return -1; | ||
253 | |||
254 | /* Make sure that after conversion it still holds that: | ||
255 | * weoff > weon, reoff > reon, recyc >= reoff, wecyc >= weoff, | ||
256 | * csoff > cson, csoff >= max(weoff, reoff), actim > reon | ||
257 | */ | ||
258 | weon = ps_to_rfbi_ticks(t->we_on_time, div); | ||
259 | weoff = ps_to_rfbi_ticks(t->we_off_time, div); | ||
260 | if (weoff <= weon) | ||
261 | weoff = weon + 1; | ||
262 | if (weon > 0x0f) | ||
263 | return -1; | ||
264 | if (weoff > 0x3f) | ||
265 | return -1; | ||
266 | |||
267 | reon = ps_to_rfbi_ticks(t->re_on_time, div); | ||
268 | reoff = ps_to_rfbi_ticks(t->re_off_time, div); | ||
269 | if (reoff <= reon) | ||
270 | reoff = reon + 1; | ||
271 | if (reon > 0x0f) | ||
272 | return -1; | ||
273 | if (reoff > 0x3f) | ||
274 | return -1; | ||
275 | |||
276 | cson = ps_to_rfbi_ticks(t->cs_on_time, div); | ||
277 | csoff = ps_to_rfbi_ticks(t->cs_off_time, div); | ||
278 | if (csoff <= cson) | ||
279 | csoff = cson + 1; | ||
280 | if (csoff < max(weoff, reoff)) | ||
281 | csoff = max(weoff, reoff); | ||
282 | if (cson > 0x0f) | ||
283 | return -1; | ||
284 | if (csoff > 0x3f) | ||
285 | return -1; | ||
286 | |||
287 | l = cson; | ||
288 | l |= csoff << 4; | ||
289 | l |= weon << 10; | ||
290 | l |= weoff << 14; | ||
291 | l |= reon << 20; | ||
292 | l |= reoff << 24; | ||
293 | |||
294 | t->tim[0] = l; | ||
295 | |||
296 | actim = ps_to_rfbi_ticks(t->access_time, div); | ||
297 | if (actim <= reon) | ||
298 | actim = reon + 1; | ||
299 | if (actim > 0x3f) | ||
300 | return -1; | ||
301 | |||
302 | wecyc = ps_to_rfbi_ticks(t->we_cycle_time, div); | ||
303 | if (wecyc < weoff) | ||
304 | wecyc = weoff; | ||
305 | if (wecyc > 0x3f) | ||
306 | return -1; | ||
307 | |||
308 | recyc = ps_to_rfbi_ticks(t->re_cycle_time, div); | ||
309 | if (recyc < reoff) | ||
310 | recyc = reoff; | ||
311 | if (recyc > 0x3f) | ||
312 | return -1; | ||
313 | |||
314 | cs_pulse = ps_to_rfbi_ticks(t->cs_pulse_width, div); | ||
315 | if (cs_pulse > 0x3f) | ||
316 | return -1; | ||
317 | |||
318 | l = wecyc; | ||
319 | l |= recyc << 6; | ||
320 | l |= cs_pulse << 12; | ||
321 | l |= actim << 22; | ||
322 | |||
323 | t->tim[1] = l; | ||
324 | |||
325 | t->tim[2] = div - 1; | ||
326 | |||
327 | t->converted = 1; | ||
328 | |||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static int rfbi_setup_tearsync(unsigned pin_cnt, | ||
333 | unsigned hs_pulse_time, unsigned vs_pulse_time, | ||
334 | int hs_pol_inv, int vs_pol_inv, int extif_div) | ||
335 | { | ||
336 | int hs, vs; | ||
337 | int min; | ||
338 | u32 l; | ||
339 | |||
340 | if (pin_cnt != 1 && pin_cnt != 2) | ||
341 | return -EINVAL; | ||
342 | |||
343 | hs = ps_to_rfbi_ticks(hs_pulse_time, 1); | ||
344 | vs = ps_to_rfbi_ticks(vs_pulse_time, 1); | ||
345 | if (hs < 2) | ||
346 | return -EDOM; | ||
347 | if (pin_cnt == 2) | ||
348 | min = 2; | ||
349 | else | ||
350 | min = 4; | ||
351 | if (vs < min) | ||
352 | return -EDOM; | ||
353 | if (vs == hs) | ||
354 | return -EINVAL; | ||
355 | rfbi.tearsync_pin_cnt = pin_cnt; | ||
356 | dev_dbg(rfbi.fbdev->dev, | ||
357 | "setup_tearsync: pins %d hs %d vs %d hs_inv %d vs_inv %d\n", | ||
358 | pin_cnt, hs, vs, hs_pol_inv, vs_pol_inv); | ||
359 | |||
360 | rfbi_enable_clocks(1); | ||
361 | rfbi_write_reg(RFBI_HSYNC_WIDTH, hs); | ||
362 | rfbi_write_reg(RFBI_VSYNC_WIDTH, vs); | ||
363 | |||
364 | l = rfbi_read_reg(RFBI_CONFIG0); | ||
365 | if (hs_pol_inv) | ||
366 | l &= ~(1 << 21); | ||
367 | else | ||
368 | l |= 1 << 21; | ||
369 | if (vs_pol_inv) | ||
370 | l &= ~(1 << 20); | ||
371 | else | ||
372 | l |= 1 << 20; | ||
373 | rfbi_enable_clocks(0); | ||
374 | |||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | static int rfbi_enable_tearsync(int enable, unsigned line) | ||
379 | { | ||
380 | u32 l; | ||
381 | |||
382 | dev_dbg(rfbi.fbdev->dev, "tearsync %d line %d mode %d\n", | ||
383 | enable, line, rfbi.tearsync_mode); | ||
384 | if (line > (1 << 11) - 1) | ||
385 | return -EINVAL; | ||
386 | |||
387 | rfbi_enable_clocks(1); | ||
388 | l = rfbi_read_reg(RFBI_CONFIG0); | ||
389 | l &= ~(0x3 << 2); | ||
390 | if (enable) { | ||
391 | rfbi.tearsync_mode = rfbi.tearsync_pin_cnt; | ||
392 | l |= rfbi.tearsync_mode << 2; | ||
393 | } else | ||
394 | rfbi.tearsync_mode = 0; | ||
395 | rfbi_write_reg(RFBI_CONFIG0, l); | ||
396 | rfbi_write_reg(RFBI_LINE_NUMBER, line); | ||
397 | rfbi_enable_clocks(0); | ||
398 | |||
399 | return 0; | ||
400 | } | ||
401 | |||
402 | static void rfbi_write_command(const void *buf, unsigned int len) | ||
403 | { | ||
404 | rfbi_enable_clocks(1); | ||
405 | if (rfbi.bits_per_cycle == 16) { | ||
406 | const u16 *w = buf; | ||
407 | BUG_ON(len & 1); | ||
408 | for (; len; len -= 2) | ||
409 | rfbi_write_reg(RFBI_CMD, *w++); | ||
410 | } else { | ||
411 | const u8 *b = buf; | ||
412 | BUG_ON(rfbi.bits_per_cycle != 8); | ||
413 | for (; len; len--) | ||
414 | rfbi_write_reg(RFBI_CMD, *b++); | ||
415 | } | ||
416 | rfbi_enable_clocks(0); | ||
417 | } | ||
418 | |||
419 | static void rfbi_read_data(void *buf, unsigned int len) | ||
420 | { | ||
421 | rfbi_enable_clocks(1); | ||
422 | if (rfbi.bits_per_cycle == 16) { | ||
423 | u16 *w = buf; | ||
424 | BUG_ON(len & ~1); | ||
425 | for (; len; len -= 2) { | ||
426 | rfbi_write_reg(RFBI_READ, 0); | ||
427 | *w++ = rfbi_read_reg(RFBI_READ); | ||
428 | } | ||
429 | } else { | ||
430 | u8 *b = buf; | ||
431 | BUG_ON(rfbi.bits_per_cycle != 8); | ||
432 | for (; len; len--) { | ||
433 | rfbi_write_reg(RFBI_READ, 0); | ||
434 | *b++ = rfbi_read_reg(RFBI_READ); | ||
435 | } | ||
436 | } | ||
437 | rfbi_enable_clocks(0); | ||
438 | } | ||
439 | |||
440 | static void rfbi_write_data(const void *buf, unsigned int len) | ||
441 | { | ||
442 | rfbi_enable_clocks(1); | ||
443 | if (rfbi.bits_per_cycle == 16) { | ||
444 | const u16 *w = buf; | ||
445 | BUG_ON(len & 1); | ||
446 | for (; len; len -= 2) | ||
447 | rfbi_write_reg(RFBI_PARAM, *w++); | ||
448 | } else { | ||
449 | const u8 *b = buf; | ||
450 | BUG_ON(rfbi.bits_per_cycle != 8); | ||
451 | for (; len; len--) | ||
452 | rfbi_write_reg(RFBI_PARAM, *b++); | ||
453 | } | ||
454 | rfbi_enable_clocks(0); | ||
455 | } | ||
456 | |||
457 | static void rfbi_transfer_area(int width, int height, | ||
458 | void (callback)(void * data), void *data) | ||
459 | { | ||
460 | u32 w; | ||
461 | |||
462 | BUG_ON(callback == NULL); | ||
463 | |||
464 | rfbi_enable_clocks(1); | ||
465 | omap_dispc_set_lcd_size(width, height); | ||
466 | |||
467 | rfbi.lcdc_callback = callback; | ||
468 | rfbi.lcdc_callback_data = data; | ||
469 | |||
470 | rfbi_write_reg(RFBI_PIXEL_CNT, width * height); | ||
471 | |||
472 | w = rfbi_read_reg(RFBI_CONTROL); | ||
473 | w |= 1; /* enable */ | ||
474 | if (!rfbi.tearsync_mode) | ||
475 | w |= 1 << 4; /* internal trigger, reset by HW */ | ||
476 | rfbi_write_reg(RFBI_CONTROL, w); | ||
477 | |||
478 | omap_dispc_enable_lcd_out(1); | ||
479 | } | ||
480 | |||
481 | static inline void _stop_transfer(void) | ||
482 | { | ||
483 | u32 w; | ||
484 | |||
485 | w = rfbi_read_reg(RFBI_CONTROL); | ||
486 | rfbi_write_reg(RFBI_CONTROL, w & ~(1 << 0)); | ||
487 | rfbi_enable_clocks(0); | ||
488 | } | ||
489 | |||
490 | static void rfbi_dma_callback(void *data) | ||
491 | { | ||
492 | _stop_transfer(); | ||
493 | rfbi.lcdc_callback(rfbi.lcdc_callback_data); | ||
494 | } | ||
495 | |||
496 | static void rfbi_set_bits_per_cycle(int bpc) | ||
497 | { | ||
498 | u32 l; | ||
499 | |||
500 | rfbi_enable_clocks(1); | ||
501 | l = rfbi_read_reg(RFBI_CONFIG0); | ||
502 | l &= ~(0x03 << 0); | ||
503 | |||
504 | switch (bpc) { | ||
505 | case 8: | ||
506 | break; | ||
507 | case 16: | ||
508 | l |= 3; | ||
509 | break; | ||
510 | default: | ||
511 | BUG(); | ||
512 | } | ||
513 | rfbi_write_reg(RFBI_CONFIG0, l); | ||
514 | rfbi.bits_per_cycle = bpc; | ||
515 | rfbi_enable_clocks(0); | ||
516 | } | ||
517 | |||
518 | static int rfbi_init(struct omapfb_device *fbdev) | ||
519 | { | ||
520 | u32 l; | ||
521 | int r; | ||
522 | |||
523 | rfbi.fbdev = fbdev; | ||
524 | rfbi.base = ioremap(RFBI_BASE, SZ_1K); | ||
525 | if (!rfbi.base) { | ||
526 | dev_err(fbdev->dev, "can't ioremap RFBI\n"); | ||
527 | return -ENOMEM; | ||
528 | } | ||
529 | |||
530 | if ((r = rfbi_get_clocks()) < 0) | ||
531 | return r; | ||
532 | rfbi_enable_clocks(1); | ||
533 | |||
534 | rfbi.l4_khz = clk_get_rate(rfbi.dss_ick) / 1000; | ||
535 | |||
536 | /* Reset */ | ||
537 | rfbi_write_reg(RFBI_SYSCONFIG, 1 << 1); | ||
538 | while (!(rfbi_read_reg(RFBI_SYSSTATUS) & (1 << 0))); | ||
539 | |||
540 | l = rfbi_read_reg(RFBI_SYSCONFIG); | ||
541 | /* Enable autoidle and smart-idle */ | ||
542 | l |= (1 << 0) | (2 << 3); | ||
543 | rfbi_write_reg(RFBI_SYSCONFIG, l); | ||
544 | |||
545 | /* 16-bit interface, ITE trigger mode, 16-bit data */ | ||
546 | l = (0x03 << 0) | (0x00 << 2) | (0x01 << 5) | (0x02 << 7); | ||
547 | l |= (0 << 9) | (1 << 20) | (1 << 21); | ||
548 | rfbi_write_reg(RFBI_CONFIG0, l); | ||
549 | |||
550 | rfbi_write_reg(RFBI_DATA_CYCLE1_0, 0x00000010); | ||
551 | |||
552 | l = rfbi_read_reg(RFBI_CONTROL); | ||
553 | /* Select CS0, clear bypass mode */ | ||
554 | l = (0x01 << 2); | ||
555 | rfbi_write_reg(RFBI_CONTROL, l); | ||
556 | |||
557 | r = omap_dispc_request_irq(DISPC_IRQ_FRAMEMASK, rfbi_dma_callback, | ||
558 | NULL); | ||
559 | if (r < 0) { | ||
560 | dev_err(fbdev->dev, "can't get DISPC irq\n"); | ||
561 | rfbi_enable_clocks(0); | ||
562 | return r; | ||
563 | } | ||
564 | |||
565 | l = rfbi_read_reg(RFBI_REVISION); | ||
566 | pr_info("omapfb: RFBI version %d.%d initialized\n", | ||
567 | (l >> 4) & 0x0f, l & 0x0f); | ||
568 | |||
569 | rfbi_enable_clocks(0); | ||
570 | |||
571 | return 0; | ||
572 | } | ||
573 | |||
574 | static void rfbi_cleanup(void) | ||
575 | { | ||
576 | omap_dispc_free_irq(DISPC_IRQ_FRAMEMASK, rfbi_dma_callback, NULL); | ||
577 | rfbi_put_clocks(); | ||
578 | iounmap(rfbi.base); | ||
579 | } | ||
580 | |||
581 | const struct lcd_ctrl_extif omap2_ext_if = { | ||
582 | .init = rfbi_init, | ||
583 | .cleanup = rfbi_cleanup, | ||
584 | .get_clk_info = rfbi_get_clk_info, | ||
585 | .get_max_tx_rate = rfbi_get_max_tx_rate, | ||
586 | .set_bits_per_cycle = rfbi_set_bits_per_cycle, | ||
587 | .convert_timings = rfbi_convert_timings, | ||
588 | .set_timings = rfbi_set_timings, | ||
589 | .write_command = rfbi_write_command, | ||
590 | .read_data = rfbi_read_data, | ||
591 | .write_data = rfbi_write_data, | ||
592 | .transfer_area = rfbi_transfer_area, | ||
593 | .setup_tearsync = rfbi_setup_tearsync, | ||
594 | .enable_tearsync = rfbi_enable_tearsync, | ||
595 | |||
596 | .max_transmit_size = (u32) ~0, | ||
597 | }; | ||
598 | |||
diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c index 51a87e149e24..d26f37ac69d8 100644 --- a/drivers/video/omap2/displays/panel-acx565akm.c +++ b/drivers/video/omap2/displays/panel-acx565akm.c | |||
@@ -809,18 +809,7 @@ static struct spi_driver acx565akm_spi_driver = { | |||
809 | .remove = __devexit_p(acx565akm_spi_remove), | 809 | .remove = __devexit_p(acx565akm_spi_remove), |
810 | }; | 810 | }; |
811 | 811 | ||
812 | static int __init acx565akm_init(void) | 812 | module_spi_driver(acx565akm_spi_driver); |
813 | { | ||
814 | return spi_register_driver(&acx565akm_spi_driver); | ||
815 | } | ||
816 | |||
817 | static void __exit acx565akm_exit(void) | ||
818 | { | ||
819 | spi_unregister_driver(&acx565akm_spi_driver); | ||
820 | } | ||
821 | |||
822 | module_init(acx565akm_init); | ||
823 | module_exit(acx565akm_exit); | ||
824 | 813 | ||
825 | MODULE_AUTHOR("Nokia Corporation"); | 814 | MODULE_AUTHOR("Nokia Corporation"); |
826 | MODULE_DESCRIPTION("acx565akm LCD Driver"); | 815 | MODULE_DESCRIPTION("acx565akm LCD Driver"); |
diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c index 28b9a6d61b0f..30fe4dfeb227 100644 --- a/drivers/video/omap2/displays/panel-generic-dpi.c +++ b/drivers/video/omap2/displays/panel-generic-dpi.c | |||
@@ -363,6 +363,29 @@ static struct panel_config generic_dpi_panels[] = { | |||
363 | 363 | ||
364 | .name = "ortustech_com43h4m10xtc", | 364 | .name = "ortustech_com43h4m10xtc", |
365 | }, | 365 | }, |
366 | |||
367 | /* Innolux AT080TN52 */ | ||
368 | { | ||
369 | { | ||
370 | .x_res = 800, | ||
371 | .y_res = 600, | ||
372 | |||
373 | .pixel_clock = 41142, | ||
374 | |||
375 | .hsw = 20, | ||
376 | .hfp = 210, | ||
377 | .hbp = 46, | ||
378 | |||
379 | .vsw = 10, | ||
380 | .vfp = 12, | ||
381 | .vbp = 23, | ||
382 | }, | ||
383 | .acb = 0x0, | ||
384 | .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | | ||
385 | OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO, | ||
386 | |||
387 | .name = "innolux_at080tn52", | ||
388 | }, | ||
366 | }; | 389 | }; |
367 | 390 | ||
368 | struct panel_drv_data { | 391 | struct panel_drv_data { |
diff --git a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c index e0eb35be303e..0841cc2b3f77 100644 --- a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c +++ b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c | |||
@@ -264,16 +264,6 @@ static struct spi_driver lb035q02_spi_driver = { | |||
264 | .remove = __devexit_p(lb035q02_panel_spi_remove), | 264 | .remove = __devexit_p(lb035q02_panel_spi_remove), |
265 | }; | 265 | }; |
266 | 266 | ||
267 | static int __init lb035q02_panel_drv_init(void) | 267 | module_spi_driver(lb035q02_spi_driver); |
268 | { | ||
269 | return spi_register_driver(&lb035q02_spi_driver); | ||
270 | } | ||
271 | |||
272 | static void __exit lb035q02_panel_drv_exit(void) | ||
273 | { | ||
274 | spi_unregister_driver(&lb035q02_spi_driver); | ||
275 | } | ||
276 | 268 | ||
277 | module_init(lb035q02_panel_drv_init); | ||
278 | module_exit(lb035q02_panel_drv_exit); | ||
279 | MODULE_LICENSE("GPL"); | 269 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c index 0eb31caddca8..8b38b39213f4 100644 --- a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c +++ b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c | |||
@@ -350,18 +350,8 @@ static struct spi_driver nec_8048_spi_driver = { | |||
350 | }, | 350 | }, |
351 | }; | 351 | }; |
352 | 352 | ||
353 | static int __init nec_8048_lcd_init(void) | 353 | module_spi_driver(nec_8048_spi_driver); |
354 | { | ||
355 | return spi_register_driver(&nec_8048_spi_driver); | ||
356 | } | ||
357 | |||
358 | static void __exit nec_8048_lcd_exit(void) | ||
359 | { | ||
360 | return spi_unregister_driver(&nec_8048_spi_driver); | ||
361 | } | ||
362 | 354 | ||
363 | module_init(nec_8048_lcd_init); | ||
364 | module_exit(nec_8048_lcd_exit); | ||
365 | MODULE_AUTHOR("Erik Gilling <konkers@android.com>"); | 355 | MODULE_AUTHOR("Erik Gilling <konkers@android.com>"); |
366 | MODULE_DESCRIPTION("NEC-nl8048hl11-01b Driver"); | 356 | MODULE_DESCRIPTION("NEC-nl8048hl11-01b Driver"); |
367 | MODULE_LICENSE("GPL"); | 357 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 00c5c615585f..0f21fa5a16ae 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c | |||
@@ -1019,14 +1019,12 @@ static int taal_probe(struct omap_dss_device *dssdev) | |||
1019 | if (panel_data->use_ext_te) { | 1019 | if (panel_data->use_ext_te) { |
1020 | int gpio = panel_data->ext_te_gpio; | 1020 | int gpio = panel_data->ext_te_gpio; |
1021 | 1021 | ||
1022 | r = gpio_request(gpio, "taal irq"); | 1022 | r = gpio_request_one(gpio, GPIOF_IN, "taal irq"); |
1023 | if (r) { | 1023 | if (r) { |
1024 | dev_err(&dssdev->dev, "GPIO request failed\n"); | 1024 | dev_err(&dssdev->dev, "GPIO request failed\n"); |
1025 | goto err_gpio; | 1025 | goto err_gpio; |
1026 | } | 1026 | } |
1027 | 1027 | ||
1028 | gpio_direction_input(gpio); | ||
1029 | |||
1030 | r = request_irq(gpio_to_irq(gpio), taal_te_isr, | 1028 | r = request_irq(gpio_to_irq(gpio), taal_te_isr, |
1031 | IRQF_TRIGGER_RISING, | 1029 | IRQF_TRIGGER_RISING, |
1032 | "taal vsync", dssdev); | 1030 | "taal vsync", dssdev); |
diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c index e6649aa89591..32f3fcd7f0f0 100644 --- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c +++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c | |||
@@ -47,16 +47,20 @@ | |||
47 | TPO_R03_EN_PRE_CHARGE | TPO_R03_SOFTWARE_CTL) | 47 | TPO_R03_EN_PRE_CHARGE | TPO_R03_SOFTWARE_CTL) |
48 | 48 | ||
49 | static const u16 tpo_td043_def_gamma[12] = { | 49 | static const u16 tpo_td043_def_gamma[12] = { |
50 | 106, 200, 289, 375, 460, 543, 625, 705, 785, 864, 942, 1020 | 50 | 105, 315, 381, 431, 490, 537, 579, 686, 780, 837, 880, 1023 |
51 | }; | 51 | }; |
52 | 52 | ||
53 | struct tpo_td043_device { | 53 | struct tpo_td043_device { |
54 | struct spi_device *spi; | 54 | struct spi_device *spi; |
55 | struct regulator *vcc_reg; | 55 | struct regulator *vcc_reg; |
56 | int nreset_gpio; | ||
56 | u16 gamma[12]; | 57 | u16 gamma[12]; |
57 | u32 mode; | 58 | u32 mode; |
58 | u32 hmirror:1; | 59 | u32 hmirror:1; |
59 | u32 vmirror:1; | 60 | u32 vmirror:1; |
61 | u32 powered_on:1; | ||
62 | u32 spi_suspended:1; | ||
63 | u32 power_on_resume:1; | ||
60 | }; | 64 | }; |
61 | 65 | ||
62 | static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data) | 66 | static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data) |
@@ -265,28 +269,16 @@ static const struct omap_video_timings tpo_td043_timings = { | |||
265 | .vbp = 34, | 269 | .vbp = 34, |
266 | }; | 270 | }; |
267 | 271 | ||
268 | static int tpo_td043_power_on(struct omap_dss_device *dssdev) | 272 | static int tpo_td043_power_on(struct tpo_td043_device *tpo_td043) |
269 | { | 273 | { |
270 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); | 274 | int nreset_gpio = tpo_td043->nreset_gpio; |
271 | int nreset_gpio = dssdev->reset_gpio; | ||
272 | int r; | ||
273 | 275 | ||
274 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | 276 | if (tpo_td043->powered_on) |
275 | return 0; | 277 | return 0; |
276 | 278 | ||
277 | r = omapdss_dpi_display_enable(dssdev); | ||
278 | if (r) | ||
279 | goto err0; | ||
280 | |||
281 | if (dssdev->platform_enable) { | ||
282 | r = dssdev->platform_enable(dssdev); | ||
283 | if (r) | ||
284 | goto err1; | ||
285 | } | ||
286 | |||
287 | regulator_enable(tpo_td043->vcc_reg); | 279 | regulator_enable(tpo_td043->vcc_reg); |
288 | 280 | ||
289 | /* wait for power up */ | 281 | /* wait for regulator to stabilize */ |
290 | msleep(160); | 282 | msleep(160); |
291 | 283 | ||
292 | if (gpio_is_valid(nreset_gpio)) | 284 | if (gpio_is_valid(nreset_gpio)) |
@@ -301,19 +293,15 @@ static int tpo_td043_power_on(struct omap_dss_device *dssdev) | |||
301 | tpo_td043->vmirror); | 293 | tpo_td043->vmirror); |
302 | tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma); | 294 | tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma); |
303 | 295 | ||
296 | tpo_td043->powered_on = 1; | ||
304 | return 0; | 297 | return 0; |
305 | err1: | ||
306 | omapdss_dpi_display_disable(dssdev); | ||
307 | err0: | ||
308 | return r; | ||
309 | } | 298 | } |
310 | 299 | ||
311 | static void tpo_td043_power_off(struct omap_dss_device *dssdev) | 300 | static void tpo_td043_power_off(struct tpo_td043_device *tpo_td043) |
312 | { | 301 | { |
313 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); | 302 | int nreset_gpio = tpo_td043->nreset_gpio; |
314 | int nreset_gpio = dssdev->reset_gpio; | ||
315 | 303 | ||
316 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | 304 | if (!tpo_td043->powered_on) |
317 | return; | 305 | return; |
318 | 306 | ||
319 | tpo_td043_write(tpo_td043->spi, 3, | 307 | tpo_td043_write(tpo_td043->spi, 3, |
@@ -329,54 +317,94 @@ static void tpo_td043_power_off(struct omap_dss_device *dssdev) | |||
329 | 317 | ||
330 | regulator_disable(tpo_td043->vcc_reg); | 318 | regulator_disable(tpo_td043->vcc_reg); |
331 | 319 | ||
320 | tpo_td043->powered_on = 0; | ||
321 | } | ||
322 | |||
323 | static int tpo_td043_enable_dss(struct omap_dss_device *dssdev) | ||
324 | { | ||
325 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); | ||
326 | int r; | ||
327 | |||
328 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | ||
329 | return 0; | ||
330 | |||
331 | r = omapdss_dpi_display_enable(dssdev); | ||
332 | if (r) | ||
333 | goto err0; | ||
334 | |||
335 | if (dssdev->platform_enable) { | ||
336 | r = dssdev->platform_enable(dssdev); | ||
337 | if (r) | ||
338 | goto err1; | ||
339 | } | ||
340 | |||
341 | /* | ||
342 | * If we are resuming from system suspend, SPI clocks might not be | ||
343 | * enabled yet, so we'll program the LCD from SPI PM resume callback. | ||
344 | */ | ||
345 | if (!tpo_td043->spi_suspended) { | ||
346 | r = tpo_td043_power_on(tpo_td043); | ||
347 | if (r) | ||
348 | goto err1; | ||
349 | } | ||
350 | |||
351 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
352 | |||
353 | return 0; | ||
354 | err1: | ||
355 | omapdss_dpi_display_disable(dssdev); | ||
356 | err0: | ||
357 | return r; | ||
358 | } | ||
359 | |||
360 | static void tpo_td043_disable_dss(struct omap_dss_device *dssdev) | ||
361 | { | ||
362 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); | ||
363 | |||
364 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
365 | return; | ||
366 | |||
332 | if (dssdev->platform_disable) | 367 | if (dssdev->platform_disable) |
333 | dssdev->platform_disable(dssdev); | 368 | dssdev->platform_disable(dssdev); |
334 | 369 | ||
335 | omapdss_dpi_display_disable(dssdev); | 370 | omapdss_dpi_display_disable(dssdev); |
371 | |||
372 | if (!tpo_td043->spi_suspended) | ||
373 | tpo_td043_power_off(tpo_td043); | ||
336 | } | 374 | } |
337 | 375 | ||
338 | static int tpo_td043_enable(struct omap_dss_device *dssdev) | 376 | static int tpo_td043_enable(struct omap_dss_device *dssdev) |
339 | { | 377 | { |
340 | int ret; | ||
341 | |||
342 | dev_dbg(&dssdev->dev, "enable\n"); | 378 | dev_dbg(&dssdev->dev, "enable\n"); |
343 | 379 | ||
344 | ret = tpo_td043_power_on(dssdev); | 380 | return tpo_td043_enable_dss(dssdev); |
345 | if (ret) | ||
346 | return ret; | ||
347 | |||
348 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
349 | |||
350 | return 0; | ||
351 | } | 381 | } |
352 | 382 | ||
353 | static void tpo_td043_disable(struct omap_dss_device *dssdev) | 383 | static void tpo_td043_disable(struct omap_dss_device *dssdev) |
354 | { | 384 | { |
355 | dev_dbg(&dssdev->dev, "disable\n"); | 385 | dev_dbg(&dssdev->dev, "disable\n"); |
356 | 386 | ||
357 | tpo_td043_power_off(dssdev); | 387 | tpo_td043_disable_dss(dssdev); |
358 | 388 | ||
359 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | 389 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; |
360 | } | 390 | } |
361 | 391 | ||
362 | static int tpo_td043_suspend(struct omap_dss_device *dssdev) | 392 | static int tpo_td043_suspend(struct omap_dss_device *dssdev) |
363 | { | 393 | { |
364 | tpo_td043_power_off(dssdev); | 394 | dev_dbg(&dssdev->dev, "suspend\n"); |
395 | |||
396 | tpo_td043_disable_dss(dssdev); | ||
397 | |||
365 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | 398 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; |
399 | |||
366 | return 0; | 400 | return 0; |
367 | } | 401 | } |
368 | 402 | ||
369 | static int tpo_td043_resume(struct omap_dss_device *dssdev) | 403 | static int tpo_td043_resume(struct omap_dss_device *dssdev) |
370 | { | 404 | { |
371 | int r = 0; | 405 | dev_dbg(&dssdev->dev, "resume\n"); |
372 | |||
373 | r = tpo_td043_power_on(dssdev); | ||
374 | if (r) | ||
375 | return r; | ||
376 | 406 | ||
377 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | 407 | return tpo_td043_enable_dss(dssdev); |
378 | |||
379 | return 0; | ||
380 | } | 408 | } |
381 | 409 | ||
382 | static int tpo_td043_probe(struct omap_dss_device *dssdev) | 410 | static int tpo_td043_probe(struct omap_dss_device *dssdev) |
@@ -408,17 +436,12 @@ static int tpo_td043_probe(struct omap_dss_device *dssdev) | |||
408 | } | 436 | } |
409 | 437 | ||
410 | if (gpio_is_valid(nreset_gpio)) { | 438 | if (gpio_is_valid(nreset_gpio)) { |
411 | ret = gpio_request(nreset_gpio, "lcd reset"); | 439 | ret = gpio_request_one(nreset_gpio, GPIOF_OUT_INIT_LOW, |
440 | "lcd reset"); | ||
412 | if (ret < 0) { | 441 | if (ret < 0) { |
413 | dev_err(&dssdev->dev, "couldn't request reset GPIO\n"); | 442 | dev_err(&dssdev->dev, "couldn't request reset GPIO\n"); |
414 | goto fail_gpio_req; | 443 | goto fail_gpio_req; |
415 | } | 444 | } |
416 | |||
417 | ret = gpio_direction_output(nreset_gpio, 0); | ||
418 | if (ret < 0) { | ||
419 | dev_err(&dssdev->dev, "couldn't set GPIO direction\n"); | ||
420 | goto fail_gpio_direction; | ||
421 | } | ||
422 | } | 445 | } |
423 | 446 | ||
424 | ret = sysfs_create_group(&dssdev->dev.kobj, &tpo_td043_attr_group); | 447 | ret = sysfs_create_group(&dssdev->dev.kobj, &tpo_td043_attr_group); |
@@ -427,8 +450,6 @@ static int tpo_td043_probe(struct omap_dss_device *dssdev) | |||
427 | 450 | ||
428 | return 0; | 451 | return 0; |
429 | 452 | ||
430 | fail_gpio_direction: | ||
431 | gpio_free(nreset_gpio); | ||
432 | fail_gpio_req: | 453 | fail_gpio_req: |
433 | regulator_put(tpo_td043->vcc_reg); | 454 | regulator_put(tpo_td043->vcc_reg); |
434 | fail_regulator: | 455 | fail_regulator: |
@@ -491,6 +512,7 @@ static int tpo_td043_spi_probe(struct spi_device *spi) | |||
491 | return -ENOMEM; | 512 | return -ENOMEM; |
492 | 513 | ||
493 | tpo_td043->spi = spi; | 514 | tpo_td043->spi = spi; |
515 | tpo_td043->nreset_gpio = dssdev->reset_gpio; | ||
494 | dev_set_drvdata(&spi->dev, tpo_td043); | 516 | dev_set_drvdata(&spi->dev, tpo_td043); |
495 | dev_set_drvdata(&dssdev->dev, tpo_td043); | 517 | dev_set_drvdata(&dssdev->dev, tpo_td043); |
496 | 518 | ||
@@ -509,27 +531,52 @@ static int __devexit tpo_td043_spi_remove(struct spi_device *spi) | |||
509 | return 0; | 531 | return 0; |
510 | } | 532 | } |
511 | 533 | ||
534 | #ifdef CONFIG_PM_SLEEP | ||
535 | static int tpo_td043_spi_suspend(struct device *dev) | ||
536 | { | ||
537 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); | ||
538 | |||
539 | dev_dbg(dev, "tpo_td043_spi_suspend, tpo %p\n", tpo_td043); | ||
540 | |||
541 | tpo_td043->power_on_resume = tpo_td043->powered_on; | ||
542 | tpo_td043_power_off(tpo_td043); | ||
543 | tpo_td043->spi_suspended = 1; | ||
544 | |||
545 | return 0; | ||
546 | } | ||
547 | |||
548 | static int tpo_td043_spi_resume(struct device *dev) | ||
549 | { | ||
550 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); | ||
551 | int ret; | ||
552 | |||
553 | dev_dbg(dev, "tpo_td043_spi_resume\n"); | ||
554 | |||
555 | if (tpo_td043->power_on_resume) { | ||
556 | ret = tpo_td043_power_on(tpo_td043); | ||
557 | if (ret) | ||
558 | return ret; | ||
559 | } | ||
560 | tpo_td043->spi_suspended = 0; | ||
561 | |||
562 | return 0; | ||
563 | } | ||
564 | #endif | ||
565 | |||
566 | static SIMPLE_DEV_PM_OPS(tpo_td043_spi_pm, | ||
567 | tpo_td043_spi_suspend, tpo_td043_spi_resume); | ||
568 | |||
512 | static struct spi_driver tpo_td043_spi_driver = { | 569 | static struct spi_driver tpo_td043_spi_driver = { |
513 | .driver = { | 570 | .driver = { |
514 | .name = "tpo_td043mtea1_panel_spi", | 571 | .name = "tpo_td043mtea1_panel_spi", |
515 | .owner = THIS_MODULE, | 572 | .owner = THIS_MODULE, |
573 | .pm = &tpo_td043_spi_pm, | ||
516 | }, | 574 | }, |
517 | .probe = tpo_td043_spi_probe, | 575 | .probe = tpo_td043_spi_probe, |
518 | .remove = __devexit_p(tpo_td043_spi_remove), | 576 | .remove = __devexit_p(tpo_td043_spi_remove), |
519 | }; | 577 | }; |
520 | 578 | ||
521 | static int __init tpo_td043_init(void) | 579 | module_spi_driver(tpo_td043_spi_driver); |
522 | { | ||
523 | return spi_register_driver(&tpo_td043_spi_driver); | ||
524 | } | ||
525 | |||
526 | static void __exit tpo_td043_exit(void) | ||
527 | { | ||
528 | spi_unregister_driver(&tpo_td043_spi_driver); | ||
529 | } | ||
530 | |||
531 | module_init(tpo_td043_init); | ||
532 | module_exit(tpo_td043_exit); | ||
533 | 580 | ||
534 | MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>"); | 581 | MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>"); |
535 | MODULE_DESCRIPTION("TPO TD043MTEA1 LCD Driver"); | 582 | MODULE_DESCRIPTION("TPO TD043MTEA1 LCD Driver"); |
diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c index 87b3e25294cf..b10b3bc1931e 100644 --- a/drivers/video/omap2/dss/apply.c +++ b/drivers/video/omap2/dss/apply.c | |||
@@ -105,6 +105,9 @@ static struct { | |||
105 | struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS]; | 105 | struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS]; |
106 | struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS]; | 106 | struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS]; |
107 | 107 | ||
108 | bool fifo_merge_dirty; | ||
109 | bool fifo_merge; | ||
110 | |||
108 | bool irq_enabled; | 111 | bool irq_enabled; |
109 | } dss_data; | 112 | } dss_data; |
110 | 113 | ||
@@ -351,6 +354,7 @@ static void wait_pending_extra_info_updates(void) | |||
351 | bool updating; | 354 | bool updating; |
352 | unsigned long flags; | 355 | unsigned long flags; |
353 | unsigned long t; | 356 | unsigned long t; |
357 | int r; | ||
354 | 358 | ||
355 | spin_lock_irqsave(&data_lock, flags); | 359 | spin_lock_irqsave(&data_lock, flags); |
356 | 360 | ||
@@ -366,11 +370,11 @@ static void wait_pending_extra_info_updates(void) | |||
366 | spin_unlock_irqrestore(&data_lock, flags); | 370 | spin_unlock_irqrestore(&data_lock, flags); |
367 | 371 | ||
368 | t = msecs_to_jiffies(500); | 372 | t = msecs_to_jiffies(500); |
369 | wait_for_completion_timeout(&extra_updated_completion, t); | 373 | r = wait_for_completion_timeout(&extra_updated_completion, t); |
370 | 374 | if (r == 0) | |
371 | updating = extra_info_update_ongoing(); | 375 | DSSWARN("timeout in wait_pending_extra_info_updates\n"); |
372 | 376 | else if (r < 0) | |
373 | WARN_ON(updating); | 377 | DSSERR("wait_pending_extra_info_updates failed: %d\n", r); |
374 | } | 378 | } |
375 | 379 | ||
376 | int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) | 380 | int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) |
@@ -388,6 +392,10 @@ int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) | |||
388 | if (mgr_manual_update(mgr)) | 392 | if (mgr_manual_update(mgr)) |
389 | return 0; | 393 | return 0; |
390 | 394 | ||
395 | r = dispc_runtime_get(); | ||
396 | if (r) | ||
397 | return r; | ||
398 | |||
391 | irq = dispc_mgr_get_vsync_irq(mgr->id); | 399 | irq = dispc_mgr_get_vsync_irq(mgr->id); |
392 | 400 | ||
393 | mp = get_mgr_priv(mgr); | 401 | mp = get_mgr_priv(mgr); |
@@ -428,6 +436,8 @@ int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) | |||
428 | } | 436 | } |
429 | } | 437 | } |
430 | 438 | ||
439 | dispc_runtime_put(); | ||
440 | |||
431 | return r; | 441 | return r; |
432 | } | 442 | } |
433 | 443 | ||
@@ -451,6 +461,10 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) | |||
451 | if (ovl_manual_update(ovl)) | 461 | if (ovl_manual_update(ovl)) |
452 | return 0; | 462 | return 0; |
453 | 463 | ||
464 | r = dispc_runtime_get(); | ||
465 | if (r) | ||
466 | return r; | ||
467 | |||
454 | irq = dispc_mgr_get_vsync_irq(ovl->manager->id); | 468 | irq = dispc_mgr_get_vsync_irq(ovl->manager->id); |
455 | 469 | ||
456 | op = get_ovl_priv(ovl); | 470 | op = get_ovl_priv(ovl); |
@@ -491,6 +505,8 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) | |||
491 | } | 505 | } |
492 | } | 506 | } |
493 | 507 | ||
508 | dispc_runtime_put(); | ||
509 | |||
494 | return r; | 510 | return r; |
495 | } | 511 | } |
496 | 512 | ||
@@ -585,11 +601,40 @@ static void dss_mgr_write_regs(struct omap_overlay_manager *mgr) | |||
585 | } | 601 | } |
586 | } | 602 | } |
587 | 603 | ||
604 | static void dss_write_regs_common(void) | ||
605 | { | ||
606 | const int num_mgrs = omap_dss_get_num_overlay_managers(); | ||
607 | int i; | ||
608 | |||
609 | if (!dss_data.fifo_merge_dirty) | ||
610 | return; | ||
611 | |||
612 | for (i = 0; i < num_mgrs; ++i) { | ||
613 | struct omap_overlay_manager *mgr; | ||
614 | struct mgr_priv_data *mp; | ||
615 | |||
616 | mgr = omap_dss_get_overlay_manager(i); | ||
617 | mp = get_mgr_priv(mgr); | ||
618 | |||
619 | if (mp->enabled) { | ||
620 | if (dss_data.fifo_merge_dirty) { | ||
621 | dispc_enable_fifomerge(dss_data.fifo_merge); | ||
622 | dss_data.fifo_merge_dirty = false; | ||
623 | } | ||
624 | |||
625 | if (mp->updating) | ||
626 | mp->shadow_info_dirty = true; | ||
627 | } | ||
628 | } | ||
629 | } | ||
630 | |||
588 | static void dss_write_regs(void) | 631 | static void dss_write_regs(void) |
589 | { | 632 | { |
590 | const int num_mgrs = omap_dss_get_num_overlay_managers(); | 633 | const int num_mgrs = omap_dss_get_num_overlay_managers(); |
591 | int i; | 634 | int i; |
592 | 635 | ||
636 | dss_write_regs_common(); | ||
637 | |||
593 | for (i = 0; i < num_mgrs; ++i) { | 638 | for (i = 0; i < num_mgrs; ++i) { |
594 | struct omap_overlay_manager *mgr; | 639 | struct omap_overlay_manager *mgr; |
595 | struct mgr_priv_data *mp; | 640 | struct mgr_priv_data *mp; |
@@ -640,6 +685,22 @@ static void dss_set_go_bits(void) | |||
640 | 685 | ||
641 | } | 686 | } |
642 | 687 | ||
688 | static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr) | ||
689 | { | ||
690 | struct omap_overlay *ovl; | ||
691 | struct mgr_priv_data *mp; | ||
692 | struct ovl_priv_data *op; | ||
693 | |||
694 | mp = get_mgr_priv(mgr); | ||
695 | mp->shadow_info_dirty = false; | ||
696 | |||
697 | list_for_each_entry(ovl, &mgr->overlays, list) { | ||
698 | op = get_ovl_priv(ovl); | ||
699 | op->shadow_info_dirty = false; | ||
700 | op->shadow_extra_info_dirty = false; | ||
701 | } | ||
702 | } | ||
703 | |||
643 | void dss_mgr_start_update(struct omap_overlay_manager *mgr) | 704 | void dss_mgr_start_update(struct omap_overlay_manager *mgr) |
644 | { | 705 | { |
645 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | 706 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
@@ -659,6 +720,8 @@ void dss_mgr_start_update(struct omap_overlay_manager *mgr) | |||
659 | 720 | ||
660 | dss_mgr_write_regs(mgr); | 721 | dss_mgr_write_regs(mgr); |
661 | 722 | ||
723 | dss_write_regs_common(); | ||
724 | |||
662 | mp->updating = true; | 725 | mp->updating = true; |
663 | 726 | ||
664 | if (!dss_data.irq_enabled && need_isr()) | 727 | if (!dss_data.irq_enabled && need_isr()) |
@@ -666,6 +729,8 @@ void dss_mgr_start_update(struct omap_overlay_manager *mgr) | |||
666 | 729 | ||
667 | dispc_mgr_enable(mgr->id, true); | 730 | dispc_mgr_enable(mgr->id, true); |
668 | 731 | ||
732 | mgr_clear_shadow_dirty(mgr); | ||
733 | |||
669 | spin_unlock_irqrestore(&data_lock, flags); | 734 | spin_unlock_irqrestore(&data_lock, flags); |
670 | } | 735 | } |
671 | 736 | ||
@@ -709,22 +774,6 @@ static void dss_unregister_vsync_isr(void) | |||
709 | dss_data.irq_enabled = false; | 774 | dss_data.irq_enabled = false; |
710 | } | 775 | } |
711 | 776 | ||
712 | static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr) | ||
713 | { | ||
714 | struct omap_overlay *ovl; | ||
715 | struct mgr_priv_data *mp; | ||
716 | struct ovl_priv_data *op; | ||
717 | |||
718 | mp = get_mgr_priv(mgr); | ||
719 | mp->shadow_info_dirty = false; | ||
720 | |||
721 | list_for_each_entry(ovl, &mgr->overlays, list) { | ||
722 | op = get_ovl_priv(ovl); | ||
723 | op->shadow_info_dirty = false; | ||
724 | op->shadow_extra_info_dirty = false; | ||
725 | } | ||
726 | } | ||
727 | |||
728 | static void dss_apply_irq_handler(void *data, u32 mask) | 777 | static void dss_apply_irq_handler(void *data, u32 mask) |
729 | { | 778 | { |
730 | const int num_mgrs = dss_feat_get_num_mgrs(); | 779 | const int num_mgrs = dss_feat_get_num_mgrs(); |
@@ -754,9 +803,6 @@ static void dss_apply_irq_handler(void *data, u32 mask) | |||
754 | 803 | ||
755 | if (was_busy && !mp->busy) | 804 | if (was_busy && !mp->busy) |
756 | mgr_clear_shadow_dirty(mgr); | 805 | mgr_clear_shadow_dirty(mgr); |
757 | } else { | ||
758 | if (was_updating && !mp->updating) | ||
759 | mgr_clear_shadow_dirty(mgr); | ||
760 | } | 806 | } |
761 | } | 807 | } |
762 | 808 | ||
@@ -859,11 +905,20 @@ static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl, | |||
859 | op->extra_info_dirty = true; | 905 | op->extra_info_dirty = true; |
860 | } | 906 | } |
861 | 907 | ||
862 | static void dss_ovl_setup_fifo(struct omap_overlay *ovl) | 908 | static void dss_apply_fifo_merge(bool use_fifo_merge) |
909 | { | ||
910 | if (dss_data.fifo_merge == use_fifo_merge) | ||
911 | return; | ||
912 | |||
913 | dss_data.fifo_merge = use_fifo_merge; | ||
914 | dss_data.fifo_merge_dirty = true; | ||
915 | } | ||
916 | |||
917 | static void dss_ovl_setup_fifo(struct omap_overlay *ovl, | ||
918 | bool use_fifo_merge) | ||
863 | { | 919 | { |
864 | struct ovl_priv_data *op = get_ovl_priv(ovl); | 920 | struct ovl_priv_data *op = get_ovl_priv(ovl); |
865 | struct omap_dss_device *dssdev; | 921 | struct omap_dss_device *dssdev; |
866 | u32 size, burst_size; | ||
867 | u32 fifo_low, fifo_high; | 922 | u32 fifo_low, fifo_high; |
868 | 923 | ||
869 | if (!op->enabled && !op->enabling) | 924 | if (!op->enabled && !op->enabling) |
@@ -871,33 +926,14 @@ static void dss_ovl_setup_fifo(struct omap_overlay *ovl) | |||
871 | 926 | ||
872 | dssdev = ovl->manager->device; | 927 | dssdev = ovl->manager->device; |
873 | 928 | ||
874 | size = dispc_ovl_get_fifo_size(ovl->id); | 929 | dispc_ovl_compute_fifo_thresholds(ovl->id, &fifo_low, &fifo_high, |
875 | 930 | use_fifo_merge); | |
876 | burst_size = dispc_ovl_get_burst_size(ovl->id); | ||
877 | |||
878 | switch (dssdev->type) { | ||
879 | case OMAP_DISPLAY_TYPE_DPI: | ||
880 | case OMAP_DISPLAY_TYPE_DBI: | ||
881 | case OMAP_DISPLAY_TYPE_SDI: | ||
882 | case OMAP_DISPLAY_TYPE_VENC: | ||
883 | case OMAP_DISPLAY_TYPE_HDMI: | ||
884 | default_get_overlay_fifo_thresholds(ovl->id, size, | ||
885 | burst_size, &fifo_low, &fifo_high); | ||
886 | break; | ||
887 | #ifdef CONFIG_OMAP2_DSS_DSI | ||
888 | case OMAP_DISPLAY_TYPE_DSI: | ||
889 | dsi_get_overlay_fifo_thresholds(ovl->id, size, | ||
890 | burst_size, &fifo_low, &fifo_high); | ||
891 | break; | ||
892 | #endif | ||
893 | default: | ||
894 | BUG(); | ||
895 | } | ||
896 | 931 | ||
897 | dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high); | 932 | dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high); |
898 | } | 933 | } |
899 | 934 | ||
900 | static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr) | 935 | static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr, |
936 | bool use_fifo_merge) | ||
901 | { | 937 | { |
902 | struct omap_overlay *ovl; | 938 | struct omap_overlay *ovl; |
903 | struct mgr_priv_data *mp; | 939 | struct mgr_priv_data *mp; |
@@ -908,19 +944,94 @@ static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr) | |||
908 | return; | 944 | return; |
909 | 945 | ||
910 | list_for_each_entry(ovl, &mgr->overlays, list) | 946 | list_for_each_entry(ovl, &mgr->overlays, list) |
911 | dss_ovl_setup_fifo(ovl); | 947 | dss_ovl_setup_fifo(ovl, use_fifo_merge); |
948 | } | ||
949 | |||
950 | static void dss_setup_fifos(bool use_fifo_merge) | ||
951 | { | ||
952 | const int num_mgrs = omap_dss_get_num_overlay_managers(); | ||
953 | struct omap_overlay_manager *mgr; | ||
954 | int i; | ||
955 | |||
956 | for (i = 0; i < num_mgrs; ++i) { | ||
957 | mgr = omap_dss_get_overlay_manager(i); | ||
958 | dss_mgr_setup_fifos(mgr, use_fifo_merge); | ||
959 | } | ||
912 | } | 960 | } |
913 | 961 | ||
914 | static void dss_setup_fifos(void) | 962 | static int get_num_used_managers(void) |
915 | { | 963 | { |
916 | const int num_mgrs = omap_dss_get_num_overlay_managers(); | 964 | const int num_mgrs = omap_dss_get_num_overlay_managers(); |
917 | struct omap_overlay_manager *mgr; | 965 | struct omap_overlay_manager *mgr; |
966 | struct mgr_priv_data *mp; | ||
918 | int i; | 967 | int i; |
968 | int enabled_mgrs; | ||
969 | |||
970 | enabled_mgrs = 0; | ||
919 | 971 | ||
920 | for (i = 0; i < num_mgrs; ++i) { | 972 | for (i = 0; i < num_mgrs; ++i) { |
921 | mgr = omap_dss_get_overlay_manager(i); | 973 | mgr = omap_dss_get_overlay_manager(i); |
922 | dss_mgr_setup_fifos(mgr); | 974 | mp = get_mgr_priv(mgr); |
975 | |||
976 | if (!mp->enabled) | ||
977 | continue; | ||
978 | |||
979 | enabled_mgrs++; | ||
980 | } | ||
981 | |||
982 | return enabled_mgrs; | ||
983 | } | ||
984 | |||
985 | static int get_num_used_overlays(void) | ||
986 | { | ||
987 | const int num_ovls = omap_dss_get_num_overlays(); | ||
988 | struct omap_overlay *ovl; | ||
989 | struct ovl_priv_data *op; | ||
990 | struct mgr_priv_data *mp; | ||
991 | int i; | ||
992 | int enabled_ovls; | ||
993 | |||
994 | enabled_ovls = 0; | ||
995 | |||
996 | for (i = 0; i < num_ovls; ++i) { | ||
997 | ovl = omap_dss_get_overlay(i); | ||
998 | op = get_ovl_priv(ovl); | ||
999 | |||
1000 | if (!op->enabled && !op->enabling) | ||
1001 | continue; | ||
1002 | |||
1003 | mp = get_mgr_priv(ovl->manager); | ||
1004 | |||
1005 | if (!mp->enabled) | ||
1006 | continue; | ||
1007 | |||
1008 | enabled_ovls++; | ||
923 | } | 1009 | } |
1010 | |||
1011 | return enabled_ovls; | ||
1012 | } | ||
1013 | |||
1014 | static bool get_use_fifo_merge(void) | ||
1015 | { | ||
1016 | int enabled_mgrs = get_num_used_managers(); | ||
1017 | int enabled_ovls = get_num_used_overlays(); | ||
1018 | |||
1019 | if (!dss_has_feature(FEAT_FIFO_MERGE)) | ||
1020 | return false; | ||
1021 | |||
1022 | /* | ||
1023 | * In theory the only requirement for fifomerge is enabled_ovls <= 1. | ||
1024 | * However, if we have two managers enabled and set/unset the fifomerge, | ||
1025 | * we need to set the GO bits in particular sequence for the managers, | ||
1026 | * and wait in between. | ||
1027 | * | ||
1028 | * This is rather difficult as new apply calls can happen at any time, | ||
1029 | * so we simplify the problem by requiring also that enabled_mgrs <= 1. | ||
1030 | * In practice this shouldn't matter, because when only one overlay is | ||
1031 | * enabled, most likely only one output is enabled. | ||
1032 | */ | ||
1033 | |||
1034 | return enabled_mgrs <= 1 && enabled_ovls <= 1; | ||
924 | } | 1035 | } |
925 | 1036 | ||
926 | int dss_mgr_enable(struct omap_overlay_manager *mgr) | 1037 | int dss_mgr_enable(struct omap_overlay_manager *mgr) |
@@ -928,6 +1039,7 @@ int dss_mgr_enable(struct omap_overlay_manager *mgr) | |||
928 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | 1039 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
929 | unsigned long flags; | 1040 | unsigned long flags; |
930 | int r; | 1041 | int r; |
1042 | bool fifo_merge; | ||
931 | 1043 | ||
932 | mutex_lock(&apply_lock); | 1044 | mutex_lock(&apply_lock); |
933 | 1045 | ||
@@ -945,11 +1057,23 @@ int dss_mgr_enable(struct omap_overlay_manager *mgr) | |||
945 | goto err; | 1057 | goto err; |
946 | } | 1058 | } |
947 | 1059 | ||
948 | dss_setup_fifos(); | 1060 | /* step 1: setup fifos/fifomerge before enabling the manager */ |
1061 | |||
1062 | fifo_merge = get_use_fifo_merge(); | ||
1063 | dss_setup_fifos(fifo_merge); | ||
1064 | dss_apply_fifo_merge(fifo_merge); | ||
949 | 1065 | ||
950 | dss_write_regs(); | 1066 | dss_write_regs(); |
951 | dss_set_go_bits(); | 1067 | dss_set_go_bits(); |
952 | 1068 | ||
1069 | spin_unlock_irqrestore(&data_lock, flags); | ||
1070 | |||
1071 | /* wait until fifo config is in */ | ||
1072 | wait_pending_extra_info_updates(); | ||
1073 | |||
1074 | /* step 2: enable the manager */ | ||
1075 | spin_lock_irqsave(&data_lock, flags); | ||
1076 | |||
953 | if (!mgr_manual_update(mgr)) | 1077 | if (!mgr_manual_update(mgr)) |
954 | mp->updating = true; | 1078 | mp->updating = true; |
955 | 1079 | ||
@@ -974,6 +1098,7 @@ void dss_mgr_disable(struct omap_overlay_manager *mgr) | |||
974 | { | 1098 | { |
975 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | 1099 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
976 | unsigned long flags; | 1100 | unsigned long flags; |
1101 | bool fifo_merge; | ||
977 | 1102 | ||
978 | mutex_lock(&apply_lock); | 1103 | mutex_lock(&apply_lock); |
979 | 1104 | ||
@@ -988,8 +1113,16 @@ void dss_mgr_disable(struct omap_overlay_manager *mgr) | |||
988 | mp->updating = false; | 1113 | mp->updating = false; |
989 | mp->enabled = false; | 1114 | mp->enabled = false; |
990 | 1115 | ||
1116 | fifo_merge = get_use_fifo_merge(); | ||
1117 | dss_setup_fifos(fifo_merge); | ||
1118 | dss_apply_fifo_merge(fifo_merge); | ||
1119 | |||
1120 | dss_write_regs(); | ||
1121 | dss_set_go_bits(); | ||
1122 | |||
991 | spin_unlock_irqrestore(&data_lock, flags); | 1123 | spin_unlock_irqrestore(&data_lock, flags); |
992 | 1124 | ||
1125 | wait_pending_extra_info_updates(); | ||
993 | out: | 1126 | out: |
994 | mutex_unlock(&apply_lock); | 1127 | mutex_unlock(&apply_lock); |
995 | } | 1128 | } |
@@ -1241,6 +1374,7 @@ int dss_ovl_enable(struct omap_overlay *ovl) | |||
1241 | { | 1374 | { |
1242 | struct ovl_priv_data *op = get_ovl_priv(ovl); | 1375 | struct ovl_priv_data *op = get_ovl_priv(ovl); |
1243 | unsigned long flags; | 1376 | unsigned long flags; |
1377 | bool fifo_merge; | ||
1244 | int r; | 1378 | int r; |
1245 | 1379 | ||
1246 | mutex_lock(&apply_lock); | 1380 | mutex_lock(&apply_lock); |
@@ -1266,7 +1400,22 @@ int dss_ovl_enable(struct omap_overlay *ovl) | |||
1266 | goto err2; | 1400 | goto err2; |
1267 | } | 1401 | } |
1268 | 1402 | ||
1269 | dss_setup_fifos(); | 1403 | /* step 1: configure fifos/fifomerge for currently enabled ovls */ |
1404 | |||
1405 | fifo_merge = get_use_fifo_merge(); | ||
1406 | dss_setup_fifos(fifo_merge); | ||
1407 | dss_apply_fifo_merge(fifo_merge); | ||
1408 | |||
1409 | dss_write_regs(); | ||
1410 | dss_set_go_bits(); | ||
1411 | |||
1412 | spin_unlock_irqrestore(&data_lock, flags); | ||
1413 | |||
1414 | /* wait for fifo configs to go in */ | ||
1415 | wait_pending_extra_info_updates(); | ||
1416 | |||
1417 | /* step 2: enable the overlay */ | ||
1418 | spin_lock_irqsave(&data_lock, flags); | ||
1270 | 1419 | ||
1271 | op->enabling = false; | 1420 | op->enabling = false; |
1272 | dss_apply_ovl_enable(ovl, true); | 1421 | dss_apply_ovl_enable(ovl, true); |
@@ -1294,6 +1443,7 @@ int dss_ovl_disable(struct omap_overlay *ovl) | |||
1294 | { | 1443 | { |
1295 | struct ovl_priv_data *op = get_ovl_priv(ovl); | 1444 | struct ovl_priv_data *op = get_ovl_priv(ovl); |
1296 | unsigned long flags; | 1445 | unsigned long flags; |
1446 | bool fifo_merge; | ||
1297 | int r; | 1447 | int r; |
1298 | 1448 | ||
1299 | mutex_lock(&apply_lock); | 1449 | mutex_lock(&apply_lock); |
@@ -1308,9 +1458,11 @@ int dss_ovl_disable(struct omap_overlay *ovl) | |||
1308 | goto err; | 1458 | goto err; |
1309 | } | 1459 | } |
1310 | 1460 | ||
1461 | /* step 1: disable the overlay */ | ||
1311 | spin_lock_irqsave(&data_lock, flags); | 1462 | spin_lock_irqsave(&data_lock, flags); |
1312 | 1463 | ||
1313 | dss_apply_ovl_enable(ovl, false); | 1464 | dss_apply_ovl_enable(ovl, false); |
1465 | |||
1314 | dss_write_regs(); | 1466 | dss_write_regs(); |
1315 | dss_set_go_bits(); | 1467 | dss_set_go_bits(); |
1316 | 1468 | ||
@@ -1319,6 +1471,21 @@ int dss_ovl_disable(struct omap_overlay *ovl) | |||
1319 | /* wait for the overlay to be disabled */ | 1471 | /* wait for the overlay to be disabled */ |
1320 | wait_pending_extra_info_updates(); | 1472 | wait_pending_extra_info_updates(); |
1321 | 1473 | ||
1474 | /* step 2: configure fifos/fifomerge */ | ||
1475 | spin_lock_irqsave(&data_lock, flags); | ||
1476 | |||
1477 | fifo_merge = get_use_fifo_merge(); | ||
1478 | dss_setup_fifos(fifo_merge); | ||
1479 | dss_apply_fifo_merge(fifo_merge); | ||
1480 | |||
1481 | dss_write_regs(); | ||
1482 | dss_set_go_bits(); | ||
1483 | |||
1484 | spin_unlock_irqrestore(&data_lock, flags); | ||
1485 | |||
1486 | /* wait for fifo config to go in */ | ||
1487 | wait_pending_extra_info_updates(); | ||
1488 | |||
1322 | mutex_unlock(&apply_lock); | 1489 | mutex_unlock(&apply_lock); |
1323 | 1490 | ||
1324 | return 0; | 1491 | return 0; |
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 8613f86fb56d..e8a120771ac6 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c | |||
@@ -183,42 +183,6 @@ static int omap_dss_probe(struct platform_device *pdev) | |||
183 | dss_init_overlay_managers(pdev); | 183 | dss_init_overlay_managers(pdev); |
184 | dss_init_overlays(pdev); | 184 | dss_init_overlays(pdev); |
185 | 185 | ||
186 | r = dss_init_platform_driver(); | ||
187 | if (r) { | ||
188 | DSSERR("Failed to initialize DSS platform driver\n"); | ||
189 | goto err_dss; | ||
190 | } | ||
191 | |||
192 | r = dispc_init_platform_driver(); | ||
193 | if (r) { | ||
194 | DSSERR("Failed to initialize dispc platform driver\n"); | ||
195 | goto err_dispc; | ||
196 | } | ||
197 | |||
198 | r = rfbi_init_platform_driver(); | ||
199 | if (r) { | ||
200 | DSSERR("Failed to initialize rfbi platform driver\n"); | ||
201 | goto err_rfbi; | ||
202 | } | ||
203 | |||
204 | r = venc_init_platform_driver(); | ||
205 | if (r) { | ||
206 | DSSERR("Failed to initialize venc platform driver\n"); | ||
207 | goto err_venc; | ||
208 | } | ||
209 | |||
210 | r = dsi_init_platform_driver(); | ||
211 | if (r) { | ||
212 | DSSERR("Failed to initialize DSI platform driver\n"); | ||
213 | goto err_dsi; | ||
214 | } | ||
215 | |||
216 | r = hdmi_init_platform_driver(); | ||
217 | if (r) { | ||
218 | DSSERR("Failed to initialize hdmi\n"); | ||
219 | goto err_hdmi; | ||
220 | } | ||
221 | |||
222 | r = dss_initialize_debugfs(); | 186 | r = dss_initialize_debugfs(); |
223 | if (r) | 187 | if (r) |
224 | goto err_debugfs; | 188 | goto err_debugfs; |
@@ -246,18 +210,6 @@ static int omap_dss_probe(struct platform_device *pdev) | |||
246 | err_register: | 210 | err_register: |
247 | dss_uninitialize_debugfs(); | 211 | dss_uninitialize_debugfs(); |
248 | err_debugfs: | 212 | err_debugfs: |
249 | hdmi_uninit_platform_driver(); | ||
250 | err_hdmi: | ||
251 | dsi_uninit_platform_driver(); | ||
252 | err_dsi: | ||
253 | venc_uninit_platform_driver(); | ||
254 | err_venc: | ||
255 | dispc_uninit_platform_driver(); | ||
256 | err_dispc: | ||
257 | rfbi_uninit_platform_driver(); | ||
258 | err_rfbi: | ||
259 | dss_uninit_platform_driver(); | ||
260 | err_dss: | ||
261 | 213 | ||
262 | return r; | 214 | return r; |
263 | } | 215 | } |
@@ -269,13 +221,6 @@ static int omap_dss_remove(struct platform_device *pdev) | |||
269 | 221 | ||
270 | dss_uninitialize_debugfs(); | 222 | dss_uninitialize_debugfs(); |
271 | 223 | ||
272 | hdmi_uninit_platform_driver(); | ||
273 | dsi_uninit_platform_driver(); | ||
274 | venc_uninit_platform_driver(); | ||
275 | rfbi_uninit_platform_driver(); | ||
276 | dispc_uninit_platform_driver(); | ||
277 | dss_uninit_platform_driver(); | ||
278 | |||
279 | dss_uninit_overlays(pdev); | 224 | dss_uninit_overlays(pdev); |
280 | dss_uninit_overlay_managers(pdev); | 225 | dss_uninit_overlay_managers(pdev); |
281 | 226 | ||
@@ -525,6 +470,80 @@ static int omap_dss_bus_register(void) | |||
525 | 470 | ||
526 | /* INIT */ | 471 | /* INIT */ |
527 | 472 | ||
473 | static int __init omap_dss_register_drivers(void) | ||
474 | { | ||
475 | int r; | ||
476 | |||
477 | r = platform_driver_register(&omap_dss_driver); | ||
478 | if (r) | ||
479 | return r; | ||
480 | |||
481 | r = dss_init_platform_driver(); | ||
482 | if (r) { | ||
483 | DSSERR("Failed to initialize DSS platform driver\n"); | ||
484 | goto err_dss; | ||
485 | } | ||
486 | |||
487 | r = dispc_init_platform_driver(); | ||
488 | if (r) { | ||
489 | DSSERR("Failed to initialize dispc platform driver\n"); | ||
490 | goto err_dispc; | ||
491 | } | ||
492 | |||
493 | r = rfbi_init_platform_driver(); | ||
494 | if (r) { | ||
495 | DSSERR("Failed to initialize rfbi platform driver\n"); | ||
496 | goto err_rfbi; | ||
497 | } | ||
498 | |||
499 | r = venc_init_platform_driver(); | ||
500 | if (r) { | ||
501 | DSSERR("Failed to initialize venc platform driver\n"); | ||
502 | goto err_venc; | ||
503 | } | ||
504 | |||
505 | r = dsi_init_platform_driver(); | ||
506 | if (r) { | ||
507 | DSSERR("Failed to initialize DSI platform driver\n"); | ||
508 | goto err_dsi; | ||
509 | } | ||
510 | |||
511 | r = hdmi_init_platform_driver(); | ||
512 | if (r) { | ||
513 | DSSERR("Failed to initialize hdmi\n"); | ||
514 | goto err_hdmi; | ||
515 | } | ||
516 | |||
517 | return 0; | ||
518 | |||
519 | err_hdmi: | ||
520 | dsi_uninit_platform_driver(); | ||
521 | err_dsi: | ||
522 | venc_uninit_platform_driver(); | ||
523 | err_venc: | ||
524 | rfbi_uninit_platform_driver(); | ||
525 | err_rfbi: | ||
526 | dispc_uninit_platform_driver(); | ||
527 | err_dispc: | ||
528 | dss_uninit_platform_driver(); | ||
529 | err_dss: | ||
530 | platform_driver_unregister(&omap_dss_driver); | ||
531 | |||
532 | return r; | ||
533 | } | ||
534 | |||
535 | static void __exit omap_dss_unregister_drivers(void) | ||
536 | { | ||
537 | hdmi_uninit_platform_driver(); | ||
538 | dsi_uninit_platform_driver(); | ||
539 | venc_uninit_platform_driver(); | ||
540 | rfbi_uninit_platform_driver(); | ||
541 | dispc_uninit_platform_driver(); | ||
542 | dss_uninit_platform_driver(); | ||
543 | |||
544 | platform_driver_unregister(&omap_dss_driver); | ||
545 | } | ||
546 | |||
528 | #ifdef CONFIG_OMAP2_DSS_MODULE | 547 | #ifdef CONFIG_OMAP2_DSS_MODULE |
529 | static void omap_dss_bus_unregister(void) | 548 | static void omap_dss_bus_unregister(void) |
530 | { | 549 | { |
@@ -541,7 +560,7 @@ static int __init omap_dss_init(void) | |||
541 | if (r) | 560 | if (r) |
542 | return r; | 561 | return r; |
543 | 562 | ||
544 | r = platform_driver_register(&omap_dss_driver); | 563 | r = omap_dss_register_drivers(); |
545 | if (r) { | 564 | if (r) { |
546 | omap_dss_bus_unregister(); | 565 | omap_dss_bus_unregister(); |
547 | return r; | 566 | return r; |
@@ -562,7 +581,7 @@ static void __exit omap_dss_exit(void) | |||
562 | core.vdds_sdi_reg = NULL; | 581 | core.vdds_sdi_reg = NULL; |
563 | } | 582 | } |
564 | 583 | ||
565 | platform_driver_unregister(&omap_dss_driver); | 584 | omap_dss_unregister_drivers(); |
566 | 585 | ||
567 | omap_dss_bus_unregister(); | 586 | omap_dss_bus_unregister(); |
568 | } | 587 | } |
@@ -577,7 +596,7 @@ static int __init omap_dss_init(void) | |||
577 | 596 | ||
578 | static int __init omap_dss_init2(void) | 597 | static int __init omap_dss_init2(void) |
579 | { | 598 | { |
580 | return platform_driver_register(&omap_dss_driver); | 599 | return omap_dss_register_drivers(); |
581 | } | 600 | } |
582 | 601 | ||
583 | core_initcall(omap_dss_init); | 602 | core_initcall(omap_dss_init); |
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index e1626a1d5c45..bddd64b435b9 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c | |||
@@ -37,7 +37,6 @@ | |||
37 | #include <linux/platform_device.h> | 37 | #include <linux/platform_device.h> |
38 | #include <linux/pm_runtime.h> | 38 | #include <linux/pm_runtime.h> |
39 | 39 | ||
40 | #include <plat/sram.h> | ||
41 | #include <plat/clock.h> | 40 | #include <plat/clock.h> |
42 | 41 | ||
43 | #include <video/omapdss.h> | 42 | #include <video/omapdss.h> |
@@ -736,11 +735,11 @@ static void dispc_ovl_set_color_mode(enum omap_plane plane, | |||
736 | switch (color_mode) { | 735 | switch (color_mode) { |
737 | case OMAP_DSS_COLOR_NV12: | 736 | case OMAP_DSS_COLOR_NV12: |
738 | m = 0x0; break; | 737 | m = 0x0; break; |
739 | case OMAP_DSS_COLOR_RGB12U: | 738 | case OMAP_DSS_COLOR_RGBX16: |
740 | m = 0x1; break; | 739 | m = 0x1; break; |
741 | case OMAP_DSS_COLOR_RGBA16: | 740 | case OMAP_DSS_COLOR_RGBA16: |
742 | m = 0x2; break; | 741 | m = 0x2; break; |
743 | case OMAP_DSS_COLOR_RGBX16: | 742 | case OMAP_DSS_COLOR_RGB12U: |
744 | m = 0x4; break; | 743 | m = 0x4; break; |
745 | case OMAP_DSS_COLOR_ARGB16: | 744 | case OMAP_DSS_COLOR_ARGB16: |
746 | m = 0x5; break; | 745 | m = 0x5; break; |
@@ -789,9 +788,9 @@ static void dispc_ovl_set_color_mode(enum omap_plane plane, | |||
789 | m = 0x8; break; | 788 | m = 0x8; break; |
790 | case OMAP_DSS_COLOR_RGB24P: | 789 | case OMAP_DSS_COLOR_RGB24P: |
791 | m = 0x9; break; | 790 | m = 0x9; break; |
792 | case OMAP_DSS_COLOR_YUV2: | 791 | case OMAP_DSS_COLOR_RGBX16: |
793 | m = 0xa; break; | 792 | m = 0xa; break; |
794 | case OMAP_DSS_COLOR_UYVY: | 793 | case OMAP_DSS_COLOR_RGBA16: |
795 | m = 0xb; break; | 794 | m = 0xb; break; |
796 | case OMAP_DSS_COLOR_ARGB32: | 795 | case OMAP_DSS_COLOR_ARGB32: |
797 | m = 0xc; break; | 796 | m = 0xc; break; |
@@ -909,7 +908,7 @@ static void dispc_configure_burst_sizes(void) | |||
909 | dispc_ovl_set_burst_size(i, burst_size); | 908 | dispc_ovl_set_burst_size(i, burst_size); |
910 | } | 909 | } |
911 | 910 | ||
912 | u32 dispc_ovl_get_burst_size(enum omap_plane plane) | 911 | static u32 dispc_ovl_get_burst_size(enum omap_plane plane) |
913 | { | 912 | { |
914 | unsigned unit = dss_feat_get_burst_size_unit(); | 913 | unsigned unit = dss_feat_get_burst_size_unit(); |
915 | /* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */ | 914 | /* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */ |
@@ -1018,7 +1017,7 @@ static void dispc_read_plane_fifo_sizes(void) | |||
1018 | } | 1017 | } |
1019 | } | 1018 | } |
1020 | 1019 | ||
1021 | u32 dispc_ovl_get_fifo_size(enum omap_plane plane) | 1020 | static u32 dispc_ovl_get_fifo_size(enum omap_plane plane) |
1022 | { | 1021 | { |
1023 | return dispc.fifo_size[plane]; | 1022 | return dispc.fifo_size[plane]; |
1024 | } | 1023 | } |
@@ -1039,13 +1038,13 @@ void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high) | |||
1039 | dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end); | 1038 | dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end); |
1040 | dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end); | 1039 | dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end); |
1041 | 1040 | ||
1042 | DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n", | 1041 | DSSDBG("fifo(%d) threshold (bytes), old %u/%u, new %u/%u\n", |
1043 | plane, | 1042 | plane, |
1044 | REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane), | 1043 | REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane), |
1045 | lo_start, lo_end), | 1044 | lo_start, lo_end) * unit, |
1046 | REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane), | 1045 | REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane), |
1047 | hi_start, hi_end), | 1046 | hi_start, hi_end) * unit, |
1048 | low, high); | 1047 | low * unit, high * unit); |
1049 | 1048 | ||
1050 | dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane), | 1049 | dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane), |
1051 | FLD_VAL(high, hi_start, hi_end) | | 1050 | FLD_VAL(high, hi_start, hi_end) | |
@@ -1054,10 +1053,53 @@ void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high) | |||
1054 | 1053 | ||
1055 | void dispc_enable_fifomerge(bool enable) | 1054 | void dispc_enable_fifomerge(bool enable) |
1056 | { | 1055 | { |
1056 | if (!dss_has_feature(FEAT_FIFO_MERGE)) { | ||
1057 | WARN_ON(enable); | ||
1058 | return; | ||
1059 | } | ||
1060 | |||
1057 | DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled"); | 1061 | DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled"); |
1058 | REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14); | 1062 | REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14); |
1059 | } | 1063 | } |
1060 | 1064 | ||
1065 | void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, | ||
1066 | u32 *fifo_low, u32 *fifo_high, bool use_fifomerge) | ||
1067 | { | ||
1068 | /* | ||
1069 | * All sizes are in bytes. Both the buffer and burst are made of | ||
1070 | * buffer_units, and the fifo thresholds must be buffer_unit aligned. | ||
1071 | */ | ||
1072 | |||
1073 | unsigned buf_unit = dss_feat_get_buffer_size_unit(); | ||
1074 | unsigned ovl_fifo_size, total_fifo_size, burst_size; | ||
1075 | int i; | ||
1076 | |||
1077 | burst_size = dispc_ovl_get_burst_size(plane); | ||
1078 | ovl_fifo_size = dispc_ovl_get_fifo_size(plane); | ||
1079 | |||
1080 | if (use_fifomerge) { | ||
1081 | total_fifo_size = 0; | ||
1082 | for (i = 0; i < omap_dss_get_num_overlays(); ++i) | ||
1083 | total_fifo_size += dispc_ovl_get_fifo_size(i); | ||
1084 | } else { | ||
1085 | total_fifo_size = ovl_fifo_size; | ||
1086 | } | ||
1087 | |||
1088 | /* | ||
1089 | * We use the same low threshold for both fifomerge and non-fifomerge | ||
1090 | * cases, but for fifomerge we calculate the high threshold using the | ||
1091 | * combined fifo size | ||
1092 | */ | ||
1093 | |||
1094 | if (dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) { | ||
1095 | *fifo_low = ovl_fifo_size - burst_size * 2; | ||
1096 | *fifo_high = total_fifo_size - burst_size; | ||
1097 | } else { | ||
1098 | *fifo_low = ovl_fifo_size - burst_size; | ||
1099 | *fifo_high = total_fifo_size - buf_unit; | ||
1100 | } | ||
1101 | } | ||
1102 | |||
1061 | static void dispc_ovl_set_fir(enum omap_plane plane, | 1103 | static void dispc_ovl_set_fir(enum omap_plane plane, |
1062 | int hinc, int vinc, | 1104 | int hinc, int vinc, |
1063 | enum omap_color_component color_comp) | 1105 | enum omap_color_component color_comp) |
@@ -1651,6 +1693,7 @@ static unsigned long calc_fclk(enum omap_channel channel, u16 width, | |||
1651 | u16 height, u16 out_width, u16 out_height) | 1693 | u16 height, u16 out_width, u16 out_height) |
1652 | { | 1694 | { |
1653 | unsigned int hf, vf; | 1695 | unsigned int hf, vf; |
1696 | unsigned long pclk = dispc_mgr_pclk_rate(channel); | ||
1654 | 1697 | ||
1655 | /* | 1698 | /* |
1656 | * FIXME how to determine the 'A' factor | 1699 | * FIXME how to determine the 'A' factor |
@@ -1673,13 +1716,16 @@ static unsigned long calc_fclk(enum omap_channel channel, u16 width, | |||
1673 | 1716 | ||
1674 | if (cpu_is_omap24xx()) { | 1717 | if (cpu_is_omap24xx()) { |
1675 | if (vf > 1 && hf > 1) | 1718 | if (vf > 1 && hf > 1) |
1676 | return dispc_mgr_pclk_rate(channel) * 4; | 1719 | return pclk * 4; |
1677 | else | 1720 | else |
1678 | return dispc_mgr_pclk_rate(channel) * 2; | 1721 | return pclk * 2; |
1679 | } else if (cpu_is_omap34xx()) { | 1722 | } else if (cpu_is_omap34xx()) { |
1680 | return dispc_mgr_pclk_rate(channel) * vf * hf; | 1723 | return pclk * vf * hf; |
1681 | } else { | 1724 | } else { |
1682 | return dispc_mgr_pclk_rate(channel) * hf; | 1725 | if (hf > 1) |
1726 | return DIV_ROUND_UP(pclk, out_width) * width; | ||
1727 | else | ||
1728 | return pclk; | ||
1683 | } | 1729 | } |
1684 | } | 1730 | } |
1685 | 1731 | ||
@@ -3298,15 +3344,6 @@ static int omap_dispchw_probe(struct platform_device *pdev) | |||
3298 | 3344 | ||
3299 | dispc.pdev = pdev; | 3345 | dispc.pdev = pdev; |
3300 | 3346 | ||
3301 | clk = clk_get(&pdev->dev, "fck"); | ||
3302 | if (IS_ERR(clk)) { | ||
3303 | DSSERR("can't get fck\n"); | ||
3304 | r = PTR_ERR(clk); | ||
3305 | goto err_get_clk; | ||
3306 | } | ||
3307 | |||
3308 | dispc.dss_clk = clk; | ||
3309 | |||
3310 | spin_lock_init(&dispc.irq_lock); | 3347 | spin_lock_init(&dispc.irq_lock); |
3311 | 3348 | ||
3312 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | 3349 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS |
@@ -3319,29 +3356,38 @@ static int omap_dispchw_probe(struct platform_device *pdev) | |||
3319 | dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0); | 3356 | dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0); |
3320 | if (!dispc_mem) { | 3357 | if (!dispc_mem) { |
3321 | DSSERR("can't get IORESOURCE_MEM DISPC\n"); | 3358 | DSSERR("can't get IORESOURCE_MEM DISPC\n"); |
3322 | r = -EINVAL; | 3359 | return -EINVAL; |
3323 | goto err_ioremap; | ||
3324 | } | 3360 | } |
3325 | dispc.base = ioremap(dispc_mem->start, resource_size(dispc_mem)); | 3361 | |
3362 | dispc.base = devm_ioremap(&pdev->dev, dispc_mem->start, | ||
3363 | resource_size(dispc_mem)); | ||
3326 | if (!dispc.base) { | 3364 | if (!dispc.base) { |
3327 | DSSERR("can't ioremap DISPC\n"); | 3365 | DSSERR("can't ioremap DISPC\n"); |
3328 | r = -ENOMEM; | 3366 | return -ENOMEM; |
3329 | goto err_ioremap; | ||
3330 | } | 3367 | } |
3368 | |||
3331 | dispc.irq = platform_get_irq(dispc.pdev, 0); | 3369 | dispc.irq = platform_get_irq(dispc.pdev, 0); |
3332 | if (dispc.irq < 0) { | 3370 | if (dispc.irq < 0) { |
3333 | DSSERR("platform_get_irq failed\n"); | 3371 | DSSERR("platform_get_irq failed\n"); |
3334 | r = -ENODEV; | 3372 | return -ENODEV; |
3335 | goto err_irq; | ||
3336 | } | 3373 | } |
3337 | 3374 | ||
3338 | r = request_irq(dispc.irq, omap_dispc_irq_handler, IRQF_SHARED, | 3375 | r = devm_request_irq(&pdev->dev, dispc.irq, omap_dispc_irq_handler, |
3339 | "OMAP DISPC", dispc.pdev); | 3376 | IRQF_SHARED, "OMAP DISPC", dispc.pdev); |
3340 | if (r < 0) { | 3377 | if (r < 0) { |
3341 | DSSERR("request_irq failed\n"); | 3378 | DSSERR("request_irq failed\n"); |
3342 | goto err_irq; | 3379 | return r; |
3380 | } | ||
3381 | |||
3382 | clk = clk_get(&pdev->dev, "fck"); | ||
3383 | if (IS_ERR(clk)) { | ||
3384 | DSSERR("can't get fck\n"); | ||
3385 | r = PTR_ERR(clk); | ||
3386 | return r; | ||
3343 | } | 3387 | } |
3344 | 3388 | ||
3389 | dispc.dss_clk = clk; | ||
3390 | |||
3345 | pm_runtime_enable(&pdev->dev); | 3391 | pm_runtime_enable(&pdev->dev); |
3346 | 3392 | ||
3347 | r = dispc_runtime_get(); | 3393 | r = dispc_runtime_get(); |
@@ -3362,12 +3408,7 @@ static int omap_dispchw_probe(struct platform_device *pdev) | |||
3362 | 3408 | ||
3363 | err_runtime_get: | 3409 | err_runtime_get: |
3364 | pm_runtime_disable(&pdev->dev); | 3410 | pm_runtime_disable(&pdev->dev); |
3365 | free_irq(dispc.irq, dispc.pdev); | ||
3366 | err_irq: | ||
3367 | iounmap(dispc.base); | ||
3368 | err_ioremap: | ||
3369 | clk_put(dispc.dss_clk); | 3411 | clk_put(dispc.dss_clk); |
3370 | err_get_clk: | ||
3371 | return r; | 3412 | return r; |
3372 | } | 3413 | } |
3373 | 3414 | ||
@@ -3377,8 +3418,6 @@ static int omap_dispchw_remove(struct platform_device *pdev) | |||
3377 | 3418 | ||
3378 | clk_put(dispc.dss_clk); | 3419 | clk_put(dispc.dss_clk); |
3379 | 3420 | ||
3380 | free_irq(dispc.irq, dispc.pdev); | ||
3381 | iounmap(dispc.base); | ||
3382 | return 0; | 3421 | return 0; |
3383 | } | 3422 | } |
3384 | 3423 | ||
diff --git a/drivers/video/omap2/dss/dispc_coefs.c b/drivers/video/omap2/dss/dispc_coefs.c index 069bccbb3f12..038c15b04215 100644 --- a/drivers/video/omap2/dss/dispc_coefs.c +++ b/drivers/video/omap2/dss/dispc_coefs.c | |||
@@ -19,14 +19,13 @@ | |||
19 | 19 | ||
20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
21 | #include <video/omapdss.h> | 21 | #include <video/omapdss.h> |
22 | #include "dispc.h" | ||
23 | 22 | ||
24 | #define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0])) | 23 | #include "dispc.h" |
25 | 24 | ||
26 | static const struct dispc_coef coef3_M8[8] = { | 25 | static const struct dispc_coef coef3_M8[8] = { |
27 | { 0, 0, 128, 0, 0 }, | 26 | { 0, 0, 128, 0, 0 }, |
28 | { 0, -4, 123, 9, 0 }, | 27 | { 0, -4, 123, 9, 0 }, |
29 | { 0, -4, 108, 87, 0 }, | 28 | { 0, -4, 108, 24, 0 }, |
30 | { 0, -2, 87, 43, 0 }, | 29 | { 0, -2, 87, 43, 0 }, |
31 | { 0, 64, 64, 0, 0 }, | 30 | { 0, 64, 64, 0, 0 }, |
32 | { 0, 43, 87, -2, 0 }, | 31 | { 0, 43, 87, -2, 0 }, |
@@ -168,7 +167,7 @@ static const struct dispc_coef coef5_M8[8] = { | |||
168 | 167 | ||
169 | static const struct dispc_coef coef5_M9[8] = { | 168 | static const struct dispc_coef coef5_M9[8] = { |
170 | { -3, 10, 114, 10, -3 }, | 169 | { -3, 10, 114, 10, -3 }, |
171 | { -6, 24, 110, 0, -1 }, | 170 | { -6, 24, 111, 0, -1 }, |
172 | { -8, 40, 103, -7, 0 }, | 171 | { -8, 40, 103, -7, 0 }, |
173 | { -11, 58, 91, -11, 1 }, | 172 | { -11, 58, 91, -11, 1 }, |
174 | { 0, -12, 76, 76, -12 }, | 173 | { 0, -12, 76, 76, -12 }, |
@@ -319,7 +318,7 @@ const struct dispc_coef *dispc_ovl_get_scale_coef(int inc, int five_taps) | |||
319 | }; | 318 | }; |
320 | 319 | ||
321 | inc /= 128; | 320 | inc /= 128; |
322 | for (i = 0; i < ARRAY_LEN(coefs); ++i) | 321 | for (i = 0; i < ARRAY_SIZE(coefs); ++i) |
323 | if (inc >= coefs[i].Mmin && inc <= coefs[i].Mmax) | 322 | if (inc >= coefs[i].Mmin && inc <= coefs[i].Mmax) |
324 | return five_taps ? coefs[i].coef_5 : coefs[i].coef_3; | 323 | return five_taps ? coefs[i].coef_5 : coefs[i].coef_3; |
325 | return NULL; | 324 | return NULL; |
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index be331dc5a61b..4424c198dbcd 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c | |||
@@ -279,16 +279,6 @@ void omapdss_default_get_resolution(struct omap_dss_device *dssdev, | |||
279 | } | 279 | } |
280 | EXPORT_SYMBOL(omapdss_default_get_resolution); | 280 | EXPORT_SYMBOL(omapdss_default_get_resolution); |
281 | 281 | ||
282 | void default_get_overlay_fifo_thresholds(enum omap_plane plane, | ||
283 | u32 fifo_size, u32 burst_size, | ||
284 | u32 *fifo_low, u32 *fifo_high) | ||
285 | { | ||
286 | unsigned buf_unit = dss_feat_get_buffer_size_unit(); | ||
287 | |||
288 | *fifo_high = fifo_size - buf_unit; | ||
289 | *fifo_low = fifo_size - burst_size; | ||
290 | } | ||
291 | |||
292 | int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev) | 282 | int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev) |
293 | { | 283 | { |
294 | switch (dssdev->type) { | 284 | switch (dssdev->type) { |
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 52f36ec1c8bb..662d14f8c2c3 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c | |||
@@ -4524,14 +4524,6 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable) | |||
4524 | } | 4524 | } |
4525 | EXPORT_SYMBOL(omapdss_dsi_enable_te); | 4525 | EXPORT_SYMBOL(omapdss_dsi_enable_te); |
4526 | 4526 | ||
4527 | void dsi_get_overlay_fifo_thresholds(enum omap_plane plane, | ||
4528 | u32 fifo_size, u32 burst_size, | ||
4529 | u32 *fifo_low, u32 *fifo_high) | ||
4530 | { | ||
4531 | *fifo_high = fifo_size - burst_size; | ||
4532 | *fifo_low = fifo_size - burst_size * 2; | ||
4533 | } | ||
4534 | |||
4535 | int dsi_init_display(struct omap_dss_device *dssdev) | 4527 | int dsi_init_display(struct omap_dss_device *dssdev) |
4536 | { | 4528 | { |
4537 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4529 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
@@ -4695,11 +4687,9 @@ static int omap_dsihw_probe(struct platform_device *dsidev) | |||
4695 | struct resource *dsi_mem; | 4687 | struct resource *dsi_mem; |
4696 | struct dsi_data *dsi; | 4688 | struct dsi_data *dsi; |
4697 | 4689 | ||
4698 | dsi = kzalloc(sizeof(*dsi), GFP_KERNEL); | 4690 | dsi = devm_kzalloc(&dsidev->dev, sizeof(*dsi), GFP_KERNEL); |
4699 | if (!dsi) { | 4691 | if (!dsi) |
4700 | r = -ENOMEM; | 4692 | return -ENOMEM; |
4701 | goto err_alloc; | ||
4702 | } | ||
4703 | 4693 | ||
4704 | dsi->pdev = dsidev; | 4694 | dsi->pdev = dsidev; |
4705 | dsi_pdev_map[dsi_module] = dsidev; | 4695 | dsi_pdev_map[dsi_module] = dsidev; |
@@ -4722,12 +4712,6 @@ static int omap_dsihw_probe(struct platform_device *dsidev) | |||
4722 | mutex_init(&dsi->lock); | 4712 | mutex_init(&dsi->lock); |
4723 | sema_init(&dsi->bus_lock, 1); | 4713 | sema_init(&dsi->bus_lock, 1); |
4724 | 4714 | ||
4725 | r = dsi_get_clocks(dsidev); | ||
4726 | if (r) | ||
4727 | goto err_get_clk; | ||
4728 | |||
4729 | pm_runtime_enable(&dsidev->dev); | ||
4730 | |||
4731 | INIT_DELAYED_WORK_DEFERRABLE(&dsi->framedone_timeout_work, | 4715 | INIT_DELAYED_WORK_DEFERRABLE(&dsi->framedone_timeout_work, |
4732 | dsi_framedone_timeout_work_callback); | 4716 | dsi_framedone_timeout_work_callback); |
4733 | 4717 | ||
@@ -4739,27 +4723,27 @@ static int omap_dsihw_probe(struct platform_device *dsidev) | |||
4739 | dsi_mem = platform_get_resource(dsi->pdev, IORESOURCE_MEM, 0); | 4723 | dsi_mem = platform_get_resource(dsi->pdev, IORESOURCE_MEM, 0); |
4740 | if (!dsi_mem) { | 4724 | if (!dsi_mem) { |
4741 | DSSERR("can't get IORESOURCE_MEM DSI\n"); | 4725 | DSSERR("can't get IORESOURCE_MEM DSI\n"); |
4742 | r = -EINVAL; | 4726 | return -EINVAL; |
4743 | goto err_ioremap; | ||
4744 | } | 4727 | } |
4745 | dsi->base = ioremap(dsi_mem->start, resource_size(dsi_mem)); | 4728 | |
4729 | dsi->base = devm_ioremap(&dsidev->dev, dsi_mem->start, | ||
4730 | resource_size(dsi_mem)); | ||
4746 | if (!dsi->base) { | 4731 | if (!dsi->base) { |
4747 | DSSERR("can't ioremap DSI\n"); | 4732 | DSSERR("can't ioremap DSI\n"); |
4748 | r = -ENOMEM; | 4733 | return -ENOMEM; |
4749 | goto err_ioremap; | ||
4750 | } | 4734 | } |
4735 | |||
4751 | dsi->irq = platform_get_irq(dsi->pdev, 0); | 4736 | dsi->irq = platform_get_irq(dsi->pdev, 0); |
4752 | if (dsi->irq < 0) { | 4737 | if (dsi->irq < 0) { |
4753 | DSSERR("platform_get_irq failed\n"); | 4738 | DSSERR("platform_get_irq failed\n"); |
4754 | r = -ENODEV; | 4739 | return -ENODEV; |
4755 | goto err_get_irq; | ||
4756 | } | 4740 | } |
4757 | 4741 | ||
4758 | r = request_irq(dsi->irq, omap_dsi_irq_handler, IRQF_SHARED, | 4742 | r = devm_request_irq(&dsidev->dev, dsi->irq, omap_dsi_irq_handler, |
4759 | dev_name(&dsidev->dev), dsi->pdev); | 4743 | IRQF_SHARED, dev_name(&dsidev->dev), dsi->pdev); |
4760 | if (r < 0) { | 4744 | if (r < 0) { |
4761 | DSSERR("request_irq failed\n"); | 4745 | DSSERR("request_irq failed\n"); |
4762 | goto err_get_irq; | 4746 | return r; |
4763 | } | 4747 | } |
4764 | 4748 | ||
4765 | /* DSI VCs initialization */ | 4749 | /* DSI VCs initialization */ |
@@ -4771,9 +4755,15 @@ static int omap_dsihw_probe(struct platform_device *dsidev) | |||
4771 | 4755 | ||
4772 | dsi_calc_clock_param_ranges(dsidev); | 4756 | dsi_calc_clock_param_ranges(dsidev); |
4773 | 4757 | ||
4758 | r = dsi_get_clocks(dsidev); | ||
4759 | if (r) | ||
4760 | return r; | ||
4761 | |||
4762 | pm_runtime_enable(&dsidev->dev); | ||
4763 | |||
4774 | r = dsi_runtime_get(dsidev); | 4764 | r = dsi_runtime_get(dsidev); |
4775 | if (r) | 4765 | if (r) |
4776 | goto err_get_dsi; | 4766 | goto err_runtime_get; |
4777 | 4767 | ||
4778 | rev = dsi_read_reg(dsidev, DSI_REVISION); | 4768 | rev = dsi_read_reg(dsidev, DSI_REVISION); |
4779 | dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n", | 4769 | dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n", |
@@ -4791,15 +4781,9 @@ static int omap_dsihw_probe(struct platform_device *dsidev) | |||
4791 | 4781 | ||
4792 | return 0; | 4782 | return 0; |
4793 | 4783 | ||
4794 | err_get_dsi: | 4784 | err_runtime_get: |
4795 | free_irq(dsi->irq, dsi->pdev); | ||
4796 | err_get_irq: | ||
4797 | iounmap(dsi->base); | ||
4798 | err_ioremap: | ||
4799 | pm_runtime_disable(&dsidev->dev); | 4785 | pm_runtime_disable(&dsidev->dev); |
4800 | err_get_clk: | 4786 | dsi_put_clocks(dsidev); |
4801 | kfree(dsi); | ||
4802 | err_alloc: | ||
4803 | return r; | 4787 | return r; |
4804 | } | 4788 | } |
4805 | 4789 | ||
@@ -4823,11 +4807,6 @@ static int omap_dsihw_remove(struct platform_device *dsidev) | |||
4823 | dsi->vdds_dsi_reg = NULL; | 4807 | dsi->vdds_dsi_reg = NULL; |
4824 | } | 4808 | } |
4825 | 4809 | ||
4826 | free_irq(dsi->irq, dsi->pdev); | ||
4827 | iounmap(dsi->base); | ||
4828 | |||
4829 | kfree(dsi); | ||
4830 | |||
4831 | return 0; | 4810 | return 0; |
4832 | } | 4811 | } |
4833 | 4812 | ||
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 77c2b5a32b5d..4a6b5eeef6a7 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c | |||
@@ -748,19 +748,19 @@ static int omap_dsshw_probe(struct platform_device *pdev) | |||
748 | dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); | 748 | dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); |
749 | if (!dss_mem) { | 749 | if (!dss_mem) { |
750 | DSSERR("can't get IORESOURCE_MEM DSS\n"); | 750 | DSSERR("can't get IORESOURCE_MEM DSS\n"); |
751 | r = -EINVAL; | 751 | return -EINVAL; |
752 | goto err_ioremap; | ||
753 | } | 752 | } |
754 | dss.base = ioremap(dss_mem->start, resource_size(dss_mem)); | 753 | |
754 | dss.base = devm_ioremap(&pdev->dev, dss_mem->start, | ||
755 | resource_size(dss_mem)); | ||
755 | if (!dss.base) { | 756 | if (!dss.base) { |
756 | DSSERR("can't ioremap DSS\n"); | 757 | DSSERR("can't ioremap DSS\n"); |
757 | r = -ENOMEM; | 758 | return -ENOMEM; |
758 | goto err_ioremap; | ||
759 | } | 759 | } |
760 | 760 | ||
761 | r = dss_get_clocks(); | 761 | r = dss_get_clocks(); |
762 | if (r) | 762 | if (r) |
763 | goto err_clocks; | 763 | return r; |
764 | 764 | ||
765 | pm_runtime_enable(&pdev->dev); | 765 | pm_runtime_enable(&pdev->dev); |
766 | 766 | ||
@@ -808,9 +808,6 @@ err_dpi: | |||
808 | err_runtime_get: | 808 | err_runtime_get: |
809 | pm_runtime_disable(&pdev->dev); | 809 | pm_runtime_disable(&pdev->dev); |
810 | dss_put_clocks(); | 810 | dss_put_clocks(); |
811 | err_clocks: | ||
812 | iounmap(dss.base); | ||
813 | err_ioremap: | ||
814 | return r; | 811 | return r; |
815 | } | 812 | } |
816 | 813 | ||
@@ -819,8 +816,6 @@ static int omap_dsshw_remove(struct platform_device *pdev) | |||
819 | dpi_exit(); | 816 | dpi_exit(); |
820 | sdi_exit(); | 817 | sdi_exit(); |
821 | 818 | ||
822 | iounmap(dss.base); | ||
823 | |||
824 | pm_runtime_disable(&pdev->dev); | 819 | pm_runtime_disable(&pdev->dev); |
825 | 820 | ||
826 | dss_put_clocks(); | 821 | dss_put_clocks(); |
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 32ff69fb3333..d4b3dff2ead3 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h | |||
@@ -202,9 +202,6 @@ void dss_uninit_device(struct platform_device *pdev, | |||
202 | struct omap_dss_device *dssdev); | 202 | struct omap_dss_device *dssdev); |
203 | bool dss_use_replication(struct omap_dss_device *dssdev, | 203 | bool dss_use_replication(struct omap_dss_device *dssdev, |
204 | enum omap_color_mode mode); | 204 | enum omap_color_mode mode); |
205 | void default_get_overlay_fifo_thresholds(enum omap_plane plane, | ||
206 | u32 fifo_size, u32 burst_size, | ||
207 | u32 *fifo_low, u32 *fifo_high); | ||
208 | 205 | ||
209 | /* manager */ | 206 | /* manager */ |
210 | int dss_init_overlay_managers(struct platform_device *pdev); | 207 | int dss_init_overlay_managers(struct platform_device *pdev); |
@@ -313,9 +310,6 @@ int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, bool is_tft, | |||
313 | int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk, | 310 | int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk, |
314 | bool enable_hsdiv); | 311 | bool enable_hsdiv); |
315 | void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes); | 312 | void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes); |
316 | void dsi_get_overlay_fifo_thresholds(enum omap_plane plane, | ||
317 | u32 fifo_size, u32 burst_size, | ||
318 | u32 *fifo_low, u32 *fifo_high); | ||
319 | void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev); | 313 | void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev); |
320 | void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev); | 314 | void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev); |
321 | struct platform_device *dsi_get_dsidev_from_id(int module); | 315 | struct platform_device *dsi_get_dsidev_from_id(int module); |
@@ -429,8 +423,8 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, | |||
429 | 423 | ||
430 | 424 | ||
431 | void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high); | 425 | void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high); |
432 | u32 dispc_ovl_get_fifo_size(enum omap_plane plane); | 426 | void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, |
433 | u32 dispc_ovl_get_burst_size(enum omap_plane plane); | 427 | u32 *fifo_low, u32 *fifo_high, bool use_fifomerge); |
434 | int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | 428 | int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, |
435 | bool ilace, bool replication); | 429 | bool ilace, bool replication); |
436 | int dispc_ovl_enable(enum omap_plane plane, bool enable); | 430 | int dispc_ovl_enable(enum omap_plane plane, bool enable); |
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index afcb59301c37..ce14aa6dd672 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c | |||
@@ -41,7 +41,8 @@ struct omap_dss_features { | |||
41 | const struct dss_reg_field *reg_fields; | 41 | const struct dss_reg_field *reg_fields; |
42 | const int num_reg_fields; | 42 | const int num_reg_fields; |
43 | 43 | ||
44 | const u32 has_feature; | 44 | const enum dss_feat_id *features; |
45 | const int num_features; | ||
45 | 46 | ||
46 | const int num_mgrs; | 47 | const int num_mgrs; |
47 | const int num_ovls; | 48 | const int num_ovls; |
@@ -189,7 +190,8 @@ static const enum omap_color_mode omap4_dss_supported_color_modes[] = { | |||
189 | OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U | | 190 | OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U | |
190 | OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 | | 191 | OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 | |
191 | OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32 | | 192 | OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32 | |
192 | OMAP_DSS_COLOR_ARGB16_1555, | 193 | OMAP_DSS_COLOR_ARGB16_1555 | OMAP_DSS_COLOR_RGBX16 | |
194 | OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_XRGB16_1555, | ||
193 | 195 | ||
194 | /* OMAP_DSS_VIDEO1 */ | 196 | /* OMAP_DSS_VIDEO1 */ |
195 | OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U | | 197 | OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U | |
@@ -337,15 +339,110 @@ static const struct dss_param_range omap4_dss_param_range[] = { | |||
337 | [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, | 339 | [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, |
338 | }; | 340 | }; |
339 | 341 | ||
342 | static const enum dss_feat_id omap2_dss_feat_list[] = { | ||
343 | FEAT_LCDENABLEPOL, | ||
344 | FEAT_LCDENABLESIGNAL, | ||
345 | FEAT_PCKFREEENABLE, | ||
346 | FEAT_FUNCGATED, | ||
347 | FEAT_ROWREPEATENABLE, | ||
348 | FEAT_RESIZECONF, | ||
349 | }; | ||
350 | |||
351 | static const enum dss_feat_id omap3430_dss_feat_list[] = { | ||
352 | FEAT_LCDENABLEPOL, | ||
353 | FEAT_LCDENABLESIGNAL, | ||
354 | FEAT_PCKFREEENABLE, | ||
355 | FEAT_FUNCGATED, | ||
356 | FEAT_LINEBUFFERSPLIT, | ||
357 | FEAT_ROWREPEATENABLE, | ||
358 | FEAT_RESIZECONF, | ||
359 | FEAT_DSI_PLL_FREQSEL, | ||
360 | FEAT_DSI_REVERSE_TXCLKESC, | ||
361 | FEAT_VENC_REQUIRES_TV_DAC_CLK, | ||
362 | FEAT_CPR, | ||
363 | FEAT_PRELOAD, | ||
364 | FEAT_FIR_COEF_V, | ||
365 | FEAT_ALPHA_FIXED_ZORDER, | ||
366 | FEAT_FIFO_MERGE, | ||
367 | FEAT_OMAP3_DSI_FIFO_BUG, | ||
368 | }; | ||
369 | |||
370 | static const enum dss_feat_id omap3630_dss_feat_list[] = { | ||
371 | FEAT_LCDENABLEPOL, | ||
372 | FEAT_LCDENABLESIGNAL, | ||
373 | FEAT_PCKFREEENABLE, | ||
374 | FEAT_FUNCGATED, | ||
375 | FEAT_LINEBUFFERSPLIT, | ||
376 | FEAT_ROWREPEATENABLE, | ||
377 | FEAT_RESIZECONF, | ||
378 | FEAT_DSI_PLL_PWR_BUG, | ||
379 | FEAT_DSI_PLL_FREQSEL, | ||
380 | FEAT_CPR, | ||
381 | FEAT_PRELOAD, | ||
382 | FEAT_FIR_COEF_V, | ||
383 | FEAT_ALPHA_FIXED_ZORDER, | ||
384 | FEAT_FIFO_MERGE, | ||
385 | FEAT_OMAP3_DSI_FIFO_BUG, | ||
386 | }; | ||
387 | |||
388 | static const enum dss_feat_id omap4430_es1_0_dss_feat_list[] = { | ||
389 | FEAT_MGR_LCD2, | ||
390 | FEAT_CORE_CLK_DIV, | ||
391 | FEAT_LCD_CLK_SRC, | ||
392 | FEAT_DSI_DCS_CMD_CONFIG_VC, | ||
393 | FEAT_DSI_VC_OCP_WIDTH, | ||
394 | FEAT_DSI_GNQ, | ||
395 | FEAT_HANDLE_UV_SEPARATE, | ||
396 | FEAT_ATTR2, | ||
397 | FEAT_CPR, | ||
398 | FEAT_PRELOAD, | ||
399 | FEAT_FIR_COEF_V, | ||
400 | FEAT_ALPHA_FREE_ZORDER, | ||
401 | FEAT_FIFO_MERGE, | ||
402 | }; | ||
403 | |||
404 | static const enum dss_feat_id omap4430_es2_0_1_2_dss_feat_list[] = { | ||
405 | FEAT_MGR_LCD2, | ||
406 | FEAT_CORE_CLK_DIV, | ||
407 | FEAT_LCD_CLK_SRC, | ||
408 | FEAT_DSI_DCS_CMD_CONFIG_VC, | ||
409 | FEAT_DSI_VC_OCP_WIDTH, | ||
410 | FEAT_DSI_GNQ, | ||
411 | FEAT_HDMI_CTS_SWMODE, | ||
412 | FEAT_HANDLE_UV_SEPARATE, | ||
413 | FEAT_ATTR2, | ||
414 | FEAT_CPR, | ||
415 | FEAT_PRELOAD, | ||
416 | FEAT_FIR_COEF_V, | ||
417 | FEAT_ALPHA_FREE_ZORDER, | ||
418 | FEAT_FIFO_MERGE, | ||
419 | }; | ||
420 | |||
421 | static const enum dss_feat_id omap4_dss_feat_list[] = { | ||
422 | FEAT_MGR_LCD2, | ||
423 | FEAT_CORE_CLK_DIV, | ||
424 | FEAT_LCD_CLK_SRC, | ||
425 | FEAT_DSI_DCS_CMD_CONFIG_VC, | ||
426 | FEAT_DSI_VC_OCP_WIDTH, | ||
427 | FEAT_DSI_GNQ, | ||
428 | FEAT_HDMI_CTS_SWMODE, | ||
429 | FEAT_HDMI_AUDIO_USE_MCLK, | ||
430 | FEAT_HANDLE_UV_SEPARATE, | ||
431 | FEAT_ATTR2, | ||
432 | FEAT_CPR, | ||
433 | FEAT_PRELOAD, | ||
434 | FEAT_FIR_COEF_V, | ||
435 | FEAT_ALPHA_FREE_ZORDER, | ||
436 | FEAT_FIFO_MERGE, | ||
437 | }; | ||
438 | |||
340 | /* OMAP2 DSS Features */ | 439 | /* OMAP2 DSS Features */ |
341 | static const struct omap_dss_features omap2_dss_features = { | 440 | static const struct omap_dss_features omap2_dss_features = { |
342 | .reg_fields = omap2_dss_reg_fields, | 441 | .reg_fields = omap2_dss_reg_fields, |
343 | .num_reg_fields = ARRAY_SIZE(omap2_dss_reg_fields), | 442 | .num_reg_fields = ARRAY_SIZE(omap2_dss_reg_fields), |
344 | 443 | ||
345 | .has_feature = | 444 | .features = omap2_dss_feat_list, |
346 | FEAT_LCDENABLEPOL | FEAT_LCDENABLESIGNAL | | 445 | .num_features = ARRAY_SIZE(omap2_dss_feat_list), |
347 | FEAT_PCKFREEENABLE | FEAT_FUNCGATED | | ||
348 | FEAT_ROWREPEATENABLE | FEAT_RESIZECONF, | ||
349 | 446 | ||
350 | .num_mgrs = 2, | 447 | .num_mgrs = 2, |
351 | .num_ovls = 3, | 448 | .num_ovls = 3, |
@@ -363,14 +460,8 @@ static const struct omap_dss_features omap3430_dss_features = { | |||
363 | .reg_fields = omap3_dss_reg_fields, | 460 | .reg_fields = omap3_dss_reg_fields, |
364 | .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), | 461 | .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), |
365 | 462 | ||
366 | .has_feature = | 463 | .features = omap3430_dss_feat_list, |
367 | FEAT_LCDENABLEPOL | | 464 | .num_features = ARRAY_SIZE(omap3430_dss_feat_list), |
368 | FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE | | ||
369 | FEAT_FUNCGATED | FEAT_ROWREPEATENABLE | | ||
370 | FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF | | ||
371 | FEAT_DSI_PLL_FREQSEL | FEAT_DSI_REVERSE_TXCLKESC | | ||
372 | FEAT_VENC_REQUIRES_TV_DAC_CLK | FEAT_CPR | FEAT_PRELOAD | | ||
373 | FEAT_FIR_COEF_V | FEAT_ALPHA_FIXED_ZORDER, | ||
374 | 465 | ||
375 | .num_mgrs = 2, | 466 | .num_mgrs = 2, |
376 | .num_ovls = 3, | 467 | .num_ovls = 3, |
@@ -387,14 +478,8 @@ static const struct omap_dss_features omap3630_dss_features = { | |||
387 | .reg_fields = omap3_dss_reg_fields, | 478 | .reg_fields = omap3_dss_reg_fields, |
388 | .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), | 479 | .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), |
389 | 480 | ||
390 | .has_feature = | 481 | .features = omap3630_dss_feat_list, |
391 | FEAT_LCDENABLEPOL | | 482 | .num_features = ARRAY_SIZE(omap3630_dss_feat_list), |
392 | FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE | | ||
393 | FEAT_FUNCGATED | | ||
394 | FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT | | ||
395 | FEAT_RESIZECONF | FEAT_DSI_PLL_PWR_BUG | | ||
396 | FEAT_DSI_PLL_FREQSEL | FEAT_CPR | FEAT_PRELOAD | | ||
397 | FEAT_FIR_COEF_V | FEAT_ALPHA_FIXED_ZORDER, | ||
398 | 483 | ||
399 | .num_mgrs = 2, | 484 | .num_mgrs = 2, |
400 | .num_ovls = 3, | 485 | .num_ovls = 3, |
@@ -413,13 +498,27 @@ static const struct omap_dss_features omap4430_es1_0_dss_features = { | |||
413 | .reg_fields = omap4_dss_reg_fields, | 498 | .reg_fields = omap4_dss_reg_fields, |
414 | .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields), | 499 | .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields), |
415 | 500 | ||
416 | .has_feature = | 501 | .features = omap4430_es1_0_dss_feat_list, |
417 | FEAT_MGR_LCD2 | | 502 | .num_features = ARRAY_SIZE(omap4430_es1_0_dss_feat_list), |
418 | FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC | | 503 | |
419 | FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH | | 504 | .num_mgrs = 3, |
420 | FEAT_DSI_GNQ | FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2 | | 505 | .num_ovls = 4, |
421 | FEAT_CPR | FEAT_PRELOAD | FEAT_FIR_COEF_V | | 506 | .supported_displays = omap4_dss_supported_displays, |
422 | FEAT_ALPHA_FREE_ZORDER, | 507 | .supported_color_modes = omap4_dss_supported_color_modes, |
508 | .overlay_caps = omap4_dss_overlay_caps, | ||
509 | .clksrc_names = omap4_dss_clk_source_names, | ||
510 | .dss_params = omap4_dss_param_range, | ||
511 | .buffer_size_unit = 16, | ||
512 | .burst_size_unit = 16, | ||
513 | }; | ||
514 | |||
515 | /* For OMAP4430 ES 2.0, 2.1 and 2.2 revisions */ | ||
516 | static const struct omap_dss_features omap4430_es2_0_1_2_dss_features = { | ||
517 | .reg_fields = omap4_dss_reg_fields, | ||
518 | .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields), | ||
519 | |||
520 | .features = omap4430_es2_0_1_2_dss_feat_list, | ||
521 | .num_features = ARRAY_SIZE(omap4430_es2_0_1_2_dss_feat_list), | ||
423 | 522 | ||
424 | .num_mgrs = 3, | 523 | .num_mgrs = 3, |
425 | .num_ovls = 4, | 524 | .num_ovls = 4, |
@@ -437,13 +536,8 @@ static const struct omap_dss_features omap4_dss_features = { | |||
437 | .reg_fields = omap4_dss_reg_fields, | 536 | .reg_fields = omap4_dss_reg_fields, |
438 | .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields), | 537 | .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields), |
439 | 538 | ||
440 | .has_feature = | 539 | .features = omap4_dss_feat_list, |
441 | FEAT_MGR_LCD2 | | 540 | .num_features = ARRAY_SIZE(omap4_dss_feat_list), |
442 | FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC | | ||
443 | FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH | | ||
444 | FEAT_DSI_GNQ | FEAT_HDMI_CTS_SWMODE | | ||
445 | FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2 | FEAT_CPR | | ||
446 | FEAT_PRELOAD | FEAT_FIR_COEF_V | FEAT_ALPHA_FREE_ZORDER, | ||
447 | 541 | ||
448 | .num_mgrs = 3, | 542 | .num_mgrs = 3, |
449 | .num_ovls = 4, | 543 | .num_ovls = 4, |
@@ -547,7 +641,16 @@ u32 dss_feat_get_burst_size_unit(void) | |||
547 | /* DSS has_feature check */ | 641 | /* DSS has_feature check */ |
548 | bool dss_has_feature(enum dss_feat_id id) | 642 | bool dss_has_feature(enum dss_feat_id id) |
549 | { | 643 | { |
550 | return omap_current_dss_features->has_feature & id; | 644 | int i; |
645 | const enum dss_feat_id *features = omap_current_dss_features->features; | ||
646 | const int num_features = omap_current_dss_features->num_features; | ||
647 | |||
648 | for (i = 0; i < num_features; i++) { | ||
649 | if (features[i] == id) | ||
650 | return true; | ||
651 | } | ||
652 | |||
653 | return false; | ||
551 | } | 654 | } |
552 | 655 | ||
553 | void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end) | 656 | void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end) |
@@ -569,6 +672,10 @@ void dss_features_init(void) | |||
569 | omap_current_dss_features = &omap3430_dss_features; | 672 | omap_current_dss_features = &omap3430_dss_features; |
570 | else if (omap_rev() == OMAP4430_REV_ES1_0) | 673 | else if (omap_rev() == OMAP4430_REV_ES1_0) |
571 | omap_current_dss_features = &omap4430_es1_0_dss_features; | 674 | omap_current_dss_features = &omap4430_es1_0_dss_features; |
675 | else if (omap_rev() == OMAP4430_REV_ES2_0 || | ||
676 | omap_rev() == OMAP4430_REV_ES2_1 || | ||
677 | omap_rev() == OMAP4430_REV_ES2_2) | ||
678 | omap_current_dss_features = &omap4430_es2_0_1_2_dss_features; | ||
572 | else if (cpu_is_omap44xx()) | 679 | else if (cpu_is_omap44xx()) |
573 | omap_current_dss_features = &omap4_dss_features; | 680 | omap_current_dss_features = &omap4_dss_features; |
574 | else | 681 | else |
diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index cd833bbaac3d..c332e7ddfce1 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h | |||
@@ -31,33 +31,37 @@ | |||
31 | 31 | ||
32 | /* DSS has feature id */ | 32 | /* DSS has feature id */ |
33 | enum dss_feat_id { | 33 | enum dss_feat_id { |
34 | FEAT_LCDENABLEPOL = 1 << 3, | 34 | FEAT_LCDENABLEPOL, |
35 | FEAT_LCDENABLESIGNAL = 1 << 4, | 35 | FEAT_LCDENABLESIGNAL, |
36 | FEAT_PCKFREEENABLE = 1 << 5, | 36 | FEAT_PCKFREEENABLE, |
37 | FEAT_FUNCGATED = 1 << 6, | 37 | FEAT_FUNCGATED, |
38 | FEAT_MGR_LCD2 = 1 << 7, | 38 | FEAT_MGR_LCD2, |
39 | FEAT_LINEBUFFERSPLIT = 1 << 8, | 39 | FEAT_LINEBUFFERSPLIT, |
40 | FEAT_ROWREPEATENABLE = 1 << 9, | 40 | FEAT_ROWREPEATENABLE, |
41 | FEAT_RESIZECONF = 1 << 10, | 41 | FEAT_RESIZECONF, |
42 | /* Independent core clk divider */ | 42 | /* Independent core clk divider */ |
43 | FEAT_CORE_CLK_DIV = 1 << 11, | 43 | FEAT_CORE_CLK_DIV, |
44 | FEAT_LCD_CLK_SRC = 1 << 12, | 44 | FEAT_LCD_CLK_SRC, |
45 | /* DSI-PLL power command 0x3 is not working */ | 45 | /* DSI-PLL power command 0x3 is not working */ |
46 | FEAT_DSI_PLL_PWR_BUG = 1 << 13, | 46 | FEAT_DSI_PLL_PWR_BUG, |
47 | FEAT_DSI_PLL_FREQSEL = 1 << 14, | 47 | FEAT_DSI_PLL_FREQSEL, |
48 | FEAT_DSI_DCS_CMD_CONFIG_VC = 1 << 15, | 48 | FEAT_DSI_DCS_CMD_CONFIG_VC, |
49 | FEAT_DSI_VC_OCP_WIDTH = 1 << 16, | 49 | FEAT_DSI_VC_OCP_WIDTH, |
50 | FEAT_DSI_REVERSE_TXCLKESC = 1 << 17, | 50 | FEAT_DSI_REVERSE_TXCLKESC, |
51 | FEAT_DSI_GNQ = 1 << 18, | 51 | FEAT_DSI_GNQ, |
52 | FEAT_HDMI_CTS_SWMODE = 1 << 19, | 52 | FEAT_HDMI_CTS_SWMODE, |
53 | FEAT_HANDLE_UV_SEPARATE = 1 << 20, | 53 | FEAT_HDMI_AUDIO_USE_MCLK, |
54 | FEAT_ATTR2 = 1 << 21, | 54 | FEAT_HANDLE_UV_SEPARATE, |
55 | FEAT_VENC_REQUIRES_TV_DAC_CLK = 1 << 22, | 55 | FEAT_ATTR2, |
56 | FEAT_CPR = 1 << 23, | 56 | FEAT_VENC_REQUIRES_TV_DAC_CLK, |
57 | FEAT_PRELOAD = 1 << 24, | 57 | FEAT_CPR, |
58 | FEAT_FIR_COEF_V = 1 << 25, | 58 | FEAT_PRELOAD, |
59 | FEAT_ALPHA_FIXED_ZORDER = 1 << 26, | 59 | FEAT_FIR_COEF_V, |
60 | FEAT_ALPHA_FREE_ZORDER = 1 << 27, | 60 | FEAT_ALPHA_FIXED_ZORDER, |
61 | FEAT_ALPHA_FREE_ZORDER, | ||
62 | FEAT_FIFO_MERGE, | ||
63 | /* An unknown HW bug causing the normal FIFO thresholds not to work */ | ||
64 | FEAT_OMAP3_DSI_FIFO_BUG, | ||
61 | }; | 65 | }; |
62 | 66 | ||
63 | /* DSS register field id */ | 67 | /* DSS register field id */ |
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index a36b934b2db4..c4b4f6950a92 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c | |||
@@ -58,8 +58,6 @@ | |||
58 | #define EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR 4 | 58 | #define EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR 4 |
59 | #define EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR 4 | 59 | #define EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR 4 |
60 | 60 | ||
61 | #define OMAP_HDMI_TIMINGS_NB 34 | ||
62 | |||
63 | #define HDMI_DEFAULT_REGN 16 | 61 | #define HDMI_DEFAULT_REGN 16 |
64 | #define HDMI_DEFAULT_REGM2 1 | 62 | #define HDMI_DEFAULT_REGM2 1 |
65 | 63 | ||
@@ -68,8 +66,6 @@ static struct { | |||
68 | struct omap_display_platform_data *pdata; | 66 | struct omap_display_platform_data *pdata; |
69 | struct platform_device *pdev; | 67 | struct platform_device *pdev; |
70 | struct hdmi_ip_data ip_data; | 68 | struct hdmi_ip_data ip_data; |
71 | int code; | ||
72 | int mode; | ||
73 | 69 | ||
74 | struct clk *sys_clk; | 70 | struct clk *sys_clk; |
75 | } hdmi; | 71 | } hdmi; |
@@ -88,77 +84,46 @@ static struct { | |||
88 | * map it to corresponding CEA or VESA index. | 84 | * map it to corresponding CEA or VESA index. |
89 | */ | 85 | */ |
90 | 86 | ||
91 | static const struct hdmi_timings cea_vesa_timings[OMAP_HDMI_TIMINGS_NB] = { | 87 | static const struct hdmi_config cea_timings[] = { |
92 | { {640, 480, 25200, 96, 16, 48, 2, 10, 33} , 0 , 0}, | 88 | { {640, 480, 25200, 96, 16, 48, 2, 10, 33, 0, 0, 0}, {1, HDMI_HDMI} }, |
93 | { {1280, 720, 74250, 40, 440, 220, 5, 5, 20}, 1, 1}, | 89 | { {720, 480, 27027, 62, 16, 60, 6, 9, 30, 0, 0, 0}, {2, HDMI_HDMI} }, |
94 | { {1280, 720, 74250, 40, 110, 220, 5, 5, 20}, 1, 1}, | 90 | { {1280, 720, 74250, 40, 110, 220, 5, 5, 20, 1, 1, 0}, {4, HDMI_HDMI} }, |
95 | { {720, 480, 27027, 62, 16, 60, 6, 9, 30}, 0, 0}, | 91 | { {1920, 540, 74250, 44, 88, 148, 5, 2, 15, 1, 1, 1}, {5, HDMI_HDMI} }, |
96 | { {2880, 576, 108000, 256, 48, 272, 5, 5, 39}, 0, 0}, | 92 | { {1440, 240, 27027, 124, 38, 114, 3, 4, 15, 0, 0, 1}, {6, HDMI_HDMI} }, |
97 | { {1440, 240, 27027, 124, 38, 114, 3, 4, 15}, 0, 0}, | 93 | { {1920, 1080, 148500, 44, 88, 148, 5, 4, 36, 1, 1, 0}, {16, HDMI_HDMI} }, |
98 | { {1440, 288, 27000, 126, 24, 138, 3, 2, 19}, 0, 0}, | 94 | { {720, 576, 27000, 64, 12, 68, 5, 5, 39, 0, 0, 0}, {17, HDMI_HDMI} }, |
99 | { {1920, 540, 74250, 44, 528, 148, 5, 2, 15}, 1, 1}, | 95 | { {1280, 720, 74250, 40, 440, 220, 5, 5, 20, 1, 1, 0}, {19, HDMI_HDMI} }, |
100 | { {1920, 540, 74250, 44, 88, 148, 5, 2, 15}, 1, 1}, | 96 | { {1920, 540, 74250, 44, 528, 148, 5, 2, 15, 1, 1, 1}, {20, HDMI_HDMI} }, |
101 | { {1920, 1080, 148500, 44, 88, 148, 5, 4, 36}, 1, 1}, | 97 | { {1440, 288, 27000, 126, 24, 138, 3, 2, 19, 0, 0, 1}, {21, HDMI_HDMI} }, |
102 | { {720, 576, 27000, 64, 12, 68, 5, 5, 39}, 0, 0}, | 98 | { {1440, 576, 54000, 128, 24, 136, 5, 5, 39, 0, 0, 0}, {29, HDMI_HDMI} }, |
103 | { {1440, 576, 54000, 128, 24, 136, 5, 5, 39}, 0, 0}, | 99 | { {1920, 1080, 148500, 44, 528, 148, 5, 4, 36, 1, 1, 0}, {31, HDMI_HDMI} }, |
104 | { {1920, 1080, 148500, 44, 528, 148, 5, 4, 36}, 1, 1}, | 100 | { {1920, 1080, 74250, 44, 638, 148, 5, 4, 36, 1, 1, 0}, {32, HDMI_HDMI} }, |
105 | { {2880, 480, 108108, 248, 64, 240, 6, 9, 30}, 0, 0}, | 101 | { {2880, 480, 108108, 248, 64, 240, 6, 9, 30, 0, 0, 0}, {35, HDMI_HDMI} }, |
106 | { {1920, 1080, 74250, 44, 638, 148, 5, 4, 36}, 1, 1}, | 102 | { {2880, 576, 108000, 256, 48, 272, 5, 5, 39, 0, 0, 0}, {37, HDMI_HDMI} }, |
107 | /* VESA From Here */ | ||
108 | { {640, 480, 25175, 96, 16, 48, 2 , 11, 31}, 0, 0}, | ||
109 | { {800, 600, 40000, 128, 40, 88, 4 , 1, 23}, 1, 1}, | ||
110 | { {848, 480, 33750, 112, 16, 112, 8 , 6, 23}, 1, 1}, | ||
111 | { {1280, 768, 79500, 128, 64, 192, 7 , 3, 20}, 1, 0}, | ||
112 | { {1280, 800, 83500, 128, 72, 200, 6 , 3, 22}, 1, 0}, | ||
113 | { {1360, 768, 85500, 112, 64, 256, 6 , 3, 18}, 1, 1}, | ||
114 | { {1280, 960, 108000, 112, 96, 312, 3 , 1, 36}, 1, 1}, | ||
115 | { {1280, 1024, 108000, 112, 48, 248, 3 , 1, 38}, 1, 1}, | ||
116 | { {1024, 768, 65000, 136, 24, 160, 6, 3, 29}, 0, 0}, | ||
117 | { {1400, 1050, 121750, 144, 88, 232, 4, 3, 32}, 1, 0}, | ||
118 | { {1440, 900, 106500, 152, 80, 232, 6, 3, 25}, 1, 0}, | ||
119 | { {1680, 1050, 146250, 176 , 104, 280, 6, 3, 30}, 1, 0}, | ||
120 | { {1366, 768, 85500, 143, 70, 213, 3, 3, 24}, 1, 1}, | ||
121 | { {1920, 1080, 148500, 44, 148, 80, 5, 4, 36}, 1, 1}, | ||
122 | { {1280, 768, 68250, 32, 48, 80, 7, 3, 12}, 0, 1}, | ||
123 | { {1400, 1050, 101000, 32, 48, 80, 4, 3, 23}, 0, 1}, | ||
124 | { {1680, 1050, 119000, 32, 48, 80, 6, 3, 21}, 0, 1}, | ||
125 | { {1280, 800, 79500, 32, 48, 80, 6, 3, 14}, 0, 1}, | ||
126 | { {1280, 720, 74250, 40, 110, 220, 5, 5, 20}, 1, 1} | ||
127 | }; | ||
128 | |||
129 | /* | ||
130 | * This is a static mapping array which maps the timing values | ||
131 | * with corresponding CEA / VESA code | ||
132 | */ | ||
133 | static const int code_index[OMAP_HDMI_TIMINGS_NB] = { | ||
134 | 1, 19, 4, 2, 37, 6, 21, 20, 5, 16, 17, 29, 31, 35, 32, | ||
135 | /* <--15 CEA 17--> vesa*/ | ||
136 | 4, 9, 0xE, 0x17, 0x1C, 0x27, 0x20, 0x23, 0x10, 0x2A, | ||
137 | 0X2F, 0x3A, 0X51, 0X52, 0x16, 0x29, 0x39, 0x1B | ||
138 | }; | 103 | }; |
139 | 104 | static const struct hdmi_config vesa_timings[] = { | |
140 | /* | 105 | /* VESA From Here */ |
141 | * This is reverse static mapping which maps the CEA / VESA code | 106 | { {640, 480, 25175, 96, 16, 48, 2 , 11, 31, 0, 0, 0}, {4, HDMI_DVI} }, |
142 | * to the corresponding timing values | 107 | { {800, 600, 40000, 128, 40, 88, 4 , 1, 23, 1, 1, 0}, {9, HDMI_DVI} }, |
143 | */ | 108 | { {848, 480, 33750, 112, 16, 112, 8 , 6, 23, 1, 1, 0}, {0xE, HDMI_DVI} }, |
144 | static const int code_cea[39] = { | 109 | { {1280, 768, 79500, 128, 64, 192, 7 , 3, 20, 1, 0, 0}, {0x17, HDMI_DVI} }, |
145 | -1, 0, 3, 3, 2, 8, 5, 5, -1, -1, | 110 | { {1280, 800, 83500, 128, 72, 200, 6 , 3, 22, 1, 0, 0}, {0x1C, HDMI_DVI} }, |
146 | -1, -1, -1, -1, -1, -1, 9, 10, 10, 1, | 111 | { {1360, 768, 85500, 112, 64, 256, 6 , 3, 18, 1, 1, 0}, {0x27, HDMI_DVI} }, |
147 | 7, 6, 6, -1, -1, -1, -1, -1, -1, 11, | 112 | { {1280, 960, 108000, 112, 96, 312, 3 , 1, 36, 1, 1, 0}, {0x20, HDMI_DVI} }, |
148 | 11, 12, 14, -1, -1, 13, 13, 4, 4 | 113 | { {1280, 1024, 108000, 112, 48, 248, 3 , 1, 38, 1, 1, 0}, {0x23, HDMI_DVI} }, |
114 | { {1024, 768, 65000, 136, 24, 160, 6, 3, 29, 0, 0, 0}, {0x10, HDMI_DVI} }, | ||
115 | { {1400, 1050, 121750, 144, 88, 232, 4, 3, 32, 1, 0, 0}, {0x2A, HDMI_DVI} }, | ||
116 | { {1440, 900, 106500, 152, 80, 232, 6, 3, 25, 1, 0, 0}, {0x2F, HDMI_DVI} }, | ||
117 | { {1680, 1050, 146250, 176 , 104, 280, 6, 3, 30, 1, 0, 0}, {0x3A, HDMI_DVI} }, | ||
118 | { {1366, 768, 85500, 143, 70, 213, 3, 3, 24, 1, 1, 0}, {0x51, HDMI_DVI} }, | ||
119 | { {1920, 1080, 148500, 44, 148, 80, 5, 4, 36, 1, 1, 0}, {0x52, HDMI_DVI} }, | ||
120 | { {1280, 768, 68250, 32, 48, 80, 7, 3, 12, 0, 1, 0}, {0x16, HDMI_DVI} }, | ||
121 | { {1400, 1050, 101000, 32, 48, 80, 4, 3, 23, 0, 1, 0}, {0x29, HDMI_DVI} }, | ||
122 | { {1680, 1050, 119000, 32, 48, 80, 6, 3, 21, 0, 1, 0}, {0x39, HDMI_DVI} }, | ||
123 | { {1280, 800, 79500, 32, 48, 80, 6, 3, 14, 0, 1, 0}, {0x1B, HDMI_DVI} }, | ||
124 | { {1280, 720, 74250, 40, 110, 220, 5, 5, 20, 1, 1, 0}, {0x55, HDMI_DVI} } | ||
149 | }; | 125 | }; |
150 | 126 | ||
151 | static const int code_vesa[85] = { | ||
152 | -1, -1, -1, -1, 15, -1, -1, -1, -1, 16, | ||
153 | -1, -1, -1, -1, 17, -1, 23, -1, -1, -1, | ||
154 | -1, -1, 29, 18, -1, -1, -1, 32, 19, -1, | ||
155 | -1, -1, 21, -1, -1, 22, -1, -1, -1, 20, | ||
156 | -1, 30, 24, -1, -1, -1, -1, 25, -1, -1, | ||
157 | -1, -1, -1, -1, -1, -1, -1, 31, 26, -1, | ||
158 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | ||
159 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | ||
160 | -1, 27, 28, -1, 33}; | ||
161 | |||
162 | static int hdmi_runtime_get(void) | 127 | static int hdmi_runtime_get(void) |
163 | { | 128 | { |
164 | int r; | 129 | int r; |
@@ -210,88 +175,89 @@ int hdmi_init_display(struct omap_dss_device *dssdev) | |||
210 | return 0; | 175 | return 0; |
211 | } | 176 | } |
212 | 177 | ||
213 | static int get_timings_index(void) | 178 | static const struct hdmi_config *hdmi_find_timing( |
179 | const struct hdmi_config *timings_arr, | ||
180 | int len) | ||
214 | { | 181 | { |
215 | int code; | 182 | int i; |
216 | 183 | ||
217 | if (hdmi.mode == 0) | 184 | for (i = 0; i < len; i++) { |
218 | code = code_vesa[hdmi.code]; | 185 | if (timings_arr[i].cm.code == hdmi.ip_data.cfg.cm.code) |
219 | else | 186 | return &timings_arr[i]; |
220 | code = code_cea[hdmi.code]; | 187 | } |
188 | return NULL; | ||
189 | } | ||
221 | 190 | ||
222 | if (code == -1) { | 191 | static const struct hdmi_config *hdmi_get_timings(void) |
223 | /* HDMI code 4 corresponds to 640 * 480 VGA */ | 192 | { |
224 | hdmi.code = 4; | 193 | const struct hdmi_config *arr; |
225 | /* DVI mode 1 corresponds to HDMI 0 to DVI */ | 194 | int len; |
226 | hdmi.mode = HDMI_DVI; | 195 | |
196 | if (hdmi.ip_data.cfg.cm.mode == HDMI_DVI) { | ||
197 | arr = vesa_timings; | ||
198 | len = ARRAY_SIZE(vesa_timings); | ||
199 | } else { | ||
200 | arr = cea_timings; | ||
201 | len = ARRAY_SIZE(cea_timings); | ||
202 | } | ||
203 | |||
204 | return hdmi_find_timing(arr, len); | ||
205 | } | ||
206 | |||
207 | static bool hdmi_timings_compare(struct omap_video_timings *timing1, | ||
208 | const struct hdmi_video_timings *timing2) | ||
209 | { | ||
210 | int timing1_vsync, timing1_hsync, timing2_vsync, timing2_hsync; | ||
227 | 211 | ||
228 | code = code_vesa[hdmi.code]; | 212 | if ((timing2->pixel_clock == timing1->pixel_clock) && |
213 | (timing2->x_res == timing1->x_res) && | ||
214 | (timing2->y_res == timing1->y_res)) { | ||
215 | |||
216 | timing2_hsync = timing2->hfp + timing2->hsw + timing2->hbp; | ||
217 | timing1_hsync = timing1->hfp + timing1->hsw + timing1->hbp; | ||
218 | timing2_vsync = timing2->vfp + timing2->vsw + timing2->vbp; | ||
219 | timing1_vsync = timing2->vfp + timing2->vsw + timing2->vbp; | ||
220 | |||
221 | DSSDBG("timing1_hsync = %d timing1_vsync = %d"\ | ||
222 | "timing2_hsync = %d timing2_vsync = %d\n", | ||
223 | timing1_hsync, timing1_vsync, | ||
224 | timing2_hsync, timing2_vsync); | ||
225 | |||
226 | if ((timing1_hsync == timing2_hsync) && | ||
227 | (timing1_vsync == timing2_vsync)) { | ||
228 | return true; | ||
229 | } | ||
229 | } | 230 | } |
230 | return code; | 231 | return false; |
231 | } | 232 | } |
232 | 233 | ||
233 | static struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing) | 234 | static struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing) |
234 | { | 235 | { |
235 | int i = 0, code = -1, temp_vsync = 0, temp_hsync = 0; | 236 | int i; |
236 | int timing_vsync = 0, timing_hsync = 0; | ||
237 | struct hdmi_video_timings temp; | ||
238 | struct hdmi_cm cm = {-1}; | 237 | struct hdmi_cm cm = {-1}; |
239 | DSSDBG("hdmi_get_code\n"); | 238 | DSSDBG("hdmi_get_code\n"); |
240 | 239 | ||
241 | for (i = 0; i < OMAP_HDMI_TIMINGS_NB; i++) { | 240 | for (i = 0; i < ARRAY_SIZE(cea_timings); i++) { |
242 | temp = cea_vesa_timings[i].timings; | 241 | if (hdmi_timings_compare(timing, &cea_timings[i].timings)) { |
243 | if ((temp.pixel_clock == timing->pixel_clock) && | 242 | cm = cea_timings[i].cm; |
244 | (temp.x_res == timing->x_res) && | 243 | goto end; |
245 | (temp.y_res == timing->y_res)) { | 244 | } |
246 | 245 | } | |
247 | temp_hsync = temp.hfp + temp.hsw + temp.hbp; | 246 | for (i = 0; i < ARRAY_SIZE(vesa_timings); i++) { |
248 | timing_hsync = timing->hfp + timing->hsw + timing->hbp; | 247 | if (hdmi_timings_compare(timing, &vesa_timings[i].timings)) { |
249 | temp_vsync = temp.vfp + temp.vsw + temp.vbp; | 248 | cm = vesa_timings[i].cm; |
250 | timing_vsync = timing->vfp + timing->vsw + timing->vbp; | 249 | goto end; |
251 | |||
252 | DSSDBG("temp_hsync = %d , temp_vsync = %d" | ||
253 | "timing_hsync = %d, timing_vsync = %d\n", | ||
254 | temp_hsync, temp_hsync, | ||
255 | timing_hsync, timing_vsync); | ||
256 | |||
257 | if ((temp_hsync == timing_hsync) && | ||
258 | (temp_vsync == timing_vsync)) { | ||
259 | code = i; | ||
260 | cm.code = code_index[i]; | ||
261 | if (code < 14) | ||
262 | cm.mode = HDMI_HDMI; | ||
263 | else | ||
264 | cm.mode = HDMI_DVI; | ||
265 | DSSDBG("Hdmi_code = %d mode = %d\n", | ||
266 | cm.code, cm.mode); | ||
267 | break; | ||
268 | } | ||
269 | } | 250 | } |
270 | } | 251 | } |
271 | 252 | ||
272 | return cm; | 253 | end: return cm; |
273 | } | ||
274 | 254 | ||
275 | static void update_hdmi_timings(struct hdmi_config *cfg, | ||
276 | struct omap_video_timings *timings, int code) | ||
277 | { | ||
278 | cfg->timings.timings.x_res = timings->x_res; | ||
279 | cfg->timings.timings.y_res = timings->y_res; | ||
280 | cfg->timings.timings.hbp = timings->hbp; | ||
281 | cfg->timings.timings.hfp = timings->hfp; | ||
282 | cfg->timings.timings.hsw = timings->hsw; | ||
283 | cfg->timings.timings.vbp = timings->vbp; | ||
284 | cfg->timings.timings.vfp = timings->vfp; | ||
285 | cfg->timings.timings.vsw = timings->vsw; | ||
286 | cfg->timings.timings.pixel_clock = timings->pixel_clock; | ||
287 | cfg->timings.vsync_pol = cea_vesa_timings[code].vsync_pol; | ||
288 | cfg->timings.hsync_pol = cea_vesa_timings[code].hsync_pol; | ||
289 | } | 255 | } |
290 | 256 | ||
291 | unsigned long hdmi_get_pixel_clock(void) | 257 | unsigned long hdmi_get_pixel_clock(void) |
292 | { | 258 | { |
293 | /* HDMI Pixel Clock in Mhz */ | 259 | /* HDMI Pixel Clock in Mhz */ |
294 | return hdmi.ip_data.cfg.timings.timings.pixel_clock * 1000; | 260 | return hdmi.ip_data.cfg.timings.pixel_clock * 1000; |
295 | } | 261 | } |
296 | 262 | ||
297 | static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, | 263 | static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, |
@@ -312,24 +278,24 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, | |||
312 | 278 | ||
313 | refclk = clkin / pi->regn; | 279 | refclk = clkin / pi->regn; |
314 | 280 | ||
315 | /* | ||
316 | * multiplier is pixel_clk/ref_clk | ||
317 | * Multiplying by 100 to avoid fractional part removal | ||
318 | */ | ||
319 | pi->regm = (phy * 100 / (refclk)) / 100; | ||
320 | |||
321 | if (dssdev->clocks.hdmi.regm2 == 0) | 281 | if (dssdev->clocks.hdmi.regm2 == 0) |
322 | pi->regm2 = HDMI_DEFAULT_REGM2; | 282 | pi->regm2 = HDMI_DEFAULT_REGM2; |
323 | else | 283 | else |
324 | pi->regm2 = dssdev->clocks.hdmi.regm2; | 284 | pi->regm2 = dssdev->clocks.hdmi.regm2; |
325 | 285 | ||
326 | /* | 286 | /* |
287 | * multiplier is pixel_clk/ref_clk | ||
288 | * Multiplying by 100 to avoid fractional part removal | ||
289 | */ | ||
290 | pi->regm = phy * pi->regm2 / refclk; | ||
291 | |||
292 | /* | ||
327 | * fractional multiplier is remainder of the difference between | 293 | * fractional multiplier is remainder of the difference between |
328 | * multiplier and actual phy(required pixel clock thus should be | 294 | * multiplier and actual phy(required pixel clock thus should be |
329 | * multiplied by 2^18(262144) divided by the reference clock | 295 | * multiplied by 2^18(262144) divided by the reference clock |
330 | */ | 296 | */ |
331 | mf = (phy - pi->regm * refclk) * 262144; | 297 | mf = (phy - pi->regm / pi->regm2 * refclk) * 262144; |
332 | pi->regmf = mf / (refclk); | 298 | pi->regmf = pi->regm2 * mf / refclk; |
333 | 299 | ||
334 | /* | 300 | /* |
335 | * Dcofreq should be set to 1 if required pixel clock | 301 | * Dcofreq should be set to 1 if required pixel clock |
@@ -347,7 +313,8 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, | |||
347 | 313 | ||
348 | static int hdmi_power_on(struct omap_dss_device *dssdev) | 314 | static int hdmi_power_on(struct omap_dss_device *dssdev) |
349 | { | 315 | { |
350 | int r, code = 0; | 316 | int r; |
317 | const struct hdmi_config *timing; | ||
351 | struct omap_video_timings *p; | 318 | struct omap_video_timings *p; |
352 | unsigned long phy; | 319 | unsigned long phy; |
353 | 320 | ||
@@ -363,9 +330,16 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) | |||
363 | dssdev->panel.timings.x_res, | 330 | dssdev->panel.timings.x_res, |
364 | dssdev->panel.timings.y_res); | 331 | dssdev->panel.timings.y_res); |
365 | 332 | ||
366 | code = get_timings_index(); | 333 | timing = hdmi_get_timings(); |
367 | update_hdmi_timings(&hdmi.ip_data.cfg, p, code); | 334 | if (timing == NULL) { |
368 | 335 | /* HDMI code 4 corresponds to 640 * 480 VGA */ | |
336 | hdmi.ip_data.cfg.cm.code = 4; | ||
337 | /* DVI mode 1 corresponds to HDMI 0 to DVI */ | ||
338 | hdmi.ip_data.cfg.cm.mode = HDMI_DVI; | ||
339 | hdmi.ip_data.cfg = vesa_timings[0]; | ||
340 | } else { | ||
341 | hdmi.ip_data.cfg = *timing; | ||
342 | } | ||
369 | phy = p->pixel_clock; | 343 | phy = p->pixel_clock; |
370 | 344 | ||
371 | hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data); | 345 | hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data); |
@@ -385,8 +359,6 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) | |||
385 | goto err; | 359 | goto err; |
386 | } | 360 | } |
387 | 361 | ||
388 | hdmi.ip_data.cfg.cm.mode = hdmi.mode; | ||
389 | hdmi.ip_data.cfg.cm.code = hdmi.code; | ||
390 | hdmi.ip_data.ops->video_configure(&hdmi.ip_data); | 362 | hdmi.ip_data.ops->video_configure(&hdmi.ip_data); |
391 | 363 | ||
392 | /* Make selection of HDMI in DSS */ | 364 | /* Make selection of HDMI in DSS */ |
@@ -453,8 +425,8 @@ void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev) | |||
453 | struct hdmi_cm cm; | 425 | struct hdmi_cm cm; |
454 | 426 | ||
455 | cm = hdmi_get_code(&dssdev->panel.timings); | 427 | cm = hdmi_get_code(&dssdev->panel.timings); |
456 | hdmi.code = cm.code; | 428 | hdmi.ip_data.cfg.cm.code = cm.code; |
457 | hdmi.mode = cm.mode; | 429 | hdmi.ip_data.cfg.cm.mode = cm.mode; |
458 | 430 | ||
459 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { | 431 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { |
460 | int r; | 432 | int r; |
@@ -717,13 +689,15 @@ static int hdmi_audio_hw_params(struct snd_pcm_substream *substream, | |||
717 | if (dss_has_feature(FEAT_HDMI_CTS_SWMODE)) { | 689 | if (dss_has_feature(FEAT_HDMI_CTS_SWMODE)) { |
718 | core_cfg.aud_par_busclk = 0; | 690 | core_cfg.aud_par_busclk = 0; |
719 | core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_SW; | 691 | core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_SW; |
720 | core_cfg.use_mclk = false; | 692 | core_cfg.use_mclk = dss_has_feature(FEAT_HDMI_AUDIO_USE_MCLK); |
721 | } else { | 693 | } else { |
722 | core_cfg.aud_par_busclk = (((128 * 31) - 1) << 8); | 694 | core_cfg.aud_par_busclk = (((128 * 31) - 1) << 8); |
723 | core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_HW; | 695 | core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_HW; |
724 | core_cfg.use_mclk = true; | 696 | core_cfg.use_mclk = true; |
725 | core_cfg.mclk_mode = HDMI_AUDIO_MCLK_128FS; | ||
726 | } | 697 | } |
698 | |||
699 | if (core_cfg.use_mclk) | ||
700 | core_cfg.mclk_mode = HDMI_AUDIO_MCLK_128FS; | ||
727 | core_cfg.layout = HDMI_AUDIO_LAYOUT_2CH; | 701 | core_cfg.layout = HDMI_AUDIO_LAYOUT_2CH; |
728 | core_cfg.en_spdif = false; | 702 | core_cfg.en_spdif = false; |
729 | /* Use sample frequency from channel status word */ | 703 | /* Use sample frequency from channel status word */ |
@@ -756,7 +730,7 @@ static int hdmi_audio_hw_params(struct snd_pcm_substream *substream, | |||
756 | static int hdmi_audio_startup(struct snd_pcm_substream *substream, | 730 | static int hdmi_audio_startup(struct snd_pcm_substream *substream, |
757 | struct snd_soc_dai *dai) | 731 | struct snd_soc_dai *dai) |
758 | { | 732 | { |
759 | if (!hdmi.mode) { | 733 | if (!hdmi.ip_data.cfg.cm.mode) { |
760 | pr_err("Current video settings do not support audio.\n"); | 734 | pr_err("Current video settings do not support audio.\n"); |
761 | return -EIO; | 735 | return -EIO; |
762 | } | 736 | } |
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index d1858e71c64e..e7364603f6a1 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c | |||
@@ -494,6 +494,11 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) | |||
494 | { | 494 | { |
495 | unsigned long timeout = msecs_to_jiffies(500); | 495 | unsigned long timeout = msecs_to_jiffies(500); |
496 | u32 irq; | 496 | u32 irq; |
497 | int r; | ||
498 | |||
499 | r = dispc_runtime_get(); | ||
500 | if (r) | ||
501 | return r; | ||
497 | 502 | ||
498 | if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) { | 503 | if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) { |
499 | irq = DISPC_IRQ_EVSYNC_ODD; | 504 | irq = DISPC_IRQ_EVSYNC_ODD; |
@@ -505,7 +510,12 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) | |||
505 | else | 510 | else |
506 | irq = DISPC_IRQ_VSYNC2; | 511 | irq = DISPC_IRQ_VSYNC2; |
507 | } | 512 | } |
508 | return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); | 513 | |
514 | r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); | ||
515 | |||
516 | dispc_runtime_put(); | ||
517 | |||
518 | return r; | ||
509 | } | 519 | } |
510 | 520 | ||
511 | int dss_init_overlay_managers(struct platform_device *pdev) | 521 | int dss_init_overlay_managers(struct platform_device *pdev) |
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index 55f398014f33..788a0ef6323a 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c | |||
@@ -922,35 +922,34 @@ static int omap_rfbihw_probe(struct platform_device *pdev) | |||
922 | rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0); | 922 | rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0); |
923 | if (!rfbi_mem) { | 923 | if (!rfbi_mem) { |
924 | DSSERR("can't get IORESOURCE_MEM RFBI\n"); | 924 | DSSERR("can't get IORESOURCE_MEM RFBI\n"); |
925 | r = -EINVAL; | 925 | return -EINVAL; |
926 | goto err_ioremap; | ||
927 | } | 926 | } |
928 | rfbi.base = ioremap(rfbi_mem->start, resource_size(rfbi_mem)); | 927 | |
928 | rfbi.base = devm_ioremap(&pdev->dev, rfbi_mem->start, | ||
929 | resource_size(rfbi_mem)); | ||
929 | if (!rfbi.base) { | 930 | if (!rfbi.base) { |
930 | DSSERR("can't ioremap RFBI\n"); | 931 | DSSERR("can't ioremap RFBI\n"); |
931 | r = -ENOMEM; | 932 | return -ENOMEM; |
932 | goto err_ioremap; | ||
933 | } | 933 | } |
934 | 934 | ||
935 | pm_runtime_enable(&pdev->dev); | ||
936 | |||
937 | r = rfbi_runtime_get(); | ||
938 | if (r) | ||
939 | goto err_get_rfbi; | ||
940 | |||
941 | msleep(10); | ||
942 | |||
943 | clk = clk_get(&pdev->dev, "ick"); | 935 | clk = clk_get(&pdev->dev, "ick"); |
944 | if (IS_ERR(clk)) { | 936 | if (IS_ERR(clk)) { |
945 | DSSERR("can't get ick\n"); | 937 | DSSERR("can't get ick\n"); |
946 | r = PTR_ERR(clk); | 938 | return PTR_ERR(clk); |
947 | goto err_get_ick; | ||
948 | } | 939 | } |
949 | 940 | ||
950 | rfbi.l4_khz = clk_get_rate(clk) / 1000; | 941 | rfbi.l4_khz = clk_get_rate(clk) / 1000; |
951 | 942 | ||
952 | clk_put(clk); | 943 | clk_put(clk); |
953 | 944 | ||
945 | pm_runtime_enable(&pdev->dev); | ||
946 | |||
947 | r = rfbi_runtime_get(); | ||
948 | if (r) | ||
949 | goto err_runtime_get; | ||
950 | |||
951 | msleep(10); | ||
952 | |||
954 | rev = rfbi_read_reg(RFBI_REVISION); | 953 | rev = rfbi_read_reg(RFBI_REVISION); |
955 | dev_dbg(&pdev->dev, "OMAP RFBI rev %d.%d\n", | 954 | dev_dbg(&pdev->dev, "OMAP RFBI rev %d.%d\n", |
956 | FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); | 955 | FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); |
@@ -959,19 +958,14 @@ static int omap_rfbihw_probe(struct platform_device *pdev) | |||
959 | 958 | ||
960 | return 0; | 959 | return 0; |
961 | 960 | ||
962 | err_get_ick: | 961 | err_runtime_get: |
963 | rfbi_runtime_put(); | ||
964 | err_get_rfbi: | ||
965 | pm_runtime_disable(&pdev->dev); | 962 | pm_runtime_disable(&pdev->dev); |
966 | iounmap(rfbi.base); | ||
967 | err_ioremap: | ||
968 | return r; | 963 | return r; |
969 | } | 964 | } |
970 | 965 | ||
971 | static int omap_rfbihw_remove(struct platform_device *pdev) | 966 | static int omap_rfbihw_remove(struct platform_device *pdev) |
972 | { | 967 | { |
973 | pm_runtime_disable(&pdev->dev); | 968 | pm_runtime_disable(&pdev->dev); |
974 | iounmap(rfbi.base); | ||
975 | return 0; | 969 | return 0; |
976 | } | 970 | } |
977 | 971 | ||
diff --git a/drivers/video/omap2/dss/ti_hdmi.h b/drivers/video/omap2/dss/ti_hdmi.h index 50dadba5070a..1f58b84d6901 100644 --- a/drivers/video/omap2/dss/ti_hdmi.h +++ b/drivers/video/omap2/dss/ti_hdmi.h | |||
@@ -42,6 +42,7 @@ enum hdmi_clk_refsel { | |||
42 | HDMI_REFSEL_SYSCLK = 3 | 42 | HDMI_REFSEL_SYSCLK = 3 |
43 | }; | 43 | }; |
44 | 44 | ||
45 | /* HDMI timing structure */ | ||
45 | struct hdmi_video_timings { | 46 | struct hdmi_video_timings { |
46 | u16 x_res; | 47 | u16 x_res; |
47 | u16 y_res; | 48 | u16 y_res; |
@@ -53,13 +54,9 @@ struct hdmi_video_timings { | |||
53 | u16 vsw; | 54 | u16 vsw; |
54 | u16 vfp; | 55 | u16 vfp; |
55 | u16 vbp; | 56 | u16 vbp; |
56 | }; | 57 | bool vsync_pol; |
57 | 58 | bool hsync_pol; | |
58 | /* HDMI timing structure */ | 59 | bool interlace; |
59 | struct hdmi_timings { | ||
60 | struct hdmi_video_timings timings; | ||
61 | int vsync_pol; | ||
62 | int hsync_pol; | ||
63 | }; | 60 | }; |
64 | 61 | ||
65 | struct hdmi_cm { | 62 | struct hdmi_cm { |
@@ -68,8 +65,7 @@ struct hdmi_cm { | |||
68 | }; | 65 | }; |
69 | 66 | ||
70 | struct hdmi_config { | 67 | struct hdmi_config { |
71 | struct hdmi_timings timings; | 68 | struct hdmi_video_timings timings; |
72 | u16 interlace; | ||
73 | struct hdmi_cm cm; | 69 | struct hdmi_cm cm; |
74 | }; | 70 | }; |
75 | 71 | ||
@@ -117,6 +113,47 @@ struct ti_hdmi_ip_ops { | |||
117 | 113 | ||
118 | }; | 114 | }; |
119 | 115 | ||
116 | /* | ||
117 | * Refer to section 8.2 in HDMI 1.3 specification for | ||
118 | * details about infoframe databytes | ||
119 | */ | ||
120 | struct hdmi_core_infoframe_avi { | ||
121 | /* Y0, Y1 rgb,yCbCr */ | ||
122 | u8 db1_format; | ||
123 | /* A0 Active information Present */ | ||
124 | u8 db1_active_info; | ||
125 | /* B0, B1 Bar info data valid */ | ||
126 | u8 db1_bar_info_dv; | ||
127 | /* S0, S1 scan information */ | ||
128 | u8 db1_scan_info; | ||
129 | /* C0, C1 colorimetry */ | ||
130 | u8 db2_colorimetry; | ||
131 | /* M0, M1 Aspect ratio (4:3, 16:9) */ | ||
132 | u8 db2_aspect_ratio; | ||
133 | /* R0...R3 Active format aspect ratio */ | ||
134 | u8 db2_active_fmt_ar; | ||
135 | /* ITC IT content. */ | ||
136 | u8 db3_itc; | ||
137 | /* EC0, EC1, EC2 Extended colorimetry */ | ||
138 | u8 db3_ec; | ||
139 | /* Q1, Q0 Quantization range */ | ||
140 | u8 db3_q_range; | ||
141 | /* SC1, SC0 Non-uniform picture scaling */ | ||
142 | u8 db3_nup_scaling; | ||
143 | /* VIC0..6 Video format identification */ | ||
144 | u8 db4_videocode; | ||
145 | /* PR0..PR3 Pixel repetition factor */ | ||
146 | u8 db5_pixel_repeat; | ||
147 | /* Line number end of top bar */ | ||
148 | u16 db6_7_line_eoftop; | ||
149 | /* Line number start of bottom bar */ | ||
150 | u16 db8_9_line_sofbottom; | ||
151 | /* Pixel number end of left bar */ | ||
152 | u16 db10_11_pixel_eofleft; | ||
153 | /* Pixel number start of right bar */ | ||
154 | u16 db12_13_pixel_sofright; | ||
155 | }; | ||
156 | |||
120 | struct hdmi_ip_data { | 157 | struct hdmi_ip_data { |
121 | void __iomem *base_wp; /* HDMI wrapper */ | 158 | void __iomem *base_wp; /* HDMI wrapper */ |
122 | unsigned long core_sys_offset; | 159 | unsigned long core_sys_offset; |
@@ -126,6 +163,7 @@ struct hdmi_ip_data { | |||
126 | const struct ti_hdmi_ip_ops *ops; | 163 | const struct ti_hdmi_ip_ops *ops; |
127 | struct hdmi_config cfg; | 164 | struct hdmi_config cfg; |
128 | struct hdmi_pll_info pll_data; | 165 | struct hdmi_pll_info pll_data; |
166 | struct hdmi_core_infoframe_avi avi_cfg; | ||
129 | 167 | ||
130 | /* ti_hdmi_4xxx_ip private data. These should be in a separate struct */ | 168 | /* ti_hdmi_4xxx_ip private data. These should be in a separate struct */ |
131 | int hpd_gpio; | 169 | int hpd_gpio; |
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c index 6847a478b459..bfe6fe65c8be 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c | |||
@@ -587,12 +587,12 @@ static void hdmi_core_video_config(struct hdmi_ip_data *ip_data, | |||
587 | HDMI_CORE_SYS_TMDS_CTRL, cfg->tclk_sel_clkmult, 6, 5); | 587 | HDMI_CORE_SYS_TMDS_CTRL, cfg->tclk_sel_clkmult, 6, 5); |
588 | } | 588 | } |
589 | 589 | ||
590 | static void hdmi_core_aux_infoframe_avi_config(struct hdmi_ip_data *ip_data, | 590 | static void hdmi_core_aux_infoframe_avi_config(struct hdmi_ip_data *ip_data) |
591 | struct hdmi_core_infoframe_avi info_avi) | ||
592 | { | 591 | { |
593 | u32 val; | 592 | u32 val; |
594 | char sum = 0, checksum = 0; | 593 | char sum = 0, checksum = 0; |
595 | void __iomem *av_base = hdmi_av_base(ip_data); | 594 | void __iomem *av_base = hdmi_av_base(ip_data); |
595 | struct hdmi_core_infoframe_avi info_avi = ip_data->avi_cfg; | ||
596 | 596 | ||
597 | sum += 0x82 + 0x002 + 0x00D; | 597 | sum += 0x82 + 0x002 + 0x00D; |
598 | hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_TYPE, 0x082); | 598 | hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_TYPE, 0x082); |
@@ -682,8 +682,7 @@ static void hdmi_core_av_packet_config(struct hdmi_ip_data *ip_data, | |||
682 | } | 682 | } |
683 | 683 | ||
684 | static void hdmi_wp_init(struct omap_video_timings *timings, | 684 | static void hdmi_wp_init(struct omap_video_timings *timings, |
685 | struct hdmi_video_format *video_fmt, | 685 | struct hdmi_video_format *video_fmt) |
686 | struct hdmi_video_interface *video_int) | ||
687 | { | 686 | { |
688 | pr_debug("Enter hdmi_wp_init\n"); | 687 | pr_debug("Enter hdmi_wp_init\n"); |
689 | 688 | ||
@@ -698,12 +697,6 @@ static void hdmi_wp_init(struct omap_video_timings *timings, | |||
698 | video_fmt->y_res = 0; | 697 | video_fmt->y_res = 0; |
699 | video_fmt->x_res = 0; | 698 | video_fmt->x_res = 0; |
700 | 699 | ||
701 | video_int->vsp = 0; | ||
702 | video_int->hsp = 0; | ||
703 | |||
704 | video_int->interlacing = 0; | ||
705 | video_int->tm = 0; /* HDMI_TIMING_SLAVE */ | ||
706 | |||
707 | } | 700 | } |
708 | 701 | ||
709 | void ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data, bool start) | 702 | void ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data, bool start) |
@@ -716,15 +709,15 @@ static void hdmi_wp_video_init_format(struct hdmi_video_format *video_fmt, | |||
716 | { | 709 | { |
717 | pr_debug("Enter hdmi_wp_video_init_format\n"); | 710 | pr_debug("Enter hdmi_wp_video_init_format\n"); |
718 | 711 | ||
719 | video_fmt->y_res = param->timings.timings.y_res; | 712 | video_fmt->y_res = param->timings.y_res; |
720 | video_fmt->x_res = param->timings.timings.x_res; | 713 | video_fmt->x_res = param->timings.x_res; |
721 | 714 | ||
722 | timings->hbp = param->timings.timings.hbp; | 715 | timings->hbp = param->timings.hbp; |
723 | timings->hfp = param->timings.timings.hfp; | 716 | timings->hfp = param->timings.hfp; |
724 | timings->hsw = param->timings.timings.hsw; | 717 | timings->hsw = param->timings.hsw; |
725 | timings->vbp = param->timings.timings.vbp; | 718 | timings->vbp = param->timings.vbp; |
726 | timings->vfp = param->timings.timings.vfp; | 719 | timings->vfp = param->timings.vfp; |
727 | timings->vsw = param->timings.timings.vsw; | 720 | timings->vsw = param->timings.vsw; |
728 | } | 721 | } |
729 | 722 | ||
730 | static void hdmi_wp_video_config_format(struct hdmi_ip_data *ip_data, | 723 | static void hdmi_wp_video_config_format(struct hdmi_ip_data *ip_data, |
@@ -740,17 +733,16 @@ static void hdmi_wp_video_config_format(struct hdmi_ip_data *ip_data, | |||
740 | hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_SIZE, l); | 733 | hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_SIZE, l); |
741 | } | 734 | } |
742 | 735 | ||
743 | static void hdmi_wp_video_config_interface(struct hdmi_ip_data *ip_data, | 736 | static void hdmi_wp_video_config_interface(struct hdmi_ip_data *ip_data) |
744 | struct hdmi_video_interface *video_int) | ||
745 | { | 737 | { |
746 | u32 r; | 738 | u32 r; |
747 | pr_debug("Enter hdmi_wp_video_config_interface\n"); | 739 | pr_debug("Enter hdmi_wp_video_config_interface\n"); |
748 | 740 | ||
749 | r = hdmi_read_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG); | 741 | r = hdmi_read_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG); |
750 | r = FLD_MOD(r, video_int->vsp, 7, 7); | 742 | r = FLD_MOD(r, ip_data->cfg.timings.vsync_pol, 7, 7); |
751 | r = FLD_MOD(r, video_int->hsp, 6, 6); | 743 | r = FLD_MOD(r, ip_data->cfg.timings.hsync_pol, 6, 6); |
752 | r = FLD_MOD(r, video_int->interlacing, 3, 3); | 744 | r = FLD_MOD(r, ip_data->cfg.timings.interlace, 3, 3); |
753 | r = FLD_MOD(r, video_int->tm, 1, 0); | 745 | r = FLD_MOD(r, 1, 1, 0); /* HDMI_TIMING_MASTER_24BIT */ |
754 | hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, r); | 746 | hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, r); |
755 | } | 747 | } |
756 | 748 | ||
@@ -778,15 +770,13 @@ void ti_hdmi_4xxx_basic_configure(struct hdmi_ip_data *ip_data) | |||
778 | /* HDMI */ | 770 | /* HDMI */ |
779 | struct omap_video_timings video_timing; | 771 | struct omap_video_timings video_timing; |
780 | struct hdmi_video_format video_format; | 772 | struct hdmi_video_format video_format; |
781 | struct hdmi_video_interface video_interface; | ||
782 | /* HDMI core */ | 773 | /* HDMI core */ |
783 | struct hdmi_core_infoframe_avi avi_cfg; | 774 | struct hdmi_core_infoframe_avi avi_cfg = ip_data->avi_cfg; |
784 | struct hdmi_core_video_config v_core_cfg; | 775 | struct hdmi_core_video_config v_core_cfg; |
785 | struct hdmi_core_packet_enable_repeat repeat_cfg; | 776 | struct hdmi_core_packet_enable_repeat repeat_cfg; |
786 | struct hdmi_config *cfg = &ip_data->cfg; | 777 | struct hdmi_config *cfg = &ip_data->cfg; |
787 | 778 | ||
788 | hdmi_wp_init(&video_timing, &video_format, | 779 | hdmi_wp_init(&video_timing, &video_format); |
789 | &video_interface); | ||
790 | 780 | ||
791 | hdmi_core_init(&v_core_cfg, | 781 | hdmi_core_init(&v_core_cfg, |
792 | &avi_cfg, | 782 | &avi_cfg, |
@@ -801,12 +791,7 @@ void ti_hdmi_4xxx_basic_configure(struct hdmi_ip_data *ip_data) | |||
801 | 791 | ||
802 | hdmi_wp_video_config_format(ip_data, &video_format); | 792 | hdmi_wp_video_config_format(ip_data, &video_format); |
803 | 793 | ||
804 | video_interface.vsp = cfg->timings.vsync_pol; | 794 | hdmi_wp_video_config_interface(ip_data); |
805 | video_interface.hsp = cfg->timings.hsync_pol; | ||
806 | video_interface.interlacing = cfg->interlace; | ||
807 | video_interface.tm = 1 ; /* HDMI_TIMING_MASTER_24BIT */ | ||
808 | |||
809 | hdmi_wp_video_config_interface(ip_data, &video_interface); | ||
810 | 795 | ||
811 | /* | 796 | /* |
812 | * configure core video part | 797 | * configure core video part |
@@ -848,7 +833,7 @@ void ti_hdmi_4xxx_basic_configure(struct hdmi_ip_data *ip_data) | |||
848 | avi_cfg.db10_11_pixel_eofleft = 0; | 833 | avi_cfg.db10_11_pixel_eofleft = 0; |
849 | avi_cfg.db12_13_pixel_sofright = 0; | 834 | avi_cfg.db12_13_pixel_sofright = 0; |
850 | 835 | ||
851 | hdmi_core_aux_infoframe_avi_config(ip_data, avi_cfg); | 836 | hdmi_core_aux_infoframe_avi_config(ip_data); |
852 | 837 | ||
853 | /* enable/repeat the infoframe */ | 838 | /* enable/repeat the infoframe */ |
854 | repeat_cfg.avi_infoframe = HDMI_PACKETENABLE; | 839 | repeat_cfg.avi_infoframe = HDMI_PACKETENABLE; |
@@ -1076,13 +1061,9 @@ void hdmi_core_audio_config(struct hdmi_ip_data *ip_data, | |||
1076 | u32 r; | 1061 | u32 r; |
1077 | void __iomem *av_base = hdmi_av_base(ip_data); | 1062 | void __iomem *av_base = hdmi_av_base(ip_data); |
1078 | 1063 | ||
1079 | /* audio clock recovery parameters */ | 1064 | /* |
1080 | r = hdmi_read_reg(av_base, HDMI_CORE_AV_ACR_CTRL); | 1065 | * Parameters for generation of Audio Clock Recovery packets |
1081 | r = FLD_MOD(r, cfg->use_mclk, 2, 2); | 1066 | */ |
1082 | r = FLD_MOD(r, cfg->en_acr_pkt, 1, 1); | ||
1083 | r = FLD_MOD(r, cfg->cts_mode, 0, 0); | ||
1084 | hdmi_write_reg(av_base, HDMI_CORE_AV_ACR_CTRL, r); | ||
1085 | |||
1086 | REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL1, cfg->n, 7, 0); | 1067 | REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL1, cfg->n, 7, 0); |
1087 | REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL2, cfg->n >> 8, 7, 0); | 1068 | REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL2, cfg->n >> 8, 7, 0); |
1088 | REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL3, cfg->n >> 16, 7, 0); | 1069 | REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL3, cfg->n >> 16, 7, 0); |
@@ -1094,14 +1075,6 @@ void hdmi_core_audio_config(struct hdmi_ip_data *ip_data, | |||
1094 | REG_FLD_MOD(av_base, | 1075 | REG_FLD_MOD(av_base, |
1095 | HDMI_CORE_AV_CTS_SVAL3, cfg->cts >> 16, 7, 0); | 1076 | HDMI_CORE_AV_CTS_SVAL3, cfg->cts >> 16, 7, 0); |
1096 | } else { | 1077 | } else { |
1097 | /* | ||
1098 | * HDMI IP uses this configuration to divide the MCLK to | ||
1099 | * update CTS value. | ||
1100 | */ | ||
1101 | REG_FLD_MOD(av_base, | ||
1102 | HDMI_CORE_AV_FREQ_SVAL, cfg->mclk_mode, 2, 0); | ||
1103 | |||
1104 | /* Configure clock for audio packets */ | ||
1105 | REG_FLD_MOD(av_base, HDMI_CORE_AV_AUD_PAR_BUSCLK_1, | 1078 | REG_FLD_MOD(av_base, HDMI_CORE_AV_AUD_PAR_BUSCLK_1, |
1106 | cfg->aud_par_busclk, 7, 0); | 1079 | cfg->aud_par_busclk, 7, 0); |
1107 | REG_FLD_MOD(av_base, HDMI_CORE_AV_AUD_PAR_BUSCLK_2, | 1080 | REG_FLD_MOD(av_base, HDMI_CORE_AV_AUD_PAR_BUSCLK_2, |
@@ -1110,6 +1083,25 @@ void hdmi_core_audio_config(struct hdmi_ip_data *ip_data, | |||
1110 | (cfg->aud_par_busclk >> 16), 7, 0); | 1083 | (cfg->aud_par_busclk >> 16), 7, 0); |
1111 | } | 1084 | } |
1112 | 1085 | ||
1086 | /* Set ACR clock divisor */ | ||
1087 | REG_FLD_MOD(av_base, | ||
1088 | HDMI_CORE_AV_FREQ_SVAL, cfg->mclk_mode, 2, 0); | ||
1089 | |||
1090 | r = hdmi_read_reg(av_base, HDMI_CORE_AV_ACR_CTRL); | ||
1091 | /* | ||
1092 | * Use TMDS clock for ACR packets. For devices that use | ||
1093 | * the MCLK, this is the first part of the MCLK initialization. | ||
1094 | */ | ||
1095 | r = FLD_MOD(r, 0, 2, 2); | ||
1096 | |||
1097 | r = FLD_MOD(r, cfg->en_acr_pkt, 1, 1); | ||
1098 | r = FLD_MOD(r, cfg->cts_mode, 0, 0); | ||
1099 | hdmi_write_reg(av_base, HDMI_CORE_AV_ACR_CTRL, r); | ||
1100 | |||
1101 | /* For devices using MCLK, this completes its initialization. */ | ||
1102 | if (cfg->use_mclk) | ||
1103 | REG_FLD_MOD(av_base, HDMI_CORE_AV_ACR_CTRL, 1, 2, 2); | ||
1104 | |||
1113 | /* Override of SPDIF sample frequency with value in I2S_CHST4 */ | 1105 | /* Override of SPDIF sample frequency with value in I2S_CHST4 */ |
1114 | REG_FLD_MOD(av_base, HDMI_CORE_AV_SPDIF_CTRL, | 1106 | REG_FLD_MOD(av_base, HDMI_CORE_AV_SPDIF_CTRL, |
1115 | cfg->fs_override, 1, 1); | 1107 | cfg->fs_override, 1, 1); |
@@ -1205,7 +1197,7 @@ int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data, | |||
1205 | { | 1197 | { |
1206 | u32 r; | 1198 | u32 r; |
1207 | u32 deep_color = 0; | 1199 | u32 deep_color = 0; |
1208 | u32 pclk = ip_data->cfg.timings.timings.pixel_clock; | 1200 | u32 pclk = ip_data->cfg.timings.pixel_clock; |
1209 | 1201 | ||
1210 | if (n == NULL || cts == NULL) | 1202 | if (n == NULL || cts == NULL) |
1211 | return -EINVAL; | 1203 | return -EINVAL; |
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h index a442998980f1..a14d1a0e6e41 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h | |||
@@ -450,46 +450,6 @@ struct hdmi_core_video_config { | |||
450 | * Refer to section 8.2 in HDMI 1.3 specification for | 450 | * Refer to section 8.2 in HDMI 1.3 specification for |
451 | * details about infoframe databytes | 451 | * details about infoframe databytes |
452 | */ | 452 | */ |
453 | struct hdmi_core_infoframe_avi { | ||
454 | /* Y0, Y1 rgb,yCbCr */ | ||
455 | u8 db1_format; | ||
456 | /* A0 Active information Present */ | ||
457 | u8 db1_active_info; | ||
458 | /* B0, B1 Bar info data valid */ | ||
459 | u8 db1_bar_info_dv; | ||
460 | /* S0, S1 scan information */ | ||
461 | u8 db1_scan_info; | ||
462 | /* C0, C1 colorimetry */ | ||
463 | u8 db2_colorimetry; | ||
464 | /* M0, M1 Aspect ratio (4:3, 16:9) */ | ||
465 | u8 db2_aspect_ratio; | ||
466 | /* R0...R3 Active format aspect ratio */ | ||
467 | u8 db2_active_fmt_ar; | ||
468 | /* ITC IT content. */ | ||
469 | u8 db3_itc; | ||
470 | /* EC0, EC1, EC2 Extended colorimetry */ | ||
471 | u8 db3_ec; | ||
472 | /* Q1, Q0 Quantization range */ | ||
473 | u8 db3_q_range; | ||
474 | /* SC1, SC0 Non-uniform picture scaling */ | ||
475 | u8 db3_nup_scaling; | ||
476 | /* VIC0..6 Video format identification */ | ||
477 | u8 db4_videocode; | ||
478 | /* PR0..PR3 Pixel repetition factor */ | ||
479 | u8 db5_pixel_repeat; | ||
480 | /* Line number end of top bar */ | ||
481 | u16 db6_7_line_eoftop; | ||
482 | /* Line number start of bottom bar */ | ||
483 | u16 db8_9_line_sofbottom; | ||
484 | /* Pixel number end of left bar */ | ||
485 | u16 db10_11_pixel_eofleft; | ||
486 | /* Pixel number start of right bar */ | ||
487 | u16 db12_13_pixel_sofright; | ||
488 | }; | ||
489 | /* | ||
490 | * Refer to section 8.2 in HDMI 1.3 specification for | ||
491 | * details about infoframe databytes | ||
492 | */ | ||
493 | struct hdmi_core_infoframe_audio { | 453 | struct hdmi_core_infoframe_audio { |
494 | u8 db1_coding_type; | 454 | u8 db1_coding_type; |
495 | u8 db1_channel_count; | 455 | u8 db1_channel_count; |
@@ -517,13 +477,6 @@ struct hdmi_video_format { | |||
517 | u32 x_res; /* pixel per line */ | 477 | u32 x_res; /* pixel per line */ |
518 | }; | 478 | }; |
519 | 479 | ||
520 | struct hdmi_video_interface { | ||
521 | int vsp; /* Vsync polarity */ | ||
522 | int hsp; /* Hsync polarity */ | ||
523 | int interlacing; | ||
524 | int tm; /* Timing mode */ | ||
525 | }; | ||
526 | |||
527 | struct hdmi_audio_format { | 480 | struct hdmi_audio_format { |
528 | enum hdmi_stereo_channels stereo_channels; | 481 | enum hdmi_stereo_channels stereo_channels; |
529 | u8 active_chnnls_msk; | 482 | u8 active_chnnls_msk; |
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 5c3d0f901510..9c3daf71750c 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c | |||
@@ -699,6 +699,11 @@ void venc_dump_regs(struct seq_file *s) | |||
699 | { | 699 | { |
700 | #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r)) | 700 | #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r)) |
701 | 701 | ||
702 | if (cpu_is_omap44xx()) { | ||
703 | seq_printf(s, "VENC currently disabled on OMAP44xx\n"); | ||
704 | return; | ||
705 | } | ||
706 | |||
702 | if (venc_runtime_get()) | 707 | if (venc_runtime_get()) |
703 | return; | 708 | return; |
704 | 709 | ||
@@ -790,39 +795,41 @@ static int omap_venchw_probe(struct platform_device *pdev) | |||
790 | venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0); | 795 | venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0); |
791 | if (!venc_mem) { | 796 | if (!venc_mem) { |
792 | DSSERR("can't get IORESOURCE_MEM VENC\n"); | 797 | DSSERR("can't get IORESOURCE_MEM VENC\n"); |
793 | r = -EINVAL; | 798 | return -EINVAL; |
794 | goto err_ioremap; | ||
795 | } | 799 | } |
796 | venc.base = ioremap(venc_mem->start, resource_size(venc_mem)); | 800 | |
801 | venc.base = devm_ioremap(&pdev->dev, venc_mem->start, | ||
802 | resource_size(venc_mem)); | ||
797 | if (!venc.base) { | 803 | if (!venc.base) { |
798 | DSSERR("can't ioremap VENC\n"); | 804 | DSSERR("can't ioremap VENC\n"); |
799 | r = -ENOMEM; | 805 | return -ENOMEM; |
800 | goto err_ioremap; | ||
801 | } | 806 | } |
802 | 807 | ||
803 | r = venc_get_clocks(pdev); | 808 | r = venc_get_clocks(pdev); |
804 | if (r) | 809 | if (r) |
805 | goto err_get_clk; | 810 | return r; |
806 | 811 | ||
807 | pm_runtime_enable(&pdev->dev); | 812 | pm_runtime_enable(&pdev->dev); |
808 | 813 | ||
809 | r = venc_runtime_get(); | 814 | r = venc_runtime_get(); |
810 | if (r) | 815 | if (r) |
811 | goto err_get_venc; | 816 | goto err_runtime_get; |
812 | 817 | ||
813 | rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff); | 818 | rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff); |
814 | dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id); | 819 | dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id); |
815 | 820 | ||
816 | venc_runtime_put(); | 821 | venc_runtime_put(); |
817 | 822 | ||
818 | return omap_dss_register_driver(&venc_driver); | 823 | r = omap_dss_register_driver(&venc_driver); |
824 | if (r) | ||
825 | goto err_reg_panel_driver; | ||
826 | |||
827 | return 0; | ||
819 | 828 | ||
820 | err_get_venc: | 829 | err_reg_panel_driver: |
830 | err_runtime_get: | ||
821 | pm_runtime_disable(&pdev->dev); | 831 | pm_runtime_disable(&pdev->dev); |
822 | venc_put_clocks(); | 832 | venc_put_clocks(); |
823 | err_get_clk: | ||
824 | iounmap(venc.base); | ||
825 | err_ioremap: | ||
826 | return r; | 833 | return r; |
827 | } | 834 | } |
828 | 835 | ||
@@ -837,7 +844,6 @@ static int omap_venchw_remove(struct platform_device *pdev) | |||
837 | pm_runtime_disable(&pdev->dev); | 844 | pm_runtime_disable(&pdev->dev); |
838 | venc_put_clocks(); | 845 | venc_put_clocks(); |
839 | 846 | ||
840 | iounmap(venc.base); | ||
841 | return 0; | 847 | return 0; |
842 | } | 848 | } |
843 | 849 | ||
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index 16ba6196f330..6a09ef87e14f 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c | |||
@@ -215,7 +215,7 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | |||
215 | int r = 0, i; | 215 | int r = 0, i; |
216 | size_t size; | 216 | size_t size; |
217 | 217 | ||
218 | if (mi->type > OMAPFB_MEMTYPE_MAX) | 218 | if (mi->type != OMAPFB_MEMTYPE_SDRAM) |
219 | return -EINVAL; | 219 | return -EINVAL; |
220 | 220 | ||
221 | size = PAGE_ALIGN(mi->size); | 221 | size = PAGE_ALIGN(mi->size); |
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index ce158311ff59..b00db4068d21 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c | |||
@@ -1399,7 +1399,7 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size, | |||
1399 | 1399 | ||
1400 | if (!paddr) { | 1400 | if (!paddr) { |
1401 | DBG("allocating %lu bytes for fb %d\n", size, ofbi->id); | 1401 | DBG("allocating %lu bytes for fb %d\n", size, ofbi->id); |
1402 | r = omap_vram_alloc(OMAP_VRAM_MEMTYPE_SDRAM, size, &paddr); | 1402 | r = omap_vram_alloc(size, &paddr); |
1403 | } else { | 1403 | } else { |
1404 | DBG("reserving %lu bytes at %lx for fb %d\n", size, paddr, | 1404 | DBG("reserving %lu bytes at %lx for fb %d\n", size, paddr, |
1405 | ofbi->id); | 1405 | ofbi->id); |
@@ -1487,60 +1487,6 @@ static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size, | |||
1487 | return omapfb_alloc_fbmem(fbi, size, paddr); | 1487 | return omapfb_alloc_fbmem(fbi, size, paddr); |
1488 | } | 1488 | } |
1489 | 1489 | ||
1490 | static enum omap_color_mode fb_format_to_dss_mode(enum omapfb_color_format fmt) | ||
1491 | { | ||
1492 | enum omap_color_mode mode; | ||
1493 | |||
1494 | switch (fmt) { | ||
1495 | case OMAPFB_COLOR_RGB565: | ||
1496 | mode = OMAP_DSS_COLOR_RGB16; | ||
1497 | break; | ||
1498 | case OMAPFB_COLOR_YUV422: | ||
1499 | mode = OMAP_DSS_COLOR_YUV2; | ||
1500 | break; | ||
1501 | case OMAPFB_COLOR_CLUT_8BPP: | ||
1502 | mode = OMAP_DSS_COLOR_CLUT8; | ||
1503 | break; | ||
1504 | case OMAPFB_COLOR_CLUT_4BPP: | ||
1505 | mode = OMAP_DSS_COLOR_CLUT4; | ||
1506 | break; | ||
1507 | case OMAPFB_COLOR_CLUT_2BPP: | ||
1508 | mode = OMAP_DSS_COLOR_CLUT2; | ||
1509 | break; | ||
1510 | case OMAPFB_COLOR_CLUT_1BPP: | ||
1511 | mode = OMAP_DSS_COLOR_CLUT1; | ||
1512 | break; | ||
1513 | case OMAPFB_COLOR_RGB444: | ||
1514 | mode = OMAP_DSS_COLOR_RGB12U; | ||
1515 | break; | ||
1516 | case OMAPFB_COLOR_YUY422: | ||
1517 | mode = OMAP_DSS_COLOR_UYVY; | ||
1518 | break; | ||
1519 | case OMAPFB_COLOR_ARGB16: | ||
1520 | mode = OMAP_DSS_COLOR_ARGB16; | ||
1521 | break; | ||
1522 | case OMAPFB_COLOR_RGB24U: | ||
1523 | mode = OMAP_DSS_COLOR_RGB24U; | ||
1524 | break; | ||
1525 | case OMAPFB_COLOR_RGB24P: | ||
1526 | mode = OMAP_DSS_COLOR_RGB24P; | ||
1527 | break; | ||
1528 | case OMAPFB_COLOR_ARGB32: | ||
1529 | mode = OMAP_DSS_COLOR_ARGB32; | ||
1530 | break; | ||
1531 | case OMAPFB_COLOR_RGBA32: | ||
1532 | mode = OMAP_DSS_COLOR_RGBA32; | ||
1533 | break; | ||
1534 | case OMAPFB_COLOR_RGBX32: | ||
1535 | mode = OMAP_DSS_COLOR_RGBX32; | ||
1536 | break; | ||
1537 | default: | ||
1538 | mode = -EINVAL; | ||
1539 | } | ||
1540 | |||
1541 | return mode; | ||
1542 | } | ||
1543 | |||
1544 | static int omapfb_parse_vram_param(const char *param, int max_entries, | 1490 | static int omapfb_parse_vram_param(const char *param, int max_entries, |
1545 | unsigned long *sizes, unsigned long *paddrs) | 1491 | unsigned long *sizes, unsigned long *paddrs) |
1546 | { | 1492 | { |
@@ -1614,23 +1560,6 @@ static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev) | |||
1614 | memset(&vram_paddrs, 0, sizeof(vram_paddrs)); | 1560 | memset(&vram_paddrs, 0, sizeof(vram_paddrs)); |
1615 | } | 1561 | } |
1616 | 1562 | ||
1617 | if (fbdev->dev->platform_data) { | ||
1618 | struct omapfb_platform_data *opd; | ||
1619 | opd = fbdev->dev->platform_data; | ||
1620 | for (i = 0; i < opd->mem_desc.region_cnt; ++i) { | ||
1621 | if (!vram_sizes[i]) { | ||
1622 | unsigned long size; | ||
1623 | unsigned long paddr; | ||
1624 | |||
1625 | size = opd->mem_desc.region[i].size; | ||
1626 | paddr = opd->mem_desc.region[i].paddr; | ||
1627 | |||
1628 | vram_sizes[i] = size; | ||
1629 | vram_paddrs[i] = paddr; | ||
1630 | } | ||
1631 | } | ||
1632 | } | ||
1633 | |||
1634 | for (i = 0; i < fbdev->num_fbs; i++) { | 1563 | for (i = 0; i < fbdev->num_fbs; i++) { |
1635 | /* allocate memory automatically only for fb0, or if | 1564 | /* allocate memory automatically only for fb0, or if |
1636 | * excplicitly defined with vram or plat data option */ | 1565 | * excplicitly defined with vram or plat data option */ |
@@ -1669,7 +1598,7 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type) | |||
1669 | int old_type = rg->type; | 1598 | int old_type = rg->type; |
1670 | int r; | 1599 | int r; |
1671 | 1600 | ||
1672 | if (type > OMAPFB_MEMTYPE_MAX) | 1601 | if (type != OMAPFB_MEMTYPE_SDRAM) |
1673 | return -EINVAL; | 1602 | return -EINVAL; |
1674 | 1603 | ||
1675 | size = PAGE_ALIGN(size); | 1604 | size = PAGE_ALIGN(size); |
@@ -1828,32 +1757,6 @@ static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi) | |||
1828 | 1757 | ||
1829 | var->rotate = def_rotate; | 1758 | var->rotate = def_rotate; |
1830 | 1759 | ||
1831 | /* | ||
1832 | * Check if there is a default color format set in the board file, | ||
1833 | * and use this format instead the default deducted from the | ||
1834 | * display bpp. | ||
1835 | */ | ||
1836 | if (fbdev->dev->platform_data) { | ||
1837 | struct omapfb_platform_data *opd; | ||
1838 | int id = ofbi->id; | ||
1839 | |||
1840 | opd = fbdev->dev->platform_data; | ||
1841 | if (opd->mem_desc.region[id].format_used) { | ||
1842 | enum omap_color_mode mode; | ||
1843 | enum omapfb_color_format format; | ||
1844 | |||
1845 | format = opd->mem_desc.region[id].format; | ||
1846 | mode = fb_format_to_dss_mode(format); | ||
1847 | if (mode < 0) { | ||
1848 | r = mode; | ||
1849 | goto err; | ||
1850 | } | ||
1851 | r = dss_mode_to_fb_mode(mode, var); | ||
1852 | if (r < 0) | ||
1853 | goto err; | ||
1854 | } | ||
1855 | } | ||
1856 | |||
1857 | if (display) { | 1760 | if (display) { |
1858 | u16 w, h; | 1761 | u16 w, h; |
1859 | int rotation = (var->rotate + ofbi->rotation[0]) % 4; | 1762 | int rotation = (var->rotate + ofbi->rotation[0]) % 4; |
diff --git a/drivers/video/omap2/vram.c b/drivers/video/omap2/vram.c index 9441e2eb3dee..87e421e25afe 100644 --- a/drivers/video/omap2/vram.c +++ b/drivers/video/omap2/vram.c | |||
@@ -33,7 +33,6 @@ | |||
33 | 33 | ||
34 | #include <asm/setup.h> | 34 | #include <asm/setup.h> |
35 | 35 | ||
36 | #include <plat/sram.h> | ||
37 | #include <plat/vram.h> | 36 | #include <plat/vram.h> |
38 | #include <plat/dma.h> | 37 | #include <plat/dma.h> |
39 | 38 | ||
@@ -43,10 +42,6 @@ | |||
43 | #define DBG(format, ...) | 42 | #define DBG(format, ...) |
44 | #endif | 43 | #endif |
45 | 44 | ||
46 | #define OMAP2_SRAM_START 0x40200000 | ||
47 | /* Maximum size, in reality this is smaller if SRAM is partially locked. */ | ||
48 | #define OMAP2_SRAM_SIZE 0xa0000 /* 640k */ | ||
49 | |||
50 | /* postponed regions are used to temporarily store region information at boot | 45 | /* postponed regions are used to temporarily store region information at boot |
51 | * time when we cannot yet allocate the region list */ | 46 | * time when we cannot yet allocate the region list */ |
52 | #define MAX_POSTPONED_REGIONS 10 | 47 | #define MAX_POSTPONED_REGIONS 10 |
@@ -74,15 +69,6 @@ struct vram_region { | |||
74 | static DEFINE_MUTEX(region_mutex); | 69 | static DEFINE_MUTEX(region_mutex); |
75 | static LIST_HEAD(region_list); | 70 | static LIST_HEAD(region_list); |
76 | 71 | ||
77 | static inline int region_mem_type(unsigned long paddr) | ||
78 | { | ||
79 | if (paddr >= OMAP2_SRAM_START && | ||
80 | paddr < OMAP2_SRAM_START + OMAP2_SRAM_SIZE) | ||
81 | return OMAP_VRAM_MEMTYPE_SRAM; | ||
82 | else | ||
83 | return OMAP_VRAM_MEMTYPE_SDRAM; | ||
84 | } | ||
85 | |||
86 | static struct vram_region *omap_vram_create_region(unsigned long paddr, | 72 | static struct vram_region *omap_vram_create_region(unsigned long paddr, |
87 | unsigned pages) | 73 | unsigned pages) |
88 | { | 74 | { |
@@ -212,9 +198,6 @@ static int _omap_vram_reserve(unsigned long paddr, unsigned pages) | |||
212 | 198 | ||
213 | DBG("checking region %lx %d\n", rm->paddr, rm->pages); | 199 | DBG("checking region %lx %d\n", rm->paddr, rm->pages); |
214 | 200 | ||
215 | if (region_mem_type(rm->paddr) != region_mem_type(paddr)) | ||
216 | continue; | ||
217 | |||
218 | start = rm->paddr; | 201 | start = rm->paddr; |
219 | end = start + (rm->pages << PAGE_SHIFT) - 1; | 202 | end = start + (rm->pages << PAGE_SHIFT) - 1; |
220 | if (start > paddr || end < paddr + size - 1) | 203 | if (start > paddr || end < paddr + size - 1) |
@@ -320,7 +303,7 @@ err: | |||
320 | return r; | 303 | return r; |
321 | } | 304 | } |
322 | 305 | ||
323 | static int _omap_vram_alloc(int mtype, unsigned pages, unsigned long *paddr) | 306 | static int _omap_vram_alloc(unsigned pages, unsigned long *paddr) |
324 | { | 307 | { |
325 | struct vram_region *rm; | 308 | struct vram_region *rm; |
326 | struct vram_alloc *alloc; | 309 | struct vram_alloc *alloc; |
@@ -330,9 +313,6 @@ static int _omap_vram_alloc(int mtype, unsigned pages, unsigned long *paddr) | |||
330 | 313 | ||
331 | DBG("checking region %lx %d\n", rm->paddr, rm->pages); | 314 | DBG("checking region %lx %d\n", rm->paddr, rm->pages); |
332 | 315 | ||
333 | if (region_mem_type(rm->paddr) != mtype) | ||
334 | continue; | ||
335 | |||
336 | start = rm->paddr; | 316 | start = rm->paddr; |
337 | 317 | ||
338 | list_for_each_entry(alloc, &rm->alloc_list, list) { | 318 | list_for_each_entry(alloc, &rm->alloc_list, list) { |
@@ -365,21 +345,21 @@ found: | |||
365 | return -ENOMEM; | 345 | return -ENOMEM; |
366 | } | 346 | } |
367 | 347 | ||
368 | int omap_vram_alloc(int mtype, size_t size, unsigned long *paddr) | 348 | int omap_vram_alloc(size_t size, unsigned long *paddr) |
369 | { | 349 | { |
370 | unsigned pages; | 350 | unsigned pages; |
371 | int r; | 351 | int r; |
372 | 352 | ||
373 | BUG_ON(mtype > OMAP_VRAM_MEMTYPE_MAX || !size); | 353 | BUG_ON(!size); |
374 | 354 | ||
375 | DBG("alloc mem type %d size %d\n", mtype, size); | 355 | DBG("alloc mem size %d\n", size); |
376 | 356 | ||
377 | size = PAGE_ALIGN(size); | 357 | size = PAGE_ALIGN(size); |
378 | pages = size >> PAGE_SHIFT; | 358 | pages = size >> PAGE_SHIFT; |
379 | 359 | ||
380 | mutex_lock(®ion_mutex); | 360 | mutex_lock(®ion_mutex); |
381 | 361 | ||
382 | r = _omap_vram_alloc(mtype, pages, paddr); | 362 | r = _omap_vram_alloc(pages, paddr); |
383 | 363 | ||
384 | mutex_unlock(®ion_mutex); | 364 | mutex_unlock(®ion_mutex); |
385 | 365 | ||
@@ -501,10 +481,6 @@ arch_initcall(omap_vram_init); | |||
501 | /* boottime vram alloc stuff */ | 481 | /* boottime vram alloc stuff */ |
502 | 482 | ||
503 | /* set from board file */ | 483 | /* set from board file */ |
504 | static u32 omap_vram_sram_start __initdata; | ||
505 | static u32 omap_vram_sram_size __initdata; | ||
506 | |||
507 | /* set from board file */ | ||
508 | static u32 omap_vram_sdram_start __initdata; | 484 | static u32 omap_vram_sdram_start __initdata; |
509 | static u32 omap_vram_sdram_size __initdata; | 485 | static u32 omap_vram_sdram_size __initdata; |
510 | 486 | ||
@@ -587,73 +563,8 @@ void __init omap_vram_reserve_sdram_memblock(void) | |||
587 | pr_info("Reserving %u bytes SDRAM for VRAM\n", size); | 563 | pr_info("Reserving %u bytes SDRAM for VRAM\n", size); |
588 | } | 564 | } |
589 | 565 | ||
590 | /* | ||
591 | * Called at sram init time, before anything is pushed to the SRAM stack. | ||
592 | * Because of the stack scheme, we will allocate everything from the | ||
593 | * start of the lowest address region to the end of SRAM. This will also | ||
594 | * include padding for page alignment and possible holes between regions. | ||
595 | * | ||
596 | * As opposed to the SDRAM case, we'll also do any dynamic allocations at | ||
597 | * this point, since the driver built as a module would have problem with | ||
598 | * freeing / reallocating the regions. | ||
599 | */ | ||
600 | unsigned long __init omap_vram_reserve_sram(unsigned long sram_pstart, | ||
601 | unsigned long sram_vstart, | ||
602 | unsigned long sram_size, | ||
603 | unsigned long pstart_avail, | ||
604 | unsigned long size_avail) | ||
605 | { | ||
606 | unsigned long pend_avail; | ||
607 | unsigned long reserved; | ||
608 | u32 paddr; | ||
609 | u32 size; | ||
610 | |||
611 | paddr = omap_vram_sram_start; | ||
612 | size = omap_vram_sram_size; | ||
613 | |||
614 | if (!size) | ||
615 | return 0; | ||
616 | |||
617 | reserved = 0; | ||
618 | pend_avail = pstart_avail + size_avail; | ||
619 | |||
620 | if (!paddr) { | ||
621 | /* Dynamic allocation */ | ||
622 | if ((size_avail & PAGE_MASK) < size) { | ||
623 | pr_err("Not enough SRAM for VRAM\n"); | ||
624 | return 0; | ||
625 | } | ||
626 | size_avail = (size_avail - size) & PAGE_MASK; | ||
627 | paddr = pstart_avail + size_avail; | ||
628 | } | ||
629 | |||
630 | if (paddr < sram_pstart || | ||
631 | paddr + size > sram_pstart + sram_size) { | ||
632 | pr_err("Illegal SRAM region for VRAM\n"); | ||
633 | return 0; | ||
634 | } | ||
635 | |||
636 | /* Reserve everything above the start of the region. */ | ||
637 | if (pend_avail - paddr > reserved) | ||
638 | reserved = pend_avail - paddr; | ||
639 | size_avail = pend_avail - reserved - pstart_avail; | ||
640 | |||
641 | omap_vram_add_region(paddr, size); | ||
642 | |||
643 | if (reserved) | ||
644 | pr_info("Reserving %lu bytes SRAM for VRAM\n", reserved); | ||
645 | |||
646 | return reserved; | ||
647 | } | ||
648 | |||
649 | void __init omap_vram_set_sdram_vram(u32 size, u32 start) | 566 | void __init omap_vram_set_sdram_vram(u32 size, u32 start) |
650 | { | 567 | { |
651 | omap_vram_sdram_start = start; | 568 | omap_vram_sdram_start = start; |
652 | omap_vram_sdram_size = size; | 569 | omap_vram_sdram_size = size; |
653 | } | 570 | } |
654 | |||
655 | void __init omap_vram_set_sram_vram(u32 size, u32 start) | ||
656 | { | ||
657 | omap_vram_sram_start = start; | ||
658 | omap_vram_sram_size = size; | ||
659 | } | ||
diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c index 3a3fdc62c75b..bcd44c32a2ed 100644 --- a/drivers/video/pvr2fb.c +++ b/drivers/video/pvr2fb.c | |||
@@ -895,7 +895,7 @@ static int __init pvr2fb_dc_init(void) | |||
895 | 895 | ||
896 | #ifdef CONFIG_PVR2_DMA | 896 | #ifdef CONFIG_PVR2_DMA |
897 | if (request_dma(pvr2dma, "pvr2") != 0) { | 897 | if (request_dma(pvr2dma, "pvr2") != 0) { |
898 | free_irq(HW_EVENT_VSYNC, 0); | 898 | free_irq(HW_EVENT_VSYNC, fb_info); |
899 | return -EBUSY; | 899 | return -EBUSY; |
900 | } | 900 | } |
901 | #endif | 901 | #endif |
@@ -914,7 +914,7 @@ static void __exit pvr2fb_dc_exit(void) | |||
914 | currentpar->mmio_base = 0; | 914 | currentpar->mmio_base = 0; |
915 | } | 915 | } |
916 | 916 | ||
917 | free_irq(HW_EVENT_VSYNC, 0); | 917 | free_irq(HW_EVENT_VSYNC, fb_info); |
918 | #ifdef CONFIG_PVR2_DMA | 918 | #ifdef CONFIG_PVR2_DMA |
919 | free_dma(pvr2dma); | 919 | free_dma(pvr2dma); |
920 | #endif | 920 | #endif |
diff --git a/drivers/video/pxa168fb.c b/drivers/video/pxa168fb.c index 8384b941f6ba..f146089261f4 100644 --- a/drivers/video/pxa168fb.c +++ b/drivers/video/pxa168fb.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/fb.h> | 21 | #include <linux/fb.h> |
22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
23 | #include <linux/init.h> | 23 | #include <linux/init.h> |
24 | #include <linux/io.h> | ||
24 | #include <linux/ioport.h> | 25 | #include <linux/ioport.h> |
25 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
26 | #include <linux/dma-mapping.h> | 27 | #include <linux/dma-mapping.h> |
@@ -670,7 +671,8 @@ static int __devinit pxa168fb_probe(struct platform_device *pdev) | |||
670 | /* | 671 | /* |
671 | * Map LCD controller registers. | 672 | * Map LCD controller registers. |
672 | */ | 673 | */ |
673 | fbi->reg_base = ioremap_nocache(res->start, resource_size(res)); | 674 | fbi->reg_base = devm_ioremap_nocache(&pdev->dev, res->start, |
675 | resource_size(res)); | ||
674 | if (fbi->reg_base == NULL) { | 676 | if (fbi->reg_base == NULL) { |
675 | ret = -ENOMEM; | 677 | ret = -ENOMEM; |
676 | goto failed_free_info; | 678 | goto failed_free_info; |
@@ -739,8 +741,8 @@ static int __devinit pxa168fb_probe(struct platform_device *pdev) | |||
739 | /* | 741 | /* |
740 | * Register irq handler. | 742 | * Register irq handler. |
741 | */ | 743 | */ |
742 | ret = request_irq(irq, pxa168fb_handle_irq, IRQF_SHARED, | 744 | ret = devm_request_irq(&pdev->dev, irq, pxa168fb_handle_irq, |
743 | info->fix.id, fbi); | 745 | IRQF_SHARED, info->fix.id, fbi); |
744 | if (ret < 0) { | 746 | if (ret < 0) { |
745 | dev_err(&pdev->dev, "unable to request IRQ\n"); | 747 | dev_err(&pdev->dev, "unable to request IRQ\n"); |
746 | ret = -ENXIO; | 748 | ret = -ENXIO; |
@@ -759,14 +761,12 @@ static int __devinit pxa168fb_probe(struct platform_device *pdev) | |||
759 | if (ret < 0) { | 761 | if (ret < 0) { |
760 | dev_err(&pdev->dev, "Failed to register pxa168-fb: %d\n", ret); | 762 | dev_err(&pdev->dev, "Failed to register pxa168-fb: %d\n", ret); |
761 | ret = -ENXIO; | 763 | ret = -ENXIO; |
762 | goto failed_free_irq; | 764 | goto failed_free_cmap; |
763 | } | 765 | } |
764 | 766 | ||
765 | platform_set_drvdata(pdev, fbi); | 767 | platform_set_drvdata(pdev, fbi); |
766 | return 0; | 768 | return 0; |
767 | 769 | ||
768 | failed_free_irq: | ||
769 | free_irq(irq, fbi); | ||
770 | failed_free_cmap: | 770 | failed_free_cmap: |
771 | fb_dealloc_cmap(&info->cmap); | 771 | fb_dealloc_cmap(&info->cmap); |
772 | failed_free_clk: | 772 | failed_free_clk: |
@@ -808,13 +808,10 @@ static int __devexit pxa168fb_remove(struct platform_device *pdev) | |||
808 | fb_dealloc_cmap(&info->cmap); | 808 | fb_dealloc_cmap(&info->cmap); |
809 | 809 | ||
810 | irq = platform_get_irq(pdev, 0); | 810 | irq = platform_get_irq(pdev, 0); |
811 | free_irq(irq, fbi); | ||
812 | 811 | ||
813 | dma_free_writecombine(fbi->dev, PAGE_ALIGN(info->fix.smem_len), | 812 | dma_free_writecombine(fbi->dev, PAGE_ALIGN(info->fix.smem_len), |
814 | info->screen_base, info->fix.smem_start); | 813 | info->screen_base, info->fix.smem_start); |
815 | 814 | ||
816 | iounmap(fbi->reg_base); | ||
817 | |||
818 | clk_disable(fbi->clk); | 815 | clk_disable(fbi->clk); |
819 | clk_put(fbi->clk); | 816 | clk_put(fbi->clk); |
820 | 817 | ||
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 1d1e4f175e78..3f902557690e 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c | |||
@@ -54,6 +54,7 @@ | |||
54 | #include <linux/mutex.h> | 54 | #include <linux/mutex.h> |
55 | #include <linux/kthread.h> | 55 | #include <linux/kthread.h> |
56 | #include <linux/freezer.h> | 56 | #include <linux/freezer.h> |
57 | #include <linux/console.h> | ||
57 | 58 | ||
58 | #include <mach/hardware.h> | 59 | #include <mach/hardware.h> |
59 | #include <asm/io.h> | 60 | #include <asm/io.h> |
@@ -730,9 +731,12 @@ static int overlayfb_open(struct fb_info *info, int user) | |||
730 | if (user == 0) | 731 | if (user == 0) |
731 | return -ENODEV; | 732 | return -ENODEV; |
732 | 733 | ||
733 | if (ofb->usage++ == 0) | 734 | if (ofb->usage++ == 0) { |
734 | /* unblank the base framebuffer */ | 735 | /* unblank the base framebuffer */ |
736 | console_lock(); | ||
735 | fb_blank(&ofb->fbi->fb, FB_BLANK_UNBLANK); | 737 | fb_blank(&ofb->fbi->fb, FB_BLANK_UNBLANK); |
738 | console_unlock(); | ||
739 | } | ||
736 | 740 | ||
737 | return 0; | 741 | return 0; |
738 | } | 742 | } |
@@ -1431,7 +1435,7 @@ static void pxafb_enable_controller(struct pxafb_info *fbi) | |||
1431 | pr_debug("reg_lccr3 0x%08x\n", (unsigned int) fbi->reg_lccr3); | 1435 | pr_debug("reg_lccr3 0x%08x\n", (unsigned int) fbi->reg_lccr3); |
1432 | 1436 | ||
1433 | /* enable LCD controller clock */ | 1437 | /* enable LCD controller clock */ |
1434 | clk_enable(fbi->clk); | 1438 | clk_prepare_enable(fbi->clk); |
1435 | 1439 | ||
1436 | if (fbi->lccr0 & LCCR0_LCDT) | 1440 | if (fbi->lccr0 & LCCR0_LCDT) |
1437 | return; | 1441 | return; |
@@ -1471,7 +1475,7 @@ static void pxafb_disable_controller(struct pxafb_info *fbi) | |||
1471 | wait_for_completion_timeout(&fbi->disable_done, 200 * HZ / 1000); | 1475 | wait_for_completion_timeout(&fbi->disable_done, 200 * HZ / 1000); |
1472 | 1476 | ||
1473 | /* disable LCD controller clock */ | 1477 | /* disable LCD controller clock */ |
1474 | clk_disable(fbi->clk); | 1478 | clk_disable_unprepare(fbi->clk); |
1475 | } | 1479 | } |
1476 | 1480 | ||
1477 | /* | 1481 | /* |
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index 2f58cf9c813b..90df1a60bd16 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c | |||
@@ -1816,6 +1816,8 @@ static void __devinit riva_update_default_var(struct fb_var_screeninfo *var, | |||
1816 | specs->modedb, specs->modedb_len, | 1816 | specs->modedb, specs->modedb_len, |
1817 | NULL, 8); | 1817 | NULL, 8); |
1818 | } else if (specs->modedb != NULL) { | 1818 | } else if (specs->modedb != NULL) { |
1819 | /* get first mode in database as fallback */ | ||
1820 | modedb = specs->modedb[0]; | ||
1819 | /* get preferred timing */ | 1821 | /* get preferred timing */ |
1820 | if (info->monspecs.misc & FB_MISC_1ST_DETAIL) { | 1822 | if (info->monspecs.misc & FB_MISC_1ST_DETAIL) { |
1821 | int i; | 1823 | int i; |
@@ -1826,9 +1828,6 @@ static void __devinit riva_update_default_var(struct fb_var_screeninfo *var, | |||
1826 | break; | 1828 | break; |
1827 | } | 1829 | } |
1828 | } | 1830 | } |
1829 | } else { | ||
1830 | /* otherwise, get first mode in database */ | ||
1831 | modedb = specs->modedb[0]; | ||
1832 | } | 1831 | } |
1833 | var->bits_per_pixel = 8; | 1832 | var->bits_per_pixel = 8; |
1834 | riva_update_var(var, &modedb); | 1833 | riva_update_var(var, &modedb); |
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index 0c63b69b6340..f3105160bf98 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c | |||
@@ -48,7 +48,8 @@ | |||
48 | #undef writel | 48 | #undef writel |
49 | #define writel(v, r) do { \ | 49 | #define writel(v, r) do { \ |
50 | printk(KERN_DEBUG "%s: %08x => %p\n", __func__, (unsigned int)v, r); \ | 50 | printk(KERN_DEBUG "%s: %08x => %p\n", __func__, (unsigned int)v, r); \ |
51 | __raw_writel(v, r); } while (0) | 51 | __raw_writel(v, r); \ |
52 | } while (0) | ||
52 | #endif /* FB_S3C_DEBUG_REGWRITE */ | 53 | #endif /* FB_S3C_DEBUG_REGWRITE */ |
53 | 54 | ||
54 | /* irq_flags bits */ | 55 | /* irq_flags bits */ |
@@ -81,12 +82,14 @@ struct s3c_fb; | |||
81 | * @palette: Address of palette memory, or 0 if none. | 82 | * @palette: Address of palette memory, or 0 if none. |
82 | * @has_prtcon: Set if has PRTCON register. | 83 | * @has_prtcon: Set if has PRTCON register. |
83 | * @has_shadowcon: Set if has SHADOWCON register. | 84 | * @has_shadowcon: Set if has SHADOWCON register. |
85 | * @has_blendcon: Set if has BLENDCON register. | ||
84 | * @has_clksel: Set if VIDCON0 register has CLKSEL bit. | 86 | * @has_clksel: Set if VIDCON0 register has CLKSEL bit. |
87 | * @has_fixvclk: Set if VIDCON1 register has FIXVCLK bits. | ||
85 | */ | 88 | */ |
86 | struct s3c_fb_variant { | 89 | struct s3c_fb_variant { |
87 | unsigned int is_2443:1; | 90 | unsigned int is_2443:1; |
88 | unsigned short nr_windows; | 91 | unsigned short nr_windows; |
89 | unsigned short vidtcon; | 92 | unsigned int vidtcon; |
90 | unsigned short wincon; | 93 | unsigned short wincon; |
91 | unsigned short winmap; | 94 | unsigned short winmap; |
92 | unsigned short keycon; | 95 | unsigned short keycon; |
@@ -99,7 +102,9 @@ struct s3c_fb_variant { | |||
99 | 102 | ||
100 | unsigned int has_prtcon:1; | 103 | unsigned int has_prtcon:1; |
101 | unsigned int has_shadowcon:1; | 104 | unsigned int has_shadowcon:1; |
105 | unsigned int has_blendcon:1; | ||
102 | unsigned int has_clksel:1; | 106 | unsigned int has_clksel:1; |
107 | unsigned int has_fixvclk:1; | ||
103 | }; | 108 | }; |
104 | 109 | ||
105 | /** | 110 | /** |
@@ -186,7 +191,6 @@ struct s3c_fb_vsync { | |||
186 | * struct s3c_fb - overall hardware state of the hardware | 191 | * struct s3c_fb - overall hardware state of the hardware |
187 | * @slock: The spinlock protection for this data sturcture. | 192 | * @slock: The spinlock protection for this data sturcture. |
188 | * @dev: The device that we bound to, for printing, etc. | 193 | * @dev: The device that we bound to, for printing, etc. |
189 | * @regs_res: The resource we claimed for the IO registers. | ||
190 | * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk. | 194 | * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk. |
191 | * @lcd_clk: The clk (sclk) feeding pixclk. | 195 | * @lcd_clk: The clk (sclk) feeding pixclk. |
192 | * @regs: The mapped hardware registers. | 196 | * @regs: The mapped hardware registers. |
@@ -202,7 +206,6 @@ struct s3c_fb_vsync { | |||
202 | struct s3c_fb { | 206 | struct s3c_fb { |
203 | spinlock_t slock; | 207 | spinlock_t slock; |
204 | struct device *dev; | 208 | struct device *dev; |
205 | struct resource *regs_res; | ||
206 | struct clk *bus_clk; | 209 | struct clk *bus_clk; |
207 | struct clk *lcd_clk; | 210 | struct clk *lcd_clk; |
208 | void __iomem *regs; | 211 | void __iomem *regs; |
@@ -565,7 +568,9 @@ static int s3c_fb_set_par(struct fb_info *info) | |||
565 | writel(data, regs + sfb->variant.vidtcon + 4); | 568 | writel(data, regs + sfb->variant.vidtcon + 4); |
566 | 569 | ||
567 | data = VIDTCON2_LINEVAL(var->yres - 1) | | 570 | data = VIDTCON2_LINEVAL(var->yres - 1) | |
568 | VIDTCON2_HOZVAL(var->xres - 1); | 571 | VIDTCON2_HOZVAL(var->xres - 1) | |
572 | VIDTCON2_LINEVAL_E(var->yres - 1) | | ||
573 | VIDTCON2_HOZVAL_E(var->xres - 1); | ||
569 | writel(data, regs + sfb->variant.vidtcon + 8); | 574 | writel(data, regs + sfb->variant.vidtcon + 8); |
570 | } | 575 | } |
571 | 576 | ||
@@ -581,17 +586,23 @@ static int s3c_fb_set_par(struct fb_info *info) | |||
581 | 586 | ||
582 | pagewidth = (var->xres * var->bits_per_pixel) >> 3; | 587 | pagewidth = (var->xres * var->bits_per_pixel) >> 3; |
583 | data = VIDW_BUF_SIZE_OFFSET(info->fix.line_length - pagewidth) | | 588 | data = VIDW_BUF_SIZE_OFFSET(info->fix.line_length - pagewidth) | |
584 | VIDW_BUF_SIZE_PAGEWIDTH(pagewidth); | 589 | VIDW_BUF_SIZE_PAGEWIDTH(pagewidth) | |
590 | VIDW_BUF_SIZE_OFFSET_E(info->fix.line_length - pagewidth) | | ||
591 | VIDW_BUF_SIZE_PAGEWIDTH_E(pagewidth); | ||
585 | writel(data, regs + sfb->variant.buf_size + (win_no * 4)); | 592 | writel(data, regs + sfb->variant.buf_size + (win_no * 4)); |
586 | 593 | ||
587 | /* write 'OSD' registers to control position of framebuffer */ | 594 | /* write 'OSD' registers to control position of framebuffer */ |
588 | 595 | ||
589 | data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0); | 596 | data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0) | |
597 | VIDOSDxA_TOPLEFT_X_E(0) | VIDOSDxA_TOPLEFT_Y_E(0); | ||
590 | writel(data, regs + VIDOSD_A(win_no, sfb->variant)); | 598 | writel(data, regs + VIDOSD_A(win_no, sfb->variant)); |
591 | 599 | ||
592 | data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel, | 600 | data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel, |
593 | var->xres - 1)) | | 601 | var->xres - 1)) | |
594 | VIDOSDxB_BOTRIGHT_Y(var->yres - 1); | 602 | VIDOSDxB_BOTRIGHT_Y(var->yres - 1) | |
603 | VIDOSDxB_BOTRIGHT_X_E(s3c_fb_align_word(var->bits_per_pixel, | ||
604 | var->xres - 1)) | | ||
605 | VIDOSDxB_BOTRIGHT_Y_E(var->yres - 1); | ||
595 | 606 | ||
596 | writel(data, regs + VIDOSD_B(win_no, sfb->variant)); | 607 | writel(data, regs + VIDOSD_B(win_no, sfb->variant)); |
597 | 608 | ||
@@ -692,6 +703,17 @@ static int s3c_fb_set_par(struct fb_info *info) | |||
692 | writel(data, regs + sfb->variant.wincon + (win_no * 4)); | 703 | writel(data, regs + sfb->variant.wincon + (win_no * 4)); |
693 | writel(0x0, regs + sfb->variant.winmap + (win_no * 4)); | 704 | writel(0x0, regs + sfb->variant.winmap + (win_no * 4)); |
694 | 705 | ||
706 | /* Set alpha value width */ | ||
707 | if (sfb->variant.has_blendcon) { | ||
708 | data = readl(sfb->regs + BLENDCON); | ||
709 | data &= ~BLENDCON_NEW_MASK; | ||
710 | if (var->transp.length > 4) | ||
711 | data |= BLENDCON_NEW_8BIT_ALPHA_VALUE; | ||
712 | else | ||
713 | data |= BLENDCON_NEW_4BIT_ALPHA_VALUE; | ||
714 | writel(data, sfb->regs + BLENDCON); | ||
715 | } | ||
716 | |||
695 | shadow_protect_win(win, 0); | 717 | shadow_protect_win(win, 0); |
696 | 718 | ||
697 | pm_runtime_put_sync(sfb->dev); | 719 | pm_runtime_put_sync(sfb->dev); |
@@ -1346,6 +1368,7 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) | |||
1346 | struct resource *res; | 1368 | struct resource *res; |
1347 | int win; | 1369 | int win; |
1348 | int ret = 0; | 1370 | int ret = 0; |
1371 | u32 reg; | ||
1349 | 1372 | ||
1350 | platid = platform_get_device_id(pdev); | 1373 | platid = platform_get_device_id(pdev); |
1351 | fbdrv = (struct s3c_fb_driverdata *)platid->driver_data; | 1374 | fbdrv = (struct s3c_fb_driverdata *)platid->driver_data; |
@@ -1361,7 +1384,7 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) | |||
1361 | return -EINVAL; | 1384 | return -EINVAL; |
1362 | } | 1385 | } |
1363 | 1386 | ||
1364 | sfb = kzalloc(sizeof(struct s3c_fb), GFP_KERNEL); | 1387 | sfb = devm_kzalloc(dev, sizeof(struct s3c_fb), GFP_KERNEL); |
1365 | if (!sfb) { | 1388 | if (!sfb) { |
1366 | dev_err(dev, "no memory for framebuffers\n"); | 1389 | dev_err(dev, "no memory for framebuffers\n"); |
1367 | return -ENOMEM; | 1390 | return -ENOMEM; |
@@ -1404,33 +1427,25 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) | |||
1404 | goto err_lcd_clk; | 1427 | goto err_lcd_clk; |
1405 | } | 1428 | } |
1406 | 1429 | ||
1407 | sfb->regs_res = request_mem_region(res->start, resource_size(res), | 1430 | sfb->regs = devm_request_and_ioremap(dev, res); |
1408 | dev_name(dev)); | ||
1409 | if (!sfb->regs_res) { | ||
1410 | dev_err(dev, "failed to claim register region\n"); | ||
1411 | ret = -ENOENT; | ||
1412 | goto err_lcd_clk; | ||
1413 | } | ||
1414 | |||
1415 | sfb->regs = ioremap(res->start, resource_size(res)); | ||
1416 | if (!sfb->regs) { | 1431 | if (!sfb->regs) { |
1417 | dev_err(dev, "failed to map registers\n"); | 1432 | dev_err(dev, "failed to map registers\n"); |
1418 | ret = -ENXIO; | 1433 | ret = -ENXIO; |
1419 | goto err_req_region; | 1434 | goto err_lcd_clk; |
1420 | } | 1435 | } |
1421 | 1436 | ||
1422 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 1437 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
1423 | if (!res) { | 1438 | if (!res) { |
1424 | dev_err(dev, "failed to acquire irq resource\n"); | 1439 | dev_err(dev, "failed to acquire irq resource\n"); |
1425 | ret = -ENOENT; | 1440 | ret = -ENOENT; |
1426 | goto err_ioremap; | 1441 | goto err_lcd_clk; |
1427 | } | 1442 | } |
1428 | sfb->irq_no = res->start; | 1443 | sfb->irq_no = res->start; |
1429 | ret = request_irq(sfb->irq_no, s3c_fb_irq, | 1444 | ret = devm_request_irq(dev, sfb->irq_no, s3c_fb_irq, |
1430 | 0, "s3c_fb", sfb); | 1445 | 0, "s3c_fb", sfb); |
1431 | if (ret) { | 1446 | if (ret) { |
1432 | dev_err(dev, "irq request failed\n"); | 1447 | dev_err(dev, "irq request failed\n"); |
1433 | goto err_ioremap; | 1448 | goto err_lcd_clk; |
1434 | } | 1449 | } |
1435 | 1450 | ||
1436 | dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs); | 1451 | dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs); |
@@ -1444,6 +1459,14 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) | |||
1444 | 1459 | ||
1445 | writel(pd->vidcon1, sfb->regs + VIDCON1); | 1460 | writel(pd->vidcon1, sfb->regs + VIDCON1); |
1446 | 1461 | ||
1462 | /* set video clock running at under-run */ | ||
1463 | if (sfb->variant.has_fixvclk) { | ||
1464 | reg = readl(sfb->regs + VIDCON1); | ||
1465 | reg &= ~VIDCON1_VCLK_MASK; | ||
1466 | reg |= VIDCON1_VCLK_RUN; | ||
1467 | writel(reg, sfb->regs + VIDCON1); | ||
1468 | } | ||
1469 | |||
1447 | /* zero all windows before we do anything */ | 1470 | /* zero all windows before we do anything */ |
1448 | 1471 | ||
1449 | for (win = 0; win < fbdrv->variant.nr_windows; win++) | 1472 | for (win = 0; win < fbdrv->variant.nr_windows; win++) |
@@ -1484,13 +1507,6 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) | |||
1484 | 1507 | ||
1485 | err_pm_runtime: | 1508 | err_pm_runtime: |
1486 | pm_runtime_put_sync(sfb->dev); | 1509 | pm_runtime_put_sync(sfb->dev); |
1487 | free_irq(sfb->irq_no, sfb); | ||
1488 | |||
1489 | err_ioremap: | ||
1490 | iounmap(sfb->regs); | ||
1491 | |||
1492 | err_req_region: | ||
1493 | release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res)); | ||
1494 | 1510 | ||
1495 | err_lcd_clk: | 1511 | err_lcd_clk: |
1496 | pm_runtime_disable(sfb->dev); | 1512 | pm_runtime_disable(sfb->dev); |
@@ -1505,7 +1521,6 @@ err_bus_clk: | |||
1505 | clk_put(sfb->bus_clk); | 1521 | clk_put(sfb->bus_clk); |
1506 | 1522 | ||
1507 | err_sfb: | 1523 | err_sfb: |
1508 | kfree(sfb); | ||
1509 | return ret; | 1524 | return ret; |
1510 | } | 1525 | } |
1511 | 1526 | ||
@@ -1527,10 +1542,6 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev) | |||
1527 | if (sfb->windows[win]) | 1542 | if (sfb->windows[win]) |
1528 | s3c_fb_release_win(sfb, sfb->windows[win]); | 1543 | s3c_fb_release_win(sfb, sfb->windows[win]); |
1529 | 1544 | ||
1530 | free_irq(sfb->irq_no, sfb); | ||
1531 | |||
1532 | iounmap(sfb->regs); | ||
1533 | |||
1534 | if (!sfb->variant.has_clksel) { | 1545 | if (!sfb->variant.has_clksel) { |
1535 | clk_disable(sfb->lcd_clk); | 1546 | clk_disable(sfb->lcd_clk); |
1536 | clk_put(sfb->lcd_clk); | 1547 | clk_put(sfb->lcd_clk); |
@@ -1539,12 +1550,9 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev) | |||
1539 | clk_disable(sfb->bus_clk); | 1550 | clk_disable(sfb->bus_clk); |
1540 | clk_put(sfb->bus_clk); | 1551 | clk_put(sfb->bus_clk); |
1541 | 1552 | ||
1542 | release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res)); | ||
1543 | |||
1544 | pm_runtime_put_sync(sfb->dev); | 1553 | pm_runtime_put_sync(sfb->dev); |
1545 | pm_runtime_disable(sfb->dev); | 1554 | pm_runtime_disable(sfb->dev); |
1546 | 1555 | ||
1547 | kfree(sfb); | ||
1548 | return 0; | 1556 | return 0; |
1549 | } | 1557 | } |
1550 | 1558 | ||
@@ -1579,6 +1587,7 @@ static int s3c_fb_resume(struct device *dev) | |||
1579 | struct s3c_fb_platdata *pd = sfb->pdata; | 1587 | struct s3c_fb_platdata *pd = sfb->pdata; |
1580 | struct s3c_fb_win *win; | 1588 | struct s3c_fb_win *win; |
1581 | int win_no; | 1589 | int win_no; |
1590 | u32 reg; | ||
1582 | 1591 | ||
1583 | clk_enable(sfb->bus_clk); | 1592 | clk_enable(sfb->bus_clk); |
1584 | 1593 | ||
@@ -1589,6 +1598,14 @@ static int s3c_fb_resume(struct device *dev) | |||
1589 | pd->setup_gpio(); | 1598 | pd->setup_gpio(); |
1590 | writel(pd->vidcon1, sfb->regs + VIDCON1); | 1599 | writel(pd->vidcon1, sfb->regs + VIDCON1); |
1591 | 1600 | ||
1601 | /* set video clock running at under-run */ | ||
1602 | if (sfb->variant.has_fixvclk) { | ||
1603 | reg = readl(sfb->regs + VIDCON1); | ||
1604 | reg &= ~VIDCON1_VCLK_MASK; | ||
1605 | reg |= VIDCON1_VCLK_RUN; | ||
1606 | writel(reg, sfb->regs + VIDCON1); | ||
1607 | } | ||
1608 | |||
1592 | /* zero all windows before we do anything */ | 1609 | /* zero all windows before we do anything */ |
1593 | for (win_no = 0; win_no < sfb->variant.nr_windows; win_no++) | 1610 | for (win_no = 0; win_no < sfb->variant.nr_windows; win_no++) |
1594 | s3c_fb_clear_win(sfb, win_no); | 1611 | s3c_fb_clear_win(sfb, win_no); |
@@ -1819,6 +1836,7 @@ static struct s3c_fb_driverdata s3c_fb_data_s5pc100 = { | |||
1819 | }, | 1836 | }, |
1820 | 1837 | ||
1821 | .has_prtcon = 1, | 1838 | .has_prtcon = 1, |
1839 | .has_blendcon = 1, | ||
1822 | .has_clksel = 1, | 1840 | .has_clksel = 1, |
1823 | }, | 1841 | }, |
1824 | .win[0] = &s3c_fb_data_s5p_wins[0], | 1842 | .win[0] = &s3c_fb_data_s5p_wins[0], |
@@ -1850,7 +1868,9 @@ static struct s3c_fb_driverdata s3c_fb_data_s5pv210 = { | |||
1850 | }, | 1868 | }, |
1851 | 1869 | ||
1852 | .has_shadowcon = 1, | 1870 | .has_shadowcon = 1, |
1871 | .has_blendcon = 1, | ||
1853 | .has_clksel = 1, | 1872 | .has_clksel = 1, |
1873 | .has_fixvclk = 1, | ||
1854 | }, | 1874 | }, |
1855 | .win[0] = &s3c_fb_data_s5p_wins[0], | 1875 | .win[0] = &s3c_fb_data_s5p_wins[0], |
1856 | .win[1] = &s3c_fb_data_s5p_wins[1], | 1876 | .win[1] = &s3c_fb_data_s5p_wins[1], |
@@ -1881,6 +1901,39 @@ static struct s3c_fb_driverdata s3c_fb_data_exynos4 = { | |||
1881 | }, | 1901 | }, |
1882 | 1902 | ||
1883 | .has_shadowcon = 1, | 1903 | .has_shadowcon = 1, |
1904 | .has_blendcon = 1, | ||
1905 | .has_fixvclk = 1, | ||
1906 | }, | ||
1907 | .win[0] = &s3c_fb_data_s5p_wins[0], | ||
1908 | .win[1] = &s3c_fb_data_s5p_wins[1], | ||
1909 | .win[2] = &s3c_fb_data_s5p_wins[2], | ||
1910 | .win[3] = &s3c_fb_data_s5p_wins[3], | ||
1911 | .win[4] = &s3c_fb_data_s5p_wins[4], | ||
1912 | }; | ||
1913 | |||
1914 | static struct s3c_fb_driverdata s3c_fb_data_exynos5 = { | ||
1915 | .variant = { | ||
1916 | .nr_windows = 5, | ||
1917 | .vidtcon = VIDTCON0, | ||
1918 | .wincon = WINCON(0), | ||
1919 | .winmap = WINxMAP(0), | ||
1920 | .keycon = WKEYCON, | ||
1921 | .osd = VIDOSD_BASE, | ||
1922 | .osd_stride = 16, | ||
1923 | .buf_start = VIDW_BUF_START(0), | ||
1924 | .buf_size = VIDW_BUF_SIZE(0), | ||
1925 | .buf_end = VIDW_BUF_END(0), | ||
1926 | |||
1927 | .palette = { | ||
1928 | [0] = 0x2400, | ||
1929 | [1] = 0x2800, | ||
1930 | [2] = 0x2c00, | ||
1931 | [3] = 0x3000, | ||
1932 | [4] = 0x3400, | ||
1933 | }, | ||
1934 | .has_shadowcon = 1, | ||
1935 | .has_blendcon = 1, | ||
1936 | .has_fixvclk = 1, | ||
1884 | }, | 1937 | }, |
1885 | .win[0] = &s3c_fb_data_s5p_wins[0], | 1938 | .win[0] = &s3c_fb_data_s5p_wins[0], |
1886 | .win[1] = &s3c_fb_data_s5p_wins[1], | 1939 | .win[1] = &s3c_fb_data_s5p_wins[1], |
@@ -1944,6 +1997,9 @@ static struct s3c_fb_driverdata s3c_fb_data_s5p64x0 = { | |||
1944 | [1] = 0x2800, | 1997 | [1] = 0x2800, |
1945 | [2] = 0x2c00, | 1998 | [2] = 0x2c00, |
1946 | }, | 1999 | }, |
2000 | |||
2001 | .has_blendcon = 1, | ||
2002 | .has_fixvclk = 1, | ||
1947 | }, | 2003 | }, |
1948 | .win[0] = &s3c_fb_data_s5p_wins[0], | 2004 | .win[0] = &s3c_fb_data_s5p_wins[0], |
1949 | .win[1] = &s3c_fb_data_s5p_wins[1], | 2005 | .win[1] = &s3c_fb_data_s5p_wins[1], |
@@ -1964,6 +2020,9 @@ static struct platform_device_id s3c_fb_driver_ids[] = { | |||
1964 | .name = "exynos4-fb", | 2020 | .name = "exynos4-fb", |
1965 | .driver_data = (unsigned long)&s3c_fb_data_exynos4, | 2021 | .driver_data = (unsigned long)&s3c_fb_data_exynos4, |
1966 | }, { | 2022 | }, { |
2023 | .name = "exynos5-fb", | ||
2024 | .driver_data = (unsigned long)&s3c_fb_data_exynos5, | ||
2025 | }, { | ||
1967 | .name = "s3c2443-fb", | 2026 | .name = "s3c2443-fb", |
1968 | .driver_data = (unsigned long)&s3c_fb_data_s3c2443, | 2027 | .driver_data = (unsigned long)&s3c_fb_data_s3c2443, |
1969 | }, { | 2028 | }, { |
diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c index 05151b82f40f..4c6b84488561 100644 --- a/drivers/video/sh_mipi_dsi.c +++ b/drivers/video/sh_mipi_dsi.c | |||
@@ -24,6 +24,8 @@ | |||
24 | #include <video/sh_mipi_dsi.h> | 24 | #include <video/sh_mipi_dsi.h> |
25 | #include <video/sh_mobile_lcdc.h> | 25 | #include <video/sh_mobile_lcdc.h> |
26 | 26 | ||
27 | #include "sh_mobile_lcdcfb.h" | ||
28 | |||
27 | #define SYSCTRL 0x0000 | 29 | #define SYSCTRL 0x0000 |
28 | #define SYSCONF 0x0004 | 30 | #define SYSCONF 0x0004 |
29 | #define TIMSET 0x0008 | 31 | #define TIMSET 0x0008 |
@@ -50,16 +52,16 @@ | |||
50 | #define MAX_SH_MIPI_DSI 2 | 52 | #define MAX_SH_MIPI_DSI 2 |
51 | 53 | ||
52 | struct sh_mipi { | 54 | struct sh_mipi { |
55 | struct sh_mobile_lcdc_entity entity; | ||
56 | |||
53 | void __iomem *base; | 57 | void __iomem *base; |
54 | void __iomem *linkbase; | 58 | void __iomem *linkbase; |
55 | struct clk *dsit_clk; | 59 | struct clk *dsit_clk; |
56 | struct platform_device *pdev; | 60 | struct platform_device *pdev; |
57 | |||
58 | void *next_board_data; | ||
59 | void (*next_display_on)(void *board_data, struct fb_info *info); | ||
60 | void (*next_display_off)(void *board_data); | ||
61 | }; | 61 | }; |
62 | 62 | ||
63 | #define to_sh_mipi(e) container_of(e, struct sh_mipi, entity) | ||
64 | |||
63 | static struct sh_mipi *mipi_dsi[MAX_SH_MIPI_DSI]; | 65 | static struct sh_mipi *mipi_dsi[MAX_SH_MIPI_DSI]; |
64 | 66 | ||
65 | /* Protect the above array */ | 67 | /* Protect the above array */ |
@@ -120,7 +122,7 @@ static void sh_mipi_dsi_enable(struct sh_mipi *mipi, bool enable) | |||
120 | 122 | ||
121 | static void sh_mipi_shutdown(struct platform_device *pdev) | 123 | static void sh_mipi_shutdown(struct platform_device *pdev) |
122 | { | 124 | { |
123 | struct sh_mipi *mipi = platform_get_drvdata(pdev); | 125 | struct sh_mipi *mipi = to_sh_mipi(platform_get_drvdata(pdev)); |
124 | 126 | ||
125 | sh_mipi_dsi_enable(mipi, false); | 127 | sh_mipi_dsi_enable(mipi, false); |
126 | } | 128 | } |
@@ -145,77 +147,77 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, | |||
145 | pctype = 0; | 147 | pctype = 0; |
146 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24; | 148 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24; |
147 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; | 149 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; |
148 | linelength = ch->lcd_cfg[0].xres * 3; | 150 | linelength = ch->lcd_modes[0].xres * 3; |
149 | yuv = false; | 151 | yuv = false; |
150 | break; | 152 | break; |
151 | case MIPI_RGB565: | 153 | case MIPI_RGB565: |
152 | pctype = 1; | 154 | pctype = 1; |
153 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16; | 155 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16; |
154 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; | 156 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; |
155 | linelength = ch->lcd_cfg[0].xres * 2; | 157 | linelength = ch->lcd_modes[0].xres * 2; |
156 | yuv = false; | 158 | yuv = false; |
157 | break; | 159 | break; |
158 | case MIPI_RGB666_LP: | 160 | case MIPI_RGB666_LP: |
159 | pctype = 2; | 161 | pctype = 2; |
160 | datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18; | 162 | datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18; |
161 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; | 163 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; |
162 | linelength = ch->lcd_cfg[0].xres * 3; | 164 | linelength = ch->lcd_modes[0].xres * 3; |
163 | yuv = false; | 165 | yuv = false; |
164 | break; | 166 | break; |
165 | case MIPI_RGB666: | 167 | case MIPI_RGB666: |
166 | pctype = 3; | 168 | pctype = 3; |
167 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18; | 169 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18; |
168 | pixfmt = MIPI_DCS_PIXEL_FMT_18BIT; | 170 | pixfmt = MIPI_DCS_PIXEL_FMT_18BIT; |
169 | linelength = (ch->lcd_cfg[0].xres * 18 + 7) / 8; | 171 | linelength = (ch->lcd_modes[0].xres * 18 + 7) / 8; |
170 | yuv = false; | 172 | yuv = false; |
171 | break; | 173 | break; |
172 | case MIPI_BGR888: | 174 | case MIPI_BGR888: |
173 | pctype = 8; | 175 | pctype = 8; |
174 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24; | 176 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24; |
175 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; | 177 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; |
176 | linelength = ch->lcd_cfg[0].xres * 3; | 178 | linelength = ch->lcd_modes[0].xres * 3; |
177 | yuv = false; | 179 | yuv = false; |
178 | break; | 180 | break; |
179 | case MIPI_BGR565: | 181 | case MIPI_BGR565: |
180 | pctype = 9; | 182 | pctype = 9; |
181 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16; | 183 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16; |
182 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; | 184 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; |
183 | linelength = ch->lcd_cfg[0].xres * 2; | 185 | linelength = ch->lcd_modes[0].xres * 2; |
184 | yuv = false; | 186 | yuv = false; |
185 | break; | 187 | break; |
186 | case MIPI_BGR666_LP: | 188 | case MIPI_BGR666_LP: |
187 | pctype = 0xa; | 189 | pctype = 0xa; |
188 | datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18; | 190 | datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18; |
189 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; | 191 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; |
190 | linelength = ch->lcd_cfg[0].xres * 3; | 192 | linelength = ch->lcd_modes[0].xres * 3; |
191 | yuv = false; | 193 | yuv = false; |
192 | break; | 194 | break; |
193 | case MIPI_BGR666: | 195 | case MIPI_BGR666: |
194 | pctype = 0xb; | 196 | pctype = 0xb; |
195 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18; | 197 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18; |
196 | pixfmt = MIPI_DCS_PIXEL_FMT_18BIT; | 198 | pixfmt = MIPI_DCS_PIXEL_FMT_18BIT; |
197 | linelength = (ch->lcd_cfg[0].xres * 18 + 7) / 8; | 199 | linelength = (ch->lcd_modes[0].xres * 18 + 7) / 8; |
198 | yuv = false; | 200 | yuv = false; |
199 | break; | 201 | break; |
200 | case MIPI_YUYV: | 202 | case MIPI_YUYV: |
201 | pctype = 4; | 203 | pctype = 4; |
202 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16; | 204 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16; |
203 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; | 205 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; |
204 | linelength = ch->lcd_cfg[0].xres * 2; | 206 | linelength = ch->lcd_modes[0].xres * 2; |
205 | yuv = true; | 207 | yuv = true; |
206 | break; | 208 | break; |
207 | case MIPI_UYVY: | 209 | case MIPI_UYVY: |
208 | pctype = 5; | 210 | pctype = 5; |
209 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16; | 211 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16; |
210 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; | 212 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; |
211 | linelength = ch->lcd_cfg[0].xres * 2; | 213 | linelength = ch->lcd_modes[0].xres * 2; |
212 | yuv = true; | 214 | yuv = true; |
213 | break; | 215 | break; |
214 | case MIPI_YUV420_L: | 216 | case MIPI_YUV420_L: |
215 | pctype = 6; | 217 | pctype = 6; |
216 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12; | 218 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12; |
217 | pixfmt = MIPI_DCS_PIXEL_FMT_12BIT; | 219 | pixfmt = MIPI_DCS_PIXEL_FMT_12BIT; |
218 | linelength = (ch->lcd_cfg[0].xres * 12 + 7) / 8; | 220 | linelength = (ch->lcd_modes[0].xres * 12 + 7) / 8; |
219 | yuv = true; | 221 | yuv = true; |
220 | break; | 222 | break; |
221 | case MIPI_YUV420: | 223 | case MIPI_YUV420: |
@@ -223,7 +225,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, | |||
223 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12; | 225 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12; |
224 | pixfmt = MIPI_DCS_PIXEL_FMT_12BIT; | 226 | pixfmt = MIPI_DCS_PIXEL_FMT_12BIT; |
225 | /* Length of U/V line */ | 227 | /* Length of U/V line */ |
226 | linelength = (ch->lcd_cfg[0].xres + 1) / 2; | 228 | linelength = (ch->lcd_modes[0].xres + 1) / 2; |
227 | yuv = true; | 229 | yuv = true; |
228 | break; | 230 | break; |
229 | default: | 231 | default: |
@@ -271,7 +273,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, | |||
271 | iowrite32(0x00000001, base + PHYCTRL); | 273 | iowrite32(0x00000001, base + PHYCTRL); |
272 | udelay(200); | 274 | udelay(200); |
273 | /* Deassert resets, power on */ | 275 | /* Deassert resets, power on */ |
274 | iowrite32(0x03070001, base + PHYCTRL); | 276 | iowrite32(0x03070001 | pdata->phyctrl, base + PHYCTRL); |
275 | 277 | ||
276 | /* | 278 | /* |
277 | * Default = ULPS enable | | 279 | * Default = ULPS enable | |
@@ -292,7 +294,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, | |||
292 | */ | 294 | */ |
293 | iowrite32(0x00000006, mipi->linkbase + DTCTR); | 295 | iowrite32(0x00000006, mipi->linkbase + DTCTR); |
294 | /* VSYNC width = 2 (<< 17) */ | 296 | /* VSYNC width = 2 (<< 17) */ |
295 | iowrite32((ch->lcd_cfg[0].vsync_len << pdata->vsynw_offset) | | 297 | iowrite32((ch->lcd_modes[0].vsync_len << pdata->vsynw_offset) | |
296 | (pdata->clksrc << 16) | (pctype << 12) | datatype, | 298 | (pdata->clksrc << 16) | (pctype << 12) | datatype, |
297 | mipi->linkbase + VMCTR1); | 299 | mipi->linkbase + VMCTR1); |
298 | 300 | ||
@@ -326,7 +328,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, | |||
326 | top = linelength << 16; /* RGBLEN */ | 328 | top = linelength << 16; /* RGBLEN */ |
327 | bottom = 0x00000001; | 329 | bottom = 0x00000001; |
328 | if (pdata->flags & SH_MIPI_DSI_HSABM) /* HSALEN */ | 330 | if (pdata->flags & SH_MIPI_DSI_HSABM) /* HSALEN */ |
329 | bottom = (pdata->lane * ch->lcd_cfg[0].hsync_len) - 10; | 331 | bottom = (pdata->lane * ch->lcd_modes[0].hsync_len) - 10; |
330 | iowrite32(top | bottom , mipi->linkbase + VMLEN1); | 332 | iowrite32(top | bottom , mipi->linkbase + VMLEN1); |
331 | 333 | ||
332 | /* | 334 | /* |
@@ -346,18 +348,18 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, | |||
346 | div = 2; | 348 | div = 2; |
347 | 349 | ||
348 | if (pdata->flags & SH_MIPI_DSI_HFPBM) { /* HBPLEN */ | 350 | if (pdata->flags & SH_MIPI_DSI_HFPBM) { /* HBPLEN */ |
349 | top = ch->lcd_cfg[0].hsync_len + ch->lcd_cfg[0].left_margin; | 351 | top = ch->lcd_modes[0].hsync_len + ch->lcd_modes[0].left_margin; |
350 | top = ((pdata->lane * top / div) - 10) << 16; | 352 | top = ((pdata->lane * top / div) - 10) << 16; |
351 | } | 353 | } |
352 | if (pdata->flags & SH_MIPI_DSI_HBPBM) { /* HFPLEN */ | 354 | if (pdata->flags & SH_MIPI_DSI_HBPBM) { /* HFPLEN */ |
353 | bottom = ch->lcd_cfg[0].right_margin; | 355 | bottom = ch->lcd_modes[0].right_margin; |
354 | bottom = (pdata->lane * bottom / div) - 12; | 356 | bottom = (pdata->lane * bottom / div) - 12; |
355 | } | 357 | } |
356 | 358 | ||
357 | bpp = linelength / ch->lcd_cfg[0].xres; /* byte / pixel */ | 359 | bpp = linelength / ch->lcd_modes[0].xres; /* byte / pixel */ |
358 | if ((pdata->lane / div) > bpp) { | 360 | if ((pdata->lane / div) > bpp) { |
359 | tmp = ch->lcd_cfg[0].xres / bpp; /* output cycle */ | 361 | tmp = ch->lcd_modes[0].xres / bpp; /* output cycle */ |
360 | tmp = ch->lcd_cfg[0].xres - tmp; /* (input - output) cycle */ | 362 | tmp = ch->lcd_modes[0].xres - tmp; /* (input - output) cycle */ |
361 | delay = (pdata->lane * tmp); | 363 | delay = (pdata->lane * tmp); |
362 | } | 364 | } |
363 | 365 | ||
@@ -392,9 +394,9 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, | |||
392 | return 0; | 394 | return 0; |
393 | } | 395 | } |
394 | 396 | ||
395 | static void mipi_display_on(void *arg, struct fb_info *info) | 397 | static int mipi_display_on(struct sh_mobile_lcdc_entity *entity) |
396 | { | 398 | { |
397 | struct sh_mipi *mipi = arg; | 399 | struct sh_mipi *mipi = to_sh_mipi(entity); |
398 | struct sh_mipi_dsi_info *pdata = mipi->pdev->dev.platform_data; | 400 | struct sh_mipi_dsi_info *pdata = mipi->pdev->dev.platform_data; |
399 | int ret; | 401 | int ret; |
400 | 402 | ||
@@ -410,25 +412,21 @@ static void mipi_display_on(void *arg, struct fb_info *info) | |||
410 | 412 | ||
411 | sh_mipi_dsi_enable(mipi, true); | 413 | sh_mipi_dsi_enable(mipi, true); |
412 | 414 | ||
413 | if (mipi->next_display_on) | 415 | return SH_MOBILE_LCDC_DISPLAY_CONNECTED; |
414 | mipi->next_display_on(mipi->next_board_data, info); | ||
415 | |||
416 | return; | ||
417 | 416 | ||
418 | mipi_display_on_fail1: | 417 | mipi_display_on_fail1: |
419 | pm_runtime_put_sync(&mipi->pdev->dev); | 418 | pm_runtime_put_sync(&mipi->pdev->dev); |
420 | mipi_display_on_fail2: | 419 | mipi_display_on_fail2: |
421 | pdata->set_dot_clock(mipi->pdev, mipi->base, 0); | 420 | pdata->set_dot_clock(mipi->pdev, mipi->base, 0); |
421 | |||
422 | return ret; | ||
422 | } | 423 | } |
423 | 424 | ||
424 | static void mipi_display_off(void *arg) | 425 | static void mipi_display_off(struct sh_mobile_lcdc_entity *entity) |
425 | { | 426 | { |
426 | struct sh_mipi *mipi = arg; | 427 | struct sh_mipi *mipi = to_sh_mipi(entity); |
427 | struct sh_mipi_dsi_info *pdata = mipi->pdev->dev.platform_data; | 428 | struct sh_mipi_dsi_info *pdata = mipi->pdev->dev.platform_data; |
428 | 429 | ||
429 | if (mipi->next_display_off) | ||
430 | mipi->next_display_off(mipi->next_board_data); | ||
431 | |||
432 | sh_mipi_dsi_enable(mipi, false); | 430 | sh_mipi_dsi_enable(mipi, false); |
433 | 431 | ||
434 | pdata->set_dot_clock(mipi->pdev, mipi->base, 0); | 432 | pdata->set_dot_clock(mipi->pdev, mipi->base, 0); |
@@ -436,6 +434,11 @@ static void mipi_display_off(void *arg) | |||
436 | pm_runtime_put_sync(&mipi->pdev->dev); | 434 | pm_runtime_put_sync(&mipi->pdev->dev); |
437 | } | 435 | } |
438 | 436 | ||
437 | static const struct sh_mobile_lcdc_entity_ops mipi_ops = { | ||
438 | .display_on = mipi_display_on, | ||
439 | .display_off = mipi_display_off, | ||
440 | }; | ||
441 | |||
439 | static int __init sh_mipi_probe(struct platform_device *pdev) | 442 | static int __init sh_mipi_probe(struct platform_device *pdev) |
440 | { | 443 | { |
441 | struct sh_mipi *mipi; | 444 | struct sh_mipi *mipi; |
@@ -467,6 +470,9 @@ static int __init sh_mipi_probe(struct platform_device *pdev) | |||
467 | goto ealloc; | 470 | goto ealloc; |
468 | } | 471 | } |
469 | 472 | ||
473 | mipi->entity.owner = THIS_MODULE; | ||
474 | mipi->entity.ops = &mipi_ops; | ||
475 | |||
470 | if (!request_mem_region(res->start, resource_size(res), pdev->name)) { | 476 | if (!request_mem_region(res->start, resource_size(res), pdev->name)) { |
471 | dev_err(&pdev->dev, "MIPI register region already claimed\n"); | 477 | dev_err(&pdev->dev, "MIPI register region already claimed\n"); |
472 | ret = -EBUSY; | 478 | ret = -EBUSY; |
@@ -521,18 +527,7 @@ static int __init sh_mipi_probe(struct platform_device *pdev) | |||
521 | pm_runtime_resume(&pdev->dev); | 527 | pm_runtime_resume(&pdev->dev); |
522 | 528 | ||
523 | mutex_unlock(&array_lock); | 529 | mutex_unlock(&array_lock); |
524 | platform_set_drvdata(pdev, mipi); | 530 | platform_set_drvdata(pdev, &mipi->entity); |
525 | |||
526 | /* Save original LCDC callbacks */ | ||
527 | mipi->next_board_data = pdata->lcd_chan->board_cfg.board_data; | ||
528 | mipi->next_display_on = pdata->lcd_chan->board_cfg.display_on; | ||
529 | mipi->next_display_off = pdata->lcd_chan->board_cfg.display_off; | ||
530 | |||
531 | /* Set up LCDC callbacks */ | ||
532 | pdata->lcd_chan->board_cfg.board_data = mipi; | ||
533 | pdata->lcd_chan->board_cfg.display_on = mipi_display_on; | ||
534 | pdata->lcd_chan->board_cfg.display_off = mipi_display_off; | ||
535 | pdata->lcd_chan->board_cfg.owner = THIS_MODULE; | ||
536 | 531 | ||
537 | return 0; | 532 | return 0; |
538 | 533 | ||
@@ -558,10 +553,9 @@ efindslot: | |||
558 | 553 | ||
559 | static int __exit sh_mipi_remove(struct platform_device *pdev) | 554 | static int __exit sh_mipi_remove(struct platform_device *pdev) |
560 | { | 555 | { |
561 | struct sh_mipi_dsi_info *pdata = pdev->dev.platform_data; | ||
562 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 556 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
563 | struct resource *res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 557 | struct resource *res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
564 | struct sh_mipi *mipi = platform_get_drvdata(pdev); | 558 | struct sh_mipi *mipi = to_sh_mipi(platform_get_drvdata(pdev)); |
565 | int i, ret; | 559 | int i, ret; |
566 | 560 | ||
567 | mutex_lock(&array_lock); | 561 | mutex_lock(&array_lock); |
@@ -581,11 +575,6 @@ static int __exit sh_mipi_remove(struct platform_device *pdev) | |||
581 | if (ret < 0) | 575 | if (ret < 0) |
582 | return ret; | 576 | return ret; |
583 | 577 | ||
584 | pdata->lcd_chan->board_cfg.owner = NULL; | ||
585 | pdata->lcd_chan->board_cfg.display_on = NULL; | ||
586 | pdata->lcd_chan->board_cfg.display_off = NULL; | ||
587 | pdata->lcd_chan->board_cfg.board_data = NULL; | ||
588 | |||
589 | pm_runtime_disable(&pdev->dev); | 578 | pm_runtime_disable(&pdev->dev); |
590 | clk_disable(mipi->dsit_clk); | 579 | clk_disable(mipi->dsit_clk); |
591 | clk_put(mipi->dsit_clk); | 580 | clk_put(mipi->dsit_clk); |
diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index 647ba984f00f..eafb19da2c07 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c | |||
@@ -208,6 +208,8 @@ enum hotplug_state { | |||
208 | }; | 208 | }; |
209 | 209 | ||
210 | struct sh_hdmi { | 210 | struct sh_hdmi { |
211 | struct sh_mobile_lcdc_entity entity; | ||
212 | |||
211 | void __iomem *base; | 213 | void __iomem *base; |
212 | enum hotplug_state hp_state; /* hot-plug status */ | 214 | enum hotplug_state hp_state; /* hot-plug status */ |
213 | u8 preprogrammed_vic; /* use a pre-programmed VIC or | 215 | u8 preprogrammed_vic; /* use a pre-programmed VIC or |
@@ -217,14 +219,13 @@ struct sh_hdmi { | |||
217 | u8 edid_blocks; | 219 | u8 edid_blocks; |
218 | struct clk *hdmi_clk; | 220 | struct clk *hdmi_clk; |
219 | struct device *dev; | 221 | struct device *dev; |
220 | struct fb_info *info; | ||
221 | struct mutex mutex; /* Protect the info pointer */ | ||
222 | struct delayed_work edid_work; | 222 | struct delayed_work edid_work; |
223 | struct fb_var_screeninfo var; | 223 | struct fb_videomode mode; |
224 | struct fb_monspecs monspec; | 224 | struct fb_monspecs monspec; |
225 | struct notifier_block notifier; | ||
226 | }; | 225 | }; |
227 | 226 | ||
227 | #define entity_to_sh_hdmi(e) container_of(e, struct sh_hdmi, entity) | ||
228 | |||
228 | static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg) | 229 | static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg) |
229 | { | 230 | { |
230 | iowrite8(data, hdmi->base + reg); | 231 | iowrite8(data, hdmi->base + reg); |
@@ -290,24 +291,24 @@ static struct snd_soc_codec_driver soc_codec_dev_sh_hdmi = { | |||
290 | /* External video parameter settings */ | 291 | /* External video parameter settings */ |
291 | static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi) | 292 | static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi) |
292 | { | 293 | { |
293 | struct fb_var_screeninfo *var = &hdmi->var; | 294 | struct fb_videomode *mode = &hdmi->mode; |
294 | u16 htotal, hblank, hdelay, vtotal, vblank, vdelay, voffset; | 295 | u16 htotal, hblank, hdelay, vtotal, vblank, vdelay, voffset; |
295 | u8 sync = 0; | 296 | u8 sync = 0; |
296 | 297 | ||
297 | htotal = var->xres + var->right_margin + var->left_margin + var->hsync_len; | 298 | htotal = mode->xres + mode->right_margin + mode->left_margin |
298 | 299 | + mode->hsync_len; | |
299 | hdelay = var->hsync_len + var->left_margin; | 300 | hdelay = mode->hsync_len + mode->left_margin; |
300 | hblank = var->right_margin + hdelay; | 301 | hblank = mode->right_margin + hdelay; |
301 | 302 | ||
302 | /* | 303 | /* |
303 | * Vertical timing looks a bit different in Figure 18, | 304 | * Vertical timing looks a bit different in Figure 18, |
304 | * but let's try the same first by setting offset = 0 | 305 | * but let's try the same first by setting offset = 0 |
305 | */ | 306 | */ |
306 | vtotal = var->yres + var->upper_margin + var->lower_margin + var->vsync_len; | 307 | vtotal = mode->yres + mode->upper_margin + mode->lower_margin |
307 | 308 | + mode->vsync_len; | |
308 | vdelay = var->vsync_len + var->upper_margin; | 309 | vdelay = mode->vsync_len + mode->upper_margin; |
309 | vblank = var->lower_margin + vdelay; | 310 | vblank = mode->lower_margin + vdelay; |
310 | voffset = min(var->upper_margin / 2, 6U); | 311 | voffset = min(mode->upper_margin / 2, 6U); |
311 | 312 | ||
312 | /* | 313 | /* |
313 | * [3]: VSYNC polarity: Positive | 314 | * [3]: VSYNC polarity: Positive |
@@ -315,14 +316,14 @@ static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi) | |||
315 | * [1]: Interlace/Progressive: Progressive | 316 | * [1]: Interlace/Progressive: Progressive |
316 | * [0]: External video settings enable: used. | 317 | * [0]: External video settings enable: used. |
317 | */ | 318 | */ |
318 | if (var->sync & FB_SYNC_HOR_HIGH_ACT) | 319 | if (mode->sync & FB_SYNC_HOR_HIGH_ACT) |
319 | sync |= 4; | 320 | sync |= 4; |
320 | if (var->sync & FB_SYNC_VERT_HIGH_ACT) | 321 | if (mode->sync & FB_SYNC_VERT_HIGH_ACT) |
321 | sync |= 8; | 322 | sync |= 8; |
322 | 323 | ||
323 | dev_dbg(hdmi->dev, "H: %u, %u, %u, %u; V: %u, %u, %u, %u; sync 0x%x\n", | 324 | dev_dbg(hdmi->dev, "H: %u, %u, %u, %u; V: %u, %u, %u, %u; sync 0x%x\n", |
324 | htotal, hblank, hdelay, var->hsync_len, | 325 | htotal, hblank, hdelay, mode->hsync_len, |
325 | vtotal, vblank, vdelay, var->vsync_len, sync); | 326 | vtotal, vblank, vdelay, mode->vsync_len, sync); |
326 | 327 | ||
327 | hdmi_write(hdmi, sync | (voffset << 4), HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS); | 328 | hdmi_write(hdmi, sync | (voffset << 4), HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS); |
328 | 329 | ||
@@ -335,8 +336,8 @@ static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi) | |||
335 | hdmi_write(hdmi, hdelay, HDMI_EXTERNAL_H_DELAY_7_0); | 336 | hdmi_write(hdmi, hdelay, HDMI_EXTERNAL_H_DELAY_7_0); |
336 | hdmi_write(hdmi, hdelay >> 8, HDMI_EXTERNAL_H_DELAY_9_8); | 337 | hdmi_write(hdmi, hdelay >> 8, HDMI_EXTERNAL_H_DELAY_9_8); |
337 | 338 | ||
338 | hdmi_write(hdmi, var->hsync_len, HDMI_EXTERNAL_H_DURATION_7_0); | 339 | hdmi_write(hdmi, mode->hsync_len, HDMI_EXTERNAL_H_DURATION_7_0); |
339 | hdmi_write(hdmi, var->hsync_len >> 8, HDMI_EXTERNAL_H_DURATION_9_8); | 340 | hdmi_write(hdmi, mode->hsync_len >> 8, HDMI_EXTERNAL_H_DURATION_9_8); |
340 | 341 | ||
341 | hdmi_write(hdmi, vtotal, HDMI_EXTERNAL_V_TOTAL_7_0); | 342 | hdmi_write(hdmi, vtotal, HDMI_EXTERNAL_V_TOTAL_7_0); |
342 | hdmi_write(hdmi, vtotal >> 8, HDMI_EXTERNAL_V_TOTAL_9_8); | 343 | hdmi_write(hdmi, vtotal >> 8, HDMI_EXTERNAL_V_TOTAL_9_8); |
@@ -345,7 +346,7 @@ static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi) | |||
345 | 346 | ||
346 | hdmi_write(hdmi, vdelay, HDMI_EXTERNAL_V_DELAY); | 347 | hdmi_write(hdmi, vdelay, HDMI_EXTERNAL_V_DELAY); |
347 | 348 | ||
348 | hdmi_write(hdmi, var->vsync_len, HDMI_EXTERNAL_V_DURATION); | 349 | hdmi_write(hdmi, mode->vsync_len, HDMI_EXTERNAL_V_DURATION); |
349 | 350 | ||
350 | /* Set bit 0 of HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS here for external mode */ | 351 | /* Set bit 0 of HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS here for external mode */ |
351 | if (!hdmi->preprogrammed_vic) | 352 | if (!hdmi->preprogrammed_vic) |
@@ -472,7 +473,7 @@ static void sh_hdmi_audio_config(struct sh_hdmi *hdmi) | |||
472 | */ | 473 | */ |
473 | static void sh_hdmi_phy_config(struct sh_hdmi *hdmi) | 474 | static void sh_hdmi_phy_config(struct sh_hdmi *hdmi) |
474 | { | 475 | { |
475 | if (hdmi->var.pixclock < 10000) { | 476 | if (hdmi->mode.pixclock < 10000) { |
476 | /* for 1080p8bit 148MHz */ | 477 | /* for 1080p8bit 148MHz */ |
477 | hdmi_write(hdmi, 0x1d, HDMI_SLIPHDMIT_PARAM_SETTINGS_1); | 478 | hdmi_write(hdmi, 0x1d, HDMI_SLIPHDMIT_PARAM_SETTINGS_1); |
478 | hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2); | 479 | hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2); |
@@ -483,7 +484,7 @@ static void sh_hdmi_phy_config(struct sh_hdmi *hdmi) | |||
483 | hdmi_write(hdmi, 0x0e, HDMI_SLIPHDMIT_PARAM_SETTINGS_8); | 484 | hdmi_write(hdmi, 0x0e, HDMI_SLIPHDMIT_PARAM_SETTINGS_8); |
484 | hdmi_write(hdmi, 0x25, HDMI_SLIPHDMIT_PARAM_SETTINGS_9); | 485 | hdmi_write(hdmi, 0x25, HDMI_SLIPHDMIT_PARAM_SETTINGS_9); |
485 | hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10); | 486 | hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10); |
486 | } else if (hdmi->var.pixclock < 30000) { | 487 | } else if (hdmi->mode.pixclock < 30000) { |
487 | /* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */ | 488 | /* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */ |
488 | /* | 489 | /* |
489 | * [1:0] Speed_A | 490 | * [1:0] Speed_A |
@@ -732,14 +733,12 @@ static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi, | |||
732 | static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, | 733 | static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, |
733 | unsigned long *parent_rate) | 734 | unsigned long *parent_rate) |
734 | { | 735 | { |
735 | struct fb_var_screeninfo tmpvar; | 736 | struct sh_mobile_lcdc_chan *ch = hdmi->entity.lcdc; |
736 | struct fb_var_screeninfo *var = &tmpvar; | ||
737 | const struct fb_videomode *mode, *found = NULL; | 737 | const struct fb_videomode *mode, *found = NULL; |
738 | struct fb_info *info = hdmi->info; | ||
739 | struct fb_modelist *modelist = NULL; | ||
740 | unsigned int f_width = 0, f_height = 0, f_refresh = 0; | 738 | unsigned int f_width = 0, f_height = 0, f_refresh = 0; |
741 | unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */ | 739 | unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */ |
742 | bool scanning = false, preferred_bad = false; | 740 | bool scanning = false, preferred_bad = false; |
741 | bool use_edid_mode = false; | ||
743 | u8 edid[128]; | 742 | u8 edid[128]; |
744 | char *forced; | 743 | char *forced; |
745 | int i; | 744 | int i; |
@@ -854,12 +853,9 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, | |||
854 | } | 853 | } |
855 | 854 | ||
856 | /* Check if supported: sufficient fb memory, supported clock-rate */ | 855 | /* Check if supported: sufficient fb memory, supported clock-rate */ |
857 | fb_videomode_to_var(var, mode); | 856 | if (ch && ch->notify && |
858 | 857 | ch->notify(ch, SH_MOBILE_LCDC_EVENT_DISPLAY_MODE, mode, | |
859 | var->bits_per_pixel = info->var.bits_per_pixel; | 858 | NULL)) { |
860 | |||
861 | if (info && info->fbops->fb_check_var && | ||
862 | info->fbops->fb_check_var(var, info)) { | ||
863 | scanning = true; | 859 | scanning = true; |
864 | preferred_bad = true; | 860 | preferred_bad = true; |
865 | continue; | 861 | continue; |
@@ -867,28 +863,19 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, | |||
867 | 863 | ||
868 | found = mode; | 864 | found = mode; |
869 | found_rate_error = rate_error; | 865 | found_rate_error = rate_error; |
866 | use_edid_mode = true; | ||
870 | } | 867 | } |
871 | 868 | ||
872 | hdmi->var.width = hdmi->monspec.max_x * 10; | ||
873 | hdmi->var.height = hdmi->monspec.max_y * 10; | ||
874 | |||
875 | /* | 869 | /* |
876 | * TODO 1: if no ->info is present, postpone running the config until | 870 | * TODO 1: if no default mode is present, postpone running the config |
877 | * after ->info first gets registered. | 871 | * until after the LCDC channel is initialized. |
878 | * TODO 2: consider registering the HDMI platform device from the LCDC | 872 | * TODO 2: consider registering the HDMI platform device from the LCDC |
879 | * driver, and passing ->info with HDMI platform data. | 873 | * driver. |
880 | */ | 874 | */ |
881 | if (info && !found) { | 875 | if (!found && hdmi->entity.def_mode.xres != 0) { |
882 | modelist = info->modelist.next && | 876 | found = &hdmi->entity.def_mode; |
883 | !list_empty(&info->modelist) ? | 877 | found_rate_error = sh_hdmi_rate_error(hdmi, found, hdmi_rate, |
884 | list_entry(info->modelist.next, | 878 | parent_rate); |
885 | struct fb_modelist, list) : | ||
886 | NULL; | ||
887 | |||
888 | if (modelist) { | ||
889 | found = &modelist->mode; | ||
890 | found_rate_error = sh_hdmi_rate_error(hdmi, found, hdmi_rate, parent_rate); | ||
891 | } | ||
892 | } | 879 | } |
893 | 880 | ||
894 | /* No cookie today */ | 881 | /* No cookie today */ |
@@ -912,12 +899,13 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, | |||
912 | else | 899 | else |
913 | hdmi->preprogrammed_vic = 0; | 900 | hdmi->preprogrammed_vic = 0; |
914 | 901 | ||
915 | dev_dbg(hdmi->dev, "Using %s %s mode %ux%u@%uHz (%luHz), clock error %luHz\n", | 902 | dev_dbg(hdmi->dev, "Using %s %s mode %ux%u@%uHz (%luHz), " |
916 | modelist ? "default" : "EDID", hdmi->preprogrammed_vic ? "VIC" : "external", | 903 | "clock error %luHz\n", use_edid_mode ? "EDID" : "default", |
917 | found->xres, found->yres, found->refresh, | 904 | hdmi->preprogrammed_vic ? "VIC" : "external", found->xres, |
918 | PICOS2KHZ(found->pixclock) * 1000, found_rate_error); | 905 | found->yres, found->refresh, PICOS2KHZ(found->pixclock) * 1000, |
906 | found_rate_error); | ||
919 | 907 | ||
920 | fb_videomode_to_var(&hdmi->var, found); | 908 | hdmi->mode = *found; |
921 | sh_hdmi_external_video_param(hdmi); | 909 | sh_hdmi_external_video_param(hdmi); |
922 | 910 | ||
923 | return 0; | 911 | return 0; |
@@ -998,22 +986,12 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) | |||
998 | return IRQ_HANDLED; | 986 | return IRQ_HANDLED; |
999 | } | 987 | } |
1000 | 988 | ||
1001 | /* locking: called with info->lock held, or before register_framebuffer() */ | 989 | static int sh_hdmi_display_on(struct sh_mobile_lcdc_entity *entity) |
1002 | static void sh_hdmi_display_on(void *arg, struct fb_info *info) | ||
1003 | { | 990 | { |
1004 | /* | 991 | struct sh_hdmi *hdmi = entity_to_sh_hdmi(entity); |
1005 | * info is guaranteed to be valid, when we are called, because our | ||
1006 | * FB_EVENT_FB_UNBIND notify is also called with info->lock held | ||
1007 | */ | ||
1008 | struct sh_hdmi *hdmi = arg; | ||
1009 | struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; | ||
1010 | struct sh_mobile_lcdc_chan *ch = info->par; | ||
1011 | 992 | ||
1012 | dev_dbg(hdmi->dev, "%s(%p): state %x\n", __func__, | 993 | dev_dbg(hdmi->dev, "%s(%p): state %x\n", __func__, hdmi, |
1013 | pdata->lcd_dev, info->state); | 994 | hdmi->hp_state); |
1014 | |||
1015 | /* No need to lock */ | ||
1016 | hdmi->info = info; | ||
1017 | 995 | ||
1018 | /* | 996 | /* |
1019 | * hp_state can be set to | 997 | * hp_state can be set to |
@@ -1021,56 +999,30 @@ static void sh_hdmi_display_on(void *arg, struct fb_info *info) | |||
1021 | * HDMI_HOTPLUG_CONNECTED: on monitor plug-in | 999 | * HDMI_HOTPLUG_CONNECTED: on monitor plug-in |
1022 | * HDMI_HOTPLUG_EDID_DONE: on EDID read completion | 1000 | * HDMI_HOTPLUG_EDID_DONE: on EDID read completion |
1023 | */ | 1001 | */ |
1024 | switch (hdmi->hp_state) { | 1002 | if (hdmi->hp_state == HDMI_HOTPLUG_EDID_DONE) { |
1025 | case HDMI_HOTPLUG_EDID_DONE: | ||
1026 | /* PS mode d->e. All functions are active */ | 1003 | /* PS mode d->e. All functions are active */ |
1027 | hdmi_write(hdmi, 0x80, HDMI_SYSTEM_CTRL); | 1004 | hdmi_write(hdmi, 0x80, HDMI_SYSTEM_CTRL); |
1028 | dev_dbg(hdmi->dev, "HDMI running\n"); | 1005 | dev_dbg(hdmi->dev, "HDMI running\n"); |
1029 | break; | ||
1030 | case HDMI_HOTPLUG_DISCONNECTED: | ||
1031 | info->state = FBINFO_STATE_SUSPENDED; | ||
1032 | default: | ||
1033 | hdmi->var = ch->display_var; | ||
1034 | } | 1006 | } |
1007 | |||
1008 | return hdmi->hp_state == HDMI_HOTPLUG_DISCONNECTED | ||
1009 | ? SH_MOBILE_LCDC_DISPLAY_DISCONNECTED | ||
1010 | : SH_MOBILE_LCDC_DISPLAY_CONNECTED; | ||
1035 | } | 1011 | } |
1036 | 1012 | ||
1037 | /* locking: called with info->lock held */ | 1013 | static void sh_hdmi_display_off(struct sh_mobile_lcdc_entity *entity) |
1038 | static void sh_hdmi_display_off(void *arg) | ||
1039 | { | 1014 | { |
1040 | struct sh_hdmi *hdmi = arg; | 1015 | struct sh_hdmi *hdmi = entity_to_sh_hdmi(entity); |
1041 | struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; | ||
1042 | 1016 | ||
1043 | dev_dbg(hdmi->dev, "%s(%p)\n", __func__, pdata->lcd_dev); | 1017 | dev_dbg(hdmi->dev, "%s(%p)\n", __func__, hdmi); |
1044 | /* PS mode e->a */ | 1018 | /* PS mode e->a */ |
1045 | hdmi_write(hdmi, 0x10, HDMI_SYSTEM_CTRL); | 1019 | hdmi_write(hdmi, 0x10, HDMI_SYSTEM_CTRL); |
1046 | } | 1020 | } |
1047 | 1021 | ||
1048 | static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi) | 1022 | static const struct sh_mobile_lcdc_entity_ops sh_hdmi_ops = { |
1049 | { | 1023 | .display_on = sh_hdmi_display_on, |
1050 | struct fb_info *info = hdmi->info; | 1024 | .display_off = sh_hdmi_display_off, |
1051 | struct sh_mobile_lcdc_chan *ch = info->par; | 1025 | }; |
1052 | struct fb_var_screeninfo *new_var = &hdmi->var, *old_var = &ch->display_var; | ||
1053 | struct fb_videomode mode1, mode2; | ||
1054 | |||
1055 | fb_var_to_videomode(&mode1, old_var); | ||
1056 | fb_var_to_videomode(&mode2, new_var); | ||
1057 | |||
1058 | dev_dbg(info->dev, "Old %ux%u, new %ux%u\n", | ||
1059 | mode1.xres, mode1.yres, mode2.xres, mode2.yres); | ||
1060 | |||
1061 | if (fb_mode_is_equal(&mode1, &mode2)) { | ||
1062 | /* It can be a different monitor with an equal video-mode */ | ||
1063 | old_var->width = new_var->width; | ||
1064 | old_var->height = new_var->height; | ||
1065 | return false; | ||
1066 | } | ||
1067 | |||
1068 | dev_dbg(info->dev, "Switching %u -> %u lines\n", | ||
1069 | mode1.yres, mode2.yres); | ||
1070 | *old_var = *new_var; | ||
1071 | |||
1072 | return true; | ||
1073 | } | ||
1074 | 1026 | ||
1075 | /** | 1027 | /** |
1076 | * sh_hdmi_clk_configure() - set HDMI clock frequency and enable the clock | 1028 | * sh_hdmi_clk_configure() - set HDMI clock frequency and enable the clock |
@@ -1111,20 +1063,11 @@ static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long hdmi_rate, | |||
1111 | static void sh_hdmi_edid_work_fn(struct work_struct *work) | 1063 | static void sh_hdmi_edid_work_fn(struct work_struct *work) |
1112 | { | 1064 | { |
1113 | struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work); | 1065 | struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work); |
1114 | struct fb_info *info; | 1066 | struct sh_mobile_lcdc_chan *ch = hdmi->entity.lcdc; |
1115 | struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; | ||
1116 | struct sh_mobile_lcdc_chan *ch; | ||
1117 | int ret; | 1067 | int ret; |
1118 | 1068 | ||
1119 | dev_dbg(hdmi->dev, "%s(%p): begin, hotplug status %d\n", __func__, | 1069 | dev_dbg(hdmi->dev, "%s(%p): begin, hotplug status %d\n", __func__, hdmi, |
1120 | pdata->lcd_dev, hdmi->hp_state); | 1070 | hdmi->hp_state); |
1121 | |||
1122 | if (!pdata->lcd_dev) | ||
1123 | return; | ||
1124 | |||
1125 | mutex_lock(&hdmi->mutex); | ||
1126 | |||
1127 | info = hdmi->info; | ||
1128 | 1071 | ||
1129 | if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) { | 1072 | if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) { |
1130 | unsigned long parent_rate = 0, hdmi_rate; | 1073 | unsigned long parent_rate = 0, hdmi_rate; |
@@ -1145,103 +1088,32 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) | |||
1145 | /* Switched to another (d) power-save mode */ | 1088 | /* Switched to another (d) power-save mode */ |
1146 | msleep(10); | 1089 | msleep(10); |
1147 | 1090 | ||
1148 | if (!info) | 1091 | if (ch && ch->notify) |
1149 | goto out; | 1092 | ch->notify(ch, SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT, |
1150 | 1093 | &hdmi->mode, &hdmi->monspec); | |
1151 | ch = info->par; | ||
1152 | |||
1153 | if (lock_fb_info(info)) { | ||
1154 | console_lock(); | ||
1155 | |||
1156 | /* HDMI plug in */ | ||
1157 | if (!sh_hdmi_must_reconfigure(hdmi) && | ||
1158 | info->state == FBINFO_STATE_RUNNING) { | ||
1159 | /* | ||
1160 | * First activation with the default monitor - just turn | ||
1161 | * on, if we run a resume here, the logo disappears | ||
1162 | */ | ||
1163 | info->var.width = hdmi->var.width; | ||
1164 | info->var.height = hdmi->var.height; | ||
1165 | sh_hdmi_display_on(hdmi, info); | ||
1166 | } else { | ||
1167 | /* New monitor or have to wake up */ | ||
1168 | fb_set_suspend(info, 0); | ||
1169 | } | ||
1170 | |||
1171 | console_unlock(); | ||
1172 | unlock_fb_info(info); | ||
1173 | } | ||
1174 | } else { | 1094 | } else { |
1175 | ret = 0; | ||
1176 | if (!info) | ||
1177 | goto out; | ||
1178 | |||
1179 | hdmi->monspec.modedb_len = 0; | 1095 | hdmi->monspec.modedb_len = 0; |
1180 | fb_destroy_modedb(hdmi->monspec.modedb); | 1096 | fb_destroy_modedb(hdmi->monspec.modedb); |
1181 | hdmi->monspec.modedb = NULL; | 1097 | hdmi->monspec.modedb = NULL; |
1182 | 1098 | ||
1183 | if (lock_fb_info(info)) { | 1099 | if (ch && ch->notify) |
1184 | console_lock(); | 1100 | ch->notify(ch, SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT, |
1101 | NULL, NULL); | ||
1185 | 1102 | ||
1186 | /* HDMI disconnect */ | 1103 | ret = 0; |
1187 | fb_set_suspend(info, 1); | ||
1188 | |||
1189 | console_unlock(); | ||
1190 | unlock_fb_info(info); | ||
1191 | } | ||
1192 | } | 1104 | } |
1193 | 1105 | ||
1194 | out: | 1106 | out: |
1195 | if (ret < 0 && ret != -EAGAIN) | 1107 | if (ret < 0 && ret != -EAGAIN) |
1196 | hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED; | 1108 | hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED; |
1197 | mutex_unlock(&hdmi->mutex); | ||
1198 | 1109 | ||
1199 | dev_dbg(hdmi->dev, "%s(%p): end\n", __func__, pdata->lcd_dev); | 1110 | dev_dbg(hdmi->dev, "%s(%p): end\n", __func__, hdmi); |
1200 | } | ||
1201 | |||
1202 | static int sh_hdmi_notify(struct notifier_block *nb, | ||
1203 | unsigned long action, void *data) | ||
1204 | { | ||
1205 | struct fb_event *event = data; | ||
1206 | struct fb_info *info = event->info; | ||
1207 | struct sh_mobile_lcdc_chan *ch = info->par; | ||
1208 | struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg; | ||
1209 | struct sh_hdmi *hdmi = board_cfg->board_data; | ||
1210 | |||
1211 | if (!hdmi || nb != &hdmi->notifier || hdmi->info != info) | ||
1212 | return NOTIFY_DONE; | ||
1213 | |||
1214 | switch(action) { | ||
1215 | case FB_EVENT_FB_REGISTERED: | ||
1216 | /* Unneeded, activation taken care by sh_hdmi_display_on() */ | ||
1217 | break; | ||
1218 | case FB_EVENT_FB_UNREGISTERED: | ||
1219 | /* | ||
1220 | * We are called from unregister_framebuffer() with the | ||
1221 | * info->lock held. This is bad for us, because we can race with | ||
1222 | * the scheduled work, which has to call fb_set_suspend(), which | ||
1223 | * takes info->lock internally, so, sh_hdmi_edid_work_fn() | ||
1224 | * cannot take and hold info->lock for the whole function | ||
1225 | * duration. Using an additional lock creates a classical AB-BA | ||
1226 | * lock up. Therefore, we have to release the info->lock | ||
1227 | * temporarily, synchronise with the work queue and re-acquire | ||
1228 | * the info->lock. | ||
1229 | */ | ||
1230 | unlock_fb_info(info); | ||
1231 | mutex_lock(&hdmi->mutex); | ||
1232 | hdmi->info = NULL; | ||
1233 | mutex_unlock(&hdmi->mutex); | ||
1234 | lock_fb_info(info); | ||
1235 | return NOTIFY_OK; | ||
1236 | } | ||
1237 | return NOTIFY_DONE; | ||
1238 | } | 1111 | } |
1239 | 1112 | ||
1240 | static int __init sh_hdmi_probe(struct platform_device *pdev) | 1113 | static int __init sh_hdmi_probe(struct platform_device *pdev) |
1241 | { | 1114 | { |
1242 | struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data; | 1115 | struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data; |
1243 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1116 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1244 | struct sh_mobile_lcdc_board_cfg *board_cfg; | ||
1245 | int irq = platform_get_irq(pdev, 0), ret; | 1117 | int irq = platform_get_irq(pdev, 0), ret; |
1246 | struct sh_hdmi *hdmi; | 1118 | struct sh_hdmi *hdmi; |
1247 | long rate; | 1119 | long rate; |
@@ -1255,9 +1127,9 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) | |||
1255 | return -ENOMEM; | 1127 | return -ENOMEM; |
1256 | } | 1128 | } |
1257 | 1129 | ||
1258 | mutex_init(&hdmi->mutex); | ||
1259 | |||
1260 | hdmi->dev = &pdev->dev; | 1130 | hdmi->dev = &pdev->dev; |
1131 | hdmi->entity.owner = THIS_MODULE; | ||
1132 | hdmi->entity.ops = &sh_hdmi_ops; | ||
1261 | 1133 | ||
1262 | hdmi->hdmi_clk = clk_get(&pdev->dev, "ick"); | 1134 | hdmi->hdmi_clk = clk_get(&pdev->dev, "ick"); |
1263 | if (IS_ERR(hdmi->hdmi_clk)) { | 1135 | if (IS_ERR(hdmi->hdmi_clk)) { |
@@ -1297,14 +1169,7 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) | |||
1297 | goto emap; | 1169 | goto emap; |
1298 | } | 1170 | } |
1299 | 1171 | ||
1300 | platform_set_drvdata(pdev, hdmi); | 1172 | platform_set_drvdata(pdev, &hdmi->entity); |
1301 | |||
1302 | /* Set up LCDC callbacks */ | ||
1303 | board_cfg = &pdata->lcd_chan->board_cfg; | ||
1304 | board_cfg->owner = THIS_MODULE; | ||
1305 | board_cfg->board_data = hdmi; | ||
1306 | board_cfg->display_on = sh_hdmi_display_on; | ||
1307 | board_cfg->display_off = sh_hdmi_display_off; | ||
1308 | 1173 | ||
1309 | INIT_DELAYED_WORK(&hdmi->edid_work, sh_hdmi_edid_work_fn); | 1174 | INIT_DELAYED_WORK(&hdmi->edid_work, sh_hdmi_edid_work_fn); |
1310 | 1175 | ||
@@ -1329,9 +1194,6 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) | |||
1329 | goto ecodec; | 1194 | goto ecodec; |
1330 | } | 1195 | } |
1331 | 1196 | ||
1332 | hdmi->notifier.notifier_call = sh_hdmi_notify; | ||
1333 | fb_register_client(&hdmi->notifier); | ||
1334 | |||
1335 | return 0; | 1197 | return 0; |
1336 | 1198 | ||
1337 | ecodec: | 1199 | ecodec: |
@@ -1347,7 +1209,6 @@ ereqreg: | |||
1347 | erate: | 1209 | erate: |
1348 | clk_put(hdmi->hdmi_clk); | 1210 | clk_put(hdmi->hdmi_clk); |
1349 | egetclk: | 1211 | egetclk: |
1350 | mutex_destroy(&hdmi->mutex); | ||
1351 | kfree(hdmi); | 1212 | kfree(hdmi); |
1352 | 1213 | ||
1353 | return ret; | 1214 | return ret; |
@@ -1355,21 +1216,12 @@ egetclk: | |||
1355 | 1216 | ||
1356 | static int __exit sh_hdmi_remove(struct platform_device *pdev) | 1217 | static int __exit sh_hdmi_remove(struct platform_device *pdev) |
1357 | { | 1218 | { |
1358 | struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data; | 1219 | struct sh_hdmi *hdmi = entity_to_sh_hdmi(platform_get_drvdata(pdev)); |
1359 | struct sh_hdmi *hdmi = platform_get_drvdata(pdev); | ||
1360 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1220 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1361 | struct sh_mobile_lcdc_board_cfg *board_cfg = &pdata->lcd_chan->board_cfg; | ||
1362 | int irq = platform_get_irq(pdev, 0); | 1221 | int irq = platform_get_irq(pdev, 0); |
1363 | 1222 | ||
1364 | snd_soc_unregister_codec(&pdev->dev); | 1223 | snd_soc_unregister_codec(&pdev->dev); |
1365 | 1224 | ||
1366 | fb_unregister_client(&hdmi->notifier); | ||
1367 | |||
1368 | board_cfg->display_on = NULL; | ||
1369 | board_cfg->display_off = NULL; | ||
1370 | board_cfg->board_data = NULL; | ||
1371 | board_cfg->owner = NULL; | ||
1372 | |||
1373 | /* No new work will be scheduled, wait for running ISR */ | 1225 | /* No new work will be scheduled, wait for running ISR */ |
1374 | free_irq(irq, hdmi); | 1226 | free_irq(irq, hdmi); |
1375 | /* Wait for already scheduled work */ | 1227 | /* Wait for already scheduled work */ |
@@ -1380,7 +1232,6 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev) | |||
1380 | clk_put(hdmi->hdmi_clk); | 1232 | clk_put(hdmi->hdmi_clk); |
1381 | iounmap(hdmi->base); | 1233 | iounmap(hdmi->base); |
1382 | release_mem_region(res->start, resource_size(res)); | 1234 | release_mem_region(res->start, resource_size(res)); |
1383 | mutex_destroy(&hdmi->mutex); | ||
1384 | kfree(hdmi); | 1235 | kfree(hdmi); |
1385 | 1236 | ||
1386 | return 0; | 1237 | return 0; |
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index aac5b369d73c..7a0b301587f6 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c | |||
@@ -8,26 +8,27 @@ | |||
8 | * for more details. | 8 | * for more details. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/kernel.h> | 11 | #include <linux/atomic.h> |
12 | #include <linux/init.h> | 12 | #include <linux/backlight.h> |
13 | #include <linux/delay.h> | ||
14 | #include <linux/mm.h> | ||
15 | #include <linux/clk.h> | 13 | #include <linux/clk.h> |
16 | #include <linux/pm_runtime.h> | 14 | #include <linux/console.h> |
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/dma-mapping.h> | 15 | #include <linux/dma-mapping.h> |
16 | #include <linux/delay.h> | ||
17 | #include <linux/gpio.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/videodev2.h> | ||
21 | #include <linux/vmalloc.h> | ||
22 | #include <linux/ioctl.h> | 20 | #include <linux/ioctl.h> |
23 | #include <linux/slab.h> | 21 | #include <linux/kernel.h> |
24 | #include <linux/console.h> | 22 | #include <linux/mm.h> |
25 | #include <linux/backlight.h> | ||
26 | #include <linux/gpio.h> | ||
27 | #include <linux/module.h> | 23 | #include <linux/module.h> |
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/pm_runtime.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/videodev2.h> | ||
28 | #include <linux/vmalloc.h> | ||
29 | |||
28 | #include <video/sh_mobile_lcdc.h> | 30 | #include <video/sh_mobile_lcdc.h> |
29 | #include <video/sh_mobile_meram.h> | 31 | #include <video/sh_mobile_meram.h> |
30 | #include <linux/atomic.h> | ||
31 | 32 | ||
32 | #include "sh_mobile_lcdcfb.h" | 33 | #include "sh_mobile_lcdcfb.h" |
33 | 34 | ||
@@ -37,6 +38,24 @@ | |||
37 | #define MAX_XRES 1920 | 38 | #define MAX_XRES 1920 |
38 | #define MAX_YRES 1080 | 39 | #define MAX_YRES 1080 |
39 | 40 | ||
41 | struct sh_mobile_lcdc_priv { | ||
42 | void __iomem *base; | ||
43 | int irq; | ||
44 | atomic_t hw_usecnt; | ||
45 | struct device *dev; | ||
46 | struct clk *dot_clk; | ||
47 | unsigned long lddckr; | ||
48 | struct sh_mobile_lcdc_chan ch[2]; | ||
49 | struct notifier_block notifier; | ||
50 | int started; | ||
51 | int forced_fourcc; /* 2 channel LCDC must share fourcc setting */ | ||
52 | struct sh_mobile_meram_info *meram_dev; | ||
53 | }; | ||
54 | |||
55 | /* ----------------------------------------------------------------------------- | ||
56 | * Registers access | ||
57 | */ | ||
58 | |||
40 | static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = { | 59 | static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = { |
41 | [LDDCKPAT1R] = 0x400, | 60 | [LDDCKPAT1R] = 0x400, |
42 | [LDDCKPAT2R] = 0x404, | 61 | [LDDCKPAT2R] = 0x404, |
@@ -75,38 +94,6 @@ static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = { | |||
75 | [LDPMR] = 0x63c, | 94 | [LDPMR] = 0x63c, |
76 | }; | 95 | }; |
77 | 96 | ||
78 | static const struct fb_videomode default_720p = { | ||
79 | .name = "HDMI 720p", | ||
80 | .xres = 1280, | ||
81 | .yres = 720, | ||
82 | |||
83 | .left_margin = 220, | ||
84 | .right_margin = 110, | ||
85 | .hsync_len = 40, | ||
86 | |||
87 | .upper_margin = 20, | ||
88 | .lower_margin = 5, | ||
89 | .vsync_len = 5, | ||
90 | |||
91 | .pixclock = 13468, | ||
92 | .refresh = 60, | ||
93 | .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT, | ||
94 | }; | ||
95 | |||
96 | struct sh_mobile_lcdc_priv { | ||
97 | void __iomem *base; | ||
98 | int irq; | ||
99 | atomic_t hw_usecnt; | ||
100 | struct device *dev; | ||
101 | struct clk *dot_clk; | ||
102 | unsigned long lddckr; | ||
103 | struct sh_mobile_lcdc_chan ch[2]; | ||
104 | struct notifier_block notifier; | ||
105 | int started; | ||
106 | int forced_fourcc; /* 2 channel LCDC must share fourcc setting */ | ||
107 | struct sh_mobile_meram_info *meram_dev; | ||
108 | }; | ||
109 | |||
110 | static bool banked(int reg_nr) | 97 | static bool banked(int reg_nr) |
111 | { | 98 | { |
112 | switch (reg_nr) { | 99 | switch (reg_nr) { |
@@ -127,6 +114,11 @@ static bool banked(int reg_nr) | |||
127 | return false; | 114 | return false; |
128 | } | 115 | } |
129 | 116 | ||
117 | static int lcdc_chan_is_sublcd(struct sh_mobile_lcdc_chan *chan) | ||
118 | { | ||
119 | return chan->cfg->chan == LCDC_CHAN_SUBLCD; | ||
120 | } | ||
121 | |||
130 | static void lcdc_write_chan(struct sh_mobile_lcdc_chan *chan, | 122 | static void lcdc_write_chan(struct sh_mobile_lcdc_chan *chan, |
131 | int reg_nr, unsigned long data) | 123 | int reg_nr, unsigned long data) |
132 | { | 124 | { |
@@ -169,11 +161,72 @@ static void lcdc_wait_bit(struct sh_mobile_lcdc_priv *priv, | |||
169 | cpu_relax(); | 161 | cpu_relax(); |
170 | } | 162 | } |
171 | 163 | ||
172 | static int lcdc_chan_is_sublcd(struct sh_mobile_lcdc_chan *chan) | 164 | /* ----------------------------------------------------------------------------- |
165 | * Clock management | ||
166 | */ | ||
167 | |||
168 | static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) | ||
169 | { | ||
170 | if (atomic_inc_and_test(&priv->hw_usecnt)) { | ||
171 | if (priv->dot_clk) | ||
172 | clk_enable(priv->dot_clk); | ||
173 | pm_runtime_get_sync(priv->dev); | ||
174 | if (priv->meram_dev && priv->meram_dev->pdev) | ||
175 | pm_runtime_get_sync(&priv->meram_dev->pdev->dev); | ||
176 | } | ||
177 | } | ||
178 | |||
179 | static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv) | ||
173 | { | 180 | { |
174 | return chan->cfg.chan == LCDC_CHAN_SUBLCD; | 181 | if (atomic_sub_return(1, &priv->hw_usecnt) == -1) { |
182 | if (priv->meram_dev && priv->meram_dev->pdev) | ||
183 | pm_runtime_put_sync(&priv->meram_dev->pdev->dev); | ||
184 | pm_runtime_put(priv->dev); | ||
185 | if (priv->dot_clk) | ||
186 | clk_disable(priv->dot_clk); | ||
187 | } | ||
175 | } | 188 | } |
176 | 189 | ||
190 | static int sh_mobile_lcdc_setup_clocks(struct sh_mobile_lcdc_priv *priv, | ||
191 | int clock_source) | ||
192 | { | ||
193 | struct clk *clk; | ||
194 | char *str; | ||
195 | |||
196 | switch (clock_source) { | ||
197 | case LCDC_CLK_BUS: | ||
198 | str = "bus_clk"; | ||
199 | priv->lddckr = LDDCKR_ICKSEL_BUS; | ||
200 | break; | ||
201 | case LCDC_CLK_PERIPHERAL: | ||
202 | str = "peripheral_clk"; | ||
203 | priv->lddckr = LDDCKR_ICKSEL_MIPI; | ||
204 | break; | ||
205 | case LCDC_CLK_EXTERNAL: | ||
206 | str = NULL; | ||
207 | priv->lddckr = LDDCKR_ICKSEL_HDMI; | ||
208 | break; | ||
209 | default: | ||
210 | return -EINVAL; | ||
211 | } | ||
212 | |||
213 | if (str == NULL) | ||
214 | return 0; | ||
215 | |||
216 | clk = clk_get(priv->dev, str); | ||
217 | if (IS_ERR(clk)) { | ||
218 | dev_err(priv->dev, "cannot get dot clock %s\n", str); | ||
219 | return PTR_ERR(clk); | ||
220 | } | ||
221 | |||
222 | priv->dot_clk = clk; | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | /* ----------------------------------------------------------------------------- | ||
227 | * Display, panel and deferred I/O | ||
228 | */ | ||
229 | |||
177 | static void lcdc_sys_write_index(void *handle, unsigned long data) | 230 | static void lcdc_sys_write_index(void *handle, unsigned long data) |
178 | { | 231 | { |
179 | struct sh_mobile_lcdc_chan *ch = handle; | 232 | struct sh_mobile_lcdc_chan *ch = handle; |
@@ -216,74 +269,11 @@ struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = { | |||
216 | lcdc_sys_read_data, | 269 | lcdc_sys_read_data, |
217 | }; | 270 | }; |
218 | 271 | ||
219 | static int sh_mobile_format_fourcc(const struct fb_var_screeninfo *var) | ||
220 | { | ||
221 | if (var->grayscale > 1) | ||
222 | return var->grayscale; | ||
223 | |||
224 | switch (var->bits_per_pixel) { | ||
225 | case 16: | ||
226 | return V4L2_PIX_FMT_RGB565; | ||
227 | case 24: | ||
228 | return V4L2_PIX_FMT_BGR24; | ||
229 | case 32: | ||
230 | return V4L2_PIX_FMT_BGR32; | ||
231 | default: | ||
232 | return 0; | ||
233 | } | ||
234 | } | ||
235 | |||
236 | static int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var) | ||
237 | { | ||
238 | return var->grayscale > 1; | ||
239 | } | ||
240 | |||
241 | static bool sh_mobile_format_is_yuv(const struct fb_var_screeninfo *var) | ||
242 | { | ||
243 | if (var->grayscale <= 1) | ||
244 | return false; | ||
245 | |||
246 | switch (var->grayscale) { | ||
247 | case V4L2_PIX_FMT_NV12: | ||
248 | case V4L2_PIX_FMT_NV21: | ||
249 | case V4L2_PIX_FMT_NV16: | ||
250 | case V4L2_PIX_FMT_NV61: | ||
251 | case V4L2_PIX_FMT_NV24: | ||
252 | case V4L2_PIX_FMT_NV42: | ||
253 | return true; | ||
254 | |||
255 | default: | ||
256 | return false; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) | ||
261 | { | ||
262 | if (atomic_inc_and_test(&priv->hw_usecnt)) { | ||
263 | if (priv->dot_clk) | ||
264 | clk_enable(priv->dot_clk); | ||
265 | pm_runtime_get_sync(priv->dev); | ||
266 | if (priv->meram_dev && priv->meram_dev->pdev) | ||
267 | pm_runtime_get_sync(&priv->meram_dev->pdev->dev); | ||
268 | } | ||
269 | } | ||
270 | |||
271 | static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv) | ||
272 | { | ||
273 | if (atomic_sub_return(1, &priv->hw_usecnt) == -1) { | ||
274 | if (priv->meram_dev && priv->meram_dev->pdev) | ||
275 | pm_runtime_put_sync(&priv->meram_dev->pdev->dev); | ||
276 | pm_runtime_put(priv->dev); | ||
277 | if (priv->dot_clk) | ||
278 | clk_disable(priv->dot_clk); | ||
279 | } | ||
280 | } | ||
281 | |||
282 | static int sh_mobile_lcdc_sginit(struct fb_info *info, | 272 | static int sh_mobile_lcdc_sginit(struct fb_info *info, |
283 | struct list_head *pagelist) | 273 | struct list_head *pagelist) |
284 | { | 274 | { |
285 | struct sh_mobile_lcdc_chan *ch = info->par; | 275 | struct sh_mobile_lcdc_chan *ch = info->par; |
286 | unsigned int nr_pages_max = info->fix.smem_len >> PAGE_SHIFT; | 276 | unsigned int nr_pages_max = ch->fb_size >> PAGE_SHIFT; |
287 | struct page *page; | 277 | struct page *page; |
288 | int nr_pages = 0; | 278 | int nr_pages = 0; |
289 | 279 | ||
@@ -299,7 +289,7 @@ static void sh_mobile_lcdc_deferred_io(struct fb_info *info, | |||
299 | struct list_head *pagelist) | 289 | struct list_head *pagelist) |
300 | { | 290 | { |
301 | struct sh_mobile_lcdc_chan *ch = info->par; | 291 | struct sh_mobile_lcdc_chan *ch = info->par; |
302 | struct sh_mobile_lcdc_board_cfg *bcfg = &ch->cfg.board_cfg; | 292 | const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg; |
303 | 293 | ||
304 | /* enable clocks before accessing hardware */ | 294 | /* enable clocks before accessing hardware */ |
305 | sh_mobile_lcdc_clk_on(ch->lcdc); | 295 | sh_mobile_lcdc_clk_on(ch->lcdc); |
@@ -323,16 +313,15 @@ static void sh_mobile_lcdc_deferred_io(struct fb_info *info, | |||
323 | unsigned int nr_pages = sh_mobile_lcdc_sginit(info, pagelist); | 313 | unsigned int nr_pages = sh_mobile_lcdc_sginit(info, pagelist); |
324 | 314 | ||
325 | /* trigger panel update */ | 315 | /* trigger panel update */ |
326 | dma_map_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE); | 316 | dma_map_sg(ch->lcdc->dev, ch->sglist, nr_pages, DMA_TO_DEVICE); |
327 | if (bcfg->start_transfer) | 317 | if (panel->start_transfer) |
328 | bcfg->start_transfer(bcfg->board_data, ch, | 318 | panel->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops); |
329 | &sh_mobile_lcdc_sys_bus_ops); | ||
330 | lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG); | 319 | lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG); |
331 | dma_unmap_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE); | 320 | dma_unmap_sg(ch->lcdc->dev, ch->sglist, nr_pages, |
321 | DMA_TO_DEVICE); | ||
332 | } else { | 322 | } else { |
333 | if (bcfg->start_transfer) | 323 | if (panel->start_transfer) |
334 | bcfg->start_transfer(bcfg->board_data, ch, | 324 | panel->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops); |
335 | &sh_mobile_lcdc_sys_bus_ops); | ||
336 | lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG); | 325 | lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG); |
337 | } | 326 | } |
338 | } | 327 | } |
@@ -345,6 +334,217 @@ static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info) | |||
345 | schedule_delayed_work(&info->deferred_work, fbdefio->delay); | 334 | schedule_delayed_work(&info->deferred_work, fbdefio->delay); |
346 | } | 335 | } |
347 | 336 | ||
337 | static void sh_mobile_lcdc_display_on(struct sh_mobile_lcdc_chan *ch) | ||
338 | { | ||
339 | const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg; | ||
340 | |||
341 | if (ch->tx_dev) { | ||
342 | int ret; | ||
343 | |||
344 | ret = ch->tx_dev->ops->display_on(ch->tx_dev); | ||
345 | if (ret < 0) | ||
346 | return; | ||
347 | |||
348 | if (ret == SH_MOBILE_LCDC_DISPLAY_DISCONNECTED) | ||
349 | ch->info->state = FBINFO_STATE_SUSPENDED; | ||
350 | } | ||
351 | |||
352 | /* HDMI must be enabled before LCDC configuration */ | ||
353 | if (panel->display_on) | ||
354 | panel->display_on(); | ||
355 | } | ||
356 | |||
357 | static void sh_mobile_lcdc_display_off(struct sh_mobile_lcdc_chan *ch) | ||
358 | { | ||
359 | const struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg->panel_cfg; | ||
360 | |||
361 | if (panel->display_off) | ||
362 | panel->display_off(); | ||
363 | |||
364 | if (ch->tx_dev) | ||
365 | ch->tx_dev->ops->display_off(ch->tx_dev); | ||
366 | } | ||
367 | |||
368 | static bool | ||
369 | sh_mobile_lcdc_must_reconfigure(struct sh_mobile_lcdc_chan *ch, | ||
370 | const struct fb_videomode *new_mode) | ||
371 | { | ||
372 | dev_dbg(ch->info->dev, "Old %ux%u, new %ux%u\n", | ||
373 | ch->display.mode.xres, ch->display.mode.yres, | ||
374 | new_mode->xres, new_mode->yres); | ||
375 | |||
376 | /* It can be a different monitor with an equal video-mode */ | ||
377 | if (fb_mode_is_equal(&ch->display.mode, new_mode)) | ||
378 | return false; | ||
379 | |||
380 | dev_dbg(ch->info->dev, "Switching %u -> %u lines\n", | ||
381 | ch->display.mode.yres, new_mode->yres); | ||
382 | ch->display.mode = *new_mode; | ||
383 | |||
384 | return true; | ||
385 | } | ||
386 | |||
387 | static int sh_mobile_check_var(struct fb_var_screeninfo *var, | ||
388 | struct fb_info *info); | ||
389 | |||
390 | static int sh_mobile_lcdc_display_notify(struct sh_mobile_lcdc_chan *ch, | ||
391 | enum sh_mobile_lcdc_entity_event event, | ||
392 | const struct fb_videomode *mode, | ||
393 | const struct fb_monspecs *monspec) | ||
394 | { | ||
395 | struct fb_info *info = ch->info; | ||
396 | struct fb_var_screeninfo var; | ||
397 | int ret = 0; | ||
398 | |||
399 | switch (event) { | ||
400 | case SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT: | ||
401 | /* HDMI plug in */ | ||
402 | if (lock_fb_info(info)) { | ||
403 | console_lock(); | ||
404 | |||
405 | ch->display.width = monspec->max_x * 10; | ||
406 | ch->display.height = monspec->max_y * 10; | ||
407 | |||
408 | if (!sh_mobile_lcdc_must_reconfigure(ch, mode) && | ||
409 | info->state == FBINFO_STATE_RUNNING) { | ||
410 | /* First activation with the default monitor. | ||
411 | * Just turn on, if we run a resume here, the | ||
412 | * logo disappears. | ||
413 | */ | ||
414 | info->var.width = monspec->max_x * 10; | ||
415 | info->var.height = monspec->max_y * 10; | ||
416 | sh_mobile_lcdc_display_on(ch); | ||
417 | } else { | ||
418 | /* New monitor or have to wake up */ | ||
419 | fb_set_suspend(info, 0); | ||
420 | } | ||
421 | |||
422 | console_unlock(); | ||
423 | unlock_fb_info(info); | ||
424 | } | ||
425 | break; | ||
426 | |||
427 | case SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT: | ||
428 | /* HDMI disconnect */ | ||
429 | if (lock_fb_info(info)) { | ||
430 | console_lock(); | ||
431 | fb_set_suspend(info, 1); | ||
432 | console_unlock(); | ||
433 | unlock_fb_info(info); | ||
434 | } | ||
435 | break; | ||
436 | |||
437 | case SH_MOBILE_LCDC_EVENT_DISPLAY_MODE: | ||
438 | /* Validate a proposed new mode */ | ||
439 | fb_videomode_to_var(&var, mode); | ||
440 | var.bits_per_pixel = info->var.bits_per_pixel; | ||
441 | var.grayscale = info->var.grayscale; | ||
442 | ret = sh_mobile_check_var(&var, info); | ||
443 | break; | ||
444 | } | ||
445 | |||
446 | return ret; | ||
447 | } | ||
448 | |||
449 | /* ----------------------------------------------------------------------------- | ||
450 | * Format helpers | ||
451 | */ | ||
452 | |||
453 | struct sh_mobile_lcdc_format_info { | ||
454 | u32 fourcc; | ||
455 | unsigned int bpp; | ||
456 | bool yuv; | ||
457 | u32 lddfr; | ||
458 | }; | ||
459 | |||
460 | static const struct sh_mobile_lcdc_format_info sh_mobile_format_infos[] = { | ||
461 | { | ||
462 | .fourcc = V4L2_PIX_FMT_RGB565, | ||
463 | .bpp = 16, | ||
464 | .yuv = false, | ||
465 | .lddfr = LDDFR_PKF_RGB16, | ||
466 | }, { | ||
467 | .fourcc = V4L2_PIX_FMT_BGR24, | ||
468 | .bpp = 24, | ||
469 | .yuv = false, | ||
470 | .lddfr = LDDFR_PKF_RGB24, | ||
471 | }, { | ||
472 | .fourcc = V4L2_PIX_FMT_BGR32, | ||
473 | .bpp = 32, | ||
474 | .yuv = false, | ||
475 | .lddfr = LDDFR_PKF_ARGB32, | ||
476 | }, { | ||
477 | .fourcc = V4L2_PIX_FMT_NV12, | ||
478 | .bpp = 12, | ||
479 | .yuv = true, | ||
480 | .lddfr = LDDFR_CC | LDDFR_YF_420, | ||
481 | }, { | ||
482 | .fourcc = V4L2_PIX_FMT_NV21, | ||
483 | .bpp = 12, | ||
484 | .yuv = true, | ||
485 | .lddfr = LDDFR_CC | LDDFR_YF_420, | ||
486 | }, { | ||
487 | .fourcc = V4L2_PIX_FMT_NV16, | ||
488 | .bpp = 16, | ||
489 | .yuv = true, | ||
490 | .lddfr = LDDFR_CC | LDDFR_YF_422, | ||
491 | }, { | ||
492 | .fourcc = V4L2_PIX_FMT_NV61, | ||
493 | .bpp = 16, | ||
494 | .yuv = true, | ||
495 | .lddfr = LDDFR_CC | LDDFR_YF_422, | ||
496 | }, { | ||
497 | .fourcc = V4L2_PIX_FMT_NV24, | ||
498 | .bpp = 24, | ||
499 | .yuv = true, | ||
500 | .lddfr = LDDFR_CC | LDDFR_YF_444, | ||
501 | }, { | ||
502 | .fourcc = V4L2_PIX_FMT_NV42, | ||
503 | .bpp = 24, | ||
504 | .yuv = true, | ||
505 | .lddfr = LDDFR_CC | LDDFR_YF_444, | ||
506 | }, | ||
507 | }; | ||
508 | |||
509 | static const struct sh_mobile_lcdc_format_info * | ||
510 | sh_mobile_format_info(u32 fourcc) | ||
511 | { | ||
512 | unsigned int i; | ||
513 | |||
514 | for (i = 0; i < ARRAY_SIZE(sh_mobile_format_infos); ++i) { | ||
515 | if (sh_mobile_format_infos[i].fourcc == fourcc) | ||
516 | return &sh_mobile_format_infos[i]; | ||
517 | } | ||
518 | |||
519 | return NULL; | ||
520 | } | ||
521 | |||
522 | static int sh_mobile_format_fourcc(const struct fb_var_screeninfo *var) | ||
523 | { | ||
524 | if (var->grayscale > 1) | ||
525 | return var->grayscale; | ||
526 | |||
527 | switch (var->bits_per_pixel) { | ||
528 | case 16: | ||
529 | return V4L2_PIX_FMT_RGB565; | ||
530 | case 24: | ||
531 | return V4L2_PIX_FMT_BGR24; | ||
532 | case 32: | ||
533 | return V4L2_PIX_FMT_BGR32; | ||
534 | default: | ||
535 | return 0; | ||
536 | } | ||
537 | } | ||
538 | |||
539 | static int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var) | ||
540 | { | ||
541 | return var->grayscale > 1; | ||
542 | } | ||
543 | |||
544 | /* ----------------------------------------------------------------------------- | ||
545 | * Start, stop and IRQ | ||
546 | */ | ||
547 | |||
348 | static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data) | 548 | static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data) |
349 | { | 549 | { |
350 | struct sh_mobile_lcdc_priv *priv = data; | 550 | struct sh_mobile_lcdc_priv *priv = data; |
@@ -385,6 +585,26 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data) | |||
385 | return IRQ_HANDLED; | 585 | return IRQ_HANDLED; |
386 | } | 586 | } |
387 | 587 | ||
588 | static int sh_mobile_wait_for_vsync(struct sh_mobile_lcdc_chan *ch) | ||
589 | { | ||
590 | unsigned long ldintr; | ||
591 | int ret; | ||
592 | |||
593 | /* Enable VSync End interrupt and be careful not to acknowledge any | ||
594 | * pending interrupt. | ||
595 | */ | ||
596 | ldintr = lcdc_read(ch->lcdc, _LDINTR); | ||
597 | ldintr |= LDINTR_VEE | LDINTR_STATUS_MASK; | ||
598 | lcdc_write(ch->lcdc, _LDINTR, ldintr); | ||
599 | |||
600 | ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion, | ||
601 | msecs_to_jiffies(100)); | ||
602 | if (!ret) | ||
603 | return -ETIMEDOUT; | ||
604 | |||
605 | return 0; | ||
606 | } | ||
607 | |||
388 | static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv, | 608 | static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv, |
389 | int start) | 609 | int start) |
390 | { | 610 | { |
@@ -416,53 +636,52 @@ static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv, | |||
416 | 636 | ||
417 | static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) | 637 | static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) |
418 | { | 638 | { |
419 | struct fb_var_screeninfo *var = &ch->info->var, *display_var = &ch->display_var; | 639 | const struct fb_var_screeninfo *var = &ch->info->var; |
640 | const struct fb_videomode *mode = &ch->display.mode; | ||
420 | unsigned long h_total, hsync_pos, display_h_total; | 641 | unsigned long h_total, hsync_pos, display_h_total; |
421 | u32 tmp; | 642 | u32 tmp; |
422 | 643 | ||
423 | tmp = ch->ldmt1r_value; | 644 | tmp = ch->ldmt1r_value; |
424 | tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : LDMT1R_VPOL; | 645 | tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : LDMT1R_VPOL; |
425 | tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : LDMT1R_HPOL; | 646 | tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : LDMT1R_HPOL; |
426 | tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? LDMT1R_DWPOL : 0; | 647 | tmp |= (ch->cfg->flags & LCDC_FLAGS_DWPOL) ? LDMT1R_DWPOL : 0; |
427 | tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? LDMT1R_DIPOL : 0; | 648 | tmp |= (ch->cfg->flags & LCDC_FLAGS_DIPOL) ? LDMT1R_DIPOL : 0; |
428 | tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? LDMT1R_DAPOL : 0; | 649 | tmp |= (ch->cfg->flags & LCDC_FLAGS_DAPOL) ? LDMT1R_DAPOL : 0; |
429 | tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? LDMT1R_HSCNT : 0; | 650 | tmp |= (ch->cfg->flags & LCDC_FLAGS_HSCNT) ? LDMT1R_HSCNT : 0; |
430 | tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? LDMT1R_DWCNT : 0; | 651 | tmp |= (ch->cfg->flags & LCDC_FLAGS_DWCNT) ? LDMT1R_DWCNT : 0; |
431 | lcdc_write_chan(ch, LDMT1R, tmp); | 652 | lcdc_write_chan(ch, LDMT1R, tmp); |
432 | 653 | ||
433 | /* setup SYS bus */ | 654 | /* setup SYS bus */ |
434 | lcdc_write_chan(ch, LDMT2R, ch->cfg.sys_bus_cfg.ldmt2r); | 655 | lcdc_write_chan(ch, LDMT2R, ch->cfg->sys_bus_cfg.ldmt2r); |
435 | lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r); | 656 | lcdc_write_chan(ch, LDMT3R, ch->cfg->sys_bus_cfg.ldmt3r); |
436 | 657 | ||
437 | /* horizontal configuration */ | 658 | /* horizontal configuration */ |
438 | h_total = display_var->xres + display_var->hsync_len + | 659 | h_total = mode->xres + mode->hsync_len + mode->left_margin |
439 | display_var->left_margin + display_var->right_margin; | 660 | + mode->right_margin; |
440 | tmp = h_total / 8; /* HTCN */ | 661 | tmp = h_total / 8; /* HTCN */ |
441 | tmp |= (min(display_var->xres, var->xres) / 8) << 16; /* HDCN */ | 662 | tmp |= (min(mode->xres, ch->xres) / 8) << 16; /* HDCN */ |
442 | lcdc_write_chan(ch, LDHCNR, tmp); | 663 | lcdc_write_chan(ch, LDHCNR, tmp); |
443 | 664 | ||
444 | hsync_pos = display_var->xres + display_var->right_margin; | 665 | hsync_pos = mode->xres + mode->right_margin; |
445 | tmp = hsync_pos / 8; /* HSYNP */ | 666 | tmp = hsync_pos / 8; /* HSYNP */ |
446 | tmp |= (display_var->hsync_len / 8) << 16; /* HSYNW */ | 667 | tmp |= (mode->hsync_len / 8) << 16; /* HSYNW */ |
447 | lcdc_write_chan(ch, LDHSYNR, tmp); | 668 | lcdc_write_chan(ch, LDHSYNR, tmp); |
448 | 669 | ||
449 | /* vertical configuration */ | 670 | /* vertical configuration */ |
450 | tmp = display_var->yres + display_var->vsync_len + | 671 | tmp = mode->yres + mode->vsync_len + mode->upper_margin |
451 | display_var->upper_margin + display_var->lower_margin; /* VTLN */ | 672 | + mode->lower_margin; /* VTLN */ |
452 | tmp |= min(display_var->yres, var->yres) << 16; /* VDLN */ | 673 | tmp |= min(mode->yres, ch->yres) << 16; /* VDLN */ |
453 | lcdc_write_chan(ch, LDVLNR, tmp); | 674 | lcdc_write_chan(ch, LDVLNR, tmp); |
454 | 675 | ||
455 | tmp = display_var->yres + display_var->lower_margin; /* VSYNP */ | 676 | tmp = mode->yres + mode->lower_margin; /* VSYNP */ |
456 | tmp |= display_var->vsync_len << 16; /* VSYNW */ | 677 | tmp |= mode->vsync_len << 16; /* VSYNW */ |
457 | lcdc_write_chan(ch, LDVSYNR, tmp); | 678 | lcdc_write_chan(ch, LDVSYNR, tmp); |
458 | 679 | ||
459 | /* Adjust horizontal synchronisation for HDMI */ | 680 | /* Adjust horizontal synchronisation for HDMI */ |
460 | display_h_total = display_var->xres + display_var->hsync_len + | 681 | display_h_total = mode->xres + mode->hsync_len + mode->left_margin |
461 | display_var->left_margin + display_var->right_margin; | 682 | + mode->right_margin; |
462 | tmp = ((display_var->xres & 7) << 24) | | 683 | tmp = ((mode->xres & 7) << 24) | ((display_h_total & 7) << 16) |
463 | ((display_h_total & 7) << 16) | | 684 | | ((mode->hsync_len & 7) << 8) | (hsync_pos & 7); |
464 | ((display_var->hsync_len & 7) << 8) | | ||
465 | (hsync_pos & 7); | ||
466 | lcdc_write_chan(ch, LDHAJR, tmp); | 685 | lcdc_write_chan(ch, LDHAJR, tmp); |
467 | } | 686 | } |
468 | 687 | ||
@@ -498,7 +717,7 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
498 | /* Power supply */ | 717 | /* Power supply */ |
499 | lcdc_write_chan(ch, LDPMR, 0); | 718 | lcdc_write_chan(ch, LDPMR, 0); |
500 | 719 | ||
501 | m = ch->cfg.clock_divider; | 720 | m = ch->cfg->clock_divider; |
502 | if (!m) | 721 | if (!m) |
503 | continue; | 722 | continue; |
504 | 723 | ||
@@ -525,32 +744,10 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
525 | 744 | ||
526 | sh_mobile_lcdc_geometry(ch); | 745 | sh_mobile_lcdc_geometry(ch); |
527 | 746 | ||
528 | switch (sh_mobile_format_fourcc(&ch->info->var)) { | 747 | tmp = ch->format->lddfr; |
529 | case V4L2_PIX_FMT_RGB565: | ||
530 | tmp = LDDFR_PKF_RGB16; | ||
531 | break; | ||
532 | case V4L2_PIX_FMT_BGR24: | ||
533 | tmp = LDDFR_PKF_RGB24; | ||
534 | break; | ||
535 | case V4L2_PIX_FMT_BGR32: | ||
536 | tmp = LDDFR_PKF_ARGB32; | ||
537 | break; | ||
538 | case V4L2_PIX_FMT_NV12: | ||
539 | case V4L2_PIX_FMT_NV21: | ||
540 | tmp = LDDFR_CC | LDDFR_YF_420; | ||
541 | break; | ||
542 | case V4L2_PIX_FMT_NV16: | ||
543 | case V4L2_PIX_FMT_NV61: | ||
544 | tmp = LDDFR_CC | LDDFR_YF_422; | ||
545 | break; | ||
546 | case V4L2_PIX_FMT_NV24: | ||
547 | case V4L2_PIX_FMT_NV42: | ||
548 | tmp = LDDFR_CC | LDDFR_YF_444; | ||
549 | break; | ||
550 | } | ||
551 | 748 | ||
552 | if (sh_mobile_format_is_yuv(&ch->info->var)) { | 749 | if (ch->format->yuv) { |
553 | switch (ch->info->var.colorspace) { | 750 | switch (ch->colorspace) { |
554 | case V4L2_COLORSPACE_REC709: | 751 | case V4L2_COLORSPACE_REC709: |
555 | tmp |= LDDFR_CF1; | 752 | tmp |= LDDFR_CF1; |
556 | break; | 753 | break; |
@@ -563,7 +760,7 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
563 | lcdc_write_chan(ch, LDDFR, tmp); | 760 | lcdc_write_chan(ch, LDDFR, tmp); |
564 | lcdc_write_chan(ch, LDMLSR, ch->pitch); | 761 | lcdc_write_chan(ch, LDMLSR, ch->pitch); |
565 | lcdc_write_chan(ch, LDSA1R, ch->base_addr_y); | 762 | lcdc_write_chan(ch, LDSA1R, ch->base_addr_y); |
566 | if (sh_mobile_format_is_yuv(&ch->info->var)) | 763 | if (ch->format->yuv) |
567 | lcdc_write_chan(ch, LDSA2R, ch->base_addr_c); | 764 | lcdc_write_chan(ch, LDSA2R, ch->base_addr_c); |
568 | 765 | ||
569 | /* When using deferred I/O mode, configure the LCDC for one-shot | 766 | /* When using deferred I/O mode, configure the LCDC for one-shot |
@@ -571,7 +768,7 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
571 | * continuous read mode. | 768 | * continuous read mode. |
572 | */ | 769 | */ |
573 | if (ch->ldmt1r_value & LDMT1R_IFM && | 770 | if (ch->ldmt1r_value & LDMT1R_IFM && |
574 | ch->cfg.sys_bus_cfg.deferred_io_msec) { | 771 | ch->cfg->sys_bus_cfg.deferred_io_msec) { |
575 | lcdc_write_chan(ch, LDSM1R, LDSM1R_OS); | 772 | lcdc_write_chan(ch, LDSM1R, LDSM1R_OS); |
576 | lcdc_write(priv, _LDINTR, LDINTR_FE); | 773 | lcdc_write(priv, _LDINTR, LDINTR_FE); |
577 | } else { | 774 | } else { |
@@ -580,7 +777,7 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
580 | } | 777 | } |
581 | 778 | ||
582 | /* Word and long word swap. */ | 779 | /* Word and long word swap. */ |
583 | switch (sh_mobile_format_fourcc(&priv->ch[0].info->var)) { | 780 | switch (priv->ch[0].format->fourcc) { |
584 | case V4L2_PIX_FMT_RGB565: | 781 | case V4L2_PIX_FMT_RGB565: |
585 | case V4L2_PIX_FMT_NV21: | 782 | case V4L2_PIX_FMT_NV21: |
586 | case V4L2_PIX_FMT_NV61: | 783 | case V4L2_PIX_FMT_NV61: |
@@ -609,7 +806,6 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
609 | static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | 806 | static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) |
610 | { | 807 | { |
611 | struct sh_mobile_meram_info *mdev = priv->meram_dev; | 808 | struct sh_mobile_meram_info *mdev = priv->meram_dev; |
612 | struct sh_mobile_lcdc_board_cfg *board_cfg; | ||
613 | struct sh_mobile_lcdc_chan *ch; | 809 | struct sh_mobile_lcdc_chan *ch; |
614 | unsigned long tmp; | 810 | unsigned long tmp; |
615 | int ret; | 811 | int ret; |
@@ -626,15 +822,15 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
626 | lcdc_wait_bit(priv, _LDCNT2R, LDCNT2R_BR, 0); | 822 | lcdc_wait_bit(priv, _LDCNT2R, LDCNT2R_BR, 0); |
627 | 823 | ||
628 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { | 824 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { |
629 | ch = &priv->ch[k]; | 825 | const struct sh_mobile_lcdc_panel_cfg *panel; |
630 | 826 | ||
827 | ch = &priv->ch[k]; | ||
631 | if (!ch->enabled) | 828 | if (!ch->enabled) |
632 | continue; | 829 | continue; |
633 | 830 | ||
634 | board_cfg = &ch->cfg.board_cfg; | 831 | panel = &ch->cfg->panel_cfg; |
635 | if (board_cfg->setup_sys) { | 832 | if (panel->setup_sys) { |
636 | ret = board_cfg->setup_sys(board_cfg->board_data, ch, | 833 | ret = panel->setup_sys(ch, &sh_mobile_lcdc_sys_bus_ops); |
637 | &sh_mobile_lcdc_sys_bus_ops); | ||
638 | if (ret) | 834 | if (ret) |
639 | return ret; | 835 | return ret; |
640 | } | 836 | } |
@@ -642,33 +838,30 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
642 | 838 | ||
643 | /* Compute frame buffer base address and pitch for each channel. */ | 839 | /* Compute frame buffer base address and pitch for each channel. */ |
644 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { | 840 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { |
645 | struct sh_mobile_meram_cfg *cfg; | ||
646 | int pixelformat; | 841 | int pixelformat; |
842 | void *meram; | ||
647 | 843 | ||
648 | ch = &priv->ch[k]; | 844 | ch = &priv->ch[k]; |
649 | if (!ch->enabled) | 845 | if (!ch->enabled) |
650 | continue; | 846 | continue; |
651 | 847 | ||
652 | ch->base_addr_y = ch->info->fix.smem_start; | 848 | ch->base_addr_y = ch->dma_handle; |
653 | ch->base_addr_c = ch->base_addr_y | 849 | ch->base_addr_c = ch->base_addr_y + ch->xres * ch->yres_virtual; |
654 | + ch->info->var.xres | ||
655 | * ch->info->var.yres_virtual; | ||
656 | ch->pitch = ch->info->fix.line_length; | ||
657 | 850 | ||
658 | /* Enable MERAM if possible. */ | 851 | /* Enable MERAM if possible. */ |
659 | cfg = ch->cfg.meram_cfg; | 852 | if (mdev == NULL || mdev->ops == NULL || |
660 | if (mdev == NULL || mdev->ops == NULL || cfg == NULL) | 853 | ch->cfg->meram_cfg == NULL) |
661 | continue; | 854 | continue; |
662 | 855 | ||
663 | /* we need to de-init configured ICBs before we can | 856 | /* we need to de-init configured ICBs before we can |
664 | * re-initialize them. | 857 | * re-initialize them. |
665 | */ | 858 | */ |
666 | if (ch->meram_enabled) { | 859 | if (ch->meram) { |
667 | mdev->ops->meram_unregister(mdev, cfg); | 860 | mdev->ops->meram_unregister(mdev, ch->meram); |
668 | ch->meram_enabled = 0; | 861 | ch->meram = NULL; |
669 | } | 862 | } |
670 | 863 | ||
671 | switch (sh_mobile_format_fourcc(&ch->info->var)) { | 864 | switch (ch->format->fourcc) { |
672 | case V4L2_PIX_FMT_NV12: | 865 | case V4L2_PIX_FMT_NV12: |
673 | case V4L2_PIX_FMT_NV21: | 866 | case V4L2_PIX_FMT_NV21: |
674 | case V4L2_PIX_FMT_NV16: | 867 | case V4L2_PIX_FMT_NV16: |
@@ -687,13 +880,15 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
687 | break; | 880 | break; |
688 | } | 881 | } |
689 | 882 | ||
690 | ret = mdev->ops->meram_register(mdev, cfg, ch->pitch, | 883 | meram = mdev->ops->meram_register(mdev, ch->cfg->meram_cfg, |
691 | ch->info->var.yres, pixelformat, | 884 | ch->pitch, ch->yres, pixelformat, |
692 | ch->base_addr_y, ch->base_addr_c, | ||
693 | &ch->base_addr_y, &ch->base_addr_c, | ||
694 | &ch->pitch); | 885 | &ch->pitch); |
695 | if (!ret) | 886 | if (!IS_ERR(meram)) { |
696 | ch->meram_enabled = 1; | 887 | mdev->ops->meram_update(mdev, meram, |
888 | ch->base_addr_y, ch->base_addr_c, | ||
889 | &ch->base_addr_y, &ch->base_addr_c); | ||
890 | ch->meram = meram; | ||
891 | } | ||
697 | } | 892 | } |
698 | 893 | ||
699 | /* Start the LCDC. */ | 894 | /* Start the LCDC. */ |
@@ -707,7 +902,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
707 | if (!ch->enabled) | 902 | if (!ch->enabled) |
708 | continue; | 903 | continue; |
709 | 904 | ||
710 | tmp = ch->cfg.sys_bus_cfg.deferred_io_msec; | 905 | tmp = ch->cfg->sys_bus_cfg.deferred_io_msec; |
711 | if (ch->ldmt1r_value & LDMT1R_IFM && tmp) { | 906 | if (ch->ldmt1r_value & LDMT1R_IFM && tmp) { |
712 | ch->defio.deferred_io = sh_mobile_lcdc_deferred_io; | 907 | ch->defio.deferred_io = sh_mobile_lcdc_deferred_io; |
713 | ch->defio.delay = msecs_to_jiffies(tmp); | 908 | ch->defio.delay = msecs_to_jiffies(tmp); |
@@ -715,11 +910,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
715 | fb_deferred_io_init(ch->info); | 910 | fb_deferred_io_init(ch->info); |
716 | } | 911 | } |
717 | 912 | ||
718 | board_cfg = &ch->cfg.board_cfg; | 913 | sh_mobile_lcdc_display_on(ch); |
719 | if (board_cfg->display_on && try_module_get(board_cfg->owner)) { | ||
720 | board_cfg->display_on(board_cfg->board_data, ch->info); | ||
721 | module_put(board_cfg->owner); | ||
722 | } | ||
723 | 914 | ||
724 | if (ch->bl) { | 915 | if (ch->bl) { |
725 | ch->bl->props.power = FB_BLANK_UNBLANK; | 916 | ch->bl->props.power = FB_BLANK_UNBLANK; |
@@ -733,7 +924,6 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
733 | static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) | 924 | static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) |
734 | { | 925 | { |
735 | struct sh_mobile_lcdc_chan *ch; | 926 | struct sh_mobile_lcdc_chan *ch; |
736 | struct sh_mobile_lcdc_board_cfg *board_cfg; | ||
737 | int k; | 927 | int k; |
738 | 928 | ||
739 | /* clean up deferred io and ask board code to disable panel */ | 929 | /* clean up deferred io and ask board code to disable panel */ |
@@ -760,20 +950,14 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) | |||
760 | backlight_update_status(ch->bl); | 950 | backlight_update_status(ch->bl); |
761 | } | 951 | } |
762 | 952 | ||
763 | board_cfg = &ch->cfg.board_cfg; | 953 | sh_mobile_lcdc_display_off(ch); |
764 | if (board_cfg->display_off && try_module_get(board_cfg->owner)) { | ||
765 | board_cfg->display_off(board_cfg->board_data); | ||
766 | module_put(board_cfg->owner); | ||
767 | } | ||
768 | 954 | ||
769 | /* disable the meram */ | 955 | /* disable the meram */ |
770 | if (ch->meram_enabled) { | 956 | if (ch->meram) { |
771 | struct sh_mobile_meram_cfg *cfg; | ||
772 | struct sh_mobile_meram_info *mdev; | 957 | struct sh_mobile_meram_info *mdev; |
773 | cfg = ch->cfg.meram_cfg; | ||
774 | mdev = priv->meram_dev; | 958 | mdev = priv->meram_dev; |
775 | mdev->ops->meram_unregister(mdev, cfg); | 959 | mdev->ops->meram_unregister(mdev, ch->meram); |
776 | ch->meram_enabled = 0; | 960 | ch->meram = 0; |
777 | } | 961 | } |
778 | 962 | ||
779 | } | 963 | } |
@@ -790,86 +974,9 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) | |||
790 | sh_mobile_lcdc_clk_off(priv); | 974 | sh_mobile_lcdc_clk_off(priv); |
791 | } | 975 | } |
792 | 976 | ||
793 | static int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch) | 977 | /* ----------------------------------------------------------------------------- |
794 | { | 978 | * Frame buffer operations |
795 | int interface_type = ch->cfg.interface_type; | 979 | */ |
796 | |||
797 | switch (interface_type) { | ||
798 | case RGB8: | ||
799 | case RGB9: | ||
800 | case RGB12A: | ||
801 | case RGB12B: | ||
802 | case RGB16: | ||
803 | case RGB18: | ||
804 | case RGB24: | ||
805 | case SYS8A: | ||
806 | case SYS8B: | ||
807 | case SYS8C: | ||
808 | case SYS8D: | ||
809 | case SYS9: | ||
810 | case SYS12: | ||
811 | case SYS16A: | ||
812 | case SYS16B: | ||
813 | case SYS16C: | ||
814 | case SYS18: | ||
815 | case SYS24: | ||
816 | break; | ||
817 | default: | ||
818 | return -EINVAL; | ||
819 | } | ||
820 | |||
821 | /* SUBLCD only supports SYS interface */ | ||
822 | if (lcdc_chan_is_sublcd(ch)) { | ||
823 | if (!(interface_type & LDMT1R_IFM)) | ||
824 | return -EINVAL; | ||
825 | |||
826 | interface_type &= ~LDMT1R_IFM; | ||
827 | } | ||
828 | |||
829 | ch->ldmt1r_value = interface_type; | ||
830 | return 0; | ||
831 | } | ||
832 | |||
833 | static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev, | ||
834 | int clock_source, | ||
835 | struct sh_mobile_lcdc_priv *priv) | ||
836 | { | ||
837 | char *str; | ||
838 | |||
839 | switch (clock_source) { | ||
840 | case LCDC_CLK_BUS: | ||
841 | str = "bus_clk"; | ||
842 | priv->lddckr = LDDCKR_ICKSEL_BUS; | ||
843 | break; | ||
844 | case LCDC_CLK_PERIPHERAL: | ||
845 | str = "peripheral_clk"; | ||
846 | priv->lddckr = LDDCKR_ICKSEL_MIPI; | ||
847 | break; | ||
848 | case LCDC_CLK_EXTERNAL: | ||
849 | str = NULL; | ||
850 | priv->lddckr = LDDCKR_ICKSEL_HDMI; | ||
851 | break; | ||
852 | default: | ||
853 | return -EINVAL; | ||
854 | } | ||
855 | |||
856 | if (str) { | ||
857 | priv->dot_clk = clk_get(&pdev->dev, str); | ||
858 | if (IS_ERR(priv->dot_clk)) { | ||
859 | dev_err(&pdev->dev, "cannot get dot clock %s\n", str); | ||
860 | return PTR_ERR(priv->dot_clk); | ||
861 | } | ||
862 | } | ||
863 | |||
864 | /* Runtime PM support involves two step for this driver: | ||
865 | * 1) Enable Runtime PM | ||
866 | * 2) Force Runtime PM Resume since hardware is accessed from probe() | ||
867 | */ | ||
868 | priv->dev = &pdev->dev; | ||
869 | pm_runtime_enable(priv->dev); | ||
870 | pm_runtime_resume(priv->dev); | ||
871 | return 0; | ||
872 | } | ||
873 | 980 | ||
874 | static int sh_mobile_lcdc_setcolreg(u_int regno, | 981 | static int sh_mobile_lcdc_setcolreg(u_int regno, |
875 | u_int red, u_int green, u_int blue, | 982 | u_int red, u_int green, u_int blue, |
@@ -936,14 +1043,12 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, | |||
936 | unsigned long new_pan_offset; | 1043 | unsigned long new_pan_offset; |
937 | unsigned long base_addr_y, base_addr_c; | 1044 | unsigned long base_addr_y, base_addr_c; |
938 | unsigned long c_offset; | 1045 | unsigned long c_offset; |
939 | bool yuv = sh_mobile_format_is_yuv(&info->var); | ||
940 | 1046 | ||
941 | if (!yuv) | 1047 | if (!ch->format->yuv) |
942 | new_pan_offset = var->yoffset * info->fix.line_length | 1048 | new_pan_offset = var->yoffset * ch->pitch |
943 | + var->xoffset * (info->var.bits_per_pixel / 8); | 1049 | + var->xoffset * (ch->format->bpp / 8); |
944 | else | 1050 | else |
945 | new_pan_offset = var->yoffset * info->fix.line_length | 1051 | new_pan_offset = var->yoffset * ch->pitch + var->xoffset; |
946 | + var->xoffset; | ||
947 | 1052 | ||
948 | if (new_pan_offset == ch->pan_offset) | 1053 | if (new_pan_offset == ch->pan_offset) |
949 | return 0; /* No change, do nothing */ | 1054 | return 0; /* No change, do nothing */ |
@@ -952,39 +1057,33 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, | |||
952 | 1057 | ||
953 | /* Set the source address for the next refresh */ | 1058 | /* Set the source address for the next refresh */ |
954 | base_addr_y = ch->dma_handle + new_pan_offset; | 1059 | base_addr_y = ch->dma_handle + new_pan_offset; |
955 | if (yuv) { | 1060 | if (ch->format->yuv) { |
956 | /* Set y offset */ | 1061 | /* Set y offset */ |
957 | c_offset = var->yoffset * info->fix.line_length | 1062 | c_offset = var->yoffset * ch->pitch |
958 | * (info->var.bits_per_pixel - 8) / 8; | 1063 | * (ch->format->bpp - 8) / 8; |
959 | base_addr_c = ch->dma_handle | 1064 | base_addr_c = ch->dma_handle + ch->xres * ch->yres_virtual |
960 | + info->var.xres * info->var.yres_virtual | ||
961 | + c_offset; | 1065 | + c_offset; |
962 | /* Set x offset */ | 1066 | /* Set x offset */ |
963 | if (sh_mobile_format_fourcc(&info->var) == V4L2_PIX_FMT_NV24) | 1067 | if (ch->format->fourcc == V4L2_PIX_FMT_NV24) |
964 | base_addr_c += 2 * var->xoffset; | 1068 | base_addr_c += 2 * var->xoffset; |
965 | else | 1069 | else |
966 | base_addr_c += var->xoffset; | 1070 | base_addr_c += var->xoffset; |
967 | } | 1071 | } |
968 | 1072 | ||
969 | if (ch->meram_enabled) { | 1073 | if (ch->meram) { |
970 | struct sh_mobile_meram_cfg *cfg; | ||
971 | struct sh_mobile_meram_info *mdev; | 1074 | struct sh_mobile_meram_info *mdev; |
972 | int ret; | ||
973 | 1075 | ||
974 | cfg = ch->cfg.meram_cfg; | ||
975 | mdev = priv->meram_dev; | 1076 | mdev = priv->meram_dev; |
976 | ret = mdev->ops->meram_update(mdev, cfg, | 1077 | mdev->ops->meram_update(mdev, ch->meram, |
977 | base_addr_y, base_addr_c, | 1078 | base_addr_y, base_addr_c, |
978 | &base_addr_y, &base_addr_c); | 1079 | &base_addr_y, &base_addr_c); |
979 | if (ret) | ||
980 | return ret; | ||
981 | } | 1080 | } |
982 | 1081 | ||
983 | ch->base_addr_y = base_addr_y; | 1082 | ch->base_addr_y = base_addr_y; |
984 | ch->base_addr_c = base_addr_c; | 1083 | ch->base_addr_c = base_addr_c; |
985 | 1084 | ||
986 | lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y); | 1085 | lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y); |
987 | if (yuv) | 1086 | if (ch->format->yuv) |
988 | lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c); | 1087 | lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c); |
989 | 1088 | ||
990 | if (lcdc_chan_is_sublcd(ch)) | 1089 | if (lcdc_chan_is_sublcd(ch)) |
@@ -999,27 +1098,6 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, | |||
999 | return 0; | 1098 | return 0; |
1000 | } | 1099 | } |
1001 | 1100 | ||
1002 | static int sh_mobile_wait_for_vsync(struct fb_info *info) | ||
1003 | { | ||
1004 | struct sh_mobile_lcdc_chan *ch = info->par; | ||
1005 | unsigned long ldintr; | ||
1006 | int ret; | ||
1007 | |||
1008 | /* Enable VSync End interrupt and be careful not to acknowledge any | ||
1009 | * pending interrupt. | ||
1010 | */ | ||
1011 | ldintr = lcdc_read(ch->lcdc, _LDINTR); | ||
1012 | ldintr |= LDINTR_VEE | LDINTR_STATUS_MASK; | ||
1013 | lcdc_write(ch->lcdc, _LDINTR, ldintr); | ||
1014 | |||
1015 | ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion, | ||
1016 | msecs_to_jiffies(100)); | ||
1017 | if (!ret) | ||
1018 | return -ETIMEDOUT; | ||
1019 | |||
1020 | return 0; | ||
1021 | } | ||
1022 | |||
1023 | static int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd, | 1101 | static int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd, |
1024 | unsigned long arg) | 1102 | unsigned long arg) |
1025 | { | 1103 | { |
@@ -1027,7 +1105,7 @@ static int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd, | |||
1027 | 1105 | ||
1028 | switch (cmd) { | 1106 | switch (cmd) { |
1029 | case FBIO_WAITFORVSYNC: | 1107 | case FBIO_WAITFORVSYNC: |
1030 | retval = sh_mobile_wait_for_vsync(info); | 1108 | retval = sh_mobile_wait_for_vsync(info->par); |
1031 | break; | 1109 | break; |
1032 | 1110 | ||
1033 | default: | 1111 | default: |
@@ -1040,7 +1118,8 @@ static int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd, | |||
1040 | static void sh_mobile_fb_reconfig(struct fb_info *info) | 1118 | static void sh_mobile_fb_reconfig(struct fb_info *info) |
1041 | { | 1119 | { |
1042 | struct sh_mobile_lcdc_chan *ch = info->par; | 1120 | struct sh_mobile_lcdc_chan *ch = info->par; |
1043 | struct fb_videomode mode1, mode2; | 1121 | struct fb_var_screeninfo var; |
1122 | struct fb_videomode mode; | ||
1044 | struct fb_event event; | 1123 | struct fb_event event; |
1045 | int evnt = FB_EVENT_MODE_CHANGE_ALL; | 1124 | int evnt = FB_EVENT_MODE_CHANGE_ALL; |
1046 | 1125 | ||
@@ -1048,14 +1127,19 @@ static void sh_mobile_fb_reconfig(struct fb_info *info) | |||
1048 | /* More framebuffer users are active */ | 1127 | /* More framebuffer users are active */ |
1049 | return; | 1128 | return; |
1050 | 1129 | ||
1051 | fb_var_to_videomode(&mode1, &ch->display_var); | 1130 | fb_var_to_videomode(&mode, &info->var); |
1052 | fb_var_to_videomode(&mode2, &info->var); | ||
1053 | 1131 | ||
1054 | if (fb_mode_is_equal(&mode1, &mode2)) | 1132 | if (fb_mode_is_equal(&ch->display.mode, &mode)) |
1055 | return; | 1133 | return; |
1056 | 1134 | ||
1057 | /* Display has been re-plugged, framebuffer is free now, reconfigure */ | 1135 | /* Display has been re-plugged, framebuffer is free now, reconfigure */ |
1058 | if (fb_set_var(info, &ch->display_var) < 0) | 1136 | var = info->var; |
1137 | fb_videomode_to_var(&var, &ch->display.mode); | ||
1138 | var.width = ch->display.width; | ||
1139 | var.height = ch->display.height; | ||
1140 | var.activate = FB_ACTIVATE_NOW; | ||
1141 | |||
1142 | if (fb_set_var(info, &var) < 0) | ||
1059 | /* Couldn't reconfigure, hopefully, can continue as before */ | 1143 | /* Couldn't reconfigure, hopefully, can continue as before */ |
1060 | return; | 1144 | return; |
1061 | 1145 | ||
@@ -1065,7 +1149,7 @@ static void sh_mobile_fb_reconfig(struct fb_info *info) | |||
1065 | * user event, we have to call the chain ourselves. | 1149 | * user event, we have to call the chain ourselves. |
1066 | */ | 1150 | */ |
1067 | event.info = info; | 1151 | event.info = info; |
1068 | event.data = &mode1; | 1152 | event.data = &ch->display.mode; |
1069 | fb_notifier_call_chain(evnt, &event); | 1153 | fb_notifier_call_chain(evnt, &event); |
1070 | } | 1154 | } |
1071 | 1155 | ||
@@ -1124,8 +1208,8 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in | |||
1124 | * distance between two modes is defined as the size of the | 1208 | * distance between two modes is defined as the size of the |
1125 | * non-overlapping parts of the two rectangles. | 1209 | * non-overlapping parts of the two rectangles. |
1126 | */ | 1210 | */ |
1127 | for (i = 0; i < ch->cfg.num_cfg; ++i) { | 1211 | for (i = 0; i < ch->cfg->num_modes; ++i) { |
1128 | const struct fb_videomode *mode = &ch->cfg.lcd_cfg[i]; | 1212 | const struct fb_videomode *mode = &ch->cfg->lcd_modes[i]; |
1129 | unsigned int dist; | 1213 | unsigned int dist; |
1130 | 1214 | ||
1131 | /* We can only round up. */ | 1215 | /* We can only round up. */ |
@@ -1144,7 +1228,7 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in | |||
1144 | } | 1228 | } |
1145 | 1229 | ||
1146 | /* If no available mode can be used, return an error. */ | 1230 | /* If no available mode can be used, return an error. */ |
1147 | if (ch->cfg.num_cfg != 0) { | 1231 | if (ch->cfg->num_modes != 0) { |
1148 | if (best_dist == (unsigned int)-1) | 1232 | if (best_dist == (unsigned int)-1) |
1149 | return -EINVAL; | 1233 | return -EINVAL; |
1150 | 1234 | ||
@@ -1161,32 +1245,17 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in | |||
1161 | var->yres_virtual = var->yres; | 1245 | var->yres_virtual = var->yres; |
1162 | 1246 | ||
1163 | if (sh_mobile_format_is_fourcc(var)) { | 1247 | if (sh_mobile_format_is_fourcc(var)) { |
1164 | switch (var->grayscale) { | 1248 | const struct sh_mobile_lcdc_format_info *format; |
1165 | case V4L2_PIX_FMT_NV12: | 1249 | |
1166 | case V4L2_PIX_FMT_NV21: | 1250 | format = sh_mobile_format_info(var->grayscale); |
1167 | var->bits_per_pixel = 12; | 1251 | if (format == NULL) |
1168 | break; | ||
1169 | case V4L2_PIX_FMT_RGB565: | ||
1170 | case V4L2_PIX_FMT_NV16: | ||
1171 | case V4L2_PIX_FMT_NV61: | ||
1172 | var->bits_per_pixel = 16; | ||
1173 | break; | ||
1174 | case V4L2_PIX_FMT_BGR24: | ||
1175 | case V4L2_PIX_FMT_NV24: | ||
1176 | case V4L2_PIX_FMT_NV42: | ||
1177 | var->bits_per_pixel = 24; | ||
1178 | break; | ||
1179 | case V4L2_PIX_FMT_BGR32: | ||
1180 | var->bits_per_pixel = 32; | ||
1181 | break; | ||
1182 | default: | ||
1183 | return -EINVAL; | 1252 | return -EINVAL; |
1184 | } | 1253 | var->bits_per_pixel = format->bpp; |
1185 | 1254 | ||
1186 | /* Default to RGB and JPEG color-spaces for RGB and YUV formats | 1255 | /* Default to RGB and JPEG color-spaces for RGB and YUV formats |
1187 | * respectively. | 1256 | * respectively. |
1188 | */ | 1257 | */ |
1189 | if (!sh_mobile_format_is_yuv(var)) | 1258 | if (!format->yuv) |
1190 | var->colorspace = V4L2_COLORSPACE_SRGB; | 1259 | var->colorspace = V4L2_COLORSPACE_SRGB; |
1191 | else if (var->colorspace != V4L2_COLORSPACE_REC709) | 1260 | else if (var->colorspace != V4L2_COLORSPACE_REC709) |
1192 | var->colorspace = V4L2_COLORSPACE_JPEG; | 1261 | var->colorspace = V4L2_COLORSPACE_JPEG; |
@@ -1246,22 +1315,28 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in | |||
1246 | static int sh_mobile_set_par(struct fb_info *info) | 1315 | static int sh_mobile_set_par(struct fb_info *info) |
1247 | { | 1316 | { |
1248 | struct sh_mobile_lcdc_chan *ch = info->par; | 1317 | struct sh_mobile_lcdc_chan *ch = info->par; |
1249 | u32 line_length = info->fix.line_length; | ||
1250 | int ret; | 1318 | int ret; |
1251 | 1319 | ||
1252 | sh_mobile_lcdc_stop(ch->lcdc); | 1320 | sh_mobile_lcdc_stop(ch->lcdc); |
1253 | 1321 | ||
1254 | if (sh_mobile_format_is_yuv(&info->var)) | 1322 | ch->format = sh_mobile_format_info(sh_mobile_format_fourcc(&info->var)); |
1255 | info->fix.line_length = info->var.xres; | 1323 | ch->colorspace = info->var.colorspace; |
1324 | |||
1325 | ch->xres = info->var.xres; | ||
1326 | ch->xres_virtual = info->var.xres_virtual; | ||
1327 | ch->yres = info->var.yres; | ||
1328 | ch->yres_virtual = info->var.yres_virtual; | ||
1329 | |||
1330 | if (ch->format->yuv) | ||
1331 | ch->pitch = info->var.xres; | ||
1256 | else | 1332 | else |
1257 | info->fix.line_length = info->var.xres | 1333 | ch->pitch = info->var.xres * ch->format->bpp / 8; |
1258 | * info->var.bits_per_pixel / 8; | ||
1259 | 1334 | ||
1260 | ret = sh_mobile_lcdc_start(ch->lcdc); | 1335 | ret = sh_mobile_lcdc_start(ch->lcdc); |
1261 | if (ret < 0) { | 1336 | if (ret < 0) |
1262 | dev_err(info->dev, "%s: unable to restart LCDC\n", __func__); | 1337 | dev_err(info->dev, "%s: unable to restart LCDC\n", __func__); |
1263 | info->fix.line_length = line_length; | 1338 | |
1264 | } | 1339 | info->fix.line_length = ch->pitch; |
1265 | 1340 | ||
1266 | if (sh_mobile_format_is_fourcc(&info->var)) { | 1341 | if (sh_mobile_format_is_fourcc(&info->var)) { |
1267 | info->fix.type = FB_TYPE_FOURCC; | 1342 | info->fix.type = FB_TYPE_FOURCC; |
@@ -1290,8 +1365,8 @@ static int sh_mobile_lcdc_blank(int blank, struct fb_info *info) | |||
1290 | /* blank the screen? */ | 1365 | /* blank the screen? */ |
1291 | if (blank > FB_BLANK_UNBLANK && ch->blank_status == FB_BLANK_UNBLANK) { | 1366 | if (blank > FB_BLANK_UNBLANK && ch->blank_status == FB_BLANK_UNBLANK) { |
1292 | struct fb_fillrect rect = { | 1367 | struct fb_fillrect rect = { |
1293 | .width = info->var.xres, | 1368 | .width = ch->xres, |
1294 | .height = info->var.yres, | 1369 | .height = ch->yres, |
1295 | }; | 1370 | }; |
1296 | sh_mobile_lcdc_fillrect(info, &rect); | 1371 | sh_mobile_lcdc_fillrect(info, &rect); |
1297 | } | 1372 | } |
@@ -1307,8 +1382,8 @@ static int sh_mobile_lcdc_blank(int blank, struct fb_info *info) | |||
1307 | * mode will reenable the clocks and update the screen in time, | 1382 | * mode will reenable the clocks and update the screen in time, |
1308 | * so it does not need this. */ | 1383 | * so it does not need this. */ |
1309 | if (!info->fbdefio) { | 1384 | if (!info->fbdefio) { |
1310 | sh_mobile_wait_for_vsync(info); | 1385 | sh_mobile_wait_for_vsync(ch); |
1311 | sh_mobile_wait_for_vsync(info); | 1386 | sh_mobile_wait_for_vsync(ch); |
1312 | } | 1387 | } |
1313 | sh_mobile_lcdc_clk_off(p); | 1388 | sh_mobile_lcdc_clk_off(p); |
1314 | } | 1389 | } |
@@ -1334,25 +1409,161 @@ static struct fb_ops sh_mobile_lcdc_ops = { | |||
1334 | .fb_set_par = sh_mobile_set_par, | 1409 | .fb_set_par = sh_mobile_set_par, |
1335 | }; | 1410 | }; |
1336 | 1411 | ||
1412 | static void | ||
1413 | sh_mobile_lcdc_channel_fb_unregister(struct sh_mobile_lcdc_chan *ch) | ||
1414 | { | ||
1415 | if (ch->info && ch->info->dev) | ||
1416 | unregister_framebuffer(ch->info); | ||
1417 | } | ||
1418 | |||
1419 | static int __devinit | ||
1420 | sh_mobile_lcdc_channel_fb_register(struct sh_mobile_lcdc_chan *ch) | ||
1421 | { | ||
1422 | struct fb_info *info = ch->info; | ||
1423 | int ret; | ||
1424 | |||
1425 | if (info->fbdefio) { | ||
1426 | ch->sglist = vmalloc(sizeof(struct scatterlist) * | ||
1427 | ch->fb_size >> PAGE_SHIFT); | ||
1428 | if (!ch->sglist) { | ||
1429 | dev_err(ch->lcdc->dev, "cannot allocate sglist\n"); | ||
1430 | return -ENOMEM; | ||
1431 | } | ||
1432 | } | ||
1433 | |||
1434 | info->bl_dev = ch->bl; | ||
1435 | |||
1436 | ret = register_framebuffer(info); | ||
1437 | if (ret < 0) | ||
1438 | return ret; | ||
1439 | |||
1440 | dev_info(ch->lcdc->dev, "registered %s/%s as %dx%d %dbpp.\n", | ||
1441 | dev_name(ch->lcdc->dev), (ch->cfg->chan == LCDC_CHAN_MAINLCD) ? | ||
1442 | "mainlcd" : "sublcd", info->var.xres, info->var.yres, | ||
1443 | info->var.bits_per_pixel); | ||
1444 | |||
1445 | /* deferred io mode: disable clock to save power */ | ||
1446 | if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED) | ||
1447 | sh_mobile_lcdc_clk_off(ch->lcdc); | ||
1448 | |||
1449 | return ret; | ||
1450 | } | ||
1451 | |||
1452 | static void | ||
1453 | sh_mobile_lcdc_channel_fb_cleanup(struct sh_mobile_lcdc_chan *ch) | ||
1454 | { | ||
1455 | struct fb_info *info = ch->info; | ||
1456 | |||
1457 | if (!info || !info->device) | ||
1458 | return; | ||
1459 | |||
1460 | if (ch->sglist) | ||
1461 | vfree(ch->sglist); | ||
1462 | |||
1463 | fb_dealloc_cmap(&info->cmap); | ||
1464 | framebuffer_release(info); | ||
1465 | } | ||
1466 | |||
1467 | static int __devinit | ||
1468 | sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch, | ||
1469 | const struct fb_videomode *mode, | ||
1470 | unsigned int num_modes) | ||
1471 | { | ||
1472 | struct sh_mobile_lcdc_priv *priv = ch->lcdc; | ||
1473 | struct fb_var_screeninfo *var; | ||
1474 | struct fb_info *info; | ||
1475 | int ret; | ||
1476 | |||
1477 | /* Allocate and initialize the frame buffer device. Create the modes | ||
1478 | * list and allocate the color map. | ||
1479 | */ | ||
1480 | info = framebuffer_alloc(0, priv->dev); | ||
1481 | if (info == NULL) { | ||
1482 | dev_err(priv->dev, "unable to allocate fb_info\n"); | ||
1483 | return -ENOMEM; | ||
1484 | } | ||
1485 | |||
1486 | ch->info = info; | ||
1487 | |||
1488 | info->flags = FBINFO_FLAG_DEFAULT; | ||
1489 | info->fbops = &sh_mobile_lcdc_ops; | ||
1490 | info->device = priv->dev; | ||
1491 | info->screen_base = ch->fb_mem; | ||
1492 | info->pseudo_palette = &ch->pseudo_palette; | ||
1493 | info->par = ch; | ||
1494 | |||
1495 | fb_videomode_to_modelist(mode, num_modes, &info->modelist); | ||
1496 | |||
1497 | ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0); | ||
1498 | if (ret < 0) { | ||
1499 | dev_err(priv->dev, "unable to allocate cmap\n"); | ||
1500 | return ret; | ||
1501 | } | ||
1502 | |||
1503 | /* Initialize fixed screen information. Restrict pan to 2 lines steps | ||
1504 | * for NV12 and NV21. | ||
1505 | */ | ||
1506 | info->fix = sh_mobile_lcdc_fix; | ||
1507 | info->fix.smem_start = ch->dma_handle; | ||
1508 | info->fix.smem_len = ch->fb_size; | ||
1509 | info->fix.line_length = ch->pitch; | ||
1510 | |||
1511 | if (ch->format->yuv) | ||
1512 | info->fix.visual = FB_VISUAL_FOURCC; | ||
1513 | else | ||
1514 | info->fix.visual = FB_VISUAL_TRUECOLOR; | ||
1515 | |||
1516 | if (ch->format->fourcc == V4L2_PIX_FMT_NV12 || | ||
1517 | ch->format->fourcc == V4L2_PIX_FMT_NV21) | ||
1518 | info->fix.ypanstep = 2; | ||
1519 | |||
1520 | /* Initialize variable screen information using the first mode as | ||
1521 | * default. The default Y virtual resolution is twice the panel size to | ||
1522 | * allow for double-buffering. | ||
1523 | */ | ||
1524 | var = &info->var; | ||
1525 | fb_videomode_to_var(var, mode); | ||
1526 | var->width = ch->cfg->panel_cfg.width; | ||
1527 | var->height = ch->cfg->panel_cfg.height; | ||
1528 | var->yres_virtual = var->yres * 2; | ||
1529 | var->activate = FB_ACTIVATE_NOW; | ||
1530 | |||
1531 | /* Use the legacy API by default for RGB formats, and the FOURCC API | ||
1532 | * for YUV formats. | ||
1533 | */ | ||
1534 | if (!ch->format->yuv) | ||
1535 | var->bits_per_pixel = ch->format->bpp; | ||
1536 | else | ||
1537 | var->grayscale = ch->format->fourcc; | ||
1538 | |||
1539 | ret = sh_mobile_check_var(var, info); | ||
1540 | if (ret) | ||
1541 | return ret; | ||
1542 | |||
1543 | return 0; | ||
1544 | } | ||
1545 | |||
1546 | /* ----------------------------------------------------------------------------- | ||
1547 | * Backlight | ||
1548 | */ | ||
1549 | |||
1337 | static int sh_mobile_lcdc_update_bl(struct backlight_device *bdev) | 1550 | static int sh_mobile_lcdc_update_bl(struct backlight_device *bdev) |
1338 | { | 1551 | { |
1339 | struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev); | 1552 | struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev); |
1340 | struct sh_mobile_lcdc_board_cfg *cfg = &ch->cfg.board_cfg; | ||
1341 | int brightness = bdev->props.brightness; | 1553 | int brightness = bdev->props.brightness; |
1342 | 1554 | ||
1343 | if (bdev->props.power != FB_BLANK_UNBLANK || | 1555 | if (bdev->props.power != FB_BLANK_UNBLANK || |
1344 | bdev->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK)) | 1556 | bdev->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK)) |
1345 | brightness = 0; | 1557 | brightness = 0; |
1346 | 1558 | ||
1347 | return cfg->set_brightness(cfg->board_data, brightness); | 1559 | return ch->cfg->bl_info.set_brightness(brightness); |
1348 | } | 1560 | } |
1349 | 1561 | ||
1350 | static int sh_mobile_lcdc_get_brightness(struct backlight_device *bdev) | 1562 | static int sh_mobile_lcdc_get_brightness(struct backlight_device *bdev) |
1351 | { | 1563 | { |
1352 | struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev); | 1564 | struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev); |
1353 | struct sh_mobile_lcdc_board_cfg *cfg = &ch->cfg.board_cfg; | ||
1354 | 1565 | ||
1355 | return cfg->get_brightness(cfg->board_data); | 1566 | return ch->cfg->bl_info.get_brightness(); |
1356 | } | 1567 | } |
1357 | 1568 | ||
1358 | static int sh_mobile_lcdc_check_fb(struct backlight_device *bdev, | 1569 | static int sh_mobile_lcdc_check_fb(struct backlight_device *bdev, |
@@ -1373,7 +1584,7 @@ static struct backlight_device *sh_mobile_lcdc_bl_probe(struct device *parent, | |||
1373 | { | 1584 | { |
1374 | struct backlight_device *bl; | 1585 | struct backlight_device *bl; |
1375 | 1586 | ||
1376 | bl = backlight_device_register(ch->cfg.bl_info.name, parent, ch, | 1587 | bl = backlight_device_register(ch->cfg->bl_info.name, parent, ch, |
1377 | &sh_mobile_lcdc_bl_ops, NULL); | 1588 | &sh_mobile_lcdc_bl_ops, NULL); |
1378 | if (IS_ERR(bl)) { | 1589 | if (IS_ERR(bl)) { |
1379 | dev_err(parent, "unable to register backlight device: %ld\n", | 1590 | dev_err(parent, "unable to register backlight device: %ld\n", |
@@ -1381,7 +1592,7 @@ static struct backlight_device *sh_mobile_lcdc_bl_probe(struct device *parent, | |||
1381 | return NULL; | 1592 | return NULL; |
1382 | } | 1593 | } |
1383 | 1594 | ||
1384 | bl->props.max_brightness = ch->cfg.bl_info.max_brightness; | 1595 | bl->props.max_brightness = ch->cfg->bl_info.max_brightness; |
1385 | bl->props.brightness = bl->props.max_brightness; | 1596 | bl->props.brightness = bl->props.max_brightness; |
1386 | backlight_update_status(bl); | 1597 | backlight_update_status(bl); |
1387 | 1598 | ||
@@ -1393,6 +1604,10 @@ static void sh_mobile_lcdc_bl_remove(struct backlight_device *bdev) | |||
1393 | backlight_device_unregister(bdev); | 1604 | backlight_device_unregister(bdev); |
1394 | } | 1605 | } |
1395 | 1606 | ||
1607 | /* ----------------------------------------------------------------------------- | ||
1608 | * Power management | ||
1609 | */ | ||
1610 | |||
1396 | static int sh_mobile_lcdc_suspend(struct device *dev) | 1611 | static int sh_mobile_lcdc_suspend(struct device *dev) |
1397 | { | 1612 | { |
1398 | struct platform_device *pdev = to_platform_device(dev); | 1613 | struct platform_device *pdev = to_platform_device(dev); |
@@ -1436,6 +1651,10 @@ static const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = { | |||
1436 | .runtime_resume = sh_mobile_lcdc_runtime_resume, | 1651 | .runtime_resume = sh_mobile_lcdc_runtime_resume, |
1437 | }; | 1652 | }; |
1438 | 1653 | ||
1654 | /* ----------------------------------------------------------------------------- | ||
1655 | * Framebuffer notifier | ||
1656 | */ | ||
1657 | |||
1439 | /* locking: called with info->lock held */ | 1658 | /* locking: called with info->lock held */ |
1440 | static int sh_mobile_lcdc_notify(struct notifier_block *nb, | 1659 | static int sh_mobile_lcdc_notify(struct notifier_block *nb, |
1441 | unsigned long action, void *data) | 1660 | unsigned long action, void *data) |
@@ -1443,7 +1662,6 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb, | |||
1443 | struct fb_event *event = data; | 1662 | struct fb_event *event = data; |
1444 | struct fb_info *info = event->info; | 1663 | struct fb_info *info = event->info; |
1445 | struct sh_mobile_lcdc_chan *ch = info->par; | 1664 | struct sh_mobile_lcdc_chan *ch = info->par; |
1446 | struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg; | ||
1447 | 1665 | ||
1448 | if (&ch->lcdc->notifier != nb) | 1666 | if (&ch->lcdc->notifier != nb) |
1449 | return NOTIFY_DONE; | 1667 | return NOTIFY_DONE; |
@@ -1453,10 +1671,7 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb, | |||
1453 | 1671 | ||
1454 | switch(action) { | 1672 | switch(action) { |
1455 | case FB_EVENT_SUSPEND: | 1673 | case FB_EVENT_SUSPEND: |
1456 | if (board_cfg->display_off && try_module_get(board_cfg->owner)) { | 1674 | sh_mobile_lcdc_display_off(ch); |
1457 | board_cfg->display_off(board_cfg->board_data); | ||
1458 | module_put(board_cfg->owner); | ||
1459 | } | ||
1460 | sh_mobile_lcdc_stop(ch->lcdc); | 1675 | sh_mobile_lcdc_stop(ch->lcdc); |
1461 | break; | 1676 | break; |
1462 | case FB_EVENT_RESUME: | 1677 | case FB_EVENT_RESUME: |
@@ -1464,47 +1679,60 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb, | |||
1464 | sh_mobile_fb_reconfig(info); | 1679 | sh_mobile_fb_reconfig(info); |
1465 | mutex_unlock(&ch->open_lock); | 1680 | mutex_unlock(&ch->open_lock); |
1466 | 1681 | ||
1467 | /* HDMI must be enabled before LCDC configuration */ | 1682 | sh_mobile_lcdc_display_on(ch); |
1468 | if (board_cfg->display_on && try_module_get(board_cfg->owner)) { | ||
1469 | board_cfg->display_on(board_cfg->board_data, info); | ||
1470 | module_put(board_cfg->owner); | ||
1471 | } | ||
1472 | |||
1473 | sh_mobile_lcdc_start(ch->lcdc); | 1683 | sh_mobile_lcdc_start(ch->lcdc); |
1474 | } | 1684 | } |
1475 | 1685 | ||
1476 | return NOTIFY_OK; | 1686 | return NOTIFY_OK; |
1477 | } | 1687 | } |
1478 | 1688 | ||
1689 | /* ----------------------------------------------------------------------------- | ||
1690 | * Probe/remove and driver init/exit | ||
1691 | */ | ||
1692 | |||
1693 | static const struct fb_videomode default_720p __devinitconst = { | ||
1694 | .name = "HDMI 720p", | ||
1695 | .xres = 1280, | ||
1696 | .yres = 720, | ||
1697 | |||
1698 | .left_margin = 220, | ||
1699 | .right_margin = 110, | ||
1700 | .hsync_len = 40, | ||
1701 | |||
1702 | .upper_margin = 20, | ||
1703 | .lower_margin = 5, | ||
1704 | .vsync_len = 5, | ||
1705 | |||
1706 | .pixclock = 13468, | ||
1707 | .refresh = 60, | ||
1708 | .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT, | ||
1709 | }; | ||
1710 | |||
1479 | static int sh_mobile_lcdc_remove(struct platform_device *pdev) | 1711 | static int sh_mobile_lcdc_remove(struct platform_device *pdev) |
1480 | { | 1712 | { |
1481 | struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev); | 1713 | struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev); |
1482 | struct fb_info *info; | ||
1483 | int i; | 1714 | int i; |
1484 | 1715 | ||
1485 | fb_unregister_client(&priv->notifier); | 1716 | fb_unregister_client(&priv->notifier); |
1486 | 1717 | ||
1487 | for (i = 0; i < ARRAY_SIZE(priv->ch); i++) | 1718 | for (i = 0; i < ARRAY_SIZE(priv->ch); i++) |
1488 | if (priv->ch[i].info && priv->ch[i].info->dev) | 1719 | sh_mobile_lcdc_channel_fb_unregister(&priv->ch[i]); |
1489 | unregister_framebuffer(priv->ch[i].info); | ||
1490 | 1720 | ||
1491 | sh_mobile_lcdc_stop(priv); | 1721 | sh_mobile_lcdc_stop(priv); |
1492 | 1722 | ||
1493 | for (i = 0; i < ARRAY_SIZE(priv->ch); i++) { | 1723 | for (i = 0; i < ARRAY_SIZE(priv->ch); i++) { |
1494 | info = priv->ch[i].info; | 1724 | struct sh_mobile_lcdc_chan *ch = &priv->ch[i]; |
1495 | 1725 | ||
1496 | if (!info || !info->device) | 1726 | if (ch->tx_dev) { |
1497 | continue; | 1727 | ch->tx_dev->lcdc = NULL; |
1728 | module_put(ch->cfg->tx_dev->dev.driver->owner); | ||
1729 | } | ||
1498 | 1730 | ||
1499 | if (priv->ch[i].sglist) | 1731 | sh_mobile_lcdc_channel_fb_cleanup(ch); |
1500 | vfree(priv->ch[i].sglist); | ||
1501 | 1732 | ||
1502 | if (info->screen_base) | 1733 | if (ch->fb_mem) |
1503 | dma_free_coherent(&pdev->dev, info->fix.smem_len, | 1734 | dma_free_coherent(&pdev->dev, ch->fb_size, |
1504 | info->screen_base, | 1735 | ch->fb_mem, ch->dma_handle); |
1505 | priv->ch[i].dma_handle); | ||
1506 | fb_dealloc_cmap(&info->cmap); | ||
1507 | framebuffer_release(info); | ||
1508 | } | 1736 | } |
1509 | 1737 | ||
1510 | for (i = 0; i < ARRAY_SIZE(priv->ch); i++) { | 1738 | for (i = 0; i < ARRAY_SIZE(priv->ch); i++) { |
@@ -1512,11 +1740,10 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev) | |||
1512 | sh_mobile_lcdc_bl_remove(priv->ch[i].bl); | 1740 | sh_mobile_lcdc_bl_remove(priv->ch[i].bl); |
1513 | } | 1741 | } |
1514 | 1742 | ||
1515 | if (priv->dot_clk) | 1743 | if (priv->dot_clk) { |
1744 | pm_runtime_disable(&pdev->dev); | ||
1516 | clk_put(priv->dot_clk); | 1745 | clk_put(priv->dot_clk); |
1517 | 1746 | } | |
1518 | if (priv->dev) | ||
1519 | pm_runtime_disable(priv->dev); | ||
1520 | 1747 | ||
1521 | if (priv->base) | 1748 | if (priv->base) |
1522 | iounmap(priv->base); | 1749 | iounmap(priv->base); |
@@ -1527,49 +1754,82 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev) | |||
1527 | return 0; | 1754 | return 0; |
1528 | } | 1755 | } |
1529 | 1756 | ||
1530 | static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch, | 1757 | static int __devinit sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch) |
1531 | struct device *dev) | ||
1532 | { | 1758 | { |
1533 | struct sh_mobile_lcdc_chan_cfg *cfg = &ch->cfg; | 1759 | int interface_type = ch->cfg->interface_type; |
1760 | |||
1761 | switch (interface_type) { | ||
1762 | case RGB8: | ||
1763 | case RGB9: | ||
1764 | case RGB12A: | ||
1765 | case RGB12B: | ||
1766 | case RGB16: | ||
1767 | case RGB18: | ||
1768 | case RGB24: | ||
1769 | case SYS8A: | ||
1770 | case SYS8B: | ||
1771 | case SYS8C: | ||
1772 | case SYS8D: | ||
1773 | case SYS9: | ||
1774 | case SYS12: | ||
1775 | case SYS16A: | ||
1776 | case SYS16B: | ||
1777 | case SYS16C: | ||
1778 | case SYS18: | ||
1779 | case SYS24: | ||
1780 | break; | ||
1781 | default: | ||
1782 | return -EINVAL; | ||
1783 | } | ||
1784 | |||
1785 | /* SUBLCD only supports SYS interface */ | ||
1786 | if (lcdc_chan_is_sublcd(ch)) { | ||
1787 | if (!(interface_type & LDMT1R_IFM)) | ||
1788 | return -EINVAL; | ||
1789 | |||
1790 | interface_type &= ~LDMT1R_IFM; | ||
1791 | } | ||
1792 | |||
1793 | ch->ldmt1r_value = interface_type; | ||
1794 | return 0; | ||
1795 | } | ||
1796 | |||
1797 | static int __devinit | ||
1798 | sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv, | ||
1799 | struct sh_mobile_lcdc_chan *ch) | ||
1800 | { | ||
1801 | const struct sh_mobile_lcdc_format_info *format; | ||
1802 | const struct sh_mobile_lcdc_chan_cfg *cfg = ch->cfg; | ||
1534 | const struct fb_videomode *max_mode; | 1803 | const struct fb_videomode *max_mode; |
1535 | const struct fb_videomode *mode; | 1804 | const struct fb_videomode *mode; |
1536 | struct fb_var_screeninfo *var; | 1805 | unsigned int num_modes; |
1537 | struct fb_info *info; | ||
1538 | unsigned int max_size; | 1806 | unsigned int max_size; |
1539 | int num_cfg; | 1807 | unsigned int i; |
1540 | void *buf; | ||
1541 | int ret; | ||
1542 | int i; | ||
1543 | 1808 | ||
1544 | mutex_init(&ch->open_lock); | 1809 | mutex_init(&ch->open_lock); |
1810 | ch->notify = sh_mobile_lcdc_display_notify; | ||
1545 | 1811 | ||
1546 | /* Allocate the frame buffer device. */ | 1812 | /* Validate the format. */ |
1547 | ch->info = framebuffer_alloc(0, dev); | 1813 | format = sh_mobile_format_info(cfg->fourcc); |
1548 | if (!ch->info) { | 1814 | if (format == NULL) { |
1549 | dev_err(dev, "unable to allocate fb_info\n"); | 1815 | dev_err(priv->dev, "Invalid FOURCC %08x.\n", cfg->fourcc); |
1550 | return -ENOMEM; | 1816 | return -EINVAL; |
1551 | } | 1817 | } |
1552 | 1818 | ||
1553 | info = ch->info; | ||
1554 | info->fbops = &sh_mobile_lcdc_ops; | ||
1555 | info->par = ch; | ||
1556 | info->pseudo_palette = &ch->pseudo_palette; | ||
1557 | info->flags = FBINFO_FLAG_DEFAULT; | ||
1558 | |||
1559 | /* Iterate through the modes to validate them and find the highest | 1819 | /* Iterate through the modes to validate them and find the highest |
1560 | * resolution. | 1820 | * resolution. |
1561 | */ | 1821 | */ |
1562 | max_mode = NULL; | 1822 | max_mode = NULL; |
1563 | max_size = 0; | 1823 | max_size = 0; |
1564 | 1824 | ||
1565 | for (i = 0, mode = cfg->lcd_cfg; i < cfg->num_cfg; i++, mode++) { | 1825 | for (i = 0, mode = cfg->lcd_modes; i < cfg->num_modes; i++, mode++) { |
1566 | unsigned int size = mode->yres * mode->xres; | 1826 | unsigned int size = mode->yres * mode->xres; |
1567 | 1827 | ||
1568 | /* NV12/NV21 buffers must have even number of lines */ | 1828 | /* NV12/NV21 buffers must have even number of lines */ |
1569 | if ((cfg->fourcc == V4L2_PIX_FMT_NV12 || | 1829 | if ((cfg->fourcc == V4L2_PIX_FMT_NV12 || |
1570 | cfg->fourcc == V4L2_PIX_FMT_NV21) && (mode->yres & 0x1)) { | 1830 | cfg->fourcc == V4L2_PIX_FMT_NV21) && (mode->yres & 0x1)) { |
1571 | dev_err(dev, "yres must be multiple of 2 for YCbCr420 " | 1831 | dev_err(priv->dev, "yres must be multiple of 2 for " |
1572 | "mode.\n"); | 1832 | "YCbCr420 mode.\n"); |
1573 | return -EINVAL; | 1833 | return -EINVAL; |
1574 | } | 1834 | } |
1575 | 1835 | ||
@@ -1582,93 +1842,59 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch, | |||
1582 | if (!max_size) | 1842 | if (!max_size) |
1583 | max_size = MAX_XRES * MAX_YRES; | 1843 | max_size = MAX_XRES * MAX_YRES; |
1584 | else | 1844 | else |
1585 | dev_dbg(dev, "Found largest videomode %ux%u\n", | 1845 | dev_dbg(priv->dev, "Found largest videomode %ux%u\n", |
1586 | max_mode->xres, max_mode->yres); | 1846 | max_mode->xres, max_mode->yres); |
1587 | 1847 | ||
1588 | /* Create the mode list. */ | 1848 | if (cfg->lcd_modes == NULL) { |
1589 | if (cfg->lcd_cfg == NULL) { | ||
1590 | mode = &default_720p; | 1849 | mode = &default_720p; |
1591 | num_cfg = 1; | 1850 | num_modes = 1; |
1592 | } else { | 1851 | } else { |
1593 | mode = cfg->lcd_cfg; | 1852 | mode = cfg->lcd_modes; |
1594 | num_cfg = cfg->num_cfg; | 1853 | num_modes = cfg->num_modes; |
1595 | } | 1854 | } |
1596 | 1855 | ||
1597 | fb_videomode_to_modelist(mode, num_cfg, &info->modelist); | 1856 | /* Use the first mode as default. */ |
1857 | ch->format = format; | ||
1858 | ch->xres = mode->xres; | ||
1859 | ch->xres_virtual = mode->xres; | ||
1860 | ch->yres = mode->yres; | ||
1861 | ch->yres_virtual = mode->yres * 2; | ||
1598 | 1862 | ||
1599 | /* Initialize variable screen information using the first mode as | 1863 | if (!format->yuv) { |
1600 | * default. The default Y virtual resolution is twice the panel size to | 1864 | ch->colorspace = V4L2_COLORSPACE_SRGB; |
1601 | * allow for double-buffering. | 1865 | ch->pitch = ch->xres * format->bpp / 8; |
1602 | */ | 1866 | } else { |
1603 | var = &info->var; | 1867 | ch->colorspace = V4L2_COLORSPACE_REC709; |
1604 | fb_videomode_to_var(var, mode); | 1868 | ch->pitch = ch->xres; |
1605 | var->width = cfg->lcd_size_cfg.width; | ||
1606 | var->height = cfg->lcd_size_cfg.height; | ||
1607 | var->yres_virtual = var->yres * 2; | ||
1608 | var->activate = FB_ACTIVATE_NOW; | ||
1609 | |||
1610 | switch (cfg->fourcc) { | ||
1611 | case V4L2_PIX_FMT_RGB565: | ||
1612 | var->bits_per_pixel = 16; | ||
1613 | break; | ||
1614 | case V4L2_PIX_FMT_BGR24: | ||
1615 | var->bits_per_pixel = 24; | ||
1616 | break; | ||
1617 | case V4L2_PIX_FMT_BGR32: | ||
1618 | var->bits_per_pixel = 32; | ||
1619 | break; | ||
1620 | default: | ||
1621 | var->grayscale = cfg->fourcc; | ||
1622 | break; | ||
1623 | } | 1869 | } |
1624 | 1870 | ||
1625 | /* Make sure the memory size check won't fail. smem_len is initialized | 1871 | ch->display.width = cfg->panel_cfg.width; |
1626 | * later based on var. | 1872 | ch->display.height = cfg->panel_cfg.height; |
1627 | */ | 1873 | ch->display.mode = *mode; |
1628 | info->fix.smem_len = UINT_MAX; | ||
1629 | ret = sh_mobile_check_var(var, info); | ||
1630 | if (ret) | ||
1631 | return ret; | ||
1632 | |||
1633 | max_size = max_size * var->bits_per_pixel / 8 * 2; | ||
1634 | 1874 | ||
1635 | /* Allocate frame buffer memory and color map. */ | 1875 | /* Allocate frame buffer memory. */ |
1636 | buf = dma_alloc_coherent(dev, max_size, &ch->dma_handle, GFP_KERNEL); | 1876 | ch->fb_size = max_size * format->bpp / 8 * 2; |
1637 | if (!buf) { | 1877 | ch->fb_mem = dma_alloc_coherent(priv->dev, ch->fb_size, &ch->dma_handle, |
1638 | dev_err(dev, "unable to allocate buffer\n"); | 1878 | GFP_KERNEL); |
1879 | if (ch->fb_mem == NULL) { | ||
1880 | dev_err(priv->dev, "unable to allocate buffer\n"); | ||
1639 | return -ENOMEM; | 1881 | return -ENOMEM; |
1640 | } | 1882 | } |
1641 | 1883 | ||
1642 | ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0); | 1884 | /* Initialize the transmitter device if present. */ |
1643 | if (ret < 0) { | 1885 | if (cfg->tx_dev) { |
1644 | dev_err(dev, "unable to allocate cmap\n"); | 1886 | if (!cfg->tx_dev->dev.driver || |
1645 | dma_free_coherent(dev, max_size, buf, ch->dma_handle); | 1887 | !try_module_get(cfg->tx_dev->dev.driver->owner)) { |
1646 | return ret; | 1888 | dev_warn(priv->dev, |
1647 | } | 1889 | "unable to get transmitter device\n"); |
1648 | 1890 | return -EINVAL; | |
1649 | /* Initialize fixed screen information. Restrict pan to 2 lines steps | 1891 | } |
1650 | * for NV12 and NV21. | 1892 | ch->tx_dev = platform_get_drvdata(cfg->tx_dev); |
1651 | */ | 1893 | ch->tx_dev->lcdc = ch; |
1652 | info->fix = sh_mobile_lcdc_fix; | 1894 | ch->tx_dev->def_mode = *mode; |
1653 | info->fix.smem_start = ch->dma_handle; | ||
1654 | info->fix.smem_len = max_size; | ||
1655 | if (cfg->fourcc == V4L2_PIX_FMT_NV12 || | ||
1656 | cfg->fourcc == V4L2_PIX_FMT_NV21) | ||
1657 | info->fix.ypanstep = 2; | ||
1658 | |||
1659 | if (sh_mobile_format_is_yuv(var)) { | ||
1660 | info->fix.line_length = var->xres; | ||
1661 | info->fix.visual = FB_VISUAL_FOURCC; | ||
1662 | } else { | ||
1663 | info->fix.line_length = var->xres * var->bits_per_pixel / 8; | ||
1664 | info->fix.visual = FB_VISUAL_TRUECOLOR; | ||
1665 | } | 1895 | } |
1666 | 1896 | ||
1667 | info->screen_base = buf; | 1897 | return sh_mobile_lcdc_channel_fb_init(ch, mode, num_modes); |
1668 | info->device = dev; | ||
1669 | ch->display_var = *var; | ||
1670 | |||
1671 | return 0; | ||
1672 | } | 1898 | } |
1673 | 1899 | ||
1674 | static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | 1900 | static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) |
@@ -1698,6 +1924,8 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
1698 | return -ENOMEM; | 1924 | return -ENOMEM; |
1699 | } | 1925 | } |
1700 | 1926 | ||
1927 | priv->dev = &pdev->dev; | ||
1928 | priv->meram_dev = pdata->meram_dev; | ||
1701 | platform_set_drvdata(pdev, priv); | 1929 | platform_set_drvdata(pdev, priv); |
1702 | 1930 | ||
1703 | error = request_irq(i, sh_mobile_lcdc_irq, 0, | 1931 | error = request_irq(i, sh_mobile_lcdc_irq, 0, |
@@ -1714,7 +1942,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
1714 | struct sh_mobile_lcdc_chan *ch = priv->ch + num_channels; | 1942 | struct sh_mobile_lcdc_chan *ch = priv->ch + num_channels; |
1715 | 1943 | ||
1716 | ch->lcdc = priv; | 1944 | ch->lcdc = priv; |
1717 | memcpy(&ch->cfg, &pdata->ch[i], sizeof(pdata->ch[i])); | 1945 | ch->cfg = &pdata->ch[i]; |
1718 | 1946 | ||
1719 | error = sh_mobile_lcdc_check_interface(ch); | 1947 | error = sh_mobile_lcdc_check_interface(ch); |
1720 | if (error) { | 1948 | if (error) { |
@@ -1726,7 +1954,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
1726 | ch->pan_offset = 0; | 1954 | ch->pan_offset = 0; |
1727 | 1955 | ||
1728 | /* probe the backlight is there is one defined */ | 1956 | /* probe the backlight is there is one defined */ |
1729 | if (ch->cfg.bl_info.max_brightness) | 1957 | if (ch->cfg->bl_info.max_brightness) |
1730 | ch->bl = sh_mobile_lcdc_bl_probe(&pdev->dev, ch); | 1958 | ch->bl = sh_mobile_lcdc_bl_probe(&pdev->dev, ch); |
1731 | 1959 | ||
1732 | switch (pdata->ch[i].chan) { | 1960 | switch (pdata->ch[i].chan) { |
@@ -1757,18 +1985,19 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
1757 | if (!priv->base) | 1985 | if (!priv->base) |
1758 | goto err1; | 1986 | goto err1; |
1759 | 1987 | ||
1760 | error = sh_mobile_lcdc_setup_clocks(pdev, pdata->clock_source, priv); | 1988 | error = sh_mobile_lcdc_setup_clocks(priv, pdata->clock_source); |
1761 | if (error) { | 1989 | if (error) { |
1762 | dev_err(&pdev->dev, "unable to setup clocks\n"); | 1990 | dev_err(&pdev->dev, "unable to setup clocks\n"); |
1763 | goto err1; | 1991 | goto err1; |
1764 | } | 1992 | } |
1765 | 1993 | ||
1766 | priv->meram_dev = pdata->meram_dev; | 1994 | /* Enable runtime PM. */ |
1995 | pm_runtime_enable(&pdev->dev); | ||
1767 | 1996 | ||
1768 | for (i = 0; i < num_channels; i++) { | 1997 | for (i = 0; i < num_channels; i++) { |
1769 | struct sh_mobile_lcdc_chan *ch = priv->ch + i; | 1998 | struct sh_mobile_lcdc_chan *ch = priv->ch + i; |
1770 | 1999 | ||
1771 | error = sh_mobile_lcdc_channel_init(ch, &pdev->dev); | 2000 | error = sh_mobile_lcdc_channel_init(priv, ch); |
1772 | if (error) | 2001 | if (error) |
1773 | goto err1; | 2002 | goto err1; |
1774 | } | 2003 | } |
@@ -1781,31 +2010,10 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
1781 | 2010 | ||
1782 | for (i = 0; i < num_channels; i++) { | 2011 | for (i = 0; i < num_channels; i++) { |
1783 | struct sh_mobile_lcdc_chan *ch = priv->ch + i; | 2012 | struct sh_mobile_lcdc_chan *ch = priv->ch + i; |
1784 | struct fb_info *info = ch->info; | ||
1785 | |||
1786 | if (info->fbdefio) { | ||
1787 | ch->sglist = vmalloc(sizeof(struct scatterlist) * | ||
1788 | info->fix.smem_len >> PAGE_SHIFT); | ||
1789 | if (!ch->sglist) { | ||
1790 | dev_err(&pdev->dev, "cannot allocate sglist\n"); | ||
1791 | goto err1; | ||
1792 | } | ||
1793 | } | ||
1794 | |||
1795 | info->bl_dev = ch->bl; | ||
1796 | 2013 | ||
1797 | error = register_framebuffer(info); | 2014 | error = sh_mobile_lcdc_channel_fb_register(ch); |
1798 | if (error < 0) | 2015 | if (error) |
1799 | goto err1; | 2016 | goto err1; |
1800 | |||
1801 | dev_info(info->dev, "registered %s/%s as %dx%d %dbpp.\n", | ||
1802 | pdev->name, (ch->cfg.chan == LCDC_CHAN_MAINLCD) ? | ||
1803 | "mainlcd" : "sublcd", info->var.xres, info->var.yres, | ||
1804 | info->var.bits_per_pixel); | ||
1805 | |||
1806 | /* deferred io mode: disable clock to save power */ | ||
1807 | if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED) | ||
1808 | sh_mobile_lcdc_clk_off(priv); | ||
1809 | } | 2017 | } |
1810 | 2018 | ||
1811 | /* Failure ignored */ | 2019 | /* Failure ignored */ |
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h index a58a0f38848b..da1c26e78a57 100644 --- a/drivers/video/sh_mobile_lcdcfb.h +++ b/drivers/video/sh_mobile_lcdcfb.h | |||
@@ -14,9 +14,35 @@ enum { LDDCKPAT1R, LDDCKPAT2R, LDMT1R, LDMT2R, LDMT3R, LDDFR, LDSM1R, | |||
14 | 14 | ||
15 | #define PALETTE_NR 16 | 15 | #define PALETTE_NR 16 |
16 | 16 | ||
17 | struct sh_mobile_lcdc_priv; | ||
18 | struct fb_info; | ||
19 | struct backlight_device; | 17 | struct backlight_device; |
18 | struct fb_info; | ||
19 | struct module; | ||
20 | struct sh_mobile_lcdc_chan; | ||
21 | struct sh_mobile_lcdc_entity; | ||
22 | struct sh_mobile_lcdc_format_info; | ||
23 | struct sh_mobile_lcdc_priv; | ||
24 | |||
25 | #define SH_MOBILE_LCDC_DISPLAY_DISCONNECTED 0 | ||
26 | #define SH_MOBILE_LCDC_DISPLAY_CONNECTED 1 | ||
27 | |||
28 | struct sh_mobile_lcdc_entity_ops { | ||
29 | /* Display */ | ||
30 | int (*display_on)(struct sh_mobile_lcdc_entity *entity); | ||
31 | void (*display_off)(struct sh_mobile_lcdc_entity *entity); | ||
32 | }; | ||
33 | |||
34 | enum sh_mobile_lcdc_entity_event { | ||
35 | SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT, | ||
36 | SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT, | ||
37 | SH_MOBILE_LCDC_EVENT_DISPLAY_MODE, | ||
38 | }; | ||
39 | |||
40 | struct sh_mobile_lcdc_entity { | ||
41 | struct module *owner; | ||
42 | const struct sh_mobile_lcdc_entity_ops *ops; | ||
43 | struct sh_mobile_lcdc_chan *lcdc; | ||
44 | struct fb_videomode def_mode; | ||
45 | }; | ||
20 | 46 | ||
21 | /* | 47 | /* |
22 | * struct sh_mobile_lcdc_chan - LCDC display channel | 48 | * struct sh_mobile_lcdc_chan - LCDC display channel |
@@ -27,29 +53,57 @@ struct backlight_device; | |||
27 | */ | 53 | */ |
28 | struct sh_mobile_lcdc_chan { | 54 | struct sh_mobile_lcdc_chan { |
29 | struct sh_mobile_lcdc_priv *lcdc; | 55 | struct sh_mobile_lcdc_priv *lcdc; |
56 | struct sh_mobile_lcdc_entity *tx_dev; | ||
57 | const struct sh_mobile_lcdc_chan_cfg *cfg; | ||
58 | |||
30 | unsigned long *reg_offs; | 59 | unsigned long *reg_offs; |
31 | unsigned long ldmt1r_value; | 60 | unsigned long ldmt1r_value; |
32 | unsigned long enabled; /* ME and SE in LDCNT2R */ | 61 | unsigned long enabled; /* ME and SE in LDCNT2R */ |
33 | struct sh_mobile_lcdc_chan_cfg cfg; | 62 | void *meram; |
34 | u32 pseudo_palette[PALETTE_NR]; | 63 | |
35 | struct fb_info *info; | 64 | struct mutex open_lock; /* protects the use counter */ |
36 | struct backlight_device *bl; | 65 | int use_count; |
66 | |||
67 | void *fb_mem; | ||
68 | unsigned long fb_size; | ||
69 | |||
37 | dma_addr_t dma_handle; | 70 | dma_addr_t dma_handle; |
38 | struct fb_deferred_io defio; | ||
39 | struct scatterlist *sglist; | ||
40 | unsigned long frame_end; | ||
41 | unsigned long pan_offset; | 71 | unsigned long pan_offset; |
72 | |||
73 | unsigned long frame_end; | ||
42 | wait_queue_head_t frame_end_wait; | 74 | wait_queue_head_t frame_end_wait; |
43 | struct completion vsync_completion; | 75 | struct completion vsync_completion; |
44 | struct fb_var_screeninfo display_var; | 76 | |
45 | int use_count; | 77 | const struct sh_mobile_lcdc_format_info *format; |
46 | int blank_status; | 78 | u32 colorspace; |
47 | struct mutex open_lock; /* protects the use counter */ | 79 | unsigned int xres; |
48 | int meram_enabled; | 80 | unsigned int xres_virtual; |
81 | unsigned int yres; | ||
82 | unsigned int yres_virtual; | ||
83 | unsigned int pitch; | ||
49 | 84 | ||
50 | unsigned long base_addr_y; | 85 | unsigned long base_addr_y; |
51 | unsigned long base_addr_c; | 86 | unsigned long base_addr_c; |
52 | unsigned int pitch; | 87 | |
88 | int (*notify)(struct sh_mobile_lcdc_chan *ch, | ||
89 | enum sh_mobile_lcdc_entity_event event, | ||
90 | const struct fb_videomode *mode, | ||
91 | const struct fb_monspecs *monspec); | ||
92 | |||
93 | /* Backlight */ | ||
94 | struct backlight_device *bl; | ||
95 | |||
96 | /* FB */ | ||
97 | struct fb_info *info; | ||
98 | u32 pseudo_palette[PALETTE_NR]; | ||
99 | struct { | ||
100 | unsigned int width; | ||
101 | unsigned int height; | ||
102 | struct fb_videomode mode; | ||
103 | } display; | ||
104 | struct fb_deferred_io defio; | ||
105 | struct scatterlist *sglist; | ||
106 | int blank_status; | ||
53 | }; | 107 | }; |
54 | 108 | ||
55 | #endif | 109 | #endif |
diff --git a/drivers/video/sh_mobile_meram.c b/drivers/video/sh_mobile_meram.c index f45d83ecfd21..82ba830bf95d 100644 --- a/drivers/video/sh_mobile_meram.c +++ b/drivers/video/sh_mobile_meram.c | |||
@@ -9,16 +9,22 @@ | |||
9 | * for more details. | 9 | * for more details. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/device.h> | ||
13 | #include <linux/err.h> | ||
14 | #include <linux/genalloc.h> | ||
15 | #include <linux/io.h> | ||
12 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
13 | #include <linux/module.h> | 17 | #include <linux/module.h> |
14 | #include <linux/device.h> | 18 | #include <linux/platform_device.h> |
15 | #include <linux/pm_runtime.h> | 19 | #include <linux/pm_runtime.h> |
16 | #include <linux/io.h> | ||
17 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
18 | #include <linux/platform_device.h> | 21 | |
19 | #include <video/sh_mobile_meram.h> | 22 | #include <video/sh_mobile_meram.h> |
20 | 23 | ||
21 | /* meram registers */ | 24 | /* ----------------------------------------------------------------------------- |
25 | * MERAM registers | ||
26 | */ | ||
27 | |||
22 | #define MEVCR1 0x4 | 28 | #define MEVCR1 0x4 |
23 | #define MEVCR1_RST (1 << 31) | 29 | #define MEVCR1_RST (1 << 31) |
24 | #define MEVCR1_WD (1 << 30) | 30 | #define MEVCR1_WD (1 << 30) |
@@ -81,16 +87,14 @@ | |||
81 | ((yszm1) << MExxBSIZE_YSZM1_SHIFT) | \ | 87 | ((yszm1) << MExxBSIZE_YSZM1_SHIFT) | \ |
82 | ((xszm1) << MExxBSIZE_XSZM1_SHIFT)) | 88 | ((xszm1) << MExxBSIZE_XSZM1_SHIFT)) |
83 | 89 | ||
84 | #define SH_MOBILE_MERAM_ICB_NUM 32 | 90 | static const unsigned long common_regs[] = { |
85 | |||
86 | static unsigned long common_regs[] = { | ||
87 | MEVCR1, | 91 | MEVCR1, |
88 | MEQSEL1, | 92 | MEQSEL1, |
89 | MEQSEL2, | 93 | MEQSEL2, |
90 | }; | 94 | }; |
91 | #define CMN_REGS_SIZE ARRAY_SIZE(common_regs) | 95 | #define MERAM_REGS_SIZE ARRAY_SIZE(common_regs) |
92 | 96 | ||
93 | static unsigned long icb_regs[] = { | 97 | static const unsigned long icb_regs[] = { |
94 | MExxCTL, | 98 | MExxCTL, |
95 | MExxBSIZE, | 99 | MExxBSIZE, |
96 | MExxMNCF, | 100 | MExxMNCF, |
@@ -100,216 +104,269 @@ static unsigned long icb_regs[] = { | |||
100 | }; | 104 | }; |
101 | #define ICB_REGS_SIZE ARRAY_SIZE(icb_regs) | 105 | #define ICB_REGS_SIZE ARRAY_SIZE(icb_regs) |
102 | 106 | ||
107 | /* | ||
108 | * sh_mobile_meram_icb - MERAM ICB information | ||
109 | * @regs: Registers cache | ||
110 | * @index: ICB index | ||
111 | * @offset: MERAM block offset | ||
112 | * @size: MERAM block size in KiB | ||
113 | * @cache_unit: Bytes to cache per ICB | ||
114 | * @pixelformat: Video pixel format of the data stored in the ICB | ||
115 | * @current_reg: Which of Start Address Register A (0) or B (1) is in use | ||
116 | */ | ||
117 | struct sh_mobile_meram_icb { | ||
118 | unsigned long regs[ICB_REGS_SIZE]; | ||
119 | unsigned int index; | ||
120 | unsigned long offset; | ||
121 | unsigned int size; | ||
122 | |||
123 | unsigned int cache_unit; | ||
124 | unsigned int pixelformat; | ||
125 | unsigned int current_reg; | ||
126 | }; | ||
127 | |||
128 | #define MERAM_ICB_NUM 32 | ||
129 | |||
130 | struct sh_mobile_meram_fb_plane { | ||
131 | struct sh_mobile_meram_icb *marker; | ||
132 | struct sh_mobile_meram_icb *cache; | ||
133 | }; | ||
134 | |||
135 | struct sh_mobile_meram_fb_cache { | ||
136 | unsigned int nplanes; | ||
137 | struct sh_mobile_meram_fb_plane planes[2]; | ||
138 | }; | ||
139 | |||
140 | /* | ||
141 | * sh_mobile_meram_priv - MERAM device | ||
142 | * @base: Registers base address | ||
143 | * @meram: MERAM physical address | ||
144 | * @regs: Registers cache | ||
145 | * @lock: Protects used_icb and icbs | ||
146 | * @used_icb: Bitmask of used ICBs | ||
147 | * @icbs: ICBs | ||
148 | * @pool: Allocation pool to manage the MERAM | ||
149 | */ | ||
103 | struct sh_mobile_meram_priv { | 150 | struct sh_mobile_meram_priv { |
104 | void __iomem *base; | 151 | void __iomem *base; |
105 | struct mutex lock; | 152 | unsigned long meram; |
106 | unsigned long used_icb; | 153 | unsigned long regs[MERAM_REGS_SIZE]; |
107 | int used_meram_cache_regions; | 154 | |
108 | unsigned long used_meram_cache[SH_MOBILE_MERAM_ICB_NUM]; | 155 | struct mutex lock; |
109 | unsigned long cmn_saved_regs[CMN_REGS_SIZE]; | 156 | unsigned long used_icb; |
110 | unsigned long icb_saved_regs[ICB_REGS_SIZE * SH_MOBILE_MERAM_ICB_NUM]; | 157 | struct sh_mobile_meram_icb icbs[MERAM_ICB_NUM]; |
158 | |||
159 | struct gen_pool *pool; | ||
111 | }; | 160 | }; |
112 | 161 | ||
113 | /* settings */ | 162 | /* settings */ |
114 | #define MERAM_SEC_LINE 15 | 163 | #define MERAM_GRANULARITY 1024 |
115 | #define MERAM_LINE_WIDTH 2048 | 164 | #define MERAM_SEC_LINE 15 |
165 | #define MERAM_LINE_WIDTH 2048 | ||
116 | 166 | ||
117 | /* | 167 | /* ----------------------------------------------------------------------------- |
118 | * MERAM/ICB access functions | 168 | * Registers access |
119 | */ | 169 | */ |
120 | 170 | ||
121 | #define MERAM_ICB_OFFSET(base, idx, off) ((base) + (off) + (idx) * 0x20) | 171 | #define MERAM_ICB_OFFSET(base, idx, off) ((base) + (off) + (idx) * 0x20) |
122 | 172 | ||
123 | static inline void meram_write_icb(void __iomem *base, int idx, int off, | 173 | static inline void meram_write_icb(void __iomem *base, unsigned int idx, |
124 | unsigned long val) | 174 | unsigned int off, unsigned long val) |
125 | { | 175 | { |
126 | iowrite32(val, MERAM_ICB_OFFSET(base, idx, off)); | 176 | iowrite32(val, MERAM_ICB_OFFSET(base, idx, off)); |
127 | } | 177 | } |
128 | 178 | ||
129 | static inline unsigned long meram_read_icb(void __iomem *base, int idx, int off) | 179 | static inline unsigned long meram_read_icb(void __iomem *base, unsigned int idx, |
180 | unsigned int off) | ||
130 | { | 181 | { |
131 | return ioread32(MERAM_ICB_OFFSET(base, idx, off)); | 182 | return ioread32(MERAM_ICB_OFFSET(base, idx, off)); |
132 | } | 183 | } |
133 | 184 | ||
134 | static inline void meram_write_reg(void __iomem *base, int off, | 185 | static inline void meram_write_reg(void __iomem *base, unsigned int off, |
135 | unsigned long val) | 186 | unsigned long val) |
136 | { | 187 | { |
137 | iowrite32(val, base + off); | 188 | iowrite32(val, base + off); |
138 | } | 189 | } |
139 | 190 | ||
140 | static inline unsigned long meram_read_reg(void __iomem *base, int off) | 191 | static inline unsigned long meram_read_reg(void __iomem *base, unsigned int off) |
141 | { | 192 | { |
142 | return ioread32(base + off); | 193 | return ioread32(base + off); |
143 | } | 194 | } |
144 | 195 | ||
145 | /* | 196 | /* ----------------------------------------------------------------------------- |
146 | * register ICB | 197 | * Allocation |
147 | */ | ||
148 | |||
149 | #define MERAM_CACHE_START(p) ((p) >> 16) | ||
150 | #define MERAM_CACHE_END(p) ((p) & 0xffff) | ||
151 | #define MERAM_CACHE_SET(o, s) ((((o) & 0xffff) << 16) | \ | ||
152 | (((o) + (s) - 1) & 0xffff)) | ||
153 | |||
154 | /* | ||
155 | * check if there's no overlaps in MERAM allocation. | ||
156 | */ | 198 | */ |
157 | 199 | ||
158 | static inline int meram_check_overlap(struct sh_mobile_meram_priv *priv, | 200 | /* Allocate ICBs and MERAM for a plane. */ |
159 | struct sh_mobile_meram_icb *new) | 201 | static int __meram_alloc(struct sh_mobile_meram_priv *priv, |
202 | struct sh_mobile_meram_fb_plane *plane, | ||
203 | size_t size) | ||
160 | { | 204 | { |
161 | int i; | 205 | unsigned long mem; |
162 | int used_start, used_end, meram_start, meram_end; | 206 | unsigned long idx; |
163 | 207 | ||
164 | /* valid ICB? */ | 208 | idx = find_first_zero_bit(&priv->used_icb, 28); |
165 | if (new->marker_icb & ~0x1f || new->cache_icb & ~0x1f) | 209 | if (idx == 28) |
166 | return 1; | 210 | return -ENOMEM; |
211 | plane->cache = &priv->icbs[idx]; | ||
167 | 212 | ||
168 | if (test_bit(new->marker_icb, &priv->used_icb) || | 213 | idx = find_next_zero_bit(&priv->used_icb, 32, 28); |
169 | test_bit(new->cache_icb, &priv->used_icb)) | 214 | if (idx == 32) |
170 | return 1; | 215 | return -ENOMEM; |
216 | plane->marker = &priv->icbs[idx]; | ||
171 | 217 | ||
172 | for (i = 0; i < priv->used_meram_cache_regions; i++) { | 218 | mem = gen_pool_alloc(priv->pool, size * 1024); |
173 | used_start = MERAM_CACHE_START(priv->used_meram_cache[i]); | 219 | if (mem == 0) |
174 | used_end = MERAM_CACHE_END(priv->used_meram_cache[i]); | 220 | return -ENOMEM; |
175 | meram_start = new->meram_offset; | ||
176 | meram_end = new->meram_offset + new->meram_size; | ||
177 | 221 | ||
178 | if ((meram_start >= used_start && meram_start < used_end) || | 222 | __set_bit(plane->marker->index, &priv->used_icb); |
179 | (meram_end > used_start && meram_end < used_end)) | 223 | __set_bit(plane->cache->index, &priv->used_icb); |
180 | return 1; | 224 | |
181 | } | 225 | plane->marker->offset = mem - priv->meram; |
226 | plane->marker->size = size; | ||
182 | 227 | ||
183 | return 0; | 228 | return 0; |
184 | } | 229 | } |
185 | 230 | ||
186 | /* | 231 | /* Free ICBs and MERAM for a plane. */ |
187 | * mark the specified ICB as used | 232 | static void __meram_free(struct sh_mobile_meram_priv *priv, |
188 | */ | 233 | struct sh_mobile_meram_fb_plane *plane) |
234 | { | ||
235 | gen_pool_free(priv->pool, priv->meram + plane->marker->offset, | ||
236 | plane->marker->size * 1024); | ||
189 | 237 | ||
190 | static inline void meram_mark(struct sh_mobile_meram_priv *priv, | 238 | __clear_bit(plane->marker->index, &priv->used_icb); |
191 | struct sh_mobile_meram_icb *new) | 239 | __clear_bit(plane->cache->index, &priv->used_icb); |
240 | } | ||
241 | |||
242 | /* Is this a YCbCr(NV12, NV16 or NV24) colorspace? */ | ||
243 | static int is_nvcolor(int cspace) | ||
192 | { | 244 | { |
193 | int n; | 245 | if (cspace == SH_MOBILE_MERAM_PF_NV || |
246 | cspace == SH_MOBILE_MERAM_PF_NV24) | ||
247 | return 1; | ||
248 | return 0; | ||
249 | } | ||
194 | 250 | ||
195 | if (new->marker_icb < 0 || new->cache_icb < 0) | 251 | /* Allocate memory for the ICBs and mark them as used. */ |
196 | return; | 252 | static struct sh_mobile_meram_fb_cache * |
253 | meram_alloc(struct sh_mobile_meram_priv *priv, | ||
254 | const struct sh_mobile_meram_cfg *cfg, | ||
255 | int pixelformat) | ||
256 | { | ||
257 | struct sh_mobile_meram_fb_cache *cache; | ||
258 | unsigned int nplanes = is_nvcolor(pixelformat) ? 2 : 1; | ||
259 | int ret; | ||
197 | 260 | ||
198 | __set_bit(new->marker_icb, &priv->used_icb); | 261 | if (cfg->icb[0].meram_size == 0) |
199 | __set_bit(new->cache_icb, &priv->used_icb); | 262 | return ERR_PTR(-EINVAL); |
200 | 263 | ||
201 | n = priv->used_meram_cache_regions; | 264 | if (nplanes == 2 && cfg->icb[1].meram_size == 0) |
265 | return ERR_PTR(-EINVAL); | ||
202 | 266 | ||
203 | priv->used_meram_cache[n] = MERAM_CACHE_SET(new->meram_offset, | 267 | cache = kzalloc(sizeof(*cache), GFP_KERNEL); |
204 | new->meram_size); | 268 | if (cache == NULL) |
269 | return ERR_PTR(-ENOMEM); | ||
205 | 270 | ||
206 | priv->used_meram_cache_regions++; | 271 | cache->nplanes = nplanes; |
207 | } | ||
208 | 272 | ||
209 | /* | 273 | ret = __meram_alloc(priv, &cache->planes[0], cfg->icb[0].meram_size); |
210 | * unmark the specified ICB as used | 274 | if (ret < 0) |
211 | */ | 275 | goto error; |
212 | 276 | ||
213 | static inline void meram_unmark(struct sh_mobile_meram_priv *priv, | 277 | cache->planes[0].marker->current_reg = 1; |
214 | struct sh_mobile_meram_icb *icb) | 278 | cache->planes[0].marker->pixelformat = pixelformat; |
215 | { | 279 | |
216 | int i; | 280 | if (cache->nplanes == 1) |
217 | unsigned long pattern; | 281 | return cache; |
218 | 282 | ||
219 | if (icb->marker_icb < 0 || icb->cache_icb < 0) | 283 | ret = __meram_alloc(priv, &cache->planes[1], cfg->icb[1].meram_size); |
220 | return; | 284 | if (ret < 0) { |
221 | 285 | __meram_free(priv, &cache->planes[0]); | |
222 | __clear_bit(icb->marker_icb, &priv->used_icb); | 286 | goto error; |
223 | __clear_bit(icb->cache_icb, &priv->used_icb); | ||
224 | |||
225 | pattern = MERAM_CACHE_SET(icb->meram_offset, icb->meram_size); | ||
226 | for (i = 0; i < priv->used_meram_cache_regions; i++) { | ||
227 | if (priv->used_meram_cache[i] == pattern) { | ||
228 | while (i < priv->used_meram_cache_regions - 1) { | ||
229 | priv->used_meram_cache[i] = | ||
230 | priv->used_meram_cache[i + 1] ; | ||
231 | i++; | ||
232 | } | ||
233 | priv->used_meram_cache[i] = 0; | ||
234 | priv->used_meram_cache_regions--; | ||
235 | break; | ||
236 | } | ||
237 | } | 287 | } |
288 | |||
289 | return cache; | ||
290 | |||
291 | error: | ||
292 | kfree(cache); | ||
293 | return ERR_PTR(-ENOMEM); | ||
238 | } | 294 | } |
239 | 295 | ||
240 | /* | 296 | /* Unmark the specified ICB as used. */ |
241 | * is this a YCbCr(NV12, NV16 or NV24) colorspace | 297 | static void meram_free(struct sh_mobile_meram_priv *priv, |
242 | */ | 298 | struct sh_mobile_meram_fb_cache *cache) |
243 | static inline int is_nvcolor(int cspace) | ||
244 | { | 299 | { |
245 | if (cspace == SH_MOBILE_MERAM_PF_NV || | 300 | __meram_free(priv, &cache->planes[0]); |
246 | cspace == SH_MOBILE_MERAM_PF_NV24) | 301 | if (cache->nplanes == 2) |
247 | return 1; | 302 | __meram_free(priv, &cache->planes[1]); |
248 | return 0; | 303 | |
304 | kfree(cache); | ||
249 | } | 305 | } |
250 | 306 | ||
251 | /* | 307 | /* Set the next address to fetch. */ |
252 | * set the next address to fetch | 308 | static void meram_set_next_addr(struct sh_mobile_meram_priv *priv, |
253 | */ | 309 | struct sh_mobile_meram_fb_cache *cache, |
254 | static inline void meram_set_next_addr(struct sh_mobile_meram_priv *priv, | 310 | unsigned long base_addr_y, |
255 | struct sh_mobile_meram_cfg *cfg, | 311 | unsigned long base_addr_c) |
256 | unsigned long base_addr_y, | ||
257 | unsigned long base_addr_c) | ||
258 | { | 312 | { |
313 | struct sh_mobile_meram_icb *icb = cache->planes[0].marker; | ||
259 | unsigned long target; | 314 | unsigned long target; |
260 | 315 | ||
261 | target = (cfg->current_reg) ? MExxSARA : MExxSARB; | 316 | icb->current_reg ^= 1; |
262 | cfg->current_reg ^= 1; | 317 | target = icb->current_reg ? MExxSARB : MExxSARA; |
263 | 318 | ||
264 | /* set the next address to fetch */ | 319 | /* set the next address to fetch */ |
265 | meram_write_icb(priv->base, cfg->icb[0].cache_icb, target, | 320 | meram_write_icb(priv->base, cache->planes[0].cache->index, target, |
266 | base_addr_y); | 321 | base_addr_y); |
267 | meram_write_icb(priv->base, cfg->icb[0].marker_icb, target, | 322 | meram_write_icb(priv->base, cache->planes[0].marker->index, target, |
268 | base_addr_y + cfg->icb[0].cache_unit); | 323 | base_addr_y + cache->planes[0].marker->cache_unit); |
269 | 324 | ||
270 | if (is_nvcolor(cfg->pixelformat)) { | 325 | if (cache->nplanes == 2) { |
271 | meram_write_icb(priv->base, cfg->icb[1].cache_icb, target, | 326 | meram_write_icb(priv->base, cache->planes[1].cache->index, |
272 | base_addr_c); | 327 | target, base_addr_c); |
273 | meram_write_icb(priv->base, cfg->icb[1].marker_icb, target, | 328 | meram_write_icb(priv->base, cache->planes[1].marker->index, |
274 | base_addr_c + cfg->icb[1].cache_unit); | 329 | target, base_addr_c + |
330 | cache->planes[1].marker->cache_unit); | ||
275 | } | 331 | } |
276 | } | 332 | } |
277 | 333 | ||
278 | /* | 334 | /* Get the next ICB address. */ |
279 | * get the next ICB address | 335 | static void |
280 | */ | 336 | meram_get_next_icb_addr(struct sh_mobile_meram_info *pdata, |
281 | static inline void meram_get_next_icb_addr(struct sh_mobile_meram_info *pdata, | 337 | struct sh_mobile_meram_fb_cache *cache, |
282 | struct sh_mobile_meram_cfg *cfg, | 338 | unsigned long *icb_addr_y, unsigned long *icb_addr_c) |
283 | unsigned long *icb_addr_y, | ||
284 | unsigned long *icb_addr_c) | ||
285 | { | 339 | { |
340 | struct sh_mobile_meram_icb *icb = cache->planes[0].marker; | ||
286 | unsigned long icb_offset; | 341 | unsigned long icb_offset; |
287 | 342 | ||
288 | if (pdata->addr_mode == SH_MOBILE_MERAM_MODE0) | 343 | if (pdata->addr_mode == SH_MOBILE_MERAM_MODE0) |
289 | icb_offset = 0x80000000 | (cfg->current_reg << 29); | 344 | icb_offset = 0x80000000 | (icb->current_reg << 29); |
290 | else | 345 | else |
291 | icb_offset = 0xc0000000 | (cfg->current_reg << 23); | 346 | icb_offset = 0xc0000000 | (icb->current_reg << 23); |
292 | 347 | ||
293 | *icb_addr_y = icb_offset | (cfg->icb[0].marker_icb << 24); | 348 | *icb_addr_y = icb_offset | (cache->planes[0].marker->index << 24); |
294 | if (is_nvcolor(cfg->pixelformat)) | 349 | if (cache->nplanes == 2) |
295 | *icb_addr_c = icb_offset | (cfg->icb[1].marker_icb << 24); | 350 | *icb_addr_c = icb_offset |
351 | | (cache->planes[1].marker->index << 24); | ||
296 | } | 352 | } |
297 | 353 | ||
298 | #define MERAM_CALC_BYTECOUNT(x, y) \ | 354 | #define MERAM_CALC_BYTECOUNT(x, y) \ |
299 | (((x) * (y) + (MERAM_LINE_WIDTH - 1)) & ~(MERAM_LINE_WIDTH - 1)) | 355 | (((x) * (y) + (MERAM_LINE_WIDTH - 1)) & ~(MERAM_LINE_WIDTH - 1)) |
300 | 356 | ||
301 | /* | 357 | /* Initialize MERAM. */ |
302 | * initialize MERAM | ||
303 | */ | ||
304 | |||
305 | static int meram_init(struct sh_mobile_meram_priv *priv, | 358 | static int meram_init(struct sh_mobile_meram_priv *priv, |
306 | struct sh_mobile_meram_icb *icb, | 359 | struct sh_mobile_meram_fb_plane *plane, |
307 | int xres, int yres, int *out_pitch) | 360 | unsigned int xres, unsigned int yres, |
361 | unsigned int *out_pitch) | ||
308 | { | 362 | { |
363 | struct sh_mobile_meram_icb *marker = plane->marker; | ||
309 | unsigned long total_byte_count = MERAM_CALC_BYTECOUNT(xres, yres); | 364 | unsigned long total_byte_count = MERAM_CALC_BYTECOUNT(xres, yres); |
310 | unsigned long bnm; | 365 | unsigned long bnm; |
311 | int lcdc_pitch, xpitch, line_cnt; | 366 | unsigned int lcdc_pitch; |
312 | int save_lines; | 367 | unsigned int xpitch; |
368 | unsigned int line_cnt; | ||
369 | unsigned int save_lines; | ||
313 | 370 | ||
314 | /* adjust pitch to 1024, 2048, 4096 or 8192 */ | 371 | /* adjust pitch to 1024, 2048, 4096 or 8192 */ |
315 | lcdc_pitch = (xres - 1) | 1023; | 372 | lcdc_pitch = (xres - 1) | 1023; |
@@ -322,13 +379,13 @@ static int meram_init(struct sh_mobile_meram_priv *priv, | |||
322 | lcdc_pitch = xpitch = MERAM_LINE_WIDTH; | 379 | lcdc_pitch = xpitch = MERAM_LINE_WIDTH; |
323 | line_cnt = total_byte_count >> 11; | 380 | line_cnt = total_byte_count >> 11; |
324 | *out_pitch = xres; | 381 | *out_pitch = xres; |
325 | save_lines = (icb->meram_size / 16 / MERAM_SEC_LINE); | 382 | save_lines = plane->marker->size / 16 / MERAM_SEC_LINE; |
326 | save_lines *= MERAM_SEC_LINE; | 383 | save_lines *= MERAM_SEC_LINE; |
327 | } else { | 384 | } else { |
328 | xpitch = xres; | 385 | xpitch = xres; |
329 | line_cnt = yres; | 386 | line_cnt = yres; |
330 | *out_pitch = lcdc_pitch; | 387 | *out_pitch = lcdc_pitch; |
331 | save_lines = icb->meram_size / (lcdc_pitch >> 10) / 2; | 388 | save_lines = plane->marker->size / (lcdc_pitch >> 10) / 2; |
332 | save_lines &= 0xff; | 389 | save_lines &= 0xff; |
333 | } | 390 | } |
334 | bnm = (save_lines - 1) << 16; | 391 | bnm = (save_lines - 1) << 16; |
@@ -336,19 +393,20 @@ static int meram_init(struct sh_mobile_meram_priv *priv, | |||
336 | /* TODO: we better to check if we have enough MERAM buffer size */ | 393 | /* TODO: we better to check if we have enough MERAM buffer size */ |
337 | 394 | ||
338 | /* set up ICB */ | 395 | /* set up ICB */ |
339 | meram_write_icb(priv->base, icb->cache_icb, MExxBSIZE, | 396 | meram_write_icb(priv->base, plane->cache->index, MExxBSIZE, |
340 | MERAM_MExxBSIZE_VAL(0x0, line_cnt - 1, xpitch - 1)); | 397 | MERAM_MExxBSIZE_VAL(0x0, line_cnt - 1, xpitch - 1)); |
341 | meram_write_icb(priv->base, icb->marker_icb, MExxBSIZE, | 398 | meram_write_icb(priv->base, plane->marker->index, MExxBSIZE, |
342 | MERAM_MExxBSIZE_VAL(0xf, line_cnt - 1, xpitch - 1)); | 399 | MERAM_MExxBSIZE_VAL(0xf, line_cnt - 1, xpitch - 1)); |
343 | 400 | ||
344 | meram_write_icb(priv->base, icb->cache_icb, MExxMNCF, bnm); | 401 | meram_write_icb(priv->base, plane->cache->index, MExxMNCF, bnm); |
345 | meram_write_icb(priv->base, icb->marker_icb, MExxMNCF, bnm); | 402 | meram_write_icb(priv->base, plane->marker->index, MExxMNCF, bnm); |
346 | 403 | ||
347 | meram_write_icb(priv->base, icb->cache_icb, MExxSBSIZE, xpitch); | 404 | meram_write_icb(priv->base, plane->cache->index, MExxSBSIZE, xpitch); |
348 | meram_write_icb(priv->base, icb->marker_icb, MExxSBSIZE, xpitch); | 405 | meram_write_icb(priv->base, plane->marker->index, MExxSBSIZE, xpitch); |
349 | 406 | ||
350 | /* save a cache unit size */ | 407 | /* save a cache unit size */ |
351 | icb->cache_unit = xres * save_lines; | 408 | plane->cache->cache_unit = xres * save_lines; |
409 | plane->marker->cache_unit = xres * save_lines; | ||
352 | 410 | ||
353 | /* | 411 | /* |
354 | * Set MERAM for framebuffer | 412 | * Set MERAM for framebuffer |
@@ -356,13 +414,13 @@ static int meram_init(struct sh_mobile_meram_priv *priv, | |||
356 | * we also chain the cache_icb and the marker_icb. | 414 | * we also chain the cache_icb and the marker_icb. |
357 | * we also split the allocated MERAM buffer between two ICBs. | 415 | * we also split the allocated MERAM buffer between two ICBs. |
358 | */ | 416 | */ |
359 | meram_write_icb(priv->base, icb->cache_icb, MExxCTL, | 417 | meram_write_icb(priv->base, plane->cache->index, MExxCTL, |
360 | MERAM_MExxCTL_VAL(icb->marker_icb, icb->meram_offset) | | 418 | MERAM_MExxCTL_VAL(plane->marker->index, marker->offset) |
361 | MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM | | 419 | | MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM | |
362 | MExxCTL_MD_FB); | 420 | MExxCTL_MD_FB); |
363 | meram_write_icb(priv->base, icb->marker_icb, MExxCTL, | 421 | meram_write_icb(priv->base, plane->marker->index, MExxCTL, |
364 | MERAM_MExxCTL_VAL(icb->cache_icb, icb->meram_offset + | 422 | MERAM_MExxCTL_VAL(plane->cache->index, marker->offset + |
365 | icb->meram_size / 2) | | 423 | plane->marker->size / 2) | |
366 | MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM | | 424 | MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM | |
367 | MExxCTL_MD_FB); | 425 | MExxCTL_MD_FB); |
368 | 426 | ||
@@ -370,239 +428,175 @@ static int meram_init(struct sh_mobile_meram_priv *priv, | |||
370 | } | 428 | } |
371 | 429 | ||
372 | static void meram_deinit(struct sh_mobile_meram_priv *priv, | 430 | static void meram_deinit(struct sh_mobile_meram_priv *priv, |
373 | struct sh_mobile_meram_icb *icb) | 431 | struct sh_mobile_meram_fb_plane *plane) |
374 | { | 432 | { |
375 | /* disable ICB */ | 433 | /* disable ICB */ |
376 | meram_write_icb(priv->base, icb->cache_icb, MExxCTL, | 434 | meram_write_icb(priv->base, plane->cache->index, MExxCTL, |
377 | MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF); | 435 | MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF); |
378 | meram_write_icb(priv->base, icb->marker_icb, MExxCTL, | 436 | meram_write_icb(priv->base, plane->marker->index, MExxCTL, |
379 | MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF); | 437 | MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF); |
380 | icb->cache_unit = 0; | 438 | |
439 | plane->cache->cache_unit = 0; | ||
440 | plane->marker->cache_unit = 0; | ||
381 | } | 441 | } |
382 | 442 | ||
383 | /* | 443 | /* ----------------------------------------------------------------------------- |
384 | * register the ICB | 444 | * Registration/unregistration |
385 | */ | 445 | */ |
386 | 446 | ||
387 | static int sh_mobile_meram_register(struct sh_mobile_meram_info *pdata, | 447 | static void *sh_mobile_meram_register(struct sh_mobile_meram_info *pdata, |
388 | struct sh_mobile_meram_cfg *cfg, | 448 | const struct sh_mobile_meram_cfg *cfg, |
389 | int xres, int yres, int pixelformat, | 449 | unsigned int xres, unsigned int yres, |
390 | unsigned long base_addr_y, | 450 | unsigned int pixelformat, |
391 | unsigned long base_addr_c, | 451 | unsigned int *pitch) |
392 | unsigned long *icb_addr_y, | ||
393 | unsigned long *icb_addr_c, | ||
394 | int *pitch) | ||
395 | { | 452 | { |
396 | struct platform_device *pdev; | 453 | struct sh_mobile_meram_fb_cache *cache; |
397 | struct sh_mobile_meram_priv *priv; | 454 | struct sh_mobile_meram_priv *priv = pdata->priv; |
398 | int n, out_pitch; | 455 | struct platform_device *pdev = pdata->pdev; |
399 | int error = 0; | 456 | unsigned int out_pitch; |
400 | |||
401 | if (!pdata || !pdata->priv || !pdata->pdev || !cfg) | ||
402 | return -EINVAL; | ||
403 | 457 | ||
404 | if (pixelformat != SH_MOBILE_MERAM_PF_NV && | 458 | if (pixelformat != SH_MOBILE_MERAM_PF_NV && |
405 | pixelformat != SH_MOBILE_MERAM_PF_NV24 && | 459 | pixelformat != SH_MOBILE_MERAM_PF_NV24 && |
406 | pixelformat != SH_MOBILE_MERAM_PF_RGB) | 460 | pixelformat != SH_MOBILE_MERAM_PF_RGB) |
407 | return -EINVAL; | 461 | return ERR_PTR(-EINVAL); |
408 | |||
409 | priv = pdata->priv; | ||
410 | pdev = pdata->pdev; | ||
411 | 462 | ||
412 | dev_dbg(&pdev->dev, "registering %dx%d (%s) (y=%08lx, c=%08lx)", | 463 | dev_dbg(&pdev->dev, "registering %dx%d (%s)", xres, yres, |
413 | xres, yres, (!pixelformat) ? "yuv" : "rgb", | 464 | !pixelformat ? "yuv" : "rgb"); |
414 | base_addr_y, base_addr_c); | ||
415 | 465 | ||
416 | /* we can't handle wider than 8192px */ | 466 | /* we can't handle wider than 8192px */ |
417 | if (xres > 8192) { | 467 | if (xres > 8192) { |
418 | dev_err(&pdev->dev, "width exceeding the limit (> 8192)."); | 468 | dev_err(&pdev->dev, "width exceeding the limit (> 8192)."); |
419 | return -EINVAL; | 469 | return ERR_PTR(-EINVAL); |
420 | } | ||
421 | |||
422 | /* do we have at least one ICB config? */ | ||
423 | if (cfg->icb[0].marker_icb < 0 || cfg->icb[0].cache_icb < 0) { | ||
424 | dev_err(&pdev->dev, "at least one ICB is required."); | ||
425 | return -EINVAL; | ||
426 | } | 470 | } |
427 | 471 | ||
428 | mutex_lock(&priv->lock); | 472 | mutex_lock(&priv->lock); |
429 | 473 | ||
430 | if (priv->used_meram_cache_regions + 2 > SH_MOBILE_MERAM_ICB_NUM) { | 474 | /* We now register the ICBs and allocate the MERAM regions. */ |
431 | dev_err(&pdev->dev, "no more ICB available."); | 475 | cache = meram_alloc(priv, cfg, pixelformat); |
432 | error = -EINVAL; | 476 | if (IS_ERR(cache)) { |
433 | goto err; | 477 | dev_err(&pdev->dev, "MERAM allocation failed (%ld).", |
434 | } | 478 | PTR_ERR(cache)); |
435 | |||
436 | /* make sure that there's no overlaps */ | ||
437 | if (meram_check_overlap(priv, &cfg->icb[0])) { | ||
438 | dev_err(&pdev->dev, "conflicting config detected."); | ||
439 | error = -EINVAL; | ||
440 | goto err; | 479 | goto err; |
441 | } | 480 | } |
442 | n = 1; | ||
443 | |||
444 | /* do the same if we have the second ICB set */ | ||
445 | if (cfg->icb[1].marker_icb >= 0 && cfg->icb[1].cache_icb >= 0) { | ||
446 | if (meram_check_overlap(priv, &cfg->icb[1])) { | ||
447 | dev_err(&pdev->dev, "conflicting config detected."); | ||
448 | error = -EINVAL; | ||
449 | goto err; | ||
450 | } | ||
451 | n = 2; | ||
452 | } | ||
453 | |||
454 | if (is_nvcolor(pixelformat) && n != 2) { | ||
455 | dev_err(&pdev->dev, "requires two ICB sets for planar Y/C."); | ||
456 | error = -EINVAL; | ||
457 | goto err; | ||
458 | } | ||
459 | |||
460 | /* we now register the ICB */ | ||
461 | cfg->pixelformat = pixelformat; | ||
462 | meram_mark(priv, &cfg->icb[0]); | ||
463 | if (is_nvcolor(pixelformat)) | ||
464 | meram_mark(priv, &cfg->icb[1]); | ||
465 | 481 | ||
466 | /* initialize MERAM */ | 482 | /* initialize MERAM */ |
467 | meram_init(priv, &cfg->icb[0], xres, yres, &out_pitch); | 483 | meram_init(priv, &cache->planes[0], xres, yres, &out_pitch); |
468 | *pitch = out_pitch; | 484 | *pitch = out_pitch; |
469 | if (pixelformat == SH_MOBILE_MERAM_PF_NV) | 485 | if (pixelformat == SH_MOBILE_MERAM_PF_NV) |
470 | meram_init(priv, &cfg->icb[1], xres, (yres + 1) / 2, | 486 | meram_init(priv, &cache->planes[1], xres, (yres + 1) / 2, |
471 | &out_pitch); | 487 | &out_pitch); |
472 | else if (pixelformat == SH_MOBILE_MERAM_PF_NV24) | 488 | else if (pixelformat == SH_MOBILE_MERAM_PF_NV24) |
473 | meram_init(priv, &cfg->icb[1], 2 * xres, (yres + 1) / 2, | 489 | meram_init(priv, &cache->planes[1], 2 * xres, (yres + 1) / 2, |
474 | &out_pitch); | 490 | &out_pitch); |
475 | 491 | ||
476 | cfg->current_reg = 1; | ||
477 | meram_set_next_addr(priv, cfg, base_addr_y, base_addr_c); | ||
478 | meram_get_next_icb_addr(pdata, cfg, icb_addr_y, icb_addr_c); | ||
479 | |||
480 | dev_dbg(&pdev->dev, "registered - can access via y=%08lx, c=%08lx", | ||
481 | *icb_addr_y, *icb_addr_c); | ||
482 | |||
483 | err: | 492 | err: |
484 | mutex_unlock(&priv->lock); | 493 | mutex_unlock(&priv->lock); |
485 | return error; | 494 | return cache; |
486 | } | 495 | } |
487 | 496 | ||
488 | static int sh_mobile_meram_unregister(struct sh_mobile_meram_info *pdata, | 497 | static void |
489 | struct sh_mobile_meram_cfg *cfg) | 498 | sh_mobile_meram_unregister(struct sh_mobile_meram_info *pdata, void *data) |
490 | { | 499 | { |
491 | struct sh_mobile_meram_priv *priv; | 500 | struct sh_mobile_meram_fb_cache *cache = data; |
492 | 501 | struct sh_mobile_meram_priv *priv = pdata->priv; | |
493 | if (!pdata || !pdata->priv || !cfg) | ||
494 | return -EINVAL; | ||
495 | |||
496 | priv = pdata->priv; | ||
497 | 502 | ||
498 | mutex_lock(&priv->lock); | 503 | mutex_lock(&priv->lock); |
499 | 504 | ||
500 | /* deinit & unmark */ | 505 | /* deinit & free */ |
501 | if (is_nvcolor(cfg->pixelformat)) { | 506 | meram_deinit(priv, &cache->planes[0]); |
502 | meram_deinit(priv, &cfg->icb[1]); | 507 | if (cache->nplanes == 2) |
503 | meram_unmark(priv, &cfg->icb[1]); | 508 | meram_deinit(priv, &cache->planes[1]); |
504 | } | ||
505 | meram_deinit(priv, &cfg->icb[0]); | ||
506 | meram_unmark(priv, &cfg->icb[0]); | ||
507 | 509 | ||
508 | mutex_unlock(&priv->lock); | 510 | meram_free(priv, cache); |
509 | 511 | ||
510 | return 0; | 512 | mutex_unlock(&priv->lock); |
511 | } | 513 | } |
512 | 514 | ||
513 | static int sh_mobile_meram_update(struct sh_mobile_meram_info *pdata, | 515 | static void |
514 | struct sh_mobile_meram_cfg *cfg, | 516 | sh_mobile_meram_update(struct sh_mobile_meram_info *pdata, void *data, |
515 | unsigned long base_addr_y, | 517 | unsigned long base_addr_y, unsigned long base_addr_c, |
516 | unsigned long base_addr_c, | 518 | unsigned long *icb_addr_y, unsigned long *icb_addr_c) |
517 | unsigned long *icb_addr_y, | ||
518 | unsigned long *icb_addr_c) | ||
519 | { | 519 | { |
520 | struct sh_mobile_meram_priv *priv; | 520 | struct sh_mobile_meram_fb_cache *cache = data; |
521 | 521 | struct sh_mobile_meram_priv *priv = pdata->priv; | |
522 | if (!pdata || !pdata->priv || !cfg) | ||
523 | return -EINVAL; | ||
524 | |||
525 | priv = pdata->priv; | ||
526 | 522 | ||
527 | mutex_lock(&priv->lock); | 523 | mutex_lock(&priv->lock); |
528 | 524 | ||
529 | meram_set_next_addr(priv, cfg, base_addr_y, base_addr_c); | 525 | meram_set_next_addr(priv, cache, base_addr_y, base_addr_c); |
530 | meram_get_next_icb_addr(pdata, cfg, icb_addr_y, icb_addr_c); | 526 | meram_get_next_icb_addr(pdata, cache, icb_addr_y, icb_addr_c); |
531 | 527 | ||
532 | mutex_unlock(&priv->lock); | 528 | mutex_unlock(&priv->lock); |
533 | |||
534 | return 0; | ||
535 | } | 529 | } |
536 | 530 | ||
537 | static int sh_mobile_meram_runtime_suspend(struct device *dev) | 531 | static struct sh_mobile_meram_ops sh_mobile_meram_ops = { |
532 | .module = THIS_MODULE, | ||
533 | .meram_register = sh_mobile_meram_register, | ||
534 | .meram_unregister = sh_mobile_meram_unregister, | ||
535 | .meram_update = sh_mobile_meram_update, | ||
536 | }; | ||
537 | |||
538 | /* ----------------------------------------------------------------------------- | ||
539 | * Power management | ||
540 | */ | ||
541 | |||
542 | static int sh_mobile_meram_suspend(struct device *dev) | ||
538 | { | 543 | { |
539 | struct platform_device *pdev = to_platform_device(dev); | 544 | struct platform_device *pdev = to_platform_device(dev); |
540 | struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev); | 545 | struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev); |
541 | int k, j; | 546 | unsigned int i, j; |
542 | 547 | ||
543 | for (k = 0; k < CMN_REGS_SIZE; k++) | 548 | for (i = 0; i < MERAM_REGS_SIZE; i++) |
544 | priv->cmn_saved_regs[k] = meram_read_reg(priv->base, | 549 | priv->regs[i] = meram_read_reg(priv->base, common_regs[i]); |
545 | common_regs[k]); | ||
546 | 550 | ||
547 | for (j = 0; j < 32; j++) { | 551 | for (i = 0; i < 32; i++) { |
548 | if (!test_bit(j, &priv->used_icb)) | 552 | if (!test_bit(i, &priv->used_icb)) |
549 | continue; | 553 | continue; |
550 | for (k = 0; k < ICB_REGS_SIZE; k++) { | 554 | for (j = 0; j < ICB_REGS_SIZE; j++) { |
551 | priv->icb_saved_regs[j * ICB_REGS_SIZE + k] = | 555 | priv->icbs[i].regs[j] = |
552 | meram_read_icb(priv->base, j, icb_regs[k]); | 556 | meram_read_icb(priv->base, i, icb_regs[j]); |
553 | /* Reset ICB on resume */ | 557 | /* Reset ICB on resume */ |
554 | if (icb_regs[k] == MExxCTL) | 558 | if (icb_regs[j] == MExxCTL) |
555 | priv->icb_saved_regs[j * ICB_REGS_SIZE + k] |= | 559 | priv->icbs[i].regs[j] |= |
556 | MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF; | 560 | MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF; |
557 | } | 561 | } |
558 | } | 562 | } |
559 | return 0; | 563 | return 0; |
560 | } | 564 | } |
561 | 565 | ||
562 | static int sh_mobile_meram_runtime_resume(struct device *dev) | 566 | static int sh_mobile_meram_resume(struct device *dev) |
563 | { | 567 | { |
564 | struct platform_device *pdev = to_platform_device(dev); | 568 | struct platform_device *pdev = to_platform_device(dev); |
565 | struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev); | 569 | struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev); |
566 | int k, j; | 570 | unsigned int i, j; |
567 | 571 | ||
568 | for (j = 0; j < 32; j++) { | 572 | for (i = 0; i < 32; i++) { |
569 | if (!test_bit(j, &priv->used_icb)) | 573 | if (!test_bit(i, &priv->used_icb)) |
570 | continue; | 574 | continue; |
571 | for (k = 0; k < ICB_REGS_SIZE; k++) { | 575 | for (j = 0; j < ICB_REGS_SIZE; j++) |
572 | meram_write_icb(priv->base, j, icb_regs[k], | 576 | meram_write_icb(priv->base, i, icb_regs[j], |
573 | priv->icb_saved_regs[j * ICB_REGS_SIZE + k]); | 577 | priv->icbs[i].regs[j]); |
574 | } | ||
575 | } | 578 | } |
576 | 579 | ||
577 | for (k = 0; k < CMN_REGS_SIZE; k++) | 580 | for (i = 0; i < MERAM_REGS_SIZE; i++) |
578 | meram_write_reg(priv->base, common_regs[k], | 581 | meram_write_reg(priv->base, common_regs[i], priv->regs[i]); |
579 | priv->cmn_saved_regs[k]); | ||
580 | return 0; | 582 | return 0; |
581 | } | 583 | } |
582 | 584 | ||
583 | static const struct dev_pm_ops sh_mobile_meram_dev_pm_ops = { | 585 | static UNIVERSAL_DEV_PM_OPS(sh_mobile_meram_dev_pm_ops, |
584 | .runtime_suspend = sh_mobile_meram_runtime_suspend, | 586 | sh_mobile_meram_suspend, |
585 | .runtime_resume = sh_mobile_meram_runtime_resume, | 587 | sh_mobile_meram_resume, NULL); |
586 | }; | ||
587 | |||
588 | static struct sh_mobile_meram_ops sh_mobile_meram_ops = { | ||
589 | .module = THIS_MODULE, | ||
590 | .meram_register = sh_mobile_meram_register, | ||
591 | .meram_unregister = sh_mobile_meram_unregister, | ||
592 | .meram_update = sh_mobile_meram_update, | ||
593 | }; | ||
594 | 588 | ||
595 | /* | 589 | /* ----------------------------------------------------------------------------- |
596 | * initialize MERAM | 590 | * Probe/remove and driver init/exit |
597 | */ | 591 | */ |
598 | 592 | ||
599 | static int sh_mobile_meram_remove(struct platform_device *pdev); | ||
600 | |||
601 | static int __devinit sh_mobile_meram_probe(struct platform_device *pdev) | 593 | static int __devinit sh_mobile_meram_probe(struct platform_device *pdev) |
602 | { | 594 | { |
603 | struct sh_mobile_meram_priv *priv; | 595 | struct sh_mobile_meram_priv *priv; |
604 | struct sh_mobile_meram_info *pdata = pdev->dev.platform_data; | 596 | struct sh_mobile_meram_info *pdata = pdev->dev.platform_data; |
605 | struct resource *res; | 597 | struct resource *regs; |
598 | struct resource *meram; | ||
599 | unsigned int i; | ||
606 | int error; | 600 | int error; |
607 | 601 | ||
608 | if (!pdata) { | 602 | if (!pdata) { |
@@ -610,8 +604,9 @@ static int __devinit sh_mobile_meram_probe(struct platform_device *pdev) | |||
610 | return -EINVAL; | 604 | return -EINVAL; |
611 | } | 605 | } |
612 | 606 | ||
613 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 607 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
614 | if (!res) { | 608 | meram = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
609 | if (regs == NULL || meram == NULL) { | ||
615 | dev_err(&pdev->dev, "cannot get platform resources\n"); | 610 | dev_err(&pdev->dev, "cannot get platform resources\n"); |
616 | return -ENOENT; | 611 | return -ENOENT; |
617 | } | 612 | } |
@@ -622,32 +617,74 @@ static int __devinit sh_mobile_meram_probe(struct platform_device *pdev) | |||
622 | return -ENOMEM; | 617 | return -ENOMEM; |
623 | } | 618 | } |
624 | 619 | ||
625 | platform_set_drvdata(pdev, priv); | 620 | /* Initialize private data. */ |
626 | |||
627 | /* initialize private data */ | ||
628 | mutex_init(&priv->lock); | 621 | mutex_init(&priv->lock); |
629 | priv->base = ioremap_nocache(res->start, resource_size(res)); | 622 | priv->used_icb = pdata->reserved_icbs; |
623 | |||
624 | for (i = 0; i < MERAM_ICB_NUM; ++i) | ||
625 | priv->icbs[i].index = i; | ||
626 | |||
627 | pdata->ops = &sh_mobile_meram_ops; | ||
628 | pdata->priv = priv; | ||
629 | pdata->pdev = pdev; | ||
630 | |||
631 | /* Request memory regions and remap the registers. */ | ||
632 | if (!request_mem_region(regs->start, resource_size(regs), pdev->name)) { | ||
633 | dev_err(&pdev->dev, "MERAM registers region already claimed\n"); | ||
634 | error = -EBUSY; | ||
635 | goto err_req_regs; | ||
636 | } | ||
637 | |||
638 | if (!request_mem_region(meram->start, resource_size(meram), | ||
639 | pdev->name)) { | ||
640 | dev_err(&pdev->dev, "MERAM memory region already claimed\n"); | ||
641 | error = -EBUSY; | ||
642 | goto err_req_meram; | ||
643 | } | ||
644 | |||
645 | priv->base = ioremap_nocache(regs->start, resource_size(regs)); | ||
630 | if (!priv->base) { | 646 | if (!priv->base) { |
631 | dev_err(&pdev->dev, "ioremap failed\n"); | 647 | dev_err(&pdev->dev, "ioremap failed\n"); |
632 | error = -EFAULT; | 648 | error = -EFAULT; |
633 | goto err; | 649 | goto err_ioremap; |
634 | } | 650 | } |
635 | pdata->ops = &sh_mobile_meram_ops; | 651 | |
636 | pdata->priv = priv; | 652 | priv->meram = meram->start; |
637 | pdata->pdev = pdev; | 653 | |
654 | /* Create and initialize the MERAM memory pool. */ | ||
655 | priv->pool = gen_pool_create(ilog2(MERAM_GRANULARITY), -1); | ||
656 | if (priv->pool == NULL) { | ||
657 | error = -ENOMEM; | ||
658 | goto err_genpool; | ||
659 | } | ||
660 | |||
661 | error = gen_pool_add(priv->pool, meram->start, resource_size(meram), | ||
662 | -1); | ||
663 | if (error < 0) | ||
664 | goto err_genpool; | ||
638 | 665 | ||
639 | /* initialize ICB addressing mode */ | 666 | /* initialize ICB addressing mode */ |
640 | if (pdata->addr_mode == SH_MOBILE_MERAM_MODE1) | 667 | if (pdata->addr_mode == SH_MOBILE_MERAM_MODE1) |
641 | meram_write_reg(priv->base, MEVCR1, MEVCR1_AMD1); | 668 | meram_write_reg(priv->base, MEVCR1, MEVCR1_AMD1); |
642 | 669 | ||
670 | platform_set_drvdata(pdev, priv); | ||
643 | pm_runtime_enable(&pdev->dev); | 671 | pm_runtime_enable(&pdev->dev); |
644 | 672 | ||
645 | dev_info(&pdev->dev, "sh_mobile_meram initialized."); | 673 | dev_info(&pdev->dev, "sh_mobile_meram initialized."); |
646 | 674 | ||
647 | return 0; | 675 | return 0; |
648 | 676 | ||
649 | err: | 677 | err_genpool: |
650 | sh_mobile_meram_remove(pdev); | 678 | if (priv->pool) |
679 | gen_pool_destroy(priv->pool); | ||
680 | iounmap(priv->base); | ||
681 | err_ioremap: | ||
682 | release_mem_region(meram->start, resource_size(meram)); | ||
683 | err_req_meram: | ||
684 | release_mem_region(regs->start, resource_size(regs)); | ||
685 | err_req_regs: | ||
686 | mutex_destroy(&priv->lock); | ||
687 | kfree(priv); | ||
651 | 688 | ||
652 | return error; | 689 | return error; |
653 | } | 690 | } |
@@ -656,11 +693,16 @@ err: | |||
656 | static int sh_mobile_meram_remove(struct platform_device *pdev) | 693 | static int sh_mobile_meram_remove(struct platform_device *pdev) |
657 | { | 694 | { |
658 | struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev); | 695 | struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev); |
696 | struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
697 | struct resource *meram = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
659 | 698 | ||
660 | pm_runtime_disable(&pdev->dev); | 699 | pm_runtime_disable(&pdev->dev); |
661 | 700 | ||
662 | if (priv->base) | 701 | gen_pool_destroy(priv->pool); |
663 | iounmap(priv->base); | 702 | |
703 | iounmap(priv->base); | ||
704 | release_mem_region(meram->start, resource_size(meram)); | ||
705 | release_mem_region(regs->start, resource_size(regs)); | ||
664 | 706 | ||
665 | mutex_destroy(&priv->lock); | 707 | mutex_destroy(&priv->lock); |
666 | 708 | ||
diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c index a40c05ebbdc2..a159b63e18b9 100644 --- a/drivers/video/udlfb.c +++ b/drivers/video/udlfb.c | |||
@@ -72,6 +72,7 @@ MODULE_DEVICE_TABLE(usb, id_table); | |||
72 | static bool console = 1; /* Allow fbcon to open framebuffer */ | 72 | static bool console = 1; /* Allow fbcon to open framebuffer */ |
73 | static bool fb_defio = 1; /* Detect mmap writes using page faults */ | 73 | static bool fb_defio = 1; /* Detect mmap writes using page faults */ |
74 | static bool shadow = 1; /* Optionally disable shadow framebuffer */ | 74 | static bool shadow = 1; /* Optionally disable shadow framebuffer */ |
75 | static int pixel_limit; /* Optionally force a pixel resolution limit */ | ||
75 | 76 | ||
76 | /* dlfb keeps a list of urbs for efficient bulk transfers */ | 77 | /* dlfb keeps a list of urbs for efficient bulk transfers */ |
77 | static void dlfb_urb_completion(struct urb *urb); | 78 | static void dlfb_urb_completion(struct urb *urb); |
@@ -918,10 +919,6 @@ static void dlfb_free(struct kref *kref) | |||
918 | { | 919 | { |
919 | struct dlfb_data *dev = container_of(kref, struct dlfb_data, kref); | 920 | struct dlfb_data *dev = container_of(kref, struct dlfb_data, kref); |
920 | 921 | ||
921 | /* this function will wait for all in-flight urbs to complete */ | ||
922 | if (dev->urbs.count > 0) | ||
923 | dlfb_free_urb_list(dev); | ||
924 | |||
925 | if (dev->backing_buffer) | 922 | if (dev->backing_buffer) |
926 | vfree(dev->backing_buffer); | 923 | vfree(dev->backing_buffer); |
927 | 924 | ||
@@ -940,35 +937,42 @@ static void dlfb_release_urb_work(struct work_struct *work) | |||
940 | up(&unode->dev->urbs.limit_sem); | 937 | up(&unode->dev->urbs.limit_sem); |
941 | } | 938 | } |
942 | 939 | ||
943 | static void dlfb_free_framebuffer_work(struct work_struct *work) | 940 | static void dlfb_free_framebuffer(struct dlfb_data *dev) |
944 | { | 941 | { |
945 | struct dlfb_data *dev = container_of(work, struct dlfb_data, | ||
946 | free_framebuffer_work.work); | ||
947 | struct fb_info *info = dev->info; | 942 | struct fb_info *info = dev->info; |
948 | int node = info->node; | ||
949 | 943 | ||
950 | unregister_framebuffer(info); | 944 | if (info) { |
945 | int node = info->node; | ||
951 | 946 | ||
952 | if (info->cmap.len != 0) | 947 | unregister_framebuffer(info); |
953 | fb_dealloc_cmap(&info->cmap); | ||
954 | if (info->monspecs.modedb) | ||
955 | fb_destroy_modedb(info->monspecs.modedb); | ||
956 | if (info->screen_base) | ||
957 | vfree(info->screen_base); | ||
958 | 948 | ||
959 | fb_destroy_modelist(&info->modelist); | 949 | if (info->cmap.len != 0) |
950 | fb_dealloc_cmap(&info->cmap); | ||
951 | if (info->monspecs.modedb) | ||
952 | fb_destroy_modedb(info->monspecs.modedb); | ||
953 | if (info->screen_base) | ||
954 | vfree(info->screen_base); | ||
960 | 955 | ||
961 | dev->info = 0; | 956 | fb_destroy_modelist(&info->modelist); |
962 | 957 | ||
963 | /* Assume info structure is freed after this point */ | 958 | dev->info = NULL; |
964 | framebuffer_release(info); | ||
965 | 959 | ||
966 | pr_warn("fb_info for /dev/fb%d has been freed\n", node); | 960 | /* Assume info structure is freed after this point */ |
961 | framebuffer_release(info); | ||
962 | |||
963 | pr_warn("fb_info for /dev/fb%d has been freed\n", node); | ||
964 | } | ||
967 | 965 | ||
968 | /* ref taken in probe() as part of registering framebfufer */ | 966 | /* ref taken in probe() as part of registering framebfufer */ |
969 | kref_put(&dev->kref, dlfb_free); | 967 | kref_put(&dev->kref, dlfb_free); |
970 | } | 968 | } |
971 | 969 | ||
970 | static void dlfb_free_framebuffer_work(struct work_struct *work) | ||
971 | { | ||
972 | struct dlfb_data *dev = container_of(work, struct dlfb_data, | ||
973 | free_framebuffer_work.work); | ||
974 | dlfb_free_framebuffer(dev); | ||
975 | } | ||
972 | /* | 976 | /* |
973 | * Assumes caller is holding info->lock mutex (for open and release at least) | 977 | * Assumes caller is holding info->lock mutex (for open and release at least) |
974 | */ | 978 | */ |
@@ -1012,7 +1016,8 @@ static int dlfb_is_valid_mode(struct fb_videomode *mode, | |||
1012 | return 0; | 1016 | return 0; |
1013 | } | 1017 | } |
1014 | 1018 | ||
1015 | pr_info("%dx%d valid mode\n", mode->xres, mode->yres); | 1019 | pr_info("%dx%d @ %d Hz valid mode\n", mode->xres, mode->yres, |
1020 | mode->refresh); | ||
1016 | 1021 | ||
1017 | return 1; | 1022 | return 1; |
1018 | } | 1023 | } |
@@ -1427,19 +1432,22 @@ static ssize_t edid_store( | |||
1427 | struct device *fbdev = container_of(kobj, struct device, kobj); | 1432 | struct device *fbdev = container_of(kobj, struct device, kobj); |
1428 | struct fb_info *fb_info = dev_get_drvdata(fbdev); | 1433 | struct fb_info *fb_info = dev_get_drvdata(fbdev); |
1429 | struct dlfb_data *dev = fb_info->par; | 1434 | struct dlfb_data *dev = fb_info->par; |
1435 | int ret; | ||
1430 | 1436 | ||
1431 | /* We only support write of entire EDID at once, no offset*/ | 1437 | /* We only support write of entire EDID at once, no offset*/ |
1432 | if ((src_size != EDID_LENGTH) || (src_off != 0)) | 1438 | if ((src_size != EDID_LENGTH) || (src_off != 0)) |
1433 | return 0; | 1439 | return -EINVAL; |
1434 | 1440 | ||
1435 | dlfb_setup_modes(dev, fb_info, src, src_size); | 1441 | ret = dlfb_setup_modes(dev, fb_info, src, src_size); |
1442 | if (ret) | ||
1443 | return ret; | ||
1436 | 1444 | ||
1437 | if (dev->edid && (memcmp(src, dev->edid, src_size) == 0)) { | 1445 | if (!dev->edid || memcmp(src, dev->edid, src_size)) |
1438 | pr_info("sysfs written EDID is new default\n"); | 1446 | return -EINVAL; |
1439 | dlfb_ops_set_par(fb_info); | 1447 | |
1440 | return src_size; | 1448 | pr_info("sysfs written EDID is new default\n"); |
1441 | } else | 1449 | dlfb_ops_set_par(fb_info); |
1442 | return 0; | 1450 | return src_size; |
1443 | } | 1451 | } |
1444 | 1452 | ||
1445 | static ssize_t metrics_reset_store(struct device *fbdev, | 1453 | static ssize_t metrics_reset_store(struct device *fbdev, |
@@ -1537,7 +1545,7 @@ static int dlfb_parse_vendor_descriptor(struct dlfb_data *dev, | |||
1537 | u8 length; | 1545 | u8 length; |
1538 | u16 key; | 1546 | u16 key; |
1539 | 1547 | ||
1540 | key = *((u16 *) desc); | 1548 | key = le16_to_cpu(*((u16 *) desc)); |
1541 | desc += sizeof(u16); | 1549 | desc += sizeof(u16); |
1542 | length = *desc; | 1550 | length = *desc; |
1543 | desc++; | 1551 | desc++; |
@@ -1570,14 +1578,15 @@ success: | |||
1570 | kfree(buf); | 1578 | kfree(buf); |
1571 | return true; | 1579 | return true; |
1572 | } | 1580 | } |
1581 | |||
1582 | static void dlfb_init_framebuffer_work(struct work_struct *work); | ||
1583 | |||
1573 | static int dlfb_usb_probe(struct usb_interface *interface, | 1584 | static int dlfb_usb_probe(struct usb_interface *interface, |
1574 | const struct usb_device_id *id) | 1585 | const struct usb_device_id *id) |
1575 | { | 1586 | { |
1576 | struct usb_device *usbdev; | 1587 | struct usb_device *usbdev; |
1577 | struct dlfb_data *dev = 0; | 1588 | struct dlfb_data *dev = 0; |
1578 | struct fb_info *info = 0; | ||
1579 | int retval = -ENOMEM; | 1589 | int retval = -ENOMEM; |
1580 | int i; | ||
1581 | 1590 | ||
1582 | /* usb initialization */ | 1591 | /* usb initialization */ |
1583 | 1592 | ||
@@ -1589,9 +1598,7 @@ static int dlfb_usb_probe(struct usb_interface *interface, | |||
1589 | goto error; | 1598 | goto error; |
1590 | } | 1599 | } |
1591 | 1600 | ||
1592 | /* we need to wait for both usb and fbdev to spin down on disconnect */ | ||
1593 | kref_init(&dev->kref); /* matching kref_put in usb .disconnect fn */ | 1601 | kref_init(&dev->kref); /* matching kref_put in usb .disconnect fn */ |
1594 | kref_get(&dev->kref); /* matching kref_put in free_framebuffer_work */ | ||
1595 | 1602 | ||
1596 | dev->udev = usbdev; | 1603 | dev->udev = usbdev; |
1597 | dev->gdev = &usbdev->dev; /* our generic struct device * */ | 1604 | dev->gdev = &usbdev->dev; /* our generic struct device * */ |
@@ -1613,16 +1620,53 @@ static int dlfb_usb_probe(struct usb_interface *interface, | |||
1613 | goto error; | 1620 | goto error; |
1614 | } | 1621 | } |
1615 | 1622 | ||
1623 | if (pixel_limit) { | ||
1624 | pr_warn("DL chip limit of %d overriden" | ||
1625 | " by module param to %d\n", | ||
1626 | dev->sku_pixel_limit, pixel_limit); | ||
1627 | dev->sku_pixel_limit = pixel_limit; | ||
1628 | } | ||
1629 | |||
1630 | |||
1616 | if (!dlfb_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) { | 1631 | if (!dlfb_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) { |
1617 | retval = -ENOMEM; | 1632 | retval = -ENOMEM; |
1618 | pr_err("dlfb_alloc_urb_list failed\n"); | 1633 | pr_err("dlfb_alloc_urb_list failed\n"); |
1619 | goto error; | 1634 | goto error; |
1620 | } | 1635 | } |
1621 | 1636 | ||
1637 | kref_get(&dev->kref); /* matching kref_put in free_framebuffer_work */ | ||
1638 | |||
1622 | /* We don't register a new USB class. Our client interface is fbdev */ | 1639 | /* We don't register a new USB class. Our client interface is fbdev */ |
1623 | 1640 | ||
1641 | /* Workitem keep things fast & simple during USB enumeration */ | ||
1642 | INIT_DELAYED_WORK(&dev->init_framebuffer_work, | ||
1643 | dlfb_init_framebuffer_work); | ||
1644 | schedule_delayed_work(&dev->init_framebuffer_work, 0); | ||
1645 | |||
1646 | return 0; | ||
1647 | |||
1648 | error: | ||
1649 | if (dev) { | ||
1650 | |||
1651 | kref_put(&dev->kref, dlfb_free); /* ref for framebuffer */ | ||
1652 | kref_put(&dev->kref, dlfb_free); /* last ref from kref_init */ | ||
1653 | |||
1654 | /* dev has been deallocated. Do not dereference */ | ||
1655 | } | ||
1656 | |||
1657 | return retval; | ||
1658 | } | ||
1659 | |||
1660 | static void dlfb_init_framebuffer_work(struct work_struct *work) | ||
1661 | { | ||
1662 | struct dlfb_data *dev = container_of(work, struct dlfb_data, | ||
1663 | init_framebuffer_work.work); | ||
1664 | struct fb_info *info; | ||
1665 | int retval; | ||
1666 | int i; | ||
1667 | |||
1624 | /* allocates framebuffer driver structure, not framebuffer memory */ | 1668 | /* allocates framebuffer driver structure, not framebuffer memory */ |
1625 | info = framebuffer_alloc(0, &interface->dev); | 1669 | info = framebuffer_alloc(0, dev->gdev); |
1626 | if (!info) { | 1670 | if (!info) { |
1627 | retval = -ENOMEM; | 1671 | retval = -ENOMEM; |
1628 | pr_err("framebuffer_alloc failed\n"); | 1672 | pr_err("framebuffer_alloc failed\n"); |
@@ -1668,15 +1712,13 @@ static int dlfb_usb_probe(struct usb_interface *interface, | |||
1668 | for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) { | 1712 | for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) { |
1669 | retval = device_create_file(info->dev, &fb_device_attrs[i]); | 1713 | retval = device_create_file(info->dev, &fb_device_attrs[i]); |
1670 | if (retval) { | 1714 | if (retval) { |
1671 | pr_err("device_create_file failed %d\n", retval); | 1715 | pr_warn("device_create_file failed %d\n", retval); |
1672 | goto err_del_attrs; | ||
1673 | } | 1716 | } |
1674 | } | 1717 | } |
1675 | 1718 | ||
1676 | retval = device_create_bin_file(info->dev, &edid_attr); | 1719 | retval = device_create_bin_file(info->dev, &edid_attr); |
1677 | if (retval) { | 1720 | if (retval) { |
1678 | pr_err("device_create_bin_file failed %d\n", retval); | 1721 | pr_warn("device_create_bin_file failed %d\n", retval); |
1679 | goto err_del_attrs; | ||
1680 | } | 1722 | } |
1681 | 1723 | ||
1682 | pr_info("DisplayLink USB device /dev/fb%d attached. %dx%d resolution." | 1724 | pr_info("DisplayLink USB device /dev/fb%d attached. %dx%d resolution." |
@@ -1684,38 +1726,10 @@ static int dlfb_usb_probe(struct usb_interface *interface, | |||
1684 | info->var.xres, info->var.yres, | 1726 | info->var.xres, info->var.yres, |
1685 | ((dev->backing_buffer) ? | 1727 | ((dev->backing_buffer) ? |
1686 | info->fix.smem_len * 2 : info->fix.smem_len) >> 10); | 1728 | info->fix.smem_len * 2 : info->fix.smem_len) >> 10); |
1687 | return 0; | 1729 | return; |
1688 | |||
1689 | err_del_attrs: | ||
1690 | for (i -= 1; i >= 0; i--) | ||
1691 | device_remove_file(info->dev, &fb_device_attrs[i]); | ||
1692 | 1730 | ||
1693 | error: | 1731 | error: |
1694 | if (dev) { | 1732 | dlfb_free_framebuffer(dev); |
1695 | |||
1696 | if (info) { | ||
1697 | if (info->cmap.len != 0) | ||
1698 | fb_dealloc_cmap(&info->cmap); | ||
1699 | if (info->monspecs.modedb) | ||
1700 | fb_destroy_modedb(info->monspecs.modedb); | ||
1701 | if (info->screen_base) | ||
1702 | vfree(info->screen_base); | ||
1703 | |||
1704 | fb_destroy_modelist(&info->modelist); | ||
1705 | |||
1706 | framebuffer_release(info); | ||
1707 | } | ||
1708 | |||
1709 | if (dev->backing_buffer) | ||
1710 | vfree(dev->backing_buffer); | ||
1711 | |||
1712 | kref_put(&dev->kref, dlfb_free); /* ref for framebuffer */ | ||
1713 | kref_put(&dev->kref, dlfb_free); /* last ref from kref_init */ | ||
1714 | |||
1715 | /* dev has been deallocated. Do not dereference */ | ||
1716 | } | ||
1717 | |||
1718 | return retval; | ||
1719 | } | 1733 | } |
1720 | 1734 | ||
1721 | static void dlfb_usb_disconnect(struct usb_interface *interface) | 1735 | static void dlfb_usb_disconnect(struct usb_interface *interface) |
@@ -1735,12 +1749,20 @@ static void dlfb_usb_disconnect(struct usb_interface *interface) | |||
1735 | /* When non-active we'll update virtual framebuffer, but no new urbs */ | 1749 | /* When non-active we'll update virtual framebuffer, but no new urbs */ |
1736 | atomic_set(&dev->usb_active, 0); | 1750 | atomic_set(&dev->usb_active, 0); |
1737 | 1751 | ||
1738 | /* remove udlfb's sysfs interfaces */ | 1752 | /* this function will wait for all in-flight urbs to complete */ |
1739 | for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) | 1753 | dlfb_free_urb_list(dev); |
1740 | device_remove_file(info->dev, &fb_device_attrs[i]); | 1754 | |
1741 | device_remove_bin_file(info->dev, &edid_attr); | 1755 | if (info) { |
1742 | unlink_framebuffer(info); | 1756 | /* remove udlfb's sysfs interfaces */ |
1757 | for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) | ||
1758 | device_remove_file(info->dev, &fb_device_attrs[i]); | ||
1759 | device_remove_bin_file(info->dev, &edid_attr); | ||
1760 | unlink_framebuffer(info); | ||
1761 | } | ||
1762 | |||
1743 | usb_set_intfdata(interface, NULL); | 1763 | usb_set_intfdata(interface, NULL); |
1764 | dev->udev = NULL; | ||
1765 | dev->gdev = NULL; | ||
1744 | 1766 | ||
1745 | /* if clients still have us open, will be freed on last close */ | 1767 | /* if clients still have us open, will be freed on last close */ |
1746 | if (dev->fb_count == 0) | 1768 | if (dev->fb_count == 0) |
@@ -1806,12 +1828,12 @@ static void dlfb_free_urb_list(struct dlfb_data *dev) | |||
1806 | int ret; | 1828 | int ret; |
1807 | unsigned long flags; | 1829 | unsigned long flags; |
1808 | 1830 | ||
1809 | pr_notice("Waiting for completes and freeing all render urbs\n"); | 1831 | pr_notice("Freeing all render urbs\n"); |
1810 | 1832 | ||
1811 | /* keep waiting and freeing, until we've got 'em all */ | 1833 | /* keep waiting and freeing, until we've got 'em all */ |
1812 | while (count--) { | 1834 | while (count--) { |
1813 | 1835 | ||
1814 | /* Getting interrupted means a leak, but ok at shutdown*/ | 1836 | /* Getting interrupted means a leak, but ok at disconnect */ |
1815 | ret = down_interruptible(&dev->urbs.limit_sem); | 1837 | ret = down_interruptible(&dev->urbs.limit_sem); |
1816 | if (ret) | 1838 | if (ret) |
1817 | break; | 1839 | break; |
@@ -1833,6 +1855,7 @@ static void dlfb_free_urb_list(struct dlfb_data *dev) | |||
1833 | kfree(node); | 1855 | kfree(node); |
1834 | } | 1856 | } |
1835 | 1857 | ||
1858 | dev->urbs.count = 0; | ||
1836 | } | 1859 | } |
1837 | 1860 | ||
1838 | static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size) | 1861 | static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size) |
@@ -1948,6 +1971,9 @@ MODULE_PARM_DESC(fb_defio, "Page fault detection of mmap writes"); | |||
1948 | module_param(shadow, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP); | 1971 | module_param(shadow, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP); |
1949 | MODULE_PARM_DESC(shadow, "Shadow vid mem. Disable to save mem but lose perf"); | 1972 | MODULE_PARM_DESC(shadow, "Shadow vid mem. Disable to save mem but lose perf"); |
1950 | 1973 | ||
1974 | module_param(pixel_limit, int, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP); | ||
1975 | MODULE_PARM_DESC(pixel_limit, "Force limit on max mode (in x*y pixels)"); | ||
1976 | |||
1951 | MODULE_AUTHOR("Roberto De Ioris <roberto@unbit.it>, " | 1977 | MODULE_AUTHOR("Roberto De Ioris <roberto@unbit.it>, " |
1952 | "Jaya Kumar <jayakumar.lkml@gmail.com>, " | 1978 | "Jaya Kumar <jayakumar.lkml@gmail.com>, " |
1953 | "Bernie Thompson <bernie@plugable.com>"); | 1979 | "Bernie Thompson <bernie@plugable.com>"); |
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index e7f69ef572dc..9db3de3a8418 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c | |||
@@ -362,7 +362,7 @@ static u8 *uvesafb_vbe_state_save(struct uvesafb_par *par) | |||
362 | 362 | ||
363 | state = kmalloc(par->vbe_state_size, GFP_KERNEL); | 363 | state = kmalloc(par->vbe_state_size, GFP_KERNEL); |
364 | if (!state) | 364 | if (!state) |
365 | return NULL; | 365 | return ERR_PTR(-ENOMEM); |
366 | 366 | ||
367 | task = uvesafb_prep(); | 367 | task = uvesafb_prep(); |
368 | if (!task) { | 368 | if (!task) { |
@@ -1172,9 +1172,17 @@ static int uvesafb_open(struct fb_info *info, int user) | |||
1172 | { | 1172 | { |
1173 | struct uvesafb_par *par = info->par; | 1173 | struct uvesafb_par *par = info->par; |
1174 | int cnt = atomic_read(&par->ref_count); | 1174 | int cnt = atomic_read(&par->ref_count); |
1175 | u8 *buf = NULL; | ||
1175 | 1176 | ||
1176 | if (!cnt && par->vbe_state_size) | 1177 | if (!cnt && par->vbe_state_size) { |
1177 | par->vbe_state_orig = uvesafb_vbe_state_save(par); | 1178 | buf = uvesafb_vbe_state_save(par); |
1179 | if (IS_ERR(buf)) { | ||
1180 | printk(KERN_WARNING "uvesafb: save hardware state" | ||
1181 | "failed, error code is %ld!\n", PTR_ERR(buf)); | ||
1182 | } else { | ||
1183 | par->vbe_state_orig = buf; | ||
1184 | } | ||
1185 | } | ||
1178 | 1186 | ||
1179 | atomic_inc(&par->ref_count); | 1187 | atomic_inc(&par->ref_count); |
1180 | return 0; | 1188 | return 0; |
diff --git a/drivers/video/via/Makefile b/drivers/video/via/Makefile index 5108136e8776..159f26e6adb5 100644 --- a/drivers/video/via/Makefile +++ b/drivers/video/via/Makefile | |||
@@ -6,4 +6,7 @@ obj-$(CONFIG_FB_VIA) += viafb.o | |||
6 | 6 | ||
7 | viafb-y :=viafbdev.o hw.o via_i2c.o dvi.o lcd.o ioctl.o accel.o \ | 7 | viafb-y :=viafbdev.o hw.o via_i2c.o dvi.o lcd.o ioctl.o accel.o \ |
8 | via_utility.o vt1636.o global.o tblDPASetting.o viamode.o \ | 8 | via_utility.o vt1636.o global.o tblDPASetting.o viamode.o \ |
9 | via-core.o via-gpio.o via_modesetting.o via_clock.o | 9 | via-core.o via-gpio.o via_modesetting.o via_clock.o \ |
10 | via_aux.o via_aux_edid.o via_aux_vt1636.o via_aux_vt1632.o \ | ||
11 | via_aux_vt1631.o via_aux_vt1625.o via_aux_vt1622.o via_aux_vt1621.o \ | ||
12 | via_aux_sii164.o via_aux_ch7301.o | ||
diff --git a/drivers/video/via/chip.h b/drivers/video/via/chip.h index 3ebf20c06eef..d32a5076c20f 100644 --- a/drivers/video/via/chip.h +++ b/drivers/video/via/chip.h | |||
@@ -146,9 +146,6 @@ struct tmds_setting_information { | |||
146 | 146 | ||
147 | struct lvds_setting_information { | 147 | struct lvds_setting_information { |
148 | int iga_path; | 148 | int iga_path; |
149 | int h_active; | ||
150 | int v_active; | ||
151 | int bpp; | ||
152 | int lcd_panel_hres; | 149 | int lcd_panel_hres; |
153 | int lcd_panel_vres; | 150 | int lcd_panel_vres; |
154 | int display_method; | 151 | int display_method; |
diff --git a/drivers/video/via/dvi.c b/drivers/video/via/dvi.c index 9138e517267c..6be72f0ba21d 100644 --- a/drivers/video/via/dvi.c +++ b/drivers/video/via/dvi.c | |||
@@ -172,10 +172,11 @@ static int tmds_register_read_bytes(int index, u8 *buff, int buff_len) | |||
172 | } | 172 | } |
173 | 173 | ||
174 | /* DVI Set Mode */ | 174 | /* DVI Set Mode */ |
175 | void viafb_dvi_set_mode(const struct fb_var_screeninfo *var, int iga) | 175 | void viafb_dvi_set_mode(const struct fb_var_screeninfo *var, |
176 | u16 cxres, u16 cyres, int iga) | ||
176 | { | 177 | { |
177 | struct fb_var_screeninfo dvi_var = *var; | 178 | struct fb_var_screeninfo dvi_var = *var; |
178 | struct crt_mode_table *rb_mode; | 179 | const struct fb_videomode *rb_mode; |
179 | int maxPixelClock; | 180 | int maxPixelClock; |
180 | 181 | ||
181 | maxPixelClock = viaparinfo->shared->tmds_setting_info.max_pixel_clock; | 182 | maxPixelClock = viaparinfo->shared->tmds_setting_info.max_pixel_clock; |
@@ -185,7 +186,7 @@ void viafb_dvi_set_mode(const struct fb_var_screeninfo *var, int iga) | |||
185 | viafb_fill_var_timing_info(&dvi_var, rb_mode); | 186 | viafb_fill_var_timing_info(&dvi_var, rb_mode); |
186 | } | 187 | } |
187 | 188 | ||
188 | viafb_fill_crtc_timing(&dvi_var, iga); | 189 | viafb_fill_crtc_timing(&dvi_var, cxres, cyres, iga); |
189 | } | 190 | } |
190 | 191 | ||
191 | /* Sense DVI Connector */ | 192 | /* Sense DVI Connector */ |
diff --git a/drivers/video/via/dvi.h b/drivers/video/via/dvi.h index e2116aaf797a..db757850c216 100644 --- a/drivers/video/via/dvi.h +++ b/drivers/video/via/dvi.h | |||
@@ -59,6 +59,7 @@ void viafb_dvi_enable(void); | |||
59 | bool __devinit viafb_tmds_trasmitter_identify(void); | 59 | bool __devinit viafb_tmds_trasmitter_identify(void); |
60 | void __devinit viafb_init_dvi_size(struct tmds_chip_information *tmds_chip, | 60 | void __devinit viafb_init_dvi_size(struct tmds_chip_information *tmds_chip, |
61 | struct tmds_setting_information *tmds_setting); | 61 | struct tmds_setting_information *tmds_setting); |
62 | void viafb_dvi_set_mode(const struct fb_var_screeninfo *var, int iga); | 62 | void viafb_dvi_set_mode(const struct fb_var_screeninfo *var, |
63 | u16 cxres, u16 cyres, int iga); | ||
63 | 64 | ||
64 | #endif /* __DVI_H__ */ | 65 | #endif /* __DVI_H__ */ |
diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index 8497727d66de..898590db5e14 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c | |||
@@ -1467,28 +1467,32 @@ void viafb_set_vclock(u32 clk, int set_iga) | |||
1467 | via_write_misc_reg_mask(0x0C, 0x0C); /* select external clock */ | 1467 | via_write_misc_reg_mask(0x0C, 0x0C); /* select external clock */ |
1468 | } | 1468 | } |
1469 | 1469 | ||
1470 | static struct display_timing var_to_timing(const struct fb_var_screeninfo *var) | 1470 | struct display_timing var_to_timing(const struct fb_var_screeninfo *var, |
1471 | u16 cxres, u16 cyres) | ||
1471 | { | 1472 | { |
1472 | struct display_timing timing; | 1473 | struct display_timing timing; |
1474 | u16 dx = (var->xres - cxres) / 2, dy = (var->yres - cyres) / 2; | ||
1473 | 1475 | ||
1474 | timing.hor_addr = var->xres; | 1476 | timing.hor_addr = cxres; |
1475 | timing.hor_sync_start = timing.hor_addr + var->right_margin; | 1477 | timing.hor_sync_start = timing.hor_addr + var->right_margin + dx; |
1476 | timing.hor_sync_end = timing.hor_sync_start + var->hsync_len; | 1478 | timing.hor_sync_end = timing.hor_sync_start + var->hsync_len; |
1477 | timing.hor_total = timing.hor_sync_end + var->left_margin; | 1479 | timing.hor_total = timing.hor_sync_end + var->left_margin + dx; |
1478 | timing.hor_blank_start = timing.hor_addr; | 1480 | timing.hor_blank_start = timing.hor_addr + dx; |
1479 | timing.hor_blank_end = timing.hor_total; | 1481 | timing.hor_blank_end = timing.hor_total - dx; |
1480 | timing.ver_addr = var->yres; | 1482 | timing.ver_addr = cyres; |
1481 | timing.ver_sync_start = timing.ver_addr + var->lower_margin; | 1483 | timing.ver_sync_start = timing.ver_addr + var->lower_margin + dy; |
1482 | timing.ver_sync_end = timing.ver_sync_start + var->vsync_len; | 1484 | timing.ver_sync_end = timing.ver_sync_start + var->vsync_len; |
1483 | timing.ver_total = timing.ver_sync_end + var->upper_margin; | 1485 | timing.ver_total = timing.ver_sync_end + var->upper_margin + dy; |
1484 | timing.ver_blank_start = timing.ver_addr; | 1486 | timing.ver_blank_start = timing.ver_addr + dy; |
1485 | timing.ver_blank_end = timing.ver_total; | 1487 | timing.ver_blank_end = timing.ver_total - dy; |
1486 | return timing; | 1488 | return timing; |
1487 | } | 1489 | } |
1488 | 1490 | ||
1489 | void viafb_fill_crtc_timing(const struct fb_var_screeninfo *var, int iga) | 1491 | void viafb_fill_crtc_timing(const struct fb_var_screeninfo *var, |
1492 | u16 cxres, u16 cyres, int iga) | ||
1490 | { | 1493 | { |
1491 | struct display_timing crt_reg = var_to_timing(var); | 1494 | struct display_timing crt_reg = var_to_timing(var, |
1495 | cxres ? cxres : var->xres, cyres ? cyres : var->yres); | ||
1492 | 1496 | ||
1493 | if (iga == IGA1) | 1497 | if (iga == IGA1) |
1494 | via_set_primary_timing(&crt_reg); | 1498 | via_set_primary_timing(&crt_reg); |
@@ -1526,13 +1530,6 @@ void viafb_update_device_setting(int hres, int vres, int bpp, int flag) | |||
1526 | if (flag == 0) { | 1530 | if (flag == 0) { |
1527 | viaparinfo->tmds_setting_info->h_active = hres; | 1531 | viaparinfo->tmds_setting_info->h_active = hres; |
1528 | viaparinfo->tmds_setting_info->v_active = vres; | 1532 | viaparinfo->tmds_setting_info->v_active = vres; |
1529 | |||
1530 | viaparinfo->lvds_setting_info->h_active = hres; | ||
1531 | viaparinfo->lvds_setting_info->v_active = vres; | ||
1532 | viaparinfo->lvds_setting_info->bpp = bpp; | ||
1533 | viaparinfo->lvds_setting_info2->h_active = hres; | ||
1534 | viaparinfo->lvds_setting_info2->v_active = vres; | ||
1535 | viaparinfo->lvds_setting_info2->bpp = bpp; | ||
1536 | } else { | 1533 | } else { |
1537 | 1534 | ||
1538 | if (viaparinfo->tmds_setting_info->iga_path == IGA2) { | 1535 | if (viaparinfo->tmds_setting_info->iga_path == IGA2) { |
@@ -1540,16 +1537,6 @@ void viafb_update_device_setting(int hres, int vres, int bpp, int flag) | |||
1540 | viaparinfo->tmds_setting_info->v_active = vres; | 1537 | viaparinfo->tmds_setting_info->v_active = vres; |
1541 | } | 1538 | } |
1542 | 1539 | ||
1543 | if (viaparinfo->lvds_setting_info->iga_path == IGA2) { | ||
1544 | viaparinfo->lvds_setting_info->h_active = hres; | ||
1545 | viaparinfo->lvds_setting_info->v_active = vres; | ||
1546 | viaparinfo->lvds_setting_info->bpp = bpp; | ||
1547 | } | ||
1548 | if (IGA2 == viaparinfo->lvds_setting_info2->iga_path) { | ||
1549 | viaparinfo->lvds_setting_info2->h_active = hres; | ||
1550 | viaparinfo->lvds_setting_info2->v_active = vres; | ||
1551 | viaparinfo->lvds_setting_info2->bpp = bpp; | ||
1552 | } | ||
1553 | } | 1540 | } |
1554 | } | 1541 | } |
1555 | 1542 | ||
@@ -1758,13 +1745,13 @@ static void set_display_channel(void) | |||
1758 | } | 1745 | } |
1759 | } | 1746 | } |
1760 | 1747 | ||
1761 | static u8 get_sync(struct fb_info *info) | 1748 | static u8 get_sync(struct fb_var_screeninfo *var) |
1762 | { | 1749 | { |
1763 | u8 polarity = 0; | 1750 | u8 polarity = 0; |
1764 | 1751 | ||
1765 | if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) | 1752 | if (!(var->sync & FB_SYNC_HOR_HIGH_ACT)) |
1766 | polarity |= VIA_HSYNC_NEGATIVE; | 1753 | polarity |= VIA_HSYNC_NEGATIVE; |
1767 | if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) | 1754 | if (!(var->sync & FB_SYNC_VERT_HIGH_ACT)) |
1768 | polarity |= VIA_VSYNC_NEGATIVE; | 1755 | polarity |= VIA_VSYNC_NEGATIVE; |
1769 | return polarity; | 1756 | return polarity; |
1770 | } | 1757 | } |
@@ -1844,9 +1831,9 @@ static void hw_init(void) | |||
1844 | load_fix_bit_crtc_reg(); | 1831 | load_fix_bit_crtc_reg(); |
1845 | } | 1832 | } |
1846 | 1833 | ||
1847 | int viafb_setmode(int video_bpp, int video_bpp1) | 1834 | int viafb_setmode(void) |
1848 | { | 1835 | { |
1849 | int j; | 1836 | int j, cxres = 0, cyres = 0; |
1850 | int port; | 1837 | int port; |
1851 | u32 devices = viaparinfo->shared->iga1_devices | 1838 | u32 devices = viaparinfo->shared->iga1_devices |
1852 | | viaparinfo->shared->iga2_devices; | 1839 | | viaparinfo->shared->iga2_devices; |
@@ -1895,6 +1882,8 @@ int viafb_setmode(int video_bpp, int video_bpp1) | |||
1895 | } else if (viafb_SAMM_ON) { | 1882 | } else if (viafb_SAMM_ON) { |
1896 | viafb_fill_var_timing_info(&var2, viafb_get_best_mode( | 1883 | viafb_fill_var_timing_info(&var2, viafb_get_best_mode( |
1897 | viafb_second_xres, viafb_second_yres, viafb_refresh1)); | 1884 | viafb_second_xres, viafb_second_yres, viafb_refresh1)); |
1885 | cxres = viafbinfo->var.xres; | ||
1886 | cyres = viafbinfo->var.yres; | ||
1898 | var2.bits_per_pixel = viafbinfo->var.bits_per_pixel; | 1887 | var2.bits_per_pixel = viafbinfo->var.bits_per_pixel; |
1899 | } | 1888 | } |
1900 | 1889 | ||
@@ -1902,9 +1891,9 @@ int viafb_setmode(int video_bpp, int video_bpp1) | |||
1902 | if (viafb_CRT_ON) { | 1891 | if (viafb_CRT_ON) { |
1903 | if (viaparinfo->shared->iga2_devices & VIA_CRT | 1892 | if (viaparinfo->shared->iga2_devices & VIA_CRT |
1904 | && viafb_SAMM_ON) | 1893 | && viafb_SAMM_ON) |
1905 | viafb_fill_crtc_timing(&var2, IGA2); | 1894 | viafb_fill_crtc_timing(&var2, cxres, cyres, IGA2); |
1906 | else | 1895 | else |
1907 | viafb_fill_crtc_timing(&viafbinfo->var, | 1896 | viafb_fill_crtc_timing(&viafbinfo->var, 0, 0, |
1908 | (viaparinfo->shared->iga1_devices & VIA_CRT) | 1897 | (viaparinfo->shared->iga1_devices & VIA_CRT) |
1909 | ? IGA1 : IGA2); | 1898 | ? IGA1 : IGA2); |
1910 | 1899 | ||
@@ -1922,17 +1911,17 @@ int viafb_setmode(int video_bpp, int video_bpp1) | |||
1922 | if (viafb_DVI_ON) { | 1911 | if (viafb_DVI_ON) { |
1923 | if (viaparinfo->shared->tmds_setting_info.iga_path == IGA2 | 1912 | if (viaparinfo->shared->tmds_setting_info.iga_path == IGA2 |
1924 | && viafb_SAMM_ON) | 1913 | && viafb_SAMM_ON) |
1925 | viafb_dvi_set_mode(&var2, IGA2); | 1914 | viafb_dvi_set_mode(&var2, cxres, cyres, IGA2); |
1926 | else | 1915 | else |
1927 | viafb_dvi_set_mode(&viafbinfo->var, | 1916 | viafb_dvi_set_mode(&viafbinfo->var, 0, 0, |
1928 | viaparinfo->tmds_setting_info->iga_path); | 1917 | viaparinfo->tmds_setting_info->iga_path); |
1929 | } | 1918 | } |
1930 | 1919 | ||
1931 | if (viafb_LCD_ON) { | 1920 | if (viafb_LCD_ON) { |
1932 | if (viafb_SAMM_ON && | 1921 | if (viafb_SAMM_ON && |
1933 | (viaparinfo->lvds_setting_info->iga_path == IGA2)) { | 1922 | (viaparinfo->lvds_setting_info->iga_path == IGA2)) { |
1934 | viaparinfo->lvds_setting_info->bpp = video_bpp1; | 1923 | viafb_lcd_set_mode(&var2, cxres, cyres, |
1935 | viafb_lcd_set_mode(viaparinfo->lvds_setting_info, | 1924 | viaparinfo->lvds_setting_info, |
1936 | &viaparinfo->chip_info->lvds_chip_info); | 1925 | &viaparinfo->chip_info->lvds_chip_info); |
1937 | } else { | 1926 | } else { |
1938 | /* IGA1 doesn't have LCD scaling, so set it center. */ | 1927 | /* IGA1 doesn't have LCD scaling, so set it center. */ |
@@ -1940,16 +1929,16 @@ int viafb_setmode(int video_bpp, int video_bpp1) | |||
1940 | viaparinfo->lvds_setting_info->display_method = | 1929 | viaparinfo->lvds_setting_info->display_method = |
1941 | LCD_CENTERING; | 1930 | LCD_CENTERING; |
1942 | } | 1931 | } |
1943 | viaparinfo->lvds_setting_info->bpp = video_bpp; | 1932 | viafb_lcd_set_mode(&viafbinfo->var, 0, 0, |
1944 | viafb_lcd_set_mode(viaparinfo->lvds_setting_info, | 1933 | viaparinfo->lvds_setting_info, |
1945 | &viaparinfo->chip_info->lvds_chip_info); | 1934 | &viaparinfo->chip_info->lvds_chip_info); |
1946 | } | 1935 | } |
1947 | } | 1936 | } |
1948 | if (viafb_LCD2_ON) { | 1937 | if (viafb_LCD2_ON) { |
1949 | if (viafb_SAMM_ON && | 1938 | if (viafb_SAMM_ON && |
1950 | (viaparinfo->lvds_setting_info2->iga_path == IGA2)) { | 1939 | (viaparinfo->lvds_setting_info2->iga_path == IGA2)) { |
1951 | viaparinfo->lvds_setting_info2->bpp = video_bpp1; | 1940 | viafb_lcd_set_mode(&var2, cxres, cyres, |
1952 | viafb_lcd_set_mode(viaparinfo->lvds_setting_info2, | 1941 | viaparinfo->lvds_setting_info2, |
1953 | &viaparinfo->chip_info->lvds_chip_info2); | 1942 | &viaparinfo->chip_info->lvds_chip_info2); |
1954 | } else { | 1943 | } else { |
1955 | /* IGA1 doesn't have LCD scaling, so set it center. */ | 1944 | /* IGA1 doesn't have LCD scaling, so set it center. */ |
@@ -1957,8 +1946,8 @@ int viafb_setmode(int video_bpp, int video_bpp1) | |||
1957 | viaparinfo->lvds_setting_info2->display_method = | 1946 | viaparinfo->lvds_setting_info2->display_method = |
1958 | LCD_CENTERING; | 1947 | LCD_CENTERING; |
1959 | } | 1948 | } |
1960 | viaparinfo->lvds_setting_info2->bpp = video_bpp; | 1949 | viafb_lcd_set_mode(&viafbinfo->var, 0, 0, |
1961 | viafb_lcd_set_mode(viaparinfo->lvds_setting_info2, | 1950 | viaparinfo->lvds_setting_info2, |
1962 | &viaparinfo->chip_info->lvds_chip_info2); | 1951 | &viaparinfo->chip_info->lvds_chip_info2); |
1963 | } | 1952 | } |
1964 | } | 1953 | } |
@@ -1971,7 +1960,7 @@ int viafb_setmode(int video_bpp, int video_bpp1) | |||
1971 | if (!viafb_hotplug) { | 1960 | if (!viafb_hotplug) { |
1972 | viafb_hotplug_Xres = viafbinfo->var.xres; | 1961 | viafb_hotplug_Xres = viafbinfo->var.xres; |
1973 | viafb_hotplug_Yres = viafbinfo->var.yres; | 1962 | viafb_hotplug_Yres = viafbinfo->var.yres; |
1974 | viafb_hotplug_bpp = video_bpp; | 1963 | viafb_hotplug_bpp = viafbinfo->var.bits_per_pixel; |
1975 | viafb_hotplug_refresh = viafb_refresh; | 1964 | viafb_hotplug_refresh = viafb_refresh; |
1976 | 1965 | ||
1977 | if (viafb_DVI_ON) | 1966 | if (viafb_DVI_ON) |
@@ -1980,13 +1969,13 @@ int viafb_setmode(int video_bpp, int video_bpp1) | |||
1980 | viafb_DeviceStatus = CRT_Device; | 1969 | viafb_DeviceStatus = CRT_Device; |
1981 | } | 1970 | } |
1982 | device_on(); | 1971 | device_on(); |
1983 | if (!viafb_dual_fb) | 1972 | if (!viafb_SAMM_ON) |
1984 | via_set_sync_polarity(devices, get_sync(viafbinfo)); | 1973 | via_set_sync_polarity(devices, get_sync(&viafbinfo->var)); |
1985 | else { | 1974 | else { |
1986 | via_set_sync_polarity(viaparinfo->shared->iga1_devices, | 1975 | via_set_sync_polarity(viaparinfo->shared->iga1_devices, |
1987 | get_sync(viafbinfo)); | 1976 | get_sync(&viafbinfo->var)); |
1988 | via_set_sync_polarity(viaparinfo->shared->iga2_devices, | 1977 | via_set_sync_polarity(viaparinfo->shared->iga2_devices, |
1989 | get_sync(viafbinfo1)); | 1978 | get_sync(&var2)); |
1990 | } | 1979 | } |
1991 | 1980 | ||
1992 | clock.set_engine_pll_state(VIA_STATE_ON); | 1981 | clock.set_engine_pll_state(VIA_STATE_ON); |
@@ -2023,20 +2012,20 @@ int viafb_setmode(int video_bpp, int video_bpp1) | |||
2023 | 2012 | ||
2024 | int viafb_get_refresh(int hres, int vres, u32 long_refresh) | 2013 | int viafb_get_refresh(int hres, int vres, u32 long_refresh) |
2025 | { | 2014 | { |
2026 | struct crt_mode_table *best; | 2015 | const struct fb_videomode *best; |
2027 | 2016 | ||
2028 | best = viafb_get_best_mode(hres, vres, long_refresh); | 2017 | best = viafb_get_best_mode(hres, vres, long_refresh); |
2029 | if (!best) | 2018 | if (!best) |
2030 | return 60; | 2019 | return 60; |
2031 | 2020 | ||
2032 | if (abs(best->refresh_rate - long_refresh) > 3) { | 2021 | if (abs(best->refresh - long_refresh) > 3) { |
2033 | if (hres == 1200 && vres == 900) | 2022 | if (hres == 1200 && vres == 900) |
2034 | return 49; /* OLPC DCON only supports 50 Hz */ | 2023 | return 49; /* OLPC DCON only supports 50 Hz */ |
2035 | else | 2024 | else |
2036 | return 60; | 2025 | return 60; |
2037 | } | 2026 | } |
2038 | 2027 | ||
2039 | return best->refresh_rate; | 2028 | return best->refresh; |
2040 | } | 2029 | } |
2041 | 2030 | ||
2042 | static void device_off(void) | 2031 | static void device_off(void) |
@@ -2129,26 +2118,17 @@ void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\ | |||
2129 | } | 2118 | } |
2130 | } | 2119 | } |
2131 | 2120 | ||
2132 | /*According var's xres, yres fill var's other timing information*/ | ||
2133 | void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, | 2121 | void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, |
2134 | struct crt_mode_table *mode) | 2122 | const struct fb_videomode *mode) |
2135 | { | 2123 | { |
2136 | struct display_timing crt_reg; | 2124 | var->pixclock = mode->pixclock; |
2137 | 2125 | var->xres = mode->xres; | |
2138 | crt_reg = mode->crtc; | 2126 | var->yres = mode->yres; |
2139 | var->pixclock = 1000000000 / (crt_reg.hor_total * crt_reg.ver_total) | 2127 | var->left_margin = mode->left_margin; |
2140 | * 1000 / mode->refresh_rate; | 2128 | var->right_margin = mode->right_margin; |
2141 | var->left_margin = | 2129 | var->hsync_len = mode->hsync_len; |
2142 | crt_reg.hor_total - (crt_reg.hor_sync_start + crt_reg.hor_sync_end); | 2130 | var->upper_margin = mode->upper_margin; |
2143 | var->right_margin = crt_reg.hor_sync_start - crt_reg.hor_addr; | 2131 | var->lower_margin = mode->lower_margin; |
2144 | var->hsync_len = crt_reg.hor_sync_end; | 2132 | var->vsync_len = mode->vsync_len; |
2145 | var->upper_margin = | 2133 | var->sync = mode->sync; |
2146 | crt_reg.ver_total - (crt_reg.ver_sync_start + crt_reg.ver_sync_end); | ||
2147 | var->lower_margin = crt_reg.ver_sync_start - crt_reg.ver_addr; | ||
2148 | var->vsync_len = crt_reg.ver_sync_end; | ||
2149 | var->sync = 0; | ||
2150 | if (mode->h_sync_polarity == POSITIVE) | ||
2151 | var->sync |= FB_SYNC_HOR_HIGH_ACT; | ||
2152 | if (mode->v_sync_polarity == POSITIVE) | ||
2153 | var->sync |= FB_SYNC_VERT_HIGH_ACT; | ||
2154 | } | 2134 | } |
diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h index 4db5b6e8d8d0..6be243cfc823 100644 --- a/drivers/video/via/hw.h +++ b/drivers/video/via/hw.h | |||
@@ -637,7 +637,10 @@ extern int viafb_LCD_ON; | |||
637 | extern int viafb_DVI_ON; | 637 | extern int viafb_DVI_ON; |
638 | extern int viafb_hotplug; | 638 | extern int viafb_hotplug; |
639 | 639 | ||
640 | void viafb_fill_crtc_timing(const struct fb_var_screeninfo *var, int iga); | 640 | struct display_timing var_to_timing(const struct fb_var_screeninfo *var, |
641 | u16 cxres, u16 cyres); | ||
642 | void viafb_fill_crtc_timing(const struct fb_var_screeninfo *var, | ||
643 | u16 cxres, u16 cyres, int iga); | ||
641 | void viafb_set_vclock(u32 CLK, int set_iga); | 644 | void viafb_set_vclock(u32 CLK, int set_iga); |
642 | void viafb_load_reg(int timing_value, int viafb_load_reg_num, | 645 | void viafb_load_reg(int timing_value, int viafb_load_reg_num, |
643 | struct io_register *reg, | 646 | struct io_register *reg, |
@@ -657,9 +660,9 @@ void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active); | |||
657 | void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\ | 660 | void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\ |
658 | *p_gfx_dpa_setting); | 661 | *p_gfx_dpa_setting); |
659 | 662 | ||
660 | int viafb_setmode(int video_bpp, int video_bpp1); | 663 | int viafb_setmode(void); |
661 | void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, | 664 | void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, |
662 | struct crt_mode_table *mode); | 665 | const struct fb_videomode *mode); |
663 | void __devinit viafb_init_chip_info(int chip_type); | 666 | void __devinit viafb_init_chip_info(int chip_type); |
664 | void __devinit viafb_init_dac(int set_iga); | 667 | void __devinit viafb_init_dac(int set_iga); |
665 | int viafb_get_refresh(int hres, int vres, u32 float_refresh); | 668 | int viafb_get_refresh(int hres, int vres, u32 float_refresh); |
diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c index 5f3b4e394e82..165037910536 100644 --- a/drivers/video/via/lcd.c +++ b/drivers/video/via/lcd.c | |||
@@ -53,10 +53,6 @@ static void __devinit fp_id_to_vindex(int panel_id); | |||
53 | static int lvds_register_read(int index); | 53 | static int lvds_register_read(int index); |
54 | static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres, | 54 | static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres, |
55 | int panel_vres); | 55 | int panel_vres); |
56 | static void via_pitch_alignment_patch_lcd( | ||
57 | struct lvds_setting_information *plvds_setting_info, | ||
58 | struct lvds_chip_information | ||
59 | *plvds_chip_info); | ||
60 | static void lcd_patch_skew_dvp0(struct lvds_setting_information | 56 | static void lcd_patch_skew_dvp0(struct lvds_setting_information |
61 | *plvds_setting_info, | 57 | *plvds_setting_info, |
62 | struct lvds_chip_information *plvds_chip_info); | 58 | struct lvds_chip_information *plvds_chip_info); |
@@ -79,9 +75,6 @@ static void check_diport_of_integrated_lvds( | |||
79 | struct lvds_chip_information *plvds_chip_info, | 75 | struct lvds_chip_information *plvds_chip_info, |
80 | struct lvds_setting_information | 76 | struct lvds_setting_information |
81 | *plvds_setting_info); | 77 | *plvds_setting_info); |
82 | static struct display_timing lcd_centering_timging(struct display_timing | ||
83 | mode_crt_reg, | ||
84 | struct display_timing panel_crt_reg); | ||
85 | 78 | ||
86 | static inline bool check_lvds_chip(int device_id_subaddr, int device_id) | 79 | static inline bool check_lvds_chip(int device_id_subaddr, int device_id) |
87 | { | 80 | { |
@@ -454,20 +447,17 @@ static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres, | |||
454 | } | 447 | } |
455 | } | 448 | } |
456 | 449 | ||
457 | static void via_pitch_alignment_patch_lcd( | 450 | static void via_pitch_alignment_patch_lcd(int iga_path, int hres, int bpp) |
458 | struct lvds_setting_information *plvds_setting_info, | ||
459 | struct lvds_chip_information | ||
460 | *plvds_chip_info) | ||
461 | { | 451 | { |
462 | unsigned char cr13, cr35, cr65, cr66, cr67; | 452 | unsigned char cr13, cr35, cr65, cr66, cr67; |
463 | unsigned long dwScreenPitch = 0; | 453 | unsigned long dwScreenPitch = 0; |
464 | unsigned long dwPitch; | 454 | unsigned long dwPitch; |
465 | 455 | ||
466 | dwPitch = plvds_setting_info->h_active * (plvds_setting_info->bpp >> 3); | 456 | dwPitch = hres * (bpp >> 3); |
467 | if (dwPitch & 0x1F) { | 457 | if (dwPitch & 0x1F) { |
468 | dwScreenPitch = ((dwPitch + 31) & ~31) >> 3; | 458 | dwScreenPitch = ((dwPitch + 31) & ~31) >> 3; |
469 | if (plvds_setting_info->iga_path == IGA2) { | 459 | if (iga_path == IGA2) { |
470 | if (plvds_setting_info->bpp > 8) { | 460 | if (bpp > 8) { |
471 | cr66 = (unsigned char)(dwScreenPitch & 0xFF); | 461 | cr66 = (unsigned char)(dwScreenPitch & 0xFF); |
472 | viafb_write_reg(CR66, VIACR, cr66); | 462 | viafb_write_reg(CR66, VIACR, cr66); |
473 | cr67 = viafb_read_reg(VIACR, CR67) & 0xFC; | 463 | cr67 = viafb_read_reg(VIACR, CR67) & 0xFC; |
@@ -485,7 +475,7 @@ static void via_pitch_alignment_patch_lcd( | |||
485 | cr65 += 2; | 475 | cr65 += 2; |
486 | viafb_write_reg(CR65, VIACR, cr65); | 476 | viafb_write_reg(CR65, VIACR, cr65); |
487 | } else { | 477 | } else { |
488 | if (plvds_setting_info->bpp > 8) { | 478 | if (bpp > 8) { |
489 | cr13 = (unsigned char)(dwScreenPitch & 0xFF); | 479 | cr13 = (unsigned char)(dwScreenPitch & 0xFF); |
490 | viafb_write_reg(CR13, VIACR, cr13); | 480 | viafb_write_reg(CR13, VIACR, cr13); |
491 | cr35 = viafb_read_reg(VIACR, CR35) & 0x1F; | 481 | cr35 = viafb_read_reg(VIACR, CR35) & 0x1F; |
@@ -548,49 +538,45 @@ static void lcd_patch_skew(struct lvds_setting_information | |||
548 | } | 538 | } |
549 | 539 | ||
550 | /* LCD Set Mode */ | 540 | /* LCD Set Mode */ |
551 | void viafb_lcd_set_mode(struct lvds_setting_information *plvds_setting_info, | 541 | void viafb_lcd_set_mode(const struct fb_var_screeninfo *var, u16 cxres, |
542 | u16 cyres, struct lvds_setting_information *plvds_setting_info, | ||
552 | struct lvds_chip_information *plvds_chip_info) | 543 | struct lvds_chip_information *plvds_chip_info) |
553 | { | 544 | { |
554 | int set_iga = plvds_setting_info->iga_path; | 545 | int set_iga = plvds_setting_info->iga_path; |
555 | int mode_bpp = plvds_setting_info->bpp; | 546 | int mode_bpp = var->bits_per_pixel; |
556 | int set_hres = plvds_setting_info->h_active; | 547 | int set_hres = cxres ? cxres : var->xres; |
557 | int set_vres = plvds_setting_info->v_active; | 548 | int set_vres = cyres ? cyres : var->yres; |
558 | int panel_hres = plvds_setting_info->lcd_panel_hres; | 549 | int panel_hres = plvds_setting_info->lcd_panel_hres; |
559 | int panel_vres = plvds_setting_info->lcd_panel_vres; | 550 | int panel_vres = plvds_setting_info->lcd_panel_vres; |
560 | u32 clock; | 551 | u32 clock; |
561 | struct display_timing mode_crt_reg, panel_crt_reg, timing; | 552 | struct display_timing timing; |
562 | struct crt_mode_table *mode_crt_table, *panel_crt_table; | 553 | struct fb_var_screeninfo panel_var; |
554 | const struct fb_videomode *mode_crt_table, *panel_crt_table; | ||
563 | 555 | ||
564 | DEBUG_MSG(KERN_INFO "viafb_lcd_set_mode!!\n"); | 556 | DEBUG_MSG(KERN_INFO "viafb_lcd_set_mode!!\n"); |
565 | /* Get mode table */ | 557 | /* Get mode table */ |
566 | mode_crt_table = viafb_get_best_mode(set_hres, set_vres, 60); | 558 | mode_crt_table = viafb_get_best_mode(set_hres, set_vres, 60); |
567 | mode_crt_reg = mode_crt_table->crtc; | ||
568 | /* Get panel table Pointer */ | 559 | /* Get panel table Pointer */ |
569 | panel_crt_table = viafb_get_best_mode(panel_hres, panel_vres, 60); | 560 | panel_crt_table = viafb_get_best_mode(panel_hres, panel_vres, 60); |
570 | panel_crt_reg = panel_crt_table->crtc; | 561 | viafb_fill_var_timing_info(&panel_var, panel_crt_table); |
571 | DEBUG_MSG(KERN_INFO "bellow viafb_lcd_set_mode!!\n"); | 562 | DEBUG_MSG(KERN_INFO "bellow viafb_lcd_set_mode!!\n"); |
572 | if (VT1636_LVDS == plvds_chip_info->lvds_chip_name) | 563 | if (VT1636_LVDS == plvds_chip_info->lvds_chip_name) |
573 | viafb_init_lvds_vt1636(plvds_setting_info, plvds_chip_info); | 564 | viafb_init_lvds_vt1636(plvds_setting_info, plvds_chip_info); |
574 | clock = panel_crt_reg.hor_total * panel_crt_reg.ver_total | 565 | clock = PICOS2KHZ(panel_crt_table->pixclock) * 1000; |
575 | * panel_crt_table->refresh_rate; | ||
576 | plvds_setting_info->vclk = clock; | 566 | plvds_setting_info->vclk = clock; |
577 | 567 | ||
578 | if (set_iga == IGA2 && (set_hres < panel_hres || set_vres < panel_vres) | 568 | if (set_iga == IGA2 && (set_hres < panel_hres || set_vres < panel_vres) |
579 | && plvds_setting_info->display_method == LCD_EXPANDSION) { | 569 | && plvds_setting_info->display_method == LCD_EXPANDSION) { |
580 | timing = panel_crt_reg; | 570 | timing = var_to_timing(&panel_var, panel_hres, panel_vres); |
581 | load_lcd_scaling(set_hres, set_vres, panel_hres, panel_vres); | 571 | load_lcd_scaling(set_hres, set_vres, panel_hres, panel_vres); |
582 | } else { | 572 | } else { |
583 | timing = lcd_centering_timging(mode_crt_reg, panel_crt_reg); | 573 | timing = var_to_timing(&panel_var, set_hres, set_vres); |
584 | if (set_iga == IGA2) | 574 | if (set_iga == IGA2) |
585 | /* disable scaling */ | 575 | /* disable scaling */ |
586 | via_write_reg_mask(VIACR, 0x79, 0x00, | 576 | via_write_reg_mask(VIACR, 0x79, 0x00, |
587 | BIT0 + BIT1 + BIT2); | 577 | BIT0 + BIT1 + BIT2); |
588 | } | 578 | } |
589 | 579 | ||
590 | timing.hor_blank_end += timing.hor_blank_start; | ||
591 | timing.hor_sync_end += timing.hor_sync_start; | ||
592 | timing.ver_blank_end += timing.ver_blank_start; | ||
593 | timing.ver_sync_end += timing.ver_sync_start; | ||
594 | if (set_iga == IGA1) | 580 | if (set_iga == IGA1) |
595 | via_set_primary_timing(&timing); | 581 | via_set_primary_timing(&timing); |
596 | else if (set_iga == IGA2) | 582 | else if (set_iga == IGA2) |
@@ -613,7 +599,8 @@ void viafb_lcd_set_mode(struct lvds_setting_information *plvds_setting_info, | |||
613 | viafb_write_reg_mask(CR6A, VIACR, 0x01, BIT0); | 599 | viafb_write_reg_mask(CR6A, VIACR, 0x01, BIT0); |
614 | 600 | ||
615 | /* Patch for non 32bit alignment mode */ | 601 | /* Patch for non 32bit alignment mode */ |
616 | via_pitch_alignment_patch_lcd(plvds_setting_info, plvds_chip_info); | 602 | via_pitch_alignment_patch_lcd(plvds_setting_info->iga_path, set_hres, |
603 | var->bits_per_pixel); | ||
617 | } | 604 | } |
618 | 605 | ||
619 | static void integrated_lvds_disable(struct lvds_setting_information | 606 | static void integrated_lvds_disable(struct lvds_setting_information |
@@ -973,37 +960,6 @@ void __devinit viafb_init_lvds_output_interface(struct lvds_chip_information | |||
973 | } | 960 | } |
974 | } | 961 | } |
975 | 962 | ||
976 | static struct display_timing lcd_centering_timging(struct display_timing | ||
977 | mode_crt_reg, | ||
978 | struct display_timing panel_crt_reg) | ||
979 | { | ||
980 | struct display_timing crt_reg; | ||
981 | |||
982 | crt_reg.hor_total = panel_crt_reg.hor_total; | ||
983 | crt_reg.hor_addr = mode_crt_reg.hor_addr; | ||
984 | crt_reg.hor_blank_start = | ||
985 | (panel_crt_reg.hor_addr - mode_crt_reg.hor_addr) / 2 + | ||
986 | crt_reg.hor_addr; | ||
987 | crt_reg.hor_blank_end = panel_crt_reg.hor_blank_end; | ||
988 | crt_reg.hor_sync_start = | ||
989 | (panel_crt_reg.hor_sync_start - | ||
990 | panel_crt_reg.hor_blank_start) + crt_reg.hor_blank_start; | ||
991 | crt_reg.hor_sync_end = panel_crt_reg.hor_sync_end; | ||
992 | |||
993 | crt_reg.ver_total = panel_crt_reg.ver_total; | ||
994 | crt_reg.ver_addr = mode_crt_reg.ver_addr; | ||
995 | crt_reg.ver_blank_start = | ||
996 | (panel_crt_reg.ver_addr - mode_crt_reg.ver_addr) / 2 + | ||
997 | crt_reg.ver_addr; | ||
998 | crt_reg.ver_blank_end = panel_crt_reg.ver_blank_end; | ||
999 | crt_reg.ver_sync_start = | ||
1000 | (panel_crt_reg.ver_sync_start - | ||
1001 | panel_crt_reg.ver_blank_start) + crt_reg.ver_blank_start; | ||
1002 | crt_reg.ver_sync_end = panel_crt_reg.ver_sync_end; | ||
1003 | |||
1004 | return crt_reg; | ||
1005 | } | ||
1006 | |||
1007 | bool viafb_lcd_get_mobile_state(bool *mobile) | 963 | bool viafb_lcd_get_mobile_state(bool *mobile) |
1008 | { | 964 | { |
1009 | unsigned char __iomem *romptr, *tableptr, *biosptr; | 965 | unsigned char __iomem *romptr, *tableptr, *biosptr; |
diff --git a/drivers/video/via/lcd.h b/drivers/video/via/lcd.h index 77ca7b862e68..8f3e4e06156c 100644 --- a/drivers/video/via/lcd.h +++ b/drivers/video/via/lcd.h | |||
@@ -76,7 +76,8 @@ void __devinit viafb_init_lvds_output_interface(struct lvds_chip_information | |||
76 | *plvds_chip_info, | 76 | *plvds_chip_info, |
77 | struct lvds_setting_information | 77 | struct lvds_setting_information |
78 | *plvds_setting_info); | 78 | *plvds_setting_info); |
79 | void viafb_lcd_set_mode(struct lvds_setting_information *plvds_setting_info, | 79 | void viafb_lcd_set_mode(const struct fb_var_screeninfo *var, u16 cxres, |
80 | u16 cyres, struct lvds_setting_information *plvds_setting_info, | ||
80 | struct lvds_chip_information *plvds_chip_info); | 81 | struct lvds_chip_information *plvds_chip_info); |
81 | bool __devinit viafb_lvds_trasmitter_identify(void); | 82 | bool __devinit viafb_lvds_trasmitter_identify(void); |
82 | void viafb_init_lvds_output_interface(struct lvds_chip_information | 83 | void viafb_init_lvds_output_interface(struct lvds_chip_information |
diff --git a/drivers/video/via/share.h b/drivers/video/via/share.h index c01c1c162726..3158dfc90bed 100644 --- a/drivers/video/via/share.h +++ b/drivers/video/via/share.h | |||
@@ -283,337 +283,6 @@ | |||
283 | #define HW_LAYOUT_LCD1_LCD2 0x04 | 283 | #define HW_LAYOUT_LCD1_LCD2 0x04 |
284 | #define HW_LAYOUT_LCD_EXTERNAL_LCD2 0x10 | 284 | #define HW_LAYOUT_LCD_EXTERNAL_LCD2 0x10 |
285 | 285 | ||
286 | /* Definition Refresh Rate */ | ||
287 | #define REFRESH_49 49 | ||
288 | #define REFRESH_50 50 | ||
289 | #define REFRESH_60 60 | ||
290 | #define REFRESH_75 75 | ||
291 | #define REFRESH_85 85 | ||
292 | #define REFRESH_100 100 | ||
293 | #define REFRESH_120 120 | ||
294 | |||
295 | /* Definition Sync Polarity*/ | ||
296 | #define NEGATIVE 1 | ||
297 | #define POSITIVE 0 | ||
298 | |||
299 | /*480x640@60 Sync Polarity (GTF) | ||
300 | */ | ||
301 | #define M480X640_R60_HSP NEGATIVE | ||
302 | #define M480X640_R60_VSP POSITIVE | ||
303 | |||
304 | /*640x480@60 Sync Polarity (VESA Mode) | ||
305 | */ | ||
306 | #define M640X480_R60_HSP NEGATIVE | ||
307 | #define M640X480_R60_VSP NEGATIVE | ||
308 | |||
309 | /*640x480@75 Sync Polarity (VESA Mode) | ||
310 | */ | ||
311 | #define M640X480_R75_HSP NEGATIVE | ||
312 | #define M640X480_R75_VSP NEGATIVE | ||
313 | |||
314 | /*640x480@85 Sync Polarity (VESA Mode) | ||
315 | */ | ||
316 | #define M640X480_R85_HSP NEGATIVE | ||
317 | #define M640X480_R85_VSP NEGATIVE | ||
318 | |||
319 | /*640x480@100 Sync Polarity (GTF Mode) | ||
320 | */ | ||
321 | #define M640X480_R100_HSP NEGATIVE | ||
322 | #define M640X480_R100_VSP POSITIVE | ||
323 | |||
324 | /*640x480@120 Sync Polarity (GTF Mode) | ||
325 | */ | ||
326 | #define M640X480_R120_HSP NEGATIVE | ||
327 | #define M640X480_R120_VSP POSITIVE | ||
328 | |||
329 | /*720x480@60 Sync Polarity (GTF Mode) | ||
330 | */ | ||
331 | #define M720X480_R60_HSP NEGATIVE | ||
332 | #define M720X480_R60_VSP POSITIVE | ||
333 | |||
334 | /*720x576@60 Sync Polarity (GTF Mode) | ||
335 | */ | ||
336 | #define M720X576_R60_HSP NEGATIVE | ||
337 | #define M720X576_R60_VSP POSITIVE | ||
338 | |||
339 | /*800x600@60 Sync Polarity (VESA Mode) | ||
340 | */ | ||
341 | #define M800X600_R60_HSP POSITIVE | ||
342 | #define M800X600_R60_VSP POSITIVE | ||
343 | |||
344 | /*800x600@75 Sync Polarity (VESA Mode) | ||
345 | */ | ||
346 | #define M800X600_R75_HSP POSITIVE | ||
347 | #define M800X600_R75_VSP POSITIVE | ||
348 | |||
349 | /*800x600@85 Sync Polarity (VESA Mode) | ||
350 | */ | ||
351 | #define M800X600_R85_HSP POSITIVE | ||
352 | #define M800X600_R85_VSP POSITIVE | ||
353 | |||
354 | /*800x600@100 Sync Polarity (GTF Mode) | ||
355 | */ | ||
356 | #define M800X600_R100_HSP NEGATIVE | ||
357 | #define M800X600_R100_VSP POSITIVE | ||
358 | |||
359 | /*800x600@120 Sync Polarity (GTF Mode) | ||
360 | */ | ||
361 | #define M800X600_R120_HSP NEGATIVE | ||
362 | #define M800X600_R120_VSP POSITIVE | ||
363 | |||
364 | /*800x480@60 Sync Polarity (CVT Mode) | ||
365 | */ | ||
366 | #define M800X480_R60_HSP NEGATIVE | ||
367 | #define M800X480_R60_VSP POSITIVE | ||
368 | |||
369 | /*848x480@60 Sync Polarity (CVT Mode) | ||
370 | */ | ||
371 | #define M848X480_R60_HSP NEGATIVE | ||
372 | #define M848X480_R60_VSP POSITIVE | ||
373 | |||
374 | /*852x480@60 Sync Polarity (GTF Mode) | ||
375 | */ | ||
376 | #define M852X480_R60_HSP NEGATIVE | ||
377 | #define M852X480_R60_VSP POSITIVE | ||
378 | |||
379 | /*1024x512@60 Sync Polarity (GTF Mode) | ||
380 | */ | ||
381 | #define M1024X512_R60_HSP NEGATIVE | ||
382 | #define M1024X512_R60_VSP POSITIVE | ||
383 | |||
384 | /*1024x600@60 Sync Polarity (GTF Mode) | ||
385 | */ | ||
386 | #define M1024X600_R60_HSP NEGATIVE | ||
387 | #define M1024X600_R60_VSP POSITIVE | ||
388 | |||
389 | /*1024x768@60 Sync Polarity (VESA Mode) | ||
390 | */ | ||
391 | #define M1024X768_R60_HSP NEGATIVE | ||
392 | #define M1024X768_R60_VSP NEGATIVE | ||
393 | |||
394 | /*1024x768@75 Sync Polarity (VESA Mode) | ||
395 | */ | ||
396 | #define M1024X768_R75_HSP POSITIVE | ||
397 | #define M1024X768_R75_VSP POSITIVE | ||
398 | |||
399 | /*1024x768@85 Sync Polarity (VESA Mode) | ||
400 | */ | ||
401 | #define M1024X768_R85_HSP POSITIVE | ||
402 | #define M1024X768_R85_VSP POSITIVE | ||
403 | |||
404 | /*1024x768@100 Sync Polarity (GTF Mode) | ||
405 | */ | ||
406 | #define M1024X768_R100_HSP NEGATIVE | ||
407 | #define M1024X768_R100_VSP POSITIVE | ||
408 | |||
409 | /*1152x864@75 Sync Polarity (VESA Mode) | ||
410 | */ | ||
411 | #define M1152X864_R75_HSP POSITIVE | ||
412 | #define M1152X864_R75_VSP POSITIVE | ||
413 | |||
414 | /*1280x720@60 Sync Polarity (GTF Mode) | ||
415 | */ | ||
416 | #define M1280X720_R60_HSP NEGATIVE | ||
417 | #define M1280X720_R60_VSP POSITIVE | ||
418 | |||
419 | /* 1280x768@50 Sync Polarity (GTF Mode) */ | ||
420 | #define M1280X768_R50_HSP NEGATIVE | ||
421 | #define M1280X768_R50_VSP POSITIVE | ||
422 | |||
423 | /*1280x768@60 Sync Polarity (GTF Mode) | ||
424 | */ | ||
425 | #define M1280X768_R60_HSP NEGATIVE | ||
426 | #define M1280X768_R60_VSP POSITIVE | ||
427 | |||
428 | /*1280x800@60 Sync Polarity (CVT Mode) | ||
429 | */ | ||
430 | #define M1280X800_R60_HSP NEGATIVE | ||
431 | #define M1280X800_R60_VSP POSITIVE | ||
432 | |||
433 | /*1280x960@60 Sync Polarity (VESA Mode) | ||
434 | */ | ||
435 | #define M1280X960_R60_HSP POSITIVE | ||
436 | #define M1280X960_R60_VSP POSITIVE | ||
437 | |||
438 | /*1280x1024@60 Sync Polarity (VESA Mode) | ||
439 | */ | ||
440 | #define M1280X1024_R60_HSP POSITIVE | ||
441 | #define M1280X1024_R60_VSP POSITIVE | ||
442 | |||
443 | /* 1360x768@60 Sync Polarity (CVT Mode) */ | ||
444 | #define M1360X768_R60_HSP POSITIVE | ||
445 | #define M1360X768_R60_VSP POSITIVE | ||
446 | |||
447 | /* 1360x768@60 Sync Polarity (CVT Reduce Blanking Mode) */ | ||
448 | #define M1360X768_RB_R60_HSP POSITIVE | ||
449 | #define M1360X768_RB_R60_VSP NEGATIVE | ||
450 | |||
451 | /* 1368x768@50 Sync Polarity (GTF Mode) */ | ||
452 | #define M1368X768_R50_HSP NEGATIVE | ||
453 | #define M1368X768_R50_VSP POSITIVE | ||
454 | |||
455 | /* 1368x768@60 Sync Polarity (VESA Mode) */ | ||
456 | #define M1368X768_R60_HSP NEGATIVE | ||
457 | #define M1368X768_R60_VSP POSITIVE | ||
458 | |||
459 | /*1280x1024@75 Sync Polarity (VESA Mode) | ||
460 | */ | ||
461 | #define M1280X1024_R75_HSP POSITIVE | ||
462 | #define M1280X1024_R75_VSP POSITIVE | ||
463 | |||
464 | /*1280x1024@85 Sync Polarity (VESA Mode) | ||
465 | */ | ||
466 | #define M1280X1024_R85_HSP POSITIVE | ||
467 | #define M1280X1024_R85_VSP POSITIVE | ||
468 | |||
469 | /*1440x1050@60 Sync Polarity (GTF Mode) | ||
470 | */ | ||
471 | #define M1440X1050_R60_HSP NEGATIVE | ||
472 | #define M1440X1050_R60_VSP POSITIVE | ||
473 | |||
474 | /*1600x1200@60 Sync Polarity (VESA Mode) | ||
475 | */ | ||
476 | #define M1600X1200_R60_HSP POSITIVE | ||
477 | #define M1600X1200_R60_VSP POSITIVE | ||
478 | |||
479 | /*1600x1200@75 Sync Polarity (VESA Mode) | ||
480 | */ | ||
481 | #define M1600X1200_R75_HSP POSITIVE | ||
482 | #define M1600X1200_R75_VSP POSITIVE | ||
483 | |||
484 | /* 1680x1050@60 Sync Polarity (CVT Mode) */ | ||
485 | #define M1680x1050_R60_HSP NEGATIVE | ||
486 | #define M1680x1050_R60_VSP NEGATIVE | ||
487 | |||
488 | /* 1680x1050@60 Sync Polarity (CVT Reduce Blanking Mode) */ | ||
489 | #define M1680x1050_RB_R60_HSP POSITIVE | ||
490 | #define M1680x1050_RB_R60_VSP NEGATIVE | ||
491 | |||
492 | /* 1680x1050@75 Sync Polarity (CVT Mode) */ | ||
493 | #define M1680x1050_R75_HSP NEGATIVE | ||
494 | #define M1680x1050_R75_VSP POSITIVE | ||
495 | |||
496 | /*1920x1080@60 Sync Polarity (CVT Mode) | ||
497 | */ | ||
498 | #define M1920X1080_R60_HSP NEGATIVE | ||
499 | #define M1920X1080_R60_VSP POSITIVE | ||
500 | |||
501 | /* 1920x1080@60 Sync Polarity (CVT Reduce Blanking Mode) */ | ||
502 | #define M1920X1080_RB_R60_HSP POSITIVE | ||
503 | #define M1920X1080_RB_R60_VSP NEGATIVE | ||
504 | |||
505 | /*1920x1440@60 Sync Polarity (VESA Mode) | ||
506 | */ | ||
507 | #define M1920X1440_R60_HSP NEGATIVE | ||
508 | #define M1920X1440_R60_VSP POSITIVE | ||
509 | |||
510 | /*1920x1440@75 Sync Polarity (VESA Mode) | ||
511 | */ | ||
512 | #define M1920X1440_R75_HSP NEGATIVE | ||
513 | #define M1920X1440_R75_VSP POSITIVE | ||
514 | |||
515 | #if 0 | ||
516 | /* 1400x1050@60 Sync Polarity (VESA Mode) */ | ||
517 | #define M1400X1050_R60_HSP NEGATIVE | ||
518 | #define M1400X1050_R60_VSP NEGATIVE | ||
519 | #endif | ||
520 | |||
521 | /* 1400x1050@60 Sync Polarity (CVT Mode) */ | ||
522 | #define M1400X1050_R60_HSP NEGATIVE | ||
523 | #define M1400X1050_R60_VSP POSITIVE | ||
524 | |||
525 | /* 1400x1050@60 Sync Polarity (CVT Reduce Blanking Mode) */ | ||
526 | #define M1400X1050_RB_R60_HSP POSITIVE | ||
527 | #define M1400X1050_RB_R60_VSP NEGATIVE | ||
528 | |||
529 | /* 1400x1050@75 Sync Polarity (CVT Mode) */ | ||
530 | #define M1400X1050_R75_HSP NEGATIVE | ||
531 | #define M1400X1050_R75_VSP POSITIVE | ||
532 | |||
533 | /* 960x600@60 Sync Polarity (CVT Mode) */ | ||
534 | #define M960X600_R60_HSP NEGATIVE | ||
535 | #define M960X600_R60_VSP POSITIVE | ||
536 | |||
537 | /* 1000x600@60 Sync Polarity (GTF Mode) */ | ||
538 | #define M1000X600_R60_HSP NEGATIVE | ||
539 | #define M1000X600_R60_VSP POSITIVE | ||
540 | |||
541 | /* 1024x576@60 Sync Polarity (GTF Mode) */ | ||
542 | #define M1024X576_R60_HSP NEGATIVE | ||
543 | #define M1024X576_R60_VSP POSITIVE | ||
544 | |||
545 | /*1024x600@60 Sync Polarity (GTF Mode)*/ | ||
546 | #define M1024X600_R60_HSP NEGATIVE | ||
547 | #define M1024X600_R60_VSP POSITIVE | ||
548 | |||
549 | /* 1088x612@60 Sync Polarity (CVT Mode) */ | ||
550 | #define M1088X612_R60_HSP NEGATIVE | ||
551 | #define M1088X612_R60_VSP POSITIVE | ||
552 | |||
553 | /* 1152x720@60 Sync Polarity (CVT Mode) */ | ||
554 | #define M1152X720_R60_HSP NEGATIVE | ||
555 | #define M1152X720_R60_VSP POSITIVE | ||
556 | |||
557 | /* 1200x720@60 Sync Polarity (GTF Mode) */ | ||
558 | #define M1200X720_R60_HSP NEGATIVE | ||
559 | #define M1200X720_R60_VSP POSITIVE | ||
560 | |||
561 | /* 1200x900@60 Sync Polarity (DCON) */ | ||
562 | #define M1200X900_R60_HSP POSITIVE | ||
563 | #define M1200X900_R60_VSP POSITIVE | ||
564 | |||
565 | /* 1280x600@60 Sync Polarity (GTF Mode) */ | ||
566 | #define M1280x600_R60_HSP NEGATIVE | ||
567 | #define M1280x600_R60_VSP POSITIVE | ||
568 | |||
569 | /* 1280x720@50 Sync Polarity (GTF Mode) */ | ||
570 | #define M1280X720_R50_HSP NEGATIVE | ||
571 | #define M1280X720_R50_VSP POSITIVE | ||
572 | |||
573 | /* 1440x900@60 Sync Polarity (CVT Mode) */ | ||
574 | #define M1440X900_R60_HSP NEGATIVE | ||
575 | #define M1440X900_R60_VSP POSITIVE | ||
576 | |||
577 | /* 1440x900@75 Sync Polarity (CVT Mode) */ | ||
578 | #define M1440X900_R75_HSP NEGATIVE | ||
579 | #define M1440X900_R75_VSP POSITIVE | ||
580 | |||
581 | /* 1440x900@60 Sync Polarity (CVT Reduce Blanking Mode) */ | ||
582 | #define M1440X900_RB_R60_HSP POSITIVE | ||
583 | #define M1440X900_RB_R60_VSP NEGATIVE | ||
584 | |||
585 | /* 1600x900@60 Sync Polarity (CVT Mode) */ | ||
586 | #define M1600X900_R60_HSP NEGATIVE | ||
587 | #define M1600X900_R60_VSP POSITIVE | ||
588 | |||
589 | /* 1600x900@60 Sync Polarity (CVT Reduce Blanking Mode) */ | ||
590 | #define M1600X900_RB_R60_HSP POSITIVE | ||
591 | #define M1600X900_RB_R60_VSP NEGATIVE | ||
592 | |||
593 | /* 1600x1024@60 Sync Polarity (GTF Mode) */ | ||
594 | #define M1600X1024_R60_HSP NEGATIVE | ||
595 | #define M1600X1024_R60_VSP POSITIVE | ||
596 | |||
597 | /* 1792x1344@60 Sync Polarity (DMT Mode) */ | ||
598 | #define M1792x1344_R60_HSP NEGATIVE | ||
599 | #define M1792x1344_R60_VSP POSITIVE | ||
600 | |||
601 | /* 1856x1392@60 Sync Polarity (DMT Mode) */ | ||
602 | #define M1856x1392_R60_HSP NEGATIVE | ||
603 | #define M1856x1392_R60_VSP POSITIVE | ||
604 | |||
605 | /* 1920x1200@60 Sync Polarity (CVT Mode) */ | ||
606 | #define M1920X1200_R60_HSP NEGATIVE | ||
607 | #define M1920X1200_R60_VSP POSITIVE | ||
608 | |||
609 | /* 1920x1200@60 Sync Polarity (CVT Reduce Blanking Mode) */ | ||
610 | #define M1920X1200_RB_R60_HSP POSITIVE | ||
611 | #define M1920X1200_RB_R60_VSP NEGATIVE | ||
612 | |||
613 | /* 2048x1536@60 Sync Polarity (CVT Mode) */ | ||
614 | #define M2048x1536_R60_HSP NEGATIVE | ||
615 | #define M2048x1536_R60_VSP POSITIVE | ||
616 | |||
617 | /* Definition CRTC Timing Index */ | 286 | /* Definition CRTC Timing Index */ |
618 | #define H_TOTAL_INDEX 0 | 287 | #define H_TOTAL_INDEX 0 |
619 | #define H_ADDR_INDEX 1 | 288 | #define H_ADDR_INDEX 1 |
diff --git a/drivers/video/via/via_aux.c b/drivers/video/via/via_aux.c new file mode 100644 index 000000000000..4a0a55cdac3d --- /dev/null +++ b/drivers/video/via/via_aux.c | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public | ||
6 | * License as published by the Free Software Foundation; | ||
7 | * either version 2, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
11 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
12 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
13 | * for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /* | ||
21 | * infrastructure for devices connected via I2C | ||
22 | */ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include "via_aux.h" | ||
26 | |||
27 | |||
28 | struct via_aux_bus *via_aux_probe(struct i2c_adapter *adap) | ||
29 | { | ||
30 | struct via_aux_bus *bus; | ||
31 | |||
32 | if (!adap) | ||
33 | return NULL; | ||
34 | |||
35 | bus = kmalloc(sizeof(*bus), GFP_KERNEL); | ||
36 | if (!bus) | ||
37 | return NULL; | ||
38 | |||
39 | bus->adap = adap; | ||
40 | INIT_LIST_HEAD(&bus->drivers); | ||
41 | |||
42 | via_aux_edid_probe(bus); | ||
43 | via_aux_vt1636_probe(bus); | ||
44 | via_aux_vt1632_probe(bus); | ||
45 | via_aux_vt1631_probe(bus); | ||
46 | via_aux_vt1625_probe(bus); | ||
47 | via_aux_vt1622_probe(bus); | ||
48 | via_aux_vt1621_probe(bus); | ||
49 | via_aux_sii164_probe(bus); | ||
50 | via_aux_ch7301_probe(bus); | ||
51 | |||
52 | return bus; | ||
53 | } | ||
54 | |||
55 | void via_aux_free(struct via_aux_bus *bus) | ||
56 | { | ||
57 | struct via_aux_drv *pos, *n; | ||
58 | |||
59 | if (!bus) | ||
60 | return; | ||
61 | |||
62 | list_for_each_entry_safe(pos, n, &bus->drivers, chain) { | ||
63 | if (pos->cleanup) | ||
64 | pos->cleanup(pos); | ||
65 | |||
66 | list_del(&pos->chain); | ||
67 | kfree(pos->data); | ||
68 | kfree(pos); | ||
69 | } | ||
70 | |||
71 | kfree(bus); | ||
72 | } | ||
73 | |||
74 | const struct fb_videomode *via_aux_get_preferred_mode(struct via_aux_bus *bus) | ||
75 | { | ||
76 | struct via_aux_drv *pos; | ||
77 | const struct fb_videomode *mode = NULL; | ||
78 | |||
79 | if (!bus) | ||
80 | return NULL; | ||
81 | |||
82 | list_for_each_entry(pos, &bus->drivers, chain) { | ||
83 | if (pos->get_preferred_mode) | ||
84 | mode = pos->get_preferred_mode(pos); | ||
85 | } | ||
86 | |||
87 | return mode; | ||
88 | } | ||
diff --git a/drivers/video/via/via_aux.h b/drivers/video/via/via_aux.h new file mode 100644 index 000000000000..a8de3f038cea --- /dev/null +++ b/drivers/video/via/via_aux.h | |||
@@ -0,0 +1,93 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public | ||
6 | * License as published by the Free Software Foundation; | ||
7 | * either version 2, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
11 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
12 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
13 | * for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /* | ||
21 | * infrastructure for devices connected via I2C | ||
22 | */ | ||
23 | |||
24 | #ifndef __VIA_AUX_H__ | ||
25 | #define __VIA_AUX_H__ | ||
26 | |||
27 | |||
28 | #include <linux/list.h> | ||
29 | #include <linux/i2c.h> | ||
30 | #include <linux/fb.h> | ||
31 | |||
32 | |||
33 | struct via_aux_bus { | ||
34 | struct i2c_adapter *adap; /* the I2C device to access the bus */ | ||
35 | struct list_head drivers; /* drivers for devices on this bus */ | ||
36 | }; | ||
37 | |||
38 | struct via_aux_drv { | ||
39 | struct list_head chain; /* chain to support multiple drivers */ | ||
40 | |||
41 | struct via_aux_bus *bus; /* the I2C bus used */ | ||
42 | u8 addr; /* the I2C slave address */ | ||
43 | |||
44 | const char *name; /* human readable name of the driver */ | ||
45 | void *data; /* private data of this driver */ | ||
46 | |||
47 | void (*cleanup)(struct via_aux_drv *drv); | ||
48 | const struct fb_videomode* (*get_preferred_mode) | ||
49 | (struct via_aux_drv *drv); | ||
50 | }; | ||
51 | |||
52 | |||
53 | struct via_aux_bus *via_aux_probe(struct i2c_adapter *adap); | ||
54 | void via_aux_free(struct via_aux_bus *bus); | ||
55 | const struct fb_videomode *via_aux_get_preferred_mode(struct via_aux_bus *bus); | ||
56 | |||
57 | |||
58 | static inline bool via_aux_add(struct via_aux_drv *drv) | ||
59 | { | ||
60 | struct via_aux_drv *data = kmalloc(sizeof(*data), GFP_KERNEL); | ||
61 | |||
62 | if (!data) | ||
63 | return false; | ||
64 | |||
65 | *data = *drv; | ||
66 | list_add_tail(&data->chain, &data->bus->drivers); | ||
67 | return true; | ||
68 | } | ||
69 | |||
70 | static inline bool via_aux_read(struct via_aux_drv *drv, u8 start, u8 *buf, | ||
71 | u8 len) | ||
72 | { | ||
73 | struct i2c_msg msg[2] = { | ||
74 | {.addr = drv->addr, .flags = 0, .len = 1, .buf = &start}, | ||
75 | {.addr = drv->addr, .flags = I2C_M_RD, .len = len, .buf = buf} }; | ||
76 | |||
77 | return i2c_transfer(drv->bus->adap, msg, 2) == 2; | ||
78 | } | ||
79 | |||
80 | |||
81 | /* probe functions of existing drivers - should only be called in via_aux.c */ | ||
82 | void via_aux_ch7301_probe(struct via_aux_bus *bus); | ||
83 | void via_aux_edid_probe(struct via_aux_bus *bus); | ||
84 | void via_aux_sii164_probe(struct via_aux_bus *bus); | ||
85 | void via_aux_vt1636_probe(struct via_aux_bus *bus); | ||
86 | void via_aux_vt1632_probe(struct via_aux_bus *bus); | ||
87 | void via_aux_vt1631_probe(struct via_aux_bus *bus); | ||
88 | void via_aux_vt1625_probe(struct via_aux_bus *bus); | ||
89 | void via_aux_vt1622_probe(struct via_aux_bus *bus); | ||
90 | void via_aux_vt1621_probe(struct via_aux_bus *bus); | ||
91 | |||
92 | |||
93 | #endif /* __VIA_AUX_H__ */ | ||
diff --git a/drivers/video/via/via_aux_ch7301.c b/drivers/video/via/via_aux_ch7301.c new file mode 100644 index 000000000000..1cbe5037a6b0 --- /dev/null +++ b/drivers/video/via/via_aux_ch7301.c | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public | ||
6 | * License as published by the Free Software Foundation; | ||
7 | * either version 2, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
11 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
12 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
13 | * for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /* | ||
21 | * driver for Chrontel CH7301 DVI Transmitter | ||
22 | */ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include "via_aux.h" | ||
26 | |||
27 | |||
28 | static const char *name = "CH7301 DVI Transmitter"; | ||
29 | |||
30 | |||
31 | static void probe(struct via_aux_bus *bus, u8 addr) | ||
32 | { | ||
33 | struct via_aux_drv drv = { | ||
34 | .bus = bus, | ||
35 | .addr = addr, | ||
36 | .name = name}; | ||
37 | u8 tmp; | ||
38 | |||
39 | if (!via_aux_read(&drv, 0x4B, &tmp, 1) || tmp != 0x17) | ||
40 | return; | ||
41 | |||
42 | printk(KERN_INFO "viafb: Found %s at address 0x%x\n", name, addr); | ||
43 | via_aux_add(&drv); | ||
44 | } | ||
45 | |||
46 | void via_aux_ch7301_probe(struct via_aux_bus *bus) | ||
47 | { | ||
48 | probe(bus, 0x75); | ||
49 | probe(bus, 0x76); | ||
50 | } | ||
diff --git a/drivers/video/via/via_aux_edid.c b/drivers/video/via/via_aux_edid.c new file mode 100644 index 000000000000..754d4509033f --- /dev/null +++ b/drivers/video/via/via_aux_edid.c | |||
@@ -0,0 +1,100 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public | ||
6 | * License as published by the Free Software Foundation; | ||
7 | * either version 2, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
11 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
12 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
13 | * for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /* | ||
21 | * generic EDID driver | ||
22 | */ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include <linux/fb.h> | ||
26 | #include "via_aux.h" | ||
27 | #include "../edid.h" | ||
28 | |||
29 | |||
30 | static const char *name = "EDID"; | ||
31 | |||
32 | |||
33 | static void query_edid(struct via_aux_drv *drv) | ||
34 | { | ||
35 | struct fb_monspecs *spec = drv->data; | ||
36 | unsigned char edid[EDID_LENGTH]; | ||
37 | bool valid = false; | ||
38 | |||
39 | if (spec) { | ||
40 | fb_destroy_modedb(spec->modedb); | ||
41 | } else { | ||
42 | spec = kmalloc(sizeof(*spec), GFP_KERNEL); | ||
43 | if (!spec) | ||
44 | return; | ||
45 | } | ||
46 | |||
47 | spec->version = spec->revision = 0; | ||
48 | if (via_aux_read(drv, 0x00, edid, EDID_LENGTH)) { | ||
49 | fb_edid_to_monspecs(edid, spec); | ||
50 | valid = spec->version || spec->revision; | ||
51 | } | ||
52 | |||
53 | if (!valid) { | ||
54 | kfree(spec); | ||
55 | spec = NULL; | ||
56 | } else | ||
57 | printk(KERN_DEBUG "EDID: %s %s\n", spec->manufacturer, spec->monitor); | ||
58 | |||
59 | drv->data = spec; | ||
60 | } | ||
61 | |||
62 | static const struct fb_videomode *get_preferred_mode(struct via_aux_drv *drv) | ||
63 | { | ||
64 | struct fb_monspecs *spec = drv->data; | ||
65 | int i; | ||
66 | |||
67 | if (!spec || !spec->modedb || !(spec->misc & FB_MISC_1ST_DETAIL)) | ||
68 | return NULL; | ||
69 | |||
70 | for (i = 0; i < spec->modedb_len; i++) { | ||
71 | if (spec->modedb[i].flag & FB_MODE_IS_FIRST && | ||
72 | spec->modedb[i].flag & FB_MODE_IS_DETAILED) | ||
73 | return &spec->modedb[i]; | ||
74 | } | ||
75 | |||
76 | return NULL; | ||
77 | } | ||
78 | |||
79 | static void cleanup(struct via_aux_drv *drv) | ||
80 | { | ||
81 | struct fb_monspecs *spec = drv->data; | ||
82 | |||
83 | if (spec) | ||
84 | fb_destroy_modedb(spec->modedb); | ||
85 | } | ||
86 | |||
87 | void via_aux_edid_probe(struct via_aux_bus *bus) | ||
88 | { | ||
89 | struct via_aux_drv drv = { | ||
90 | .bus = bus, | ||
91 | .addr = 0x50, | ||
92 | .name = name, | ||
93 | .cleanup = cleanup, | ||
94 | .get_preferred_mode = get_preferred_mode}; | ||
95 | |||
96 | query_edid(&drv); | ||
97 | |||
98 | /* as EDID devices can be connected/disconnected just add the driver */ | ||
99 | via_aux_add(&drv); | ||
100 | } | ||
diff --git a/drivers/video/via/via_aux_sii164.c b/drivers/video/via/via_aux_sii164.c new file mode 100644 index 000000000000..ca1b35f033b1 --- /dev/null +++ b/drivers/video/via/via_aux_sii164.c | |||
@@ -0,0 +1,54 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public | ||
6 | * License as published by the Free Software Foundation; | ||
7 | * either version 2, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
11 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
12 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
13 | * for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /* | ||
21 | * driver for Silicon Image SiI 164 PanelLink Transmitter | ||
22 | */ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include "via_aux.h" | ||
26 | |||
27 | |||
28 | static const char *name = "SiI 164 PanelLink Transmitter"; | ||
29 | |||
30 | |||
31 | static void probe(struct via_aux_bus *bus, u8 addr) | ||
32 | { | ||
33 | struct via_aux_drv drv = { | ||
34 | .bus = bus, | ||
35 | .addr = addr, | ||
36 | .name = name}; | ||
37 | /* check vendor id and device id */ | ||
38 | const u8 id[] = {0x01, 0x00, 0x06, 0x00}, len = ARRAY_SIZE(id); | ||
39 | u8 tmp[len]; | ||
40 | |||
41 | if (!via_aux_read(&drv, 0x00, tmp, len) || memcmp(id, tmp, len)) | ||
42 | return; | ||
43 | |||
44 | printk(KERN_INFO "viafb: Found %s at address 0x%x\n", name, addr); | ||
45 | via_aux_add(&drv); | ||
46 | } | ||
47 | |||
48 | void via_aux_sii164_probe(struct via_aux_bus *bus) | ||
49 | { | ||
50 | u8 i; | ||
51 | |||
52 | for (i = 0x38; i <= 0x3F; i++) | ||
53 | probe(bus, i); | ||
54 | } | ||
diff --git a/drivers/video/via/via_aux_vt1621.c b/drivers/video/via/via_aux_vt1621.c new file mode 100644 index 000000000000..38eca8479898 --- /dev/null +++ b/drivers/video/via/via_aux_vt1621.c | |||
@@ -0,0 +1,44 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public | ||
6 | * License as published by the Free Software Foundation; | ||
7 | * either version 2, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
11 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
12 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
13 | * for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /* | ||
21 | * driver for VIA VT1621(M) TV Encoder | ||
22 | */ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include "via_aux.h" | ||
26 | |||
27 | |||
28 | static const char *name = "VT1621(M) TV Encoder"; | ||
29 | |||
30 | |||
31 | void via_aux_vt1621_probe(struct via_aux_bus *bus) | ||
32 | { | ||
33 | struct via_aux_drv drv = { | ||
34 | .bus = bus, | ||
35 | .addr = 0x20, | ||
36 | .name = name}; | ||
37 | u8 tmp; | ||
38 | |||
39 | if (!via_aux_read(&drv, 0x1B, &tmp, 1) || tmp != 0x02) | ||
40 | return; | ||
41 | |||
42 | printk(KERN_INFO "viafb: Found %s\n", name); | ||
43 | via_aux_add(&drv); | ||
44 | } | ||
diff --git a/drivers/video/via/via_aux_vt1622.c b/drivers/video/via/via_aux_vt1622.c new file mode 100644 index 000000000000..8c79c68ba683 --- /dev/null +++ b/drivers/video/via/via_aux_vt1622.c | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public | ||
6 | * License as published by the Free Software Foundation; | ||
7 | * either version 2, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
11 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
12 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
13 | * for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /* | ||
21 | * driver for VIA VT1622(M) Digital TV Encoder | ||
22 | */ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include "via_aux.h" | ||
26 | |||
27 | |||
28 | static const char *name = "VT1622(M) Digital TV Encoder"; | ||
29 | |||
30 | |||
31 | static void probe(struct via_aux_bus *bus, u8 addr) | ||
32 | { | ||
33 | struct via_aux_drv drv = { | ||
34 | .bus = bus, | ||
35 | .addr = addr, | ||
36 | .name = name}; | ||
37 | u8 tmp; | ||
38 | |||
39 | if (!via_aux_read(&drv, 0x1B, &tmp, 1) || tmp != 0x03) | ||
40 | return; | ||
41 | |||
42 | printk(KERN_INFO "viafb: Found %s at address 0x%x\n", name, addr); | ||
43 | via_aux_add(&drv); | ||
44 | } | ||
45 | |||
46 | void via_aux_vt1622_probe(struct via_aux_bus *bus) | ||
47 | { | ||
48 | probe(bus, 0x20); | ||
49 | probe(bus, 0x21); | ||
50 | } | ||
diff --git a/drivers/video/via/via_aux_vt1625.c b/drivers/video/via/via_aux_vt1625.c new file mode 100644 index 000000000000..03eb30165d36 --- /dev/null +++ b/drivers/video/via/via_aux_vt1625.c | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public | ||
6 | * License as published by the Free Software Foundation; | ||
7 | * either version 2, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
11 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
12 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
13 | * for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /* | ||
21 | * driver for VIA VT1625(M) HDTV Encoder | ||
22 | */ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include "via_aux.h" | ||
26 | |||
27 | |||
28 | static const char *name = "VT1625(M) HDTV Encoder"; | ||
29 | |||
30 | |||
31 | static void probe(struct via_aux_bus *bus, u8 addr) | ||
32 | { | ||
33 | struct via_aux_drv drv = { | ||
34 | .bus = bus, | ||
35 | .addr = addr, | ||
36 | .name = name}; | ||
37 | u8 tmp; | ||
38 | |||
39 | if (!via_aux_read(&drv, 0x1B, &tmp, 1) || tmp != 0x50) | ||
40 | return; | ||
41 | |||
42 | printk(KERN_INFO "viafb: Found %s at address 0x%x\n", name, addr); | ||
43 | via_aux_add(&drv); | ||
44 | } | ||
45 | |||
46 | void via_aux_vt1625_probe(struct via_aux_bus *bus) | ||
47 | { | ||
48 | probe(bus, 0x20); | ||
49 | probe(bus, 0x21); | ||
50 | } | ||
diff --git a/drivers/video/via/via_aux_vt1631.c b/drivers/video/via/via_aux_vt1631.c new file mode 100644 index 000000000000..06e742f1f723 --- /dev/null +++ b/drivers/video/via/via_aux_vt1631.c | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public | ||
6 | * License as published by the Free Software Foundation; | ||
7 | * either version 2, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
11 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
12 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
13 | * for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /* | ||
21 | * driver for VIA VT1631 LVDS Transmitter | ||
22 | */ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include "via_aux.h" | ||
26 | |||
27 | |||
28 | static const char *name = "VT1631 LVDS Transmitter"; | ||
29 | |||
30 | |||
31 | void via_aux_vt1631_probe(struct via_aux_bus *bus) | ||
32 | { | ||
33 | struct via_aux_drv drv = { | ||
34 | .bus = bus, | ||
35 | .addr = 0x38, | ||
36 | .name = name}; | ||
37 | /* check vendor id and device id */ | ||
38 | const u8 id[] = {0x06, 0x11, 0x91, 0x31}, len = ARRAY_SIZE(id); | ||
39 | u8 tmp[len]; | ||
40 | |||
41 | if (!via_aux_read(&drv, 0x00, tmp, len) || memcmp(id, tmp, len)) | ||
42 | return; | ||
43 | |||
44 | printk(KERN_INFO "viafb: Found %s\n", name); | ||
45 | via_aux_add(&drv); | ||
46 | } | ||
diff --git a/drivers/video/via/via_aux_vt1632.c b/drivers/video/via/via_aux_vt1632.c new file mode 100644 index 000000000000..d24f4cd97401 --- /dev/null +++ b/drivers/video/via/via_aux_vt1632.c | |||
@@ -0,0 +1,54 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public | ||
6 | * License as published by the Free Software Foundation; | ||
7 | * either version 2, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
11 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
12 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
13 | * for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /* | ||
21 | * driver for VIA VT1632 DVI Transmitter | ||
22 | */ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include "via_aux.h" | ||
26 | |||
27 | |||
28 | static const char *name = "VT1632 DVI Transmitter"; | ||
29 | |||
30 | |||
31 | static void probe(struct via_aux_bus *bus, u8 addr) | ||
32 | { | ||
33 | struct via_aux_drv drv = { | ||
34 | .bus = bus, | ||
35 | .addr = addr, | ||
36 | .name = name}; | ||
37 | /* check vendor id and device id */ | ||
38 | const u8 id[] = {0x06, 0x11, 0x92, 0x31}, len = ARRAY_SIZE(id); | ||
39 | u8 tmp[len]; | ||
40 | |||
41 | if (!via_aux_read(&drv, 0x00, tmp, len) || memcmp(id, tmp, len)) | ||
42 | return; | ||
43 | |||
44 | printk(KERN_INFO "viafb: Found %s at address 0x%x\n", name, addr); | ||
45 | via_aux_add(&drv); | ||
46 | } | ||
47 | |||
48 | void via_aux_vt1632_probe(struct via_aux_bus *bus) | ||
49 | { | ||
50 | u8 i; | ||
51 | |||
52 | for (i = 0x08; i <= 0x0F; i++) | ||
53 | probe(bus, i); | ||
54 | } | ||
diff --git a/drivers/video/via/via_aux_vt1636.c b/drivers/video/via/via_aux_vt1636.c new file mode 100644 index 000000000000..9e015c101d4d --- /dev/null +++ b/drivers/video/via/via_aux_vt1636.c | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public | ||
6 | * License as published by the Free Software Foundation; | ||
7 | * either version 2, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even | ||
11 | * the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
12 | * A PARTICULAR PURPOSE.See the GNU General Public License | ||
13 | * for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /* | ||
21 | * driver for VIA VT1636 LVDS Transmitter | ||
22 | */ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include "via_aux.h" | ||
26 | |||
27 | |||
28 | static const char *name = "VT1636 LVDS Transmitter"; | ||
29 | |||
30 | |||
31 | void via_aux_vt1636_probe(struct via_aux_bus *bus) | ||
32 | { | ||
33 | struct via_aux_drv drv = { | ||
34 | .bus = bus, | ||
35 | .addr = 0x40, | ||
36 | .name = name}; | ||
37 | /* check vendor id and device id */ | ||
38 | const u8 id[] = {0x06, 0x11, 0x45, 0x33}, len = ARRAY_SIZE(id); | ||
39 | u8 tmp[len]; | ||
40 | |||
41 | if (!via_aux_read(&drv, 0x00, tmp, len) || memcmp(id, tmp, len)) | ||
42 | return; | ||
43 | |||
44 | printk(KERN_INFO "viafb: Found %s\n", name); | ||
45 | via_aux_add(&drv); | ||
46 | } | ||
diff --git a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c index 78f1405dbab7..dd53058bbbb7 100644 --- a/drivers/video/via/via_i2c.c +++ b/drivers/video/via/via_i2c.c | |||
@@ -51,7 +51,7 @@ static void via_i2c_setscl(void *data, int state) | |||
51 | val |= 0x01; | 51 | val |= 0x01; |
52 | break; | 52 | break; |
53 | case VIA_PORT_GPIO: | 53 | case VIA_PORT_GPIO: |
54 | val |= 0x80; | 54 | val |= 0x82; |
55 | break; | 55 | break; |
56 | default: | 56 | default: |
57 | printk(KERN_ERR "viafb_i2c: specify wrong i2c type.\n"); | 57 | printk(KERN_ERR "viafb_i2c: specify wrong i2c type.\n"); |
@@ -67,6 +67,9 @@ static int via_i2c_getscl(void *data) | |||
67 | int ret = 0; | 67 | int ret = 0; |
68 | 68 | ||
69 | spin_lock_irqsave(&i2c_vdev->reg_lock, flags); | 69 | spin_lock_irqsave(&i2c_vdev->reg_lock, flags); |
70 | if (adap_data->type == VIA_PORT_GPIO) | ||
71 | via_write_reg_mask(adap_data->io_port, adap_data->ioport_index, | ||
72 | 0, 0x80); | ||
70 | if (via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x08) | 73 | if (via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x08) |
71 | ret = 1; | 74 | ret = 1; |
72 | spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags); | 75 | spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags); |
@@ -80,6 +83,9 @@ static int via_i2c_getsda(void *data) | |||
80 | int ret = 0; | 83 | int ret = 0; |
81 | 84 | ||
82 | spin_lock_irqsave(&i2c_vdev->reg_lock, flags); | 85 | spin_lock_irqsave(&i2c_vdev->reg_lock, flags); |
86 | if (adap_data->type == VIA_PORT_GPIO) | ||
87 | via_write_reg_mask(adap_data->io_port, adap_data->ioport_index, | ||
88 | 0, 0x40); | ||
83 | if (via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x04) | 89 | if (via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x04) |
84 | ret = 1; | 90 | ret = 1; |
85 | spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags); | 91 | spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags); |
@@ -103,7 +109,7 @@ static void via_i2c_setsda(void *data, int state) | |||
103 | val |= 0x01; | 109 | val |= 0x01; |
104 | break; | 110 | break; |
105 | case VIA_PORT_GPIO: | 111 | case VIA_PORT_GPIO: |
106 | val |= 0x40; | 112 | val |= 0x42; |
107 | break; | 113 | break; |
108 | default: | 114 | default: |
109 | printk(KERN_ERR "viafb_i2c: specify wrong i2c type.\n"); | 115 | printk(KERN_ERR "viafb_i2c: specify wrong i2c type.\n"); |
diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index a13c258bd32f..0c8837565bc7 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/stat.h> | 25 | #include <linux/stat.h> |
26 | #include <linux/via-core.h> | 26 | #include <linux/via-core.h> |
27 | #include <linux/via_i2c.h> | ||
27 | #include <asm/olpc.h> | 28 | #include <asm/olpc.h> |
28 | 29 | ||
29 | #define _MASTER_FILE | 30 | #define _MASTER_FILE |
@@ -286,26 +287,22 @@ static int viafb_set_par(struct fb_info *info) | |||
286 | viafb_second_yres, viafb_bpp1, 1); | 287 | viafb_second_yres, viafb_bpp1, 1); |
287 | } | 288 | } |
288 | 289 | ||
289 | refresh = viafb_get_refresh(info->var.xres, info->var.yres, | 290 | refresh = get_var_refresh(&info->var); |
290 | get_var_refresh(&info->var)); | 291 | if (viafb_dual_fb && viapar->iga_path == IGA2) { |
291 | if (viafb_get_best_mode(viafbinfo->var.xres, viafbinfo->var.yres, | 292 | viafb_bpp1 = info->var.bits_per_pixel; |
292 | refresh)) { | 293 | viafb_refresh1 = refresh; |
293 | if (viafb_dual_fb && viapar->iga_path == IGA2) { | 294 | } else { |
294 | viafb_bpp1 = info->var.bits_per_pixel; | 295 | viafb_bpp = info->var.bits_per_pixel; |
295 | viafb_refresh1 = refresh; | 296 | viafb_refresh = refresh; |
296 | } else { | ||
297 | viafb_bpp = info->var.bits_per_pixel; | ||
298 | viafb_refresh = refresh; | ||
299 | } | ||
300 | |||
301 | if (info->var.accel_flags & FB_ACCELF_TEXT) | ||
302 | info->flags &= ~FBINFO_HWACCEL_DISABLED; | ||
303 | else | ||
304 | info->flags |= FBINFO_HWACCEL_DISABLED; | ||
305 | viafb_setmode(info->var.bits_per_pixel, viafb_bpp1); | ||
306 | viafb_pan_display(&info->var, info); | ||
307 | } | 297 | } |
308 | 298 | ||
299 | if (info->var.accel_flags & FB_ACCELF_TEXT) | ||
300 | info->flags &= ~FBINFO_HWACCEL_DISABLED; | ||
301 | else | ||
302 | info->flags |= FBINFO_HWACCEL_DISABLED; | ||
303 | viafb_setmode(); | ||
304 | viafb_pan_display(&info->var, info); | ||
305 | |||
309 | return 0; | 306 | return 0; |
310 | } | 307 | } |
311 | 308 | ||
@@ -1670,12 +1667,23 @@ static void viafb_remove_proc(struct viafb_shared *shared) | |||
1670 | } | 1667 | } |
1671 | #undef IS_VT1636 | 1668 | #undef IS_VT1636 |
1672 | 1669 | ||
1673 | static int parse_mode(const char *str, u32 *xres, u32 *yres) | 1670 | static int parse_mode(const char *str, u32 devices, u32 *xres, u32 *yres) |
1674 | { | 1671 | { |
1672 | const struct fb_videomode *mode = NULL; | ||
1675 | char *ptr; | 1673 | char *ptr; |
1676 | 1674 | ||
1677 | if (!str) { | 1675 | if (!str) { |
1678 | if (machine_is_olpc()) { | 1676 | if (devices == VIA_CRT) |
1677 | mode = via_aux_get_preferred_mode( | ||
1678 | viaparinfo->shared->i2c_26); | ||
1679 | else if (devices == VIA_DVP1) | ||
1680 | mode = via_aux_get_preferred_mode( | ||
1681 | viaparinfo->shared->i2c_31); | ||
1682 | |||
1683 | if (mode) { | ||
1684 | *xres = mode->xres; | ||
1685 | *yres = mode->yres; | ||
1686 | } else if (machine_is_olpc()) { | ||
1679 | *xres = 1200; | 1687 | *xres = 1200; |
1680 | *yres = 900; | 1688 | *yres = 900; |
1681 | } else { | 1689 | } else { |
@@ -1729,6 +1737,31 @@ static struct viafb_pm_hooks viafb_fb_pm_hooks = { | |||
1729 | 1737 | ||
1730 | #endif | 1738 | #endif |
1731 | 1739 | ||
1740 | static void __devinit i2c_bus_probe(struct viafb_shared *shared) | ||
1741 | { | ||
1742 | /* should be always CRT */ | ||
1743 | printk(KERN_INFO "viafb: Probing I2C bus 0x26\n"); | ||
1744 | shared->i2c_26 = via_aux_probe(viafb_find_i2c_adapter(VIA_PORT_26)); | ||
1745 | |||
1746 | /* seems to be usually DVP1 */ | ||
1747 | printk(KERN_INFO "viafb: Probing I2C bus 0x31\n"); | ||
1748 | shared->i2c_31 = via_aux_probe(viafb_find_i2c_adapter(VIA_PORT_31)); | ||
1749 | |||
1750 | /* FIXME: what is this? */ | ||
1751 | if (!machine_is_olpc()) { | ||
1752 | printk(KERN_INFO "viafb: Probing I2C bus 0x2C\n"); | ||
1753 | shared->i2c_2C = via_aux_probe(viafb_find_i2c_adapter(VIA_PORT_2C)); | ||
1754 | } | ||
1755 | |||
1756 | printk(KERN_INFO "viafb: Finished I2C bus probing"); | ||
1757 | } | ||
1758 | |||
1759 | static void i2c_bus_free(struct viafb_shared *shared) | ||
1760 | { | ||
1761 | via_aux_free(shared->i2c_26); | ||
1762 | via_aux_free(shared->i2c_31); | ||
1763 | via_aux_free(shared->i2c_2C); | ||
1764 | } | ||
1732 | 1765 | ||
1733 | int __devinit via_fb_pci_probe(struct viafb_dev *vdev) | 1766 | int __devinit via_fb_pci_probe(struct viafb_dev *vdev) |
1734 | { | 1767 | { |
@@ -1762,6 +1795,7 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev) | |||
1762 | &viaparinfo->shared->lvds_setting_info2; | 1795 | &viaparinfo->shared->lvds_setting_info2; |
1763 | viaparinfo->chip_info = &viaparinfo->shared->chip_info; | 1796 | viaparinfo->chip_info = &viaparinfo->shared->chip_info; |
1764 | 1797 | ||
1798 | i2c_bus_probe(viaparinfo->shared); | ||
1765 | if (viafb_dual_fb) | 1799 | if (viafb_dual_fb) |
1766 | viafb_SAMM_ON = 1; | 1800 | viafb_SAMM_ON = 1; |
1767 | parse_lcd_port(); | 1801 | parse_lcd_port(); |
@@ -1804,10 +1838,11 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev) | |||
1804 | viafb_second_size * 1024 * 1024; | 1838 | viafb_second_size * 1024 * 1024; |
1805 | } | 1839 | } |
1806 | 1840 | ||
1807 | parse_mode(viafb_mode, &default_xres, &default_yres); | 1841 | parse_mode(viafb_mode, viaparinfo->shared->iga1_devices, |
1842 | &default_xres, &default_yres); | ||
1808 | if (viafb_SAMM_ON == 1) | 1843 | if (viafb_SAMM_ON == 1) |
1809 | parse_mode(viafb_mode1, &viafb_second_xres, | 1844 | parse_mode(viafb_mode1, viaparinfo->shared->iga2_devices, |
1810 | &viafb_second_yres); | 1845 | &viafb_second_xres, &viafb_second_yres); |
1811 | 1846 | ||
1812 | default_var.xres = default_xres; | 1847 | default_var.xres = default_xres; |
1813 | default_var.yres = default_yres; | 1848 | default_var.yres = default_yres; |
@@ -1915,6 +1950,7 @@ out_fb1_release: | |||
1915 | if (viafbinfo1) | 1950 | if (viafbinfo1) |
1916 | framebuffer_release(viafbinfo1); | 1951 | framebuffer_release(viafbinfo1); |
1917 | out_fb_release: | 1952 | out_fb_release: |
1953 | i2c_bus_free(viaparinfo->shared); | ||
1918 | framebuffer_release(viafbinfo); | 1954 | framebuffer_release(viafbinfo); |
1919 | return rc; | 1955 | return rc; |
1920 | } | 1956 | } |
@@ -1927,6 +1963,7 @@ void __devexit via_fb_pci_remove(struct pci_dev *pdev) | |||
1927 | if (viafb_dual_fb) | 1963 | if (viafb_dual_fb) |
1928 | unregister_framebuffer(viafbinfo1); | 1964 | unregister_framebuffer(viafbinfo1); |
1929 | viafb_remove_proc(viaparinfo->shared); | 1965 | viafb_remove_proc(viaparinfo->shared); |
1966 | i2c_bus_free(viaparinfo->shared); | ||
1930 | framebuffer_release(viafbinfo); | 1967 | framebuffer_release(viafbinfo); |
1931 | if (viafb_dual_fb) | 1968 | if (viafb_dual_fb) |
1932 | framebuffer_release(viafbinfo1); | 1969 | framebuffer_release(viafbinfo1); |
@@ -2033,9 +2070,9 @@ int __init viafb_init(void) | |||
2033 | if (r < 0) | 2070 | if (r < 0) |
2034 | return r; | 2071 | return r; |
2035 | #endif | 2072 | #endif |
2036 | if (parse_mode(viafb_mode, &dummy_x, &dummy_y) | 2073 | if (parse_mode(viafb_mode, 0, &dummy_x, &dummy_y) |
2037 | || !viafb_get_best_mode(dummy_x, dummy_y, viafb_refresh) | 2074 | || !viafb_get_best_mode(dummy_x, dummy_y, viafb_refresh) |
2038 | || parse_mode(viafb_mode1, &dummy_x, &dummy_y) | 2075 | || parse_mode(viafb_mode1, 0, &dummy_x, &dummy_y) |
2039 | || !viafb_get_best_mode(dummy_x, dummy_y, viafb_refresh1) | 2076 | || !viafb_get_best_mode(dummy_x, dummy_y, viafb_refresh1) |
2040 | || viafb_bpp < 0 || viafb_bpp > 32 | 2077 | || viafb_bpp < 0 || viafb_bpp > 32 |
2041 | || viafb_bpp1 < 0 || viafb_bpp1 > 32 | 2078 | || viafb_bpp1 < 0 || viafb_bpp1 > 32 |
diff --git a/drivers/video/via/viafbdev.h b/drivers/video/via/viafbdev.h index d9440635d1d4..f6b2ddf56e94 100644 --- a/drivers/video/via/viafbdev.h +++ b/drivers/video/via/viafbdev.h | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/fb.h> | 26 | #include <linux/fb.h> |
27 | #include <linux/spinlock.h> | 27 | #include <linux/spinlock.h> |
28 | 28 | ||
29 | #include "via_aux.h" | ||
29 | #include "ioctl.h" | 30 | #include "ioctl.h" |
30 | #include "share.h" | 31 | #include "share.h" |
31 | #include "chip.h" | 32 | #include "chip.h" |
@@ -48,6 +49,11 @@ struct viafb_shared { | |||
48 | struct proc_dir_entry *iga2_proc_entry; | 49 | struct proc_dir_entry *iga2_proc_entry; |
49 | struct viafb_dev *vdev; /* Global dev info */ | 50 | struct viafb_dev *vdev; /* Global dev info */ |
50 | 51 | ||
52 | /* I2C busses that may have auxiliary devices */ | ||
53 | struct via_aux_bus *i2c_26; | ||
54 | struct via_aux_bus *i2c_31; | ||
55 | struct via_aux_bus *i2c_2C; | ||
56 | |||
51 | /* All the information will be needed to set engine */ | 57 | /* All the information will be needed to set engine */ |
52 | struct tmds_setting_information tmds_setting_info; | 58 | struct tmds_setting_information tmds_setting_info; |
53 | struct lvds_setting_information lvds_setting_info; | 59 | struct lvds_setting_information lvds_setting_info; |
diff --git a/drivers/video/via/viamode.c b/drivers/video/via/viamode.c index 0911cac1b2ff..0666ab01cf4a 100644 --- a/drivers/video/via/viamode.c +++ b/drivers/video/via/viamode.c | |||
@@ -268,591 +268,78 @@ struct VPITTable VPIT = { | |||
268 | /* Mode Table */ | 268 | /* Mode Table */ |
269 | /********************/ | 269 | /********************/ |
270 | 270 | ||
271 | /* 480x640 */ | 271 | static const struct fb_videomode viafb_modes[] = { |
272 | static struct crt_mode_table CRTM480x640[] = { | 272 | {NULL, 60, 480, 640, 40285, 72, 24, 19, 1, 48, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
273 | /* r_rate, hsp, vsp */ | 273 | {NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2, 0, 0, 0}, |
274 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | 274 | {NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3, 0, 0, 0}, |
275 | {REFRESH_60, M480X640_R60_HSP, M480X640_R60_VSP, | 275 | {NULL, 85, 640, 480, 27780, 80, 56, 25, 1, 56, 3, 0, 0, 0}, |
276 | {624, 480, 480, 144, 504, 48, 663, 640, 640, 23, 641, 3} } /* GTF*/ | 276 | {NULL, 100, 640, 480, 23167, 104, 40, 25, 1, 64, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
277 | }; | 277 | {NULL, 120, 640, 480, 19081, 104, 40, 31, 1, 64, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
278 | 278 | {NULL, 60, 720, 480, 37426, 88, 16, 13, 1, 72, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | |
279 | /* 640x480*/ | 279 | {NULL, 60, 720, 576, 30611, 96, 24, 17, 1, 72, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
280 | static struct crt_mode_table CRTM640x480[] = { | 280 | {NULL, 60, 800, 600, 25131, 88, 40, 23, 1, 128, 4, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
281 | /*r_rate,hsp,vsp */ | 281 | {NULL, 75, 800, 600, 20202, 160, 16, 21, 1, 80, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
282 | /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | 282 | {NULL, 85, 800, 600, 17790, 152, 32, 27, 1, 64, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
283 | {REFRESH_60, M640X480_R60_HSP, M640X480_R60_VSP, | 283 | {NULL, 100, 800, 600, 14667, 136, 48, 32, 1, 88, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
284 | {800, 640, 640, 160, 656, 96, 525, 480, 480, 45, 490, 2} }, | 284 | {NULL, 120, 800, 600, 11911, 144, 56, 39, 1, 88, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
285 | {REFRESH_75, M640X480_R75_HSP, M640X480_R75_VSP, | 285 | {NULL, 60, 800, 480, 33602, 96, 24, 10, 3, 72, 7, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
286 | {840, 640, 640, 200, 656, 64, 500, 480, 480, 20, 481, 3} }, | 286 | {NULL, 60, 848, 480, 31565, 104, 24, 12, 3, 80, 5, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
287 | {REFRESH_85, M640X480_R85_HSP, M640X480_R85_VSP, | 287 | {NULL, 60, 856, 480, 31517, 104, 16, 13, 1, 88, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
288 | {832, 640, 640, 192, 696, 56, 509, 480, 480, 29, 481, 3} }, | 288 | {NULL, 60, 1024, 512, 24218, 136, 32, 15, 1, 104, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
289 | {REFRESH_100, M640X480_R100_HSP, M640X480_R100_VSP, | 289 | {NULL, 60, 1024, 600, 20423, 144, 40, 18, 1, 104, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
290 | {848, 640, 640, 208, 680, 64, 509, 480, 480, 29, 481, 3} }, /*GTF*/ | 290 | {NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6, 0, 0, 0}, |
291 | {REFRESH_120, M640X480_R120_HSP, M640X480_R120_VSP, | 291 | {NULL, 75, 1024, 768, 12703, 176, 16, 28, 1, 96, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
292 | {848, 640, 640, 208, 680, 64, 515, 480, 480, 35, 481, 3} } /*GTF*/ | 292 | {NULL, 85, 1024, 768, 10581, 208, 48, 36, 1, 96, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
293 | }; | 293 | {NULL, 100, 1024, 768, 8825, 184, 72, 42, 1, 112, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
294 | 294 | {NULL, 75, 1152, 864, 9259, 256, 64, 32, 1, 128, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, | |
295 | /*720x480 (GTF)*/ | 295 | {NULL, 60, 1280, 768, 12478, 200, 64, 23, 1, 136, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
296 | static struct crt_mode_table CRTM720x480[] = { | 296 | {NULL, 50, 1280, 768, 15342, 184, 56, 19, 1, 128, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
297 | /*r_rate,hsp,vsp */ | 297 | {NULL, 60, 960, 600, 21964, 128, 32, 15, 3, 96, 6, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
298 | /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | 298 | {NULL, 60, 1000, 600, 20803, 144, 40, 18, 1, 104, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
299 | {REFRESH_60, M720X480_R60_HSP, M720X480_R60_VSP, | 299 | {NULL, 60, 1024, 576, 21278, 144, 40, 17, 1, 104, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
300 | {896, 720, 720, 176, 736, 72, 497, 480, 480, 17, 481, 3} } | 300 | {NULL, 60, 1088, 612, 18825, 152, 48, 16, 3, 104, 5, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
301 | 301 | {NULL, 60, 1152, 720, 14974, 168, 56, 19, 3, 112, 6, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | |
302 | }; | 302 | {NULL, 60, 1200, 720, 14248, 184, 56, 22, 1, 128, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
303 | 303 | {NULL, 49, 1200, 900, 17703, 21, 11, 1, 1, 32, 10, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, | |
304 | /*720x576 (GTF)*/ | 304 | {NULL, 60, 1280, 600, 16259, 184, 56, 18, 1, 128, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
305 | static struct crt_mode_table CRTM720x576[] = { | 305 | {NULL, 60, 1280, 800, 11938, 200, 72, 22, 3, 128, 6, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
306 | /*r_rate,hsp,vsp */ | 306 | {NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
307 | /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | 307 | {NULL, 60, 1280, 1024, 9262, 248, 48, 38, 1, 112, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
308 | {REFRESH_60, M720X576_R60_HSP, M720X576_R60_VSP, | 308 | {NULL, 75, 1280, 1024, 7409, 248, 16, 38, 1, 144, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
309 | {912, 720, 720, 192, 744, 72, 597, 576, 576, 21, 577, 3} } | 309 | {NULL, 85, 1280, 1024, 6351, 224, 64, 44, 1, 160, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
310 | }; | 310 | {NULL, 60, 1360, 768, 11759, 208, 72, 22, 3, 136, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
311 | 311 | {NULL, 60, 1368, 768, 11646, 216, 72, 23, 1, 144, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, | |
312 | /* 800x480 (CVT) */ | 312 | {NULL, 50, 1368, 768, 14301, 200, 56, 19, 1, 144, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
313 | static struct crt_mode_table CRTM800x480[] = { | 313 | {NULL, 60, 1368, 768, 11646, 216, 72, 23, 1, 144, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
314 | /* r_rate, hsp, vsp */ | 314 | {NULL, 60, 1440, 900, 9372, 232, 80, 25, 3, 152, 6, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
315 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | 315 | {NULL, 75, 1440, 900, 7311, 248, 96, 33, 3, 152, 6, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
316 | {REFRESH_60, M800X480_R60_HSP, M800X480_R60_VSP, | 316 | {NULL, 60, 1440, 1040, 7993, 248, 96, 33, 1, 152, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
317 | {992, 800, 800, 192, 824, 72, 500, 480, 480, 20, 483, 7} } | 317 | {NULL, 60, 1600, 900, 8449, 256, 88, 26, 3, 168, 5, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
318 | }; | 318 | {NULL, 60, 1600, 1024, 7333, 272, 104, 32, 1, 168, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
319 | 319 | {NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, | |
320 | /* 800x600*/ | 320 | {NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
321 | static struct crt_mode_table CRTM800x600[] = { | 321 | {NULL, 60, 1680, 1050, 6832, 280, 104, 30, 3, 176, 6, 0, 0, 0}, |
322 | /*r_rate,hsp,vsp */ | 322 | {NULL, 75, 1680, 1050, 5339, 296, 120, 40, 3, 176, 6, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
323 | /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | 323 | {NULL, 60, 1792, 1344, 4883, 328, 128, 46, 1, 200, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
324 | {REFRESH_60, M800X600_R60_HSP, M800X600_R60_VSP, | 324 | {NULL, 60, 1856, 1392, 4581, 352, 96, 43, 1, 224, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
325 | {1056, 800, 800, 256, 840, 128, 628, 600, 600, 28, 601, 4} }, | 325 | {NULL, 60, 1920, 1440, 4273, 344, 128, 56, 1, 208, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
326 | {REFRESH_75, M800X600_R75_HSP, M800X600_R75_VSP, | 326 | {NULL, 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
327 | {1056, 800, 800, 256, 816, 80, 625, 600, 600, 25, 601, 3} }, | 327 | {NULL, 60, 2048, 1536, 3738, 376, 152, 49, 3, 224, 4, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
328 | {REFRESH_85, M800X600_R85_HSP, M800X600_R85_VSP, | 328 | {NULL, 60, 1280, 720, 13484, 216, 112, 20, 5, 40, 5, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
329 | {1048, 800, 800, 248, 832, 64, 631, 600, 600, 31, 601, 3} }, | 329 | {NULL, 50, 1280, 720, 16538, 176, 48, 17, 1, 128, 3, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
330 | {REFRESH_100, M800X600_R100_HSP, M800X600_R100_VSP, | 330 | {NULL, 60, 1920, 1080, 5776, 328, 128, 32, 3, 200, 5, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
331 | {1072, 800, 800, 272, 848, 88, 636, 600, 600, 36, 601, 3} }, | 331 | {NULL, 60, 1920, 1200, 5164, 336, 136, 36, 3, 200, 6, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
332 | {REFRESH_120, M800X600_R120_HSP, M800X600_R120_VSP, | 332 | {NULL, 60, 1400, 1050, 8210, 232, 88, 32, 3, 144, 4, FB_SYNC_VERT_HIGH_ACT, 0, 0}, |
333 | {1088, 800, 800, 288, 856, 88, 643, 600, 600, 43, 601, 3} } | 333 | {NULL, 75, 1400, 1050, 6398, 248, 104, 42, 3, 144, 4, FB_SYNC_VERT_HIGH_ACT, 0, 0} }; |
334 | }; | 334 | |
335 | 335 | static const struct fb_videomode viafb_rb_modes[] = { | |
336 | /* 848x480 (CVT) */ | 336 | {NULL, 60, 1360, 768, 13879, 80, 48, 14, 3, 32, 5, FB_SYNC_HOR_HIGH_ACT, 0, 0}, |
337 | static struct crt_mode_table CRTM848x480[] = { | 337 | {NULL, 60, 1440, 900, 11249, 80, 48, 17, 3, 32, 6, FB_SYNC_HOR_HIGH_ACT, 0, 0}, |
338 | /* r_rate, hsp, vsp */ | 338 | {NULL, 60, 1400, 1050, 9892, 80, 48, 23, 3, 32, 4, FB_SYNC_HOR_HIGH_ACT, 0, 0}, |
339 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | 339 | {NULL, 60, 1600, 900, 10226, 80, 48, 18, 3, 32, 5, FB_SYNC_HOR_HIGH_ACT, 0, 0}, |
340 | {REFRESH_60, M848X480_R60_HSP, M848X480_R60_VSP, | 340 | {NULL, 60, 1680, 1050, 8387, 80, 48, 21, 3, 32, 6, FB_SYNC_HOR_HIGH_ACT, 0, 0}, |
341 | {1056, 848, 848, 208, 872, 80, 500, 480, 480, 20, 483, 5} } | 341 | {NULL, 60, 1920, 1080, 7212, 80, 48, 23, 3, 32, 5, FB_SYNC_HOR_HIGH_ACT, 0, 0}, |
342 | }; | 342 | {NULL, 60, 1920, 1200, 6488, 80, 48, 26, 3, 32, 6, FB_SYNC_HOR_HIGH_ACT, 0, 0} }; |
343 | |||
344 | /*856x480 (GTF) convert to 852x480*/ | ||
345 | static struct crt_mode_table CRTM852x480[] = { | ||
346 | /*r_rate,hsp,vsp */ | ||
347 | /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
348 | {REFRESH_60, M852X480_R60_HSP, M852X480_R60_VSP, | ||
349 | {1064, 856, 856, 208, 872, 88, 497, 480, 480, 17, 481, 3} } | ||
350 | }; | ||
351 | |||
352 | /*1024x512 (GTF)*/ | ||
353 | static struct crt_mode_table CRTM1024x512[] = { | ||
354 | /*r_rate,hsp,vsp */ | ||
355 | /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
356 | {REFRESH_60, M1024X512_R60_HSP, M1024X512_R60_VSP, | ||
357 | {1296, 1024, 1024, 272, 1056, 104, 531, 512, 512, 19, 513, 3} } | ||
358 | |||
359 | }; | ||
360 | |||
361 | /* 1024x600*/ | ||
362 | static struct crt_mode_table CRTM1024x600[] = { | ||
363 | /*r_rate,hsp,vsp */ | ||
364 | /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
365 | {REFRESH_60, M1024X600_R60_HSP, M1024X600_R60_VSP, | ||
366 | {1312, 1024, 1024, 288, 1064, 104, 622, 600, 600, 22, 601, 3} }, | ||
367 | }; | ||
368 | |||
369 | /* 1024x768*/ | ||
370 | static struct crt_mode_table CRTM1024x768[] = { | ||
371 | /*r_rate,hsp,vsp */ | ||
372 | /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
373 | {REFRESH_60, M1024X768_R60_HSP, M1024X768_R60_VSP, | ||
374 | {1344, 1024, 1024, 320, 1048, 136, 806, 768, 768, 38, 771, 6} }, | ||
375 | {REFRESH_75, M1024X768_R75_HSP, M1024X768_R75_VSP, | ||
376 | {1312, 1024, 1024, 288, 1040, 96, 800, 768, 768, 32, 769, 3} }, | ||
377 | {REFRESH_85, M1024X768_R85_HSP, M1024X768_R85_VSP, | ||
378 | {1376, 1024, 1024, 352, 1072, 96, 808, 768, 768, 40, 769, 3} }, | ||
379 | {REFRESH_100, M1024X768_R100_HSP, M1024X768_R100_VSP, | ||
380 | {1392, 1024, 1024, 368, 1096, 112, 814, 768, 768, 46, 769, 3} } | ||
381 | }; | ||
382 | |||
383 | /* 1152x864*/ | ||
384 | static struct crt_mode_table CRTM1152x864[] = { | ||
385 | /*r_rate,hsp,vsp */ | ||
386 | /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
387 | {REFRESH_75, M1152X864_R75_HSP, M1152X864_R75_VSP, | ||
388 | {1600, 1152, 1152, 448, 1216, 128, 900, 864, 864, 36, 865, 3} } | ||
389 | |||
390 | }; | ||
391 | |||
392 | /* 1280x720 (HDMI 720P)*/ | ||
393 | static struct crt_mode_table CRTM1280x720[] = { | ||
394 | /*r_rate,hsp,vsp */ | ||
395 | /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
396 | {REFRESH_60, M1280X720_R60_HSP, M1280X720_R60_VSP, | ||
397 | {1648, 1280, 1280, 368, 1392, 40, 750, 720, 720, 30, 725, 5} }, | ||
398 | {REFRESH_50, M1280X720_R50_HSP, M1280X720_R50_VSP, | ||
399 | {1632, 1280, 1280, 352, 1328, 128, 741, 720, 720, 21, 721, 3} } | ||
400 | }; | ||
401 | |||
402 | /*1280x768 (GTF)*/ | ||
403 | static struct crt_mode_table CRTM1280x768[] = { | ||
404 | /*r_rate,hsp,vsp */ | ||
405 | /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
406 | {REFRESH_60, M1280X768_R60_HSP, M1280X768_R60_VSP, | ||
407 | {1680, 1280, 1280, 400, 1344, 136, 795, 768, 768, 27, 769, 3} }, | ||
408 | {REFRESH_50, M1280X768_R50_HSP, M1280X768_R50_VSP, | ||
409 | {1648, 1280, 1280, 368, 1336, 128, 791, 768, 768, 23, 769, 3} } | ||
410 | }; | ||
411 | |||
412 | /* 1280x800 (CVT) */ | ||
413 | static struct crt_mode_table CRTM1280x800[] = { | ||
414 | /* r_rate, hsp, vsp */ | ||
415 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
416 | {REFRESH_60, M1280X800_R60_HSP, M1280X800_R60_VSP, | ||
417 | {1680, 1280, 1280, 400, 1352, 128, 831, 800, 800, 31, 803, 6} } | ||
418 | }; | ||
419 | |||
420 | /*1280x960*/ | ||
421 | static struct crt_mode_table CRTM1280x960[] = { | ||
422 | /*r_rate,hsp,vsp */ | ||
423 | /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
424 | {REFRESH_60, M1280X960_R60_HSP, M1280X960_R60_VSP, | ||
425 | {1800, 1280, 1280, 520, 1376, 112, 1000, 960, 960, 40, 961, 3} } | ||
426 | }; | ||
427 | |||
428 | /* 1280x1024*/ | ||
429 | static struct crt_mode_table CRTM1280x1024[] = { | ||
430 | /*r_rate,hsp,vsp */ | ||
431 | /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
432 | {REFRESH_60, M1280X1024_R60_HSP, M1280X1024_R60_VSP, | ||
433 | {1688, 1280, 1280, 408, 1328, 112, 1066, 1024, 1024, 42, 1025, | ||
434 | 3} }, | ||
435 | {REFRESH_75, M1280X1024_R75_HSP, M1280X1024_R75_VSP, | ||
436 | {1688, 1280, 1280, 408, 1296, 144, 1066, 1024, 1024, 42, 1025, | ||
437 | 3} }, | ||
438 | {REFRESH_85, M1280X1024_R85_HSP, M1280X1024_R85_VSP, | ||
439 | {1728, 1280, 1280, 448, 1344, 160, 1072, 1024, 1024, 48, 1025, 3} } | ||
440 | }; | ||
441 | |||
442 | /* 1368x768 (GTF) */ | ||
443 | static struct crt_mode_table CRTM1368x768[] = { | ||
444 | /* r_rate, hsp, vsp */ | ||
445 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
446 | {REFRESH_60, M1368X768_R60_HSP, M1368X768_R60_VSP, | ||
447 | {1800, 1368, 1368, 432, 1440, 144, 795, 768, 768, 27, 769, 3} } | ||
448 | }; | ||
449 | |||
450 | /*1440x1050 (GTF)*/ | ||
451 | static struct crt_mode_table CRTM1440x1050[] = { | ||
452 | /*r_rate,hsp,vsp */ | ||
453 | /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
454 | {REFRESH_60, M1440X1050_R60_HSP, M1440X1050_R60_VSP, | ||
455 | {1936, 1440, 1440, 496, 1536, 152, 1077, 1040, 1040, 37, 1041, 3} } | ||
456 | }; | ||
457 | |||
458 | /* 1600x1200*/ | ||
459 | static struct crt_mode_table CRTM1600x1200[] = { | ||
460 | /*r_rate,hsp,vsp */ | ||
461 | /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
462 | {REFRESH_60, M1600X1200_R60_HSP, M1600X1200_R60_VSP, | ||
463 | {2160, 1600, 1600, 560, 1664, 192, 1250, 1200, 1200, 50, 1201, | ||
464 | 3} }, | ||
465 | {REFRESH_75, M1600X1200_R75_HSP, M1600X1200_R75_VSP, | ||
466 | {2160, 1600, 1600, 560, 1664, 192, 1250, 1200, 1200, 50, 1201, 3} } | ||
467 | |||
468 | }; | ||
469 | |||
470 | /* 1680x1050 (CVT) */ | ||
471 | static struct crt_mode_table CRTM1680x1050[] = { | ||
472 | /* r_rate, hsp, vsp */ | ||
473 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
474 | {REFRESH_60, M1680x1050_R60_HSP, M1680x1050_R60_VSP, | ||
475 | {2240, 1680, 1680, 560, 1784, 176, 1089, 1050, 1050, 39, 1053, | ||
476 | 6} }, | ||
477 | {REFRESH_75, M1680x1050_R75_HSP, M1680x1050_R75_VSP, | ||
478 | {2272, 1680, 1680, 592, 1800, 176, 1099, 1050, 1050, 49, 1053, 6} } | ||
479 | }; | ||
480 | |||
481 | /* 1680x1050 (CVT Reduce Blanking) */ | ||
482 | static struct crt_mode_table CRTM1680x1050_RB[] = { | ||
483 | /* r_rate, hsp, vsp */ | ||
484 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
485 | {REFRESH_60, M1680x1050_RB_R60_HSP, M1680x1050_RB_R60_VSP, | ||
486 | {1840, 1680, 1680, 160, 1728, 32, 1080, 1050, 1050, 30, 1053, 6} } | ||
487 | }; | ||
488 | |||
489 | /* 1920x1080 (CVT)*/ | ||
490 | static struct crt_mode_table CRTM1920x1080[] = { | ||
491 | /*r_rate,hsp,vsp */ | ||
492 | /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
493 | {REFRESH_60, M1920X1080_R60_HSP, M1920X1080_R60_VSP, | ||
494 | {2576, 1920, 1920, 656, 2048, 200, 1120, 1080, 1080, 40, 1083, 5} } | ||
495 | }; | ||
496 | |||
497 | /* 1920x1080 (CVT with Reduce Blanking) */ | ||
498 | static struct crt_mode_table CRTM1920x1080_RB[] = { | ||
499 | /* r_rate, hsp, vsp */ | ||
500 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
501 | {REFRESH_60, M1920X1080_RB_R60_HSP, M1920X1080_RB_R60_VSP, | ||
502 | {2080, 1920, 1920, 160, 1968, 32, 1111, 1080, 1080, 31, 1083, 5} } | ||
503 | }; | ||
504 | |||
505 | /* 1920x1440*/ | ||
506 | static struct crt_mode_table CRTM1920x1440[] = { | ||
507 | /*r_rate,hsp,vsp */ | ||
508 | /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
509 | {REFRESH_60, M1920X1440_R60_HSP, M1920X1440_R60_VSP, | ||
510 | {2600, 1920, 1920, 680, 2048, 208, 1500, 1440, 1440, 60, 1441, | ||
511 | 3} }, | ||
512 | {REFRESH_75, M1920X1440_R75_HSP, M1920X1440_R75_VSP, | ||
513 | {2640, 1920, 1920, 720, 2064, 224, 1500, 1440, 1440, 60, 1441, 3} } | ||
514 | }; | ||
515 | |||
516 | /* 1400x1050 (CVT) */ | ||
517 | static struct crt_mode_table CRTM1400x1050[] = { | ||
518 | /* r_rate, hsp, vsp */ | ||
519 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
520 | {REFRESH_60, M1400X1050_R60_HSP, M1400X1050_R60_VSP, | ||
521 | {1864, 1400, 1400, 464, 1488, 144, 1089, 1050, 1050, 39, 1053, | ||
522 | 4} }, | ||
523 | {REFRESH_75, M1400X1050_R75_HSP, M1400X1050_R75_VSP, | ||
524 | {1896, 1400, 1400, 496, 1504, 144, 1099, 1050, 1050, 49, 1053, 4} } | ||
525 | }; | ||
526 | |||
527 | /* 1400x1050 (CVT Reduce Blanking) */ | ||
528 | static struct crt_mode_table CRTM1400x1050_RB[] = { | ||
529 | /* r_rate, hsp, vsp */ | ||
530 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
531 | {REFRESH_60, M1400X1050_RB_R60_HSP, M1400X1050_RB_R60_VSP, | ||
532 | {1560, 1400, 1400, 160, 1448, 32, 1080, 1050, 1050, 30, 1053, 4} } | ||
533 | }; | ||
534 | |||
535 | /* 960x600 (CVT) */ | ||
536 | static struct crt_mode_table CRTM960x600[] = { | ||
537 | /* r_rate, hsp, vsp */ | ||
538 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
539 | {REFRESH_60, M960X600_R60_HSP, M960X600_R60_VSP, | ||
540 | {1216, 960, 960, 256, 992, 96, 624, 600, 600, 24, 603, 6} } | ||
541 | }; | ||
542 | |||
543 | /* 1000x600 (GTF) */ | ||
544 | static struct crt_mode_table CRTM1000x600[] = { | ||
545 | /* r_rate, hsp, vsp */ | ||
546 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
547 | {REFRESH_60, M1000X600_R60_HSP, M1000X600_R60_VSP, | ||
548 | {1288, 1000, 1000, 288, 1040, 104, 622, 600, 600, 22, 601, 3} } | ||
549 | }; | ||
550 | |||
551 | /* 1024x576 (GTF) */ | ||
552 | static struct crt_mode_table CRTM1024x576[] = { | ||
553 | /* r_rate, hsp, vsp */ | ||
554 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
555 | {REFRESH_60, M1024X576_R60_HSP, M1024X576_R60_VSP, | ||
556 | {1312, 1024, 1024, 288, 1064, 104, 597, 576, 576, 21, 577, 3} } | ||
557 | }; | ||
558 | |||
559 | /* 1088x612 (CVT) */ | ||
560 | static struct crt_mode_table CRTM1088x612[] = { | ||
561 | /* r_rate, hsp, vsp */ | ||
562 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
563 | {REFRESH_60, M1088X612_R60_HSP, M1088X612_R60_VSP, | ||
564 | {1392, 1088, 1088, 304, 1136, 104, 636, 612, 612, 24, 615, 5} } | ||
565 | }; | ||
566 | |||
567 | /* 1152x720 (CVT) */ | ||
568 | static struct crt_mode_table CRTM1152x720[] = { | ||
569 | /* r_rate, hsp, vsp */ | ||
570 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
571 | {REFRESH_60, M1152X720_R60_HSP, M1152X720_R60_VSP, | ||
572 | {1488, 1152, 1152, 336, 1208, 112, 748, 720, 720, 28, 723, 6} } | ||
573 | }; | ||
574 | |||
575 | /* 1200x720 (GTF) */ | ||
576 | static struct crt_mode_table CRTM1200x720[] = { | ||
577 | /* r_rate, hsp, vsp */ | ||
578 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
579 | {REFRESH_60, M1200X720_R60_HSP, M1200X720_R60_VSP, | ||
580 | {1568, 1200, 1200, 368, 1256, 128, 746, 720, 720, 26, 721, 3} } | ||
581 | }; | ||
582 | |||
583 | /* 1200x900 (DCON) */ | ||
584 | static struct crt_mode_table DCON1200x900[] = { | ||
585 | /* r_rate, hsp, vsp */ | ||
586 | {REFRESH_49, M1200X900_R60_HSP, M1200X900_R60_VSP, | ||
587 | /* The correct htotal is 1240, but this doesn't raster on VX855. */ | ||
588 | /* Via suggested changing to a multiple of 16, hence 1264. */ | ||
589 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
590 | {1264, 1200, 1200, 64, 1211, 32, 912, 900, 900, 12, 901, 10} } | ||
591 | }; | ||
592 | |||
593 | /* 1280x600 (GTF) */ | ||
594 | static struct crt_mode_table CRTM1280x600[] = { | ||
595 | /* r_rate, hsp, vsp */ | ||
596 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
597 | {REFRESH_60, M1280x600_R60_HSP, M1280x600_R60_VSP, | ||
598 | {1648, 1280, 1280, 368, 1336, 128, 622, 600, 600, 22, 601, 3} } | ||
599 | }; | ||
600 | |||
601 | /* 1360x768 (CVT) */ | ||
602 | static struct crt_mode_table CRTM1360x768[] = { | ||
603 | /* r_rate, hsp, vsp */ | ||
604 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
605 | {REFRESH_60, M1360X768_R60_HSP, M1360X768_R60_VSP, | ||
606 | {1776, 1360, 1360, 416, 1432, 136, 798, 768, 768, 30, 771, 5} } | ||
607 | }; | ||
608 | |||
609 | /* 1360x768 (CVT Reduce Blanking) */ | ||
610 | static struct crt_mode_table CRTM1360x768_RB[] = { | ||
611 | /* r_rate, hsp, vsp */ | ||
612 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
613 | {REFRESH_60, M1360X768_RB_R60_HSP, M1360X768_RB_R60_VSP, | ||
614 | {1520, 1360, 1360, 160, 1408, 32, 790, 768, 768, 22, 771, 5} } | ||
615 | }; | ||
616 | |||
617 | /* 1366x768 (GTF) */ | ||
618 | static struct crt_mode_table CRTM1366x768[] = { | ||
619 | /* r_rate, hsp, vsp */ | ||
620 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
621 | {REFRESH_60, M1368X768_R60_HSP, M1368X768_R60_VSP, | ||
622 | {1800, 1368, 1368, 432, 1440, 144, 795, 768, 768, 27, 769, 3} }, | ||
623 | {REFRESH_50, M1368X768_R50_HSP, M1368X768_R50_VSP, | ||
624 | {1768, 1368, 1368, 400, 1424, 144, 791, 768, 768, 23, 769, 3} } | ||
625 | }; | ||
626 | |||
627 | /* 1440x900 (CVT) */ | ||
628 | static struct crt_mode_table CRTM1440x900[] = { | ||
629 | /* r_rate, hsp, vsp */ | ||
630 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
631 | {REFRESH_60, M1440X900_R60_HSP, M1440X900_R60_VSP, | ||
632 | {1904, 1440, 1440, 464, 1520, 152, 934, 900, 900, 34, 903, 6} }, | ||
633 | {REFRESH_75, M1440X900_R75_HSP, M1440X900_R75_VSP, | ||
634 | {1936, 1440, 1440, 496, 1536, 152, 942, 900, 900, 42, 903, 6} } | ||
635 | }; | ||
636 | |||
637 | /* 1440x900 (CVT Reduce Blanking) */ | ||
638 | static struct crt_mode_table CRTM1440x900_RB[] = { | ||
639 | /* r_rate, hsp, vsp */ | ||
640 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
641 | {REFRESH_60, M1440X900_RB_R60_HSP, M1440X900_RB_R60_VSP, | ||
642 | {1600, 1440, 1440, 160, 1488, 32, 926, 900, 900, 26, 903, 6} } | ||
643 | }; | ||
644 | |||
645 | /* 1600x900 (CVT) */ | ||
646 | static struct crt_mode_table CRTM1600x900[] = { | ||
647 | /* r_rate, hsp, vsp */ | ||
648 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
649 | {REFRESH_60, M1600X900_R60_HSP, M1600X900_R60_VSP, | ||
650 | {2112, 1600, 1600, 512, 1688, 168, 934, 900, 900, 34, 903, 5} } | ||
651 | }; | ||
652 | |||
653 | /* 1600x900 (CVT Reduce Blanking) */ | ||
654 | static struct crt_mode_table CRTM1600x900_RB[] = { | ||
655 | /* r_rate, hsp, vsp */ | ||
656 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
657 | {REFRESH_60, M1600X900_RB_R60_HSP, M1600X900_RB_R60_VSP, | ||
658 | {1760, 1600, 1600, 160, 1648, 32, 926, 900, 900, 26, 903, 5} } | ||
659 | }; | ||
660 | |||
661 | /* 1600x1024 (GTF) */ | ||
662 | static struct crt_mode_table CRTM1600x1024[] = { | ||
663 | /* r_rate, hsp, vsp */ | ||
664 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
665 | {REFRESH_60, M1600X1024_R60_HSP, M1600X1024_R60_VSP, | ||
666 | {2144, 1600, 1600, 544, 1704, 168, 1060, 1024, 1024, 36, 1025, 3} } | ||
667 | }; | ||
668 | |||
669 | /* 1792x1344 (DMT) */ | ||
670 | static struct crt_mode_table CRTM1792x1344[] = { | ||
671 | /* r_rate, hsp, vsp */ | ||
672 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
673 | {REFRESH_60, M1792x1344_R60_HSP, M1792x1344_R60_VSP, | ||
674 | {2448, 1792, 1792, 656, 1920, 200, 1394, 1344, 1344, 50, 1345, 3} } | ||
675 | }; | ||
676 | |||
677 | /* 1856x1392 (DMT) */ | ||
678 | static struct crt_mode_table CRTM1856x1392[] = { | ||
679 | /* r_rate, hsp, vsp */ | ||
680 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
681 | {REFRESH_60, M1856x1392_R60_HSP, M1856x1392_R60_VSP, | ||
682 | {2528, 1856, 1856, 672, 1952, 224, 1439, 1392, 1392, 47, 1393, 3} } | ||
683 | }; | ||
684 | |||
685 | /* 1920x1200 (CVT) */ | ||
686 | static struct crt_mode_table CRTM1920x1200[] = { | ||
687 | /* r_rate, hsp, vsp */ | ||
688 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
689 | {REFRESH_60, M1920X1200_R60_HSP, M1920X1200_R60_VSP, | ||
690 | {2592, 1920, 1920, 672, 2056, 200, 1245, 1200, 1200, 45, 1203, 6} } | ||
691 | }; | ||
692 | |||
693 | /* 1920x1200 (CVT with Reduce Blanking) */ | ||
694 | static struct crt_mode_table CRTM1920x1200_RB[] = { | ||
695 | /* r_rate, hsp, vsp */ | ||
696 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
697 | {REFRESH_60, M1920X1200_RB_R60_HSP, M1920X1200_RB_R60_VSP, | ||
698 | {2080, 1920, 1920, 160, 1968, 32, 1235, 1200, 1200, 35, 1203, 6} } | ||
699 | }; | ||
700 | |||
701 | /* 2048x1536 (CVT) */ | ||
702 | static struct crt_mode_table CRTM2048x1536[] = { | ||
703 | /* r_rate, hsp, vsp */ | ||
704 | /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ | ||
705 | {REFRESH_60, M2048x1536_R60_HSP, M2048x1536_R60_VSP, | ||
706 | {2800, 2048, 2048, 752, 2200, 224, 1592, 1536, 1536, 56, 1539, 4} } | ||
707 | }; | ||
708 | |||
709 | static struct VideoModeTable viafb_modes[] = { | ||
710 | /* Display : 480x640 (GTF) */ | ||
711 | {CRTM480x640, ARRAY_SIZE(CRTM480x640)}, | ||
712 | |||
713 | /* Display : 640x480 */ | ||
714 | {CRTM640x480, ARRAY_SIZE(CRTM640x480)}, | ||
715 | |||
716 | /* Display : 720x480 (GTF) */ | ||
717 | {CRTM720x480, ARRAY_SIZE(CRTM720x480)}, | ||
718 | |||
719 | /* Display : 720x576 (GTF) */ | ||
720 | {CRTM720x576, ARRAY_SIZE(CRTM720x576)}, | ||
721 | |||
722 | /* Display : 800x600 */ | ||
723 | {CRTM800x600, ARRAY_SIZE(CRTM800x600)}, | ||
724 | |||
725 | /* Display : 800x480 (CVT) */ | ||
726 | {CRTM800x480, ARRAY_SIZE(CRTM800x480)}, | ||
727 | |||
728 | /* Display : 848x480 (CVT) */ | ||
729 | {CRTM848x480, ARRAY_SIZE(CRTM848x480)}, | ||
730 | |||
731 | /* Display : 852x480 (GTF) */ | ||
732 | {CRTM852x480, ARRAY_SIZE(CRTM852x480)}, | ||
733 | |||
734 | /* Display : 1024x512 (GTF) */ | ||
735 | {CRTM1024x512, ARRAY_SIZE(CRTM1024x512)}, | ||
736 | |||
737 | /* Display : 1024x600 */ | ||
738 | {CRTM1024x600, ARRAY_SIZE(CRTM1024x600)}, | ||
739 | |||
740 | /* Display : 1024x768 */ | ||
741 | {CRTM1024x768, ARRAY_SIZE(CRTM1024x768)}, | ||
742 | |||
743 | /* Display : 1152x864 */ | ||
744 | {CRTM1152x864, ARRAY_SIZE(CRTM1152x864)}, | ||
745 | |||
746 | /* Display : 1280x768 (GTF) */ | ||
747 | {CRTM1280x768, ARRAY_SIZE(CRTM1280x768)}, | ||
748 | |||
749 | /* Display : 960x600 (CVT) */ | ||
750 | {CRTM960x600, ARRAY_SIZE(CRTM960x600)}, | ||
751 | |||
752 | /* Display : 1000x600 (GTF) */ | ||
753 | {CRTM1000x600, ARRAY_SIZE(CRTM1000x600)}, | ||
754 | |||
755 | /* Display : 1024x576 (GTF) */ | ||
756 | {CRTM1024x576, ARRAY_SIZE(CRTM1024x576)}, | ||
757 | |||
758 | /* Display : 1088x612 (GTF) */ | ||
759 | {CRTM1088x612, ARRAY_SIZE(CRTM1088x612)}, | ||
760 | |||
761 | /* Display : 1152x720 (CVT) */ | ||
762 | {CRTM1152x720, ARRAY_SIZE(CRTM1152x720)}, | ||
763 | |||
764 | /* Display : 1200x720 (GTF) */ | ||
765 | {CRTM1200x720, ARRAY_SIZE(CRTM1200x720)}, | ||
766 | |||
767 | /* Display : 1200x900 (DCON) */ | ||
768 | {DCON1200x900, ARRAY_SIZE(DCON1200x900)}, | ||
769 | |||
770 | /* Display : 1280x600 (GTF) */ | ||
771 | {CRTM1280x600, ARRAY_SIZE(CRTM1280x600)}, | ||
772 | |||
773 | /* Display : 1280x800 (CVT) */ | ||
774 | {CRTM1280x800, ARRAY_SIZE(CRTM1280x800)}, | ||
775 | |||
776 | /* Display : 1280x960 */ | ||
777 | {CRTM1280x960, ARRAY_SIZE(CRTM1280x960)}, | ||
778 | |||
779 | /* Display : 1280x1024 */ | ||
780 | {CRTM1280x1024, ARRAY_SIZE(CRTM1280x1024)}, | ||
781 | |||
782 | /* Display : 1360x768 (CVT) */ | ||
783 | {CRTM1360x768, ARRAY_SIZE(CRTM1360x768)}, | ||
784 | |||
785 | /* Display : 1366x768 */ | ||
786 | {CRTM1366x768, ARRAY_SIZE(CRTM1366x768)}, | ||
787 | |||
788 | /* Display : 1368x768 (GTF) */ | ||
789 | {CRTM1368x768, ARRAY_SIZE(CRTM1368x768)}, | ||
790 | |||
791 | /* Display : 1440x900 (CVT) */ | ||
792 | {CRTM1440x900, ARRAY_SIZE(CRTM1440x900)}, | ||
793 | |||
794 | /* Display : 1440x1050 (GTF) */ | ||
795 | {CRTM1440x1050, ARRAY_SIZE(CRTM1440x1050)}, | ||
796 | |||
797 | /* Display : 1600x900 (CVT) */ | ||
798 | {CRTM1600x900, ARRAY_SIZE(CRTM1600x900)}, | ||
799 | |||
800 | /* Display : 1600x1024 (GTF) */ | ||
801 | {CRTM1600x1024, ARRAY_SIZE(CRTM1600x1024)}, | ||
802 | |||
803 | /* Display : 1600x1200 */ | ||
804 | {CRTM1600x1200, ARRAY_SIZE(CRTM1600x1200)}, | ||
805 | |||
806 | /* Display : 1680x1050 (CVT) */ | ||
807 | {CRTM1680x1050, ARRAY_SIZE(CRTM1680x1050)}, | ||
808 | |||
809 | /* Display : 1792x1344 (DMT) */ | ||
810 | {CRTM1792x1344, ARRAY_SIZE(CRTM1792x1344)}, | ||
811 | |||
812 | /* Display : 1856x1392 (DMT) */ | ||
813 | {CRTM1856x1392, ARRAY_SIZE(CRTM1856x1392)}, | ||
814 | |||
815 | /* Display : 1920x1440 */ | ||
816 | {CRTM1920x1440, ARRAY_SIZE(CRTM1920x1440)}, | ||
817 | |||
818 | /* Display : 2048x1536 */ | ||
819 | {CRTM2048x1536, ARRAY_SIZE(CRTM2048x1536)}, | ||
820 | |||
821 | /* Display : 1280x720 */ | ||
822 | {CRTM1280x720, ARRAY_SIZE(CRTM1280x720)}, | ||
823 | |||
824 | /* Display : 1920x1080 (CVT) */ | ||
825 | {CRTM1920x1080, ARRAY_SIZE(CRTM1920x1080)}, | ||
826 | |||
827 | /* Display : 1920x1200 (CVT) */ | ||
828 | {CRTM1920x1200, ARRAY_SIZE(CRTM1920x1200)}, | ||
829 | |||
830 | /* Display : 1400x1050 (CVT) */ | ||
831 | {CRTM1400x1050, ARRAY_SIZE(CRTM1400x1050)} | ||
832 | }; | ||
833 | |||
834 | static struct VideoModeTable viafb_rb_modes[] = { | ||
835 | /* Display : 1360x768 (CVT Reduce Blanking) */ | ||
836 | {CRTM1360x768_RB, ARRAY_SIZE(CRTM1360x768_RB)}, | ||
837 | |||
838 | /* Display : 1440x900 (CVT Reduce Blanking) */ | ||
839 | {CRTM1440x900_RB, ARRAY_SIZE(CRTM1440x900_RB)}, | ||
840 | |||
841 | /* Display : 1400x1050 (CVT Reduce Blanking) */ | ||
842 | {CRTM1400x1050_RB, ARRAY_SIZE(CRTM1400x1050_RB)}, | ||
843 | |||
844 | /* Display : 1600x900 (CVT Reduce Blanking) */ | ||
845 | {CRTM1600x900_RB, ARRAY_SIZE(CRTM1600x900_RB)}, | ||
846 | |||
847 | /* Display : 1680x1050 (CVT Reduce Blanking) */ | ||
848 | {CRTM1680x1050_RB, ARRAY_SIZE(CRTM1680x1050_RB)}, | ||
849 | |||
850 | /* Display : 1920x1080 (CVT Reduce Blanking) */ | ||
851 | {CRTM1920x1080_RB, ARRAY_SIZE(CRTM1920x1080_RB)}, | ||
852 | |||
853 | /* Display : 1920x1200 (CVT Reduce Blanking) */ | ||
854 | {CRTM1920x1200_RB, ARRAY_SIZE(CRTM1920x1200_RB)} | ||
855 | }; | ||
856 | 343 | ||
857 | int NUM_TOTAL_CN400_ModeXregs = ARRAY_SIZE(CN400_ModeXregs); | 344 | int NUM_TOTAL_CN400_ModeXregs = ARRAY_SIZE(CN400_ModeXregs); |
858 | int NUM_TOTAL_CN700_ModeXregs = ARRAY_SIZE(CN700_ModeXregs); | 345 | int NUM_TOTAL_CN700_ModeXregs = ARRAY_SIZE(CN700_ModeXregs); |
@@ -863,56 +350,34 @@ int NUM_TOTAL_CLE266_ModeXregs = ARRAY_SIZE(CLE266_ModeXregs); | |||
863 | int NUM_TOTAL_PATCH_MODE = ARRAY_SIZE(res_patch_table); | 350 | int NUM_TOTAL_PATCH_MODE = ARRAY_SIZE(res_patch_table); |
864 | 351 | ||
865 | 352 | ||
866 | static struct VideoModeTable *get_modes(struct VideoModeTable *vmt, int n, | 353 | static const struct fb_videomode *get_best_mode( |
867 | int hres, int vres) | 354 | const struct fb_videomode *modes, int n, |
868 | { | 355 | int hres, int vres, int refresh) |
869 | int i; | ||
870 | |||
871 | for (i = 0; i < n; i++) | ||
872 | if (vmt[i].mode_array && | ||
873 | vmt[i].crtc[0].crtc.hor_addr == hres && | ||
874 | vmt[i].crtc[0].crtc.ver_addr == vres) | ||
875 | return &viafb_modes[i]; | ||
876 | |||
877 | return NULL; | ||
878 | } | ||
879 | |||
880 | static struct crt_mode_table *get_best_mode(struct VideoModeTable *vmt, | ||
881 | int refresh) | ||
882 | { | 356 | { |
883 | struct crt_mode_table *best; | 357 | const struct fb_videomode *best = NULL; |
884 | int i; | 358 | int i; |
885 | 359 | ||
886 | if (!vmt) | 360 | for (i = 0; i < n; i++) { |
887 | return NULL; | 361 | if (modes[i].xres != hres || modes[i].yres != vres) |
362 | continue; | ||
888 | 363 | ||
889 | best = &vmt->crtc[0]; | 364 | if (!best || abs(modes[i].refresh - refresh) < |
890 | for (i = 1; i < vmt->mode_array; i++) { | 365 | abs(best->refresh - refresh)) |
891 | if (abs(vmt->crtc[i].refresh_rate - refresh) | 366 | best = &modes[i]; |
892 | < abs(best->refresh_rate - refresh)) | ||
893 | best = &vmt->crtc[i]; | ||
894 | } | 367 | } |
895 | 368 | ||
896 | return best; | 369 | return best; |
897 | } | 370 | } |
898 | 371 | ||
899 | static struct VideoModeTable *viafb_get_mode(int hres, int vres) | 372 | const struct fb_videomode *viafb_get_best_mode(int hres, int vres, int refresh) |
900 | { | ||
901 | return get_modes(viafb_modes, ARRAY_SIZE(viafb_modes), hres, vres); | ||
902 | } | ||
903 | |||
904 | struct crt_mode_table *viafb_get_best_mode(int hres, int vres, int refresh) | ||
905 | { | 373 | { |
906 | return get_best_mode(viafb_get_mode(hres, vres), refresh); | 374 | return get_best_mode(viafb_modes, ARRAY_SIZE(viafb_modes), |
375 | hres, vres, refresh); | ||
907 | } | 376 | } |
908 | 377 | ||
909 | static struct VideoModeTable *viafb_get_rb_mode(int hres, int vres) | 378 | const struct fb_videomode *viafb_get_best_rb_mode(int hres, int vres, |
910 | { | 379 | int refresh) |
911 | return get_modes(viafb_rb_modes, ARRAY_SIZE(viafb_rb_modes), hres, | ||
912 | vres); | ||
913 | } | ||
914 | |||
915 | struct crt_mode_table *viafb_get_best_rb_mode(int hres, int vres, int refresh) | ||
916 | { | 380 | { |
917 | return get_best_mode(viafb_get_rb_mode(hres, vres), refresh); | 381 | return get_best_mode(viafb_rb_modes, ARRAY_SIZE(viafb_rb_modes), |
382 | hres, vres, refresh); | ||
918 | } | 383 | } |
diff --git a/drivers/video/via/viamode.h b/drivers/video/via/viamode.h index 5917a2b00e1b..dd19106698e7 100644 --- a/drivers/video/via/viamode.h +++ b/drivers/video/via/viamode.h | |||
@@ -31,11 +31,6 @@ struct VPITTable { | |||
31 | unsigned char AR[StdAR]; | 31 | unsigned char AR[StdAR]; |
32 | }; | 32 | }; |
33 | 33 | ||
34 | struct VideoModeTable { | ||
35 | struct crt_mode_table *crtc; | ||
36 | int mode_array; | ||
37 | }; | ||
38 | |||
39 | struct patch_table { | 34 | struct patch_table { |
40 | int table_length; | 35 | int table_length; |
41 | struct io_reg *io_reg_table; | 36 | struct io_reg *io_reg_table; |
@@ -60,7 +55,9 @@ extern struct io_reg PM1024x768[]; | |||
60 | extern struct patch_table res_patch_table[]; | 55 | extern struct patch_table res_patch_table[]; |
61 | extern struct VPITTable VPIT; | 56 | extern struct VPITTable VPIT; |
62 | 57 | ||
63 | struct crt_mode_table *viafb_get_best_mode(int hres, int vres, int refresh); | 58 | const struct fb_videomode *viafb_get_best_mode(int hres, int vres, |
64 | struct crt_mode_table *viafb_get_best_rb_mode(int hres, int vres, int refresh); | 59 | int refresh); |
60 | const struct fb_videomode *viafb_get_best_rb_mode(int hres, int vres, | ||
61 | int refresh); | ||
65 | 62 | ||
66 | #endif /* __VIAMODE_H__ */ | 63 | #endif /* __VIAMODE_H__ */ |