diff options
Diffstat (limited to 'drivers/video')
103 files changed, 15191 insertions, 4315 deletions
diff --git a/drivers/video/68328fb.c b/drivers/video/68328fb.c index 0dda73da8628..7f907fb23b8a 100644 --- a/drivers/video/68328fb.c +++ b/drivers/video/68328fb.c | |||
@@ -60,7 +60,7 @@ static u_long videomemory; | |||
60 | static u_long videomemorysize; | 60 | static u_long videomemorysize; |
61 | 61 | ||
62 | static struct fb_info fb_info; | 62 | static struct fb_info fb_info; |
63 | static u32 mc68x328fb_pseudo_palette[17]; | 63 | static u32 mc68x328fb_pseudo_palette[16]; |
64 | 64 | ||
65 | static struct fb_var_screeninfo mc68x328fb_default __initdata = { | 65 | static struct fb_var_screeninfo mc68x328fb_default __initdata = { |
66 | .red = { 0, 8, 0 }, | 66 | .red = { 0, 8, 0 }, |
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 6c8ffe6757e1..564cc9b51822 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -3,6 +3,7 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | menu "Graphics support" | 5 | menu "Graphics support" |
6 | depends on HAS_IOMEM | ||
6 | 7 | ||
7 | source "drivers/video/backlight/Kconfig" | 8 | source "drivers/video/backlight/Kconfig" |
8 | source "drivers/video/display/Kconfig" | 9 | source "drivers/video/display/Kconfig" |
@@ -710,6 +711,91 @@ config FB_CG6 | |||
710 | This is the frame buffer device driver for the CGsix (GX, TurboGX) | 711 | This is the frame buffer device driver for the CGsix (GX, TurboGX) |
711 | frame buffer. | 712 | frame buffer. |
712 | 713 | ||
714 | config FB_FFB | ||
715 | bool "Creator/Creator3D/Elite3D support" | ||
716 | depends on FB_SBUS && SPARC64 | ||
717 | select FB_CFB_COPYAREA | ||
718 | select FB_CFB_IMAGEBLIT | ||
719 | help | ||
720 | This is the frame buffer device driver for the Creator, Creator3D, | ||
721 | and Elite3D graphics boards. | ||
722 | |||
723 | config FB_TCX | ||
724 | bool "TCX (SS4/SS5 only) support" | ||
725 | depends on FB_SBUS | ||
726 | select FB_CFB_FILLRECT | ||
727 | select FB_CFB_COPYAREA | ||
728 | select FB_CFB_IMAGEBLIT | ||
729 | help | ||
730 | This is the frame buffer device driver for the TCX 24/8bit frame | ||
731 | buffer. | ||
732 | |||
733 | config FB_CG14 | ||
734 | bool "CGfourteen (SX) support" | ||
735 | depends on FB_SBUS | ||
736 | select FB_CFB_FILLRECT | ||
737 | select FB_CFB_COPYAREA | ||
738 | select FB_CFB_IMAGEBLIT | ||
739 | help | ||
740 | This is the frame buffer device driver for the CGfourteen frame | ||
741 | buffer on Desktop SPARCsystems with the SX graphics option. | ||
742 | |||
743 | config FB_P9100 | ||
744 | bool "P9100 (Sparcbook 3 only) support" | ||
745 | depends on FB_SBUS | ||
746 | select FB_CFB_FILLRECT | ||
747 | select FB_CFB_COPYAREA | ||
748 | select FB_CFB_IMAGEBLIT | ||
749 | help | ||
750 | This is the frame buffer device driver for the P9100 card | ||
751 | supported on Sparcbook 3 machines. | ||
752 | |||
753 | config FB_LEO | ||
754 | bool "Leo (ZX) support" | ||
755 | depends on FB_SBUS | ||
756 | select FB_CFB_FILLRECT | ||
757 | select FB_CFB_COPYAREA | ||
758 | select FB_CFB_IMAGEBLIT | ||
759 | help | ||
760 | This is the frame buffer device driver for the SBUS-based Sun ZX | ||
761 | (leo) frame buffer cards. | ||
762 | |||
763 | config FB_IGA | ||
764 | bool "IGA 168x display support" | ||
765 | depends on (FB = y) && SPARC32 | ||
766 | select FB_CFB_FILLRECT | ||
767 | select FB_CFB_COPYAREA | ||
768 | select FB_CFB_IMAGEBLIT | ||
769 | help | ||
770 | This is the framebuffer device for the INTERGRAPHICS 1680 and | ||
771 | successor frame buffer cards. | ||
772 | |||
773 | config FB_XVR500 | ||
774 | bool "Sun XVR-500 3DLABS Wildcat support" | ||
775 | depends on (FB = y) && PCI && SPARC64 | ||
776 | select FB_CFB_FILLRECT | ||
777 | select FB_CFB_COPYAREA | ||
778 | select FB_CFB_IMAGEBLIT | ||
779 | help | ||
780 | This is the framebuffer device for the Sun XVR-500 and similar | ||
781 | graphics cards based upon the 3DLABS Wildcat chipset. The driver | ||
782 | only works on sparc64 systems where the system firwmare has | ||
783 | mostly initialized the card already. It is treated as a | ||
784 | completely dumb framebuffer device. | ||
785 | |||
786 | config FB_XVR2500 | ||
787 | bool "Sun XVR-2500 3DLABS Wildcat support" | ||
788 | depends on (FB = y) && PCI && SPARC64 | ||
789 | select FB_CFB_FILLRECT | ||
790 | select FB_CFB_COPYAREA | ||
791 | select FB_CFB_IMAGEBLIT | ||
792 | help | ||
793 | This is the framebuffer device for the Sun XVR-2500 and similar | ||
794 | graphics cards based upon the 3DLABS Wildcat chipset. The driver | ||
795 | only works on sparc64 systems where the system firwmare has | ||
796 | mostly initialized the card already. It is treated as a | ||
797 | completely dumb framebuffer device. | ||
798 | |||
713 | config FB_PVR2 | 799 | config FB_PVR2 |
714 | tristate "NEC PowerVR 2 display support" | 800 | tristate "NEC PowerVR 2 display support" |
715 | depends on FB && SH_DREAMCAST | 801 | depends on FB && SH_DREAMCAST |
@@ -733,7 +819,7 @@ config FB_PVR2 | |||
733 | 819 | ||
734 | config FB_EPSON1355 | 820 | config FB_EPSON1355 |
735 | bool "Epson 1355 framebuffer support" | 821 | bool "Epson 1355 framebuffer support" |
736 | depends on (FB = y) && (SUPERH || ARCH_CEIVA) | 822 | depends on (FB = y) && ARCH_CEIVA |
737 | select FB_CFB_FILLRECT | 823 | select FB_CFB_FILLRECT |
738 | select FB_CFB_COPYAREA | 824 | select FB_CFB_COPYAREA |
739 | select FB_CFB_IMAGEBLIT | 825 | select FB_CFB_IMAGEBLIT |
@@ -754,6 +840,32 @@ config FB_S1D13XXX | |||
754 | working with S1D13806). Product specs at | 840 | working with S1D13806). Product specs at |
755 | <http://www.erd.epson.com/vdc/html/legacy_13xxx.htm> | 841 | <http://www.erd.epson.com/vdc/html/legacy_13xxx.htm> |
756 | 842 | ||
843 | config FB_ATMEL | ||
844 | tristate "AT91/AT32 LCD Controller support" | ||
845 | depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || AVR32) | ||
846 | select FB_CFB_FILLRECT | ||
847 | select FB_CFB_COPYAREA | ||
848 | select FB_CFB_IMAGEBLIT | ||
849 | help | ||
850 | This enables support for the AT91/AT32 LCD Controller. | ||
851 | |||
852 | config FB_INTSRAM | ||
853 | bool "Frame Buffer in internal SRAM" | ||
854 | depends on FB_ATMEL && ARCH_AT91SAM9261 | ||
855 | help | ||
856 | Say Y if you want to map Frame Buffer in internal SRAM. Say N if you want | ||
857 | to let frame buffer in external SDRAM. | ||
858 | |||
859 | config FB_ATMEL_STN | ||
860 | bool "Use a STN display with AT91/AT32 LCD Controller" | ||
861 | depends on FB_ATMEL && MACH_AT91SAM9261EK | ||
862 | default n | ||
863 | help | ||
864 | Say Y if you want to connect a STN LCD display to the AT91/AT32 LCD | ||
865 | Controller. Say N if you want to connect a TFT. | ||
866 | |||
867 | If unsure, say N. | ||
868 | |||
757 | config FB_NVIDIA | 869 | config FB_NVIDIA |
758 | tristate "nVidia Framebuffer Support" | 870 | tristate "nVidia Framebuffer Support" |
759 | depends on FB && PCI | 871 | depends on FB && PCI |
@@ -786,6 +898,15 @@ config FB_NVIDIA_I2C | |||
786 | independently validate video mode parameters, you should say Y | 898 | independently validate video mode parameters, you should say Y |
787 | here. | 899 | here. |
788 | 900 | ||
901 | config FB_NVIDIA_DEBUG | ||
902 | bool "Lots of debug output" | ||
903 | depends on FB_NVIDIA | ||
904 | default n | ||
905 | help | ||
906 | Say Y here if you want the nVidia driver to output all sorts | ||
907 | of debugging information to provide to the maintainer when | ||
908 | something goes wrong. | ||
909 | |||
789 | config FB_NVIDIA_BACKLIGHT | 910 | config FB_NVIDIA_BACKLIGHT |
790 | bool "Support for backlight control" | 911 | bool "Support for backlight control" |
791 | depends on FB_NVIDIA | 912 | depends on FB_NVIDIA |
@@ -825,7 +946,7 @@ config FB_RIVA_I2C | |||
825 | here. | 946 | here. |
826 | 947 | ||
827 | config FB_RIVA_DEBUG | 948 | config FB_RIVA_DEBUG |
828 | bool "Lots of debug output from Riva(nVidia) driver" | 949 | bool "Lots of debug output" |
829 | depends on FB_RIVA | 950 | depends on FB_RIVA |
830 | default n | 951 | default n |
831 | help | 952 | help |
@@ -1176,7 +1297,7 @@ config FB_ATY | |||
1176 | config FB_ATY_CT | 1297 | config FB_ATY_CT |
1177 | bool "Mach64 CT/VT/GT/LT (incl. 3D RAGE) support" | 1298 | bool "Mach64 CT/VT/GT/LT (incl. 3D RAGE) support" |
1178 | depends on PCI && FB_ATY | 1299 | depends on PCI && FB_ATY |
1179 | default y if SPARC64 && FB_PCI | 1300 | default y if SPARC64 && PCI |
1180 | help | 1301 | help |
1181 | Say Y here to support use of ATI's 64-bit Rage boards (or other | 1302 | Say Y here to support use of ATI's 64-bit Rage boards (or other |
1182 | boards based on the Mach64 CT, VT, GT, and LT chipsets) as a | 1303 | boards based on the Mach64 CT, VT, GT, and LT chipsets) as a |
@@ -1355,6 +1476,20 @@ config FB_VOODOO1 | |||
1355 | Please read the <file:Documentation/fb/README-sstfb.txt> for supported | 1476 | Please read the <file:Documentation/fb/README-sstfb.txt> for supported |
1356 | options and other important info support. | 1477 | options and other important info support. |
1357 | 1478 | ||
1479 | config FB_VT8623 | ||
1480 | tristate "VIA VT8623 support" | ||
1481 | depends on FB && PCI | ||
1482 | select FB_CFB_FILLRECT | ||
1483 | select FB_CFB_COPYAREA | ||
1484 | select FB_CFB_IMAGEBLIT | ||
1485 | select FB_TILEBLITTING | ||
1486 | select FB_SVGALIB | ||
1487 | select VGASTATE | ||
1488 | select FONT_8x16 if FRAMEBUFFER_CONSOLE | ||
1489 | ---help--- | ||
1490 | Driver for CastleRock integrated graphics core in the | ||
1491 | VIA VT8623 [Apollo CLE266] chipset. | ||
1492 | |||
1358 | config FB_CYBLA | 1493 | config FB_CYBLA |
1359 | tristate "Cyberblade/i1 support" | 1494 | tristate "Cyberblade/i1 support" |
1360 | depends on FB && PCI && X86_32 && !64BIT | 1495 | depends on FB && PCI && X86_32 && !64BIT |
@@ -1408,9 +1543,26 @@ config FB_TRIDENT_ACCEL | |||
1408 | This will compile the Trident frame buffer device with | 1543 | This will compile the Trident frame buffer device with |
1409 | acceleration functions. | 1544 | acceleration functions. |
1410 | 1545 | ||
1546 | config FB_ARK | ||
1547 | tristate "ARK 2000PV support" | ||
1548 | depends on FB && PCI | ||
1549 | select FB_CFB_FILLRECT | ||
1550 | select FB_CFB_COPYAREA | ||
1551 | select FB_CFB_IMAGEBLIT | ||
1552 | select FB_TILEBLITTING | ||
1553 | select FB_SVGALIB | ||
1554 | select VGASTATE | ||
1555 | select FONT_8x16 if FRAMEBUFFER_CONSOLE | ||
1556 | ---help--- | ||
1557 | Driver for PCI graphics boards with ARK 2000PV chip | ||
1558 | and ICS 5342 RAMDAC. | ||
1559 | |||
1411 | config FB_PM3 | 1560 | config FB_PM3 |
1412 | tristate "Permedia3 support" | 1561 | tristate "Permedia3 support (EXPERIMENTAL)" |
1413 | depends on FB && PCI && BROKEN | 1562 | depends on FB && PCI && EXPERIMENTAL |
1563 | select FB_CFB_FILLRECT | ||
1564 | select FB_CFB_COPYAREA | ||
1565 | select FB_CFB_IMAGEBLIT | ||
1414 | help | 1566 | help |
1415 | This is the frame buffer device driver for the 3DLabs Permedia3 | 1567 | This is the frame buffer device driver for the 3DLabs Permedia3 |
1416 | chipset, used in Formac ProFormance III, 3DLabs Oxygen VX1 & | 1568 | chipset, used in Formac ProFormance III, 3DLabs Oxygen VX1 & |
@@ -1434,95 +1586,6 @@ config FB_AU1200 | |||
1434 | 1586 | ||
1435 | source "drivers/video/geode/Kconfig" | 1587 | source "drivers/video/geode/Kconfig" |
1436 | 1588 | ||
1437 | config FB_FFB | ||
1438 | bool "Creator/Creator3D/Elite3D support" | ||
1439 | depends on FB_SBUS && SPARC64 | ||
1440 | select FB_CFB_COPYAREA | ||
1441 | select FB_CFB_IMAGEBLIT | ||
1442 | help | ||
1443 | This is the frame buffer device driver for the Creator, Creator3D, | ||
1444 | and Elite3D graphics boards. | ||
1445 | |||
1446 | config FB_TCX | ||
1447 | bool "TCX (SS4/SS5 only) support" | ||
1448 | depends on FB_SBUS | ||
1449 | select FB_CFB_FILLRECT | ||
1450 | select FB_CFB_COPYAREA | ||
1451 | select FB_CFB_IMAGEBLIT | ||
1452 | help | ||
1453 | This is the frame buffer device driver for the TCX 24/8bit frame | ||
1454 | buffer. | ||
1455 | |||
1456 | config FB_CG14 | ||
1457 | bool "CGfourteen (SX) support" | ||
1458 | depends on FB_SBUS | ||
1459 | select FB_CFB_FILLRECT | ||
1460 | select FB_CFB_COPYAREA | ||
1461 | select FB_CFB_IMAGEBLIT | ||
1462 | help | ||
1463 | This is the frame buffer device driver for the CGfourteen frame | ||
1464 | buffer on Desktop SPARCsystems with the SX graphics option. | ||
1465 | |||
1466 | config FB_P9100 | ||
1467 | bool "P9100 (Sparcbook 3 only) support" | ||
1468 | depends on FB_SBUS | ||
1469 | select FB_CFB_FILLRECT | ||
1470 | select FB_CFB_COPYAREA | ||
1471 | select FB_CFB_IMAGEBLIT | ||
1472 | help | ||
1473 | This is the frame buffer device driver for the P9100 card | ||
1474 | supported on Sparcbook 3 machines. | ||
1475 | |||
1476 | config FB_LEO | ||
1477 | bool "Leo (ZX) support" | ||
1478 | depends on FB_SBUS | ||
1479 | select FB_CFB_FILLRECT | ||
1480 | select FB_CFB_COPYAREA | ||
1481 | select FB_CFB_IMAGEBLIT | ||
1482 | help | ||
1483 | This is the frame buffer device driver for the SBUS-based Sun ZX | ||
1484 | (leo) frame buffer cards. | ||
1485 | |||
1486 | config FB_XVR500 | ||
1487 | bool "Sun XVR-500 3DLABS Wildcat support" | ||
1488 | depends on FB && PCI && SPARC64 | ||
1489 | select FB_CFB_FILLRECT | ||
1490 | select FB_CFB_COPYAREA | ||
1491 | select FB_CFB_IMAGEBLIT | ||
1492 | help | ||
1493 | This is the framebuffer device for the Sun XVR-500 and similar | ||
1494 | graphics cards based upon the 3DLABS Wildcat chipset. The driver | ||
1495 | only works on sparc64 systems where the system firwmare has | ||
1496 | mostly initialized the card already. It is treated as a | ||
1497 | completely dumb framebuffer device. | ||
1498 | |||
1499 | config FB_XVR2500 | ||
1500 | bool "Sun XVR-2500 3DLABS Wildcat support" | ||
1501 | depends on FB && PCI && SPARC64 | ||
1502 | select FB_CFB_FILLRECT | ||
1503 | select FB_CFB_COPYAREA | ||
1504 | select FB_CFB_IMAGEBLIT | ||
1505 | help | ||
1506 | This is the framebuffer device for the Sun XVR-2500 and similar | ||
1507 | graphics cards based upon the 3DLABS Wildcat chipset. The driver | ||
1508 | only works on sparc64 systems where the system firwmare has | ||
1509 | mostly initialized the card already. It is treated as a | ||
1510 | completely dumb framebuffer device. | ||
1511 | |||
1512 | config FB_PCI | ||
1513 | bool "PCI framebuffers" | ||
1514 | depends on (FB = y) && PCI && SPARC | ||
1515 | |||
1516 | config FB_IGA | ||
1517 | bool "IGA 168x display support" | ||
1518 | depends on SPARC32 && FB_PCI | ||
1519 | select FB_CFB_FILLRECT | ||
1520 | select FB_CFB_COPYAREA | ||
1521 | select FB_CFB_IMAGEBLIT | ||
1522 | help | ||
1523 | This is the framebuffer device for the INTERGRAPHICS 1680 and | ||
1524 | successor frame buffer cards. | ||
1525 | |||
1526 | config FB_HIT | 1589 | config FB_HIT |
1527 | tristate "HD64461 Frame Buffer support" | 1590 | tristate "HD64461 Frame Buffer support" |
1528 | depends on FB && HD64461 | 1591 | depends on FB && HD64461 |
@@ -1744,18 +1807,20 @@ config FB_IBM_GXT4500 | |||
1744 | adaptor, found on some IBM System P (pSeries) machines. | 1807 | adaptor, found on some IBM System P (pSeries) machines. |
1745 | 1808 | ||
1746 | config FB_PS3 | 1809 | config FB_PS3 |
1747 | bool "PS3 GPU framebuffer driver" | 1810 | tristate "PS3 GPU framebuffer driver" |
1748 | depends on (FB = y) && PS3_PS3AV | 1811 | depends on FB && PS3_PS3AV |
1749 | select FB_CFB_FILLRECT | 1812 | select FB_SYS_FILLRECT |
1750 | select FB_CFB_COPYAREA | 1813 | select FB_SYS_COPYAREA |
1751 | select FB_CFB_IMAGEBLIT | 1814 | select FB_SYS_IMAGEBLIT |
1815 | select FB_SYS_FOPS | ||
1816 | select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE | ||
1752 | ---help--- | 1817 | ---help--- |
1753 | Include support for the virtual frame buffer in the PS3 platform. | 1818 | Include support for the virtual frame buffer in the PS3 platform. |
1754 | 1819 | ||
1755 | config FB_PS3_DEFAULT_SIZE_M | 1820 | config FB_PS3_DEFAULT_SIZE_M |
1756 | int "PS3 default frame buffer size (in MiB)" | 1821 | int "PS3 default frame buffer size (in MiB)" |
1757 | depends on FB_PS3 | 1822 | depends on FB_PS3 |
1758 | default 18 | 1823 | default 9 |
1759 | ---help--- | 1824 | ---help--- |
1760 | This is the default size (in MiB) of the virtual frame buffer in | 1825 | This is the default size (in MiB) of the virtual frame buffer in |
1761 | the PS3. | 1826 | the PS3. |
@@ -1773,6 +1838,10 @@ config FB_XILINX | |||
1773 | framebuffer. ML300 carries a 640*480 LCD display on the board, | 1838 | framebuffer. ML300 carries a 640*480 LCD display on the board, |
1774 | ML403 uses a standard DB15 VGA connector. | 1839 | ML403 uses a standard DB15 VGA connector. |
1775 | 1840 | ||
1841 | if ARCH_OMAP | ||
1842 | source "drivers/video/omap/Kconfig" | ||
1843 | endif | ||
1844 | |||
1776 | config FB_VIRTUAL | 1845 | config FB_VIRTUAL |
1777 | tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" | 1846 | tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" |
1778 | depends on FB | 1847 | depends on FB |
diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 08b7c26a5734..518933d4905f 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile | |||
@@ -54,10 +54,12 @@ obj-$(CONFIG_FB_VALKYRIE) += valkyriefb.o | |||
54 | obj-$(CONFIG_FB_CT65550) += chipsfb.o | 54 | obj-$(CONFIG_FB_CT65550) += chipsfb.o |
55 | obj-$(CONFIG_FB_IMSTT) += imsttfb.o | 55 | obj-$(CONFIG_FB_IMSTT) += imsttfb.o |
56 | obj-$(CONFIG_FB_FM2) += fm2fb.o | 56 | obj-$(CONFIG_FB_FM2) += fm2fb.o |
57 | obj-$(CONFIG_FB_VT8623) += vt8623fb.o | ||
57 | obj-$(CONFIG_FB_CYBLA) += cyblafb.o | 58 | obj-$(CONFIG_FB_CYBLA) += cyblafb.o |
58 | obj-$(CONFIG_FB_TRIDENT) += tridentfb.o | 59 | obj-$(CONFIG_FB_TRIDENT) += tridentfb.o |
59 | obj-$(CONFIG_FB_LE80578) += vermilion/ | 60 | obj-$(CONFIG_FB_LE80578) += vermilion/ |
60 | obj-$(CONFIG_FB_S3) += s3fb.o | 61 | obj-$(CONFIG_FB_S3) += s3fb.o |
62 | obj-$(CONFIG_FB_ARK) += arkfb.o | ||
61 | obj-$(CONFIG_FB_STI) += stifb.o | 63 | obj-$(CONFIG_FB_STI) += stifb.o |
62 | obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o | 64 | obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o |
63 | obj-$(CONFIG_FB_CG6) += cg6.o sbuslib.o | 65 | obj-$(CONFIG_FB_CG6) += cg6.o sbuslib.o |
@@ -85,6 +87,7 @@ obj-$(CONFIG_FB_G364) += g364fb.o | |||
85 | obj-$(CONFIG_FB_SA1100) += sa1100fb.o | 87 | obj-$(CONFIG_FB_SA1100) += sa1100fb.o |
86 | obj-$(CONFIG_FB_HIT) += hitfb.o | 88 | obj-$(CONFIG_FB_HIT) += hitfb.o |
87 | obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o | 89 | obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o |
90 | obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o | ||
88 | obj-$(CONFIG_FB_PVR2) += pvr2fb.o | 91 | obj-$(CONFIG_FB_PVR2) += pvr2fb.o |
89 | obj-$(CONFIG_FB_VOODOO1) += sstfb.o | 92 | obj-$(CONFIG_FB_VOODOO1) += sstfb.o |
90 | obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o | 93 | obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o |
@@ -110,6 +113,7 @@ obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o | |||
110 | obj-$(CONFIG_FB_PS3) += ps3fb.o | 113 | obj-$(CONFIG_FB_PS3) += ps3fb.o |
111 | obj-$(CONFIG_FB_SM501) += sm501fb.o | 114 | obj-$(CONFIG_FB_SM501) += sm501fb.o |
112 | obj-$(CONFIG_FB_XILINX) += xilinxfb.o | 115 | obj-$(CONFIG_FB_XILINX) += xilinxfb.o |
116 | obj-$(CONFIG_FB_OMAP) += omap/ | ||
113 | 117 | ||
114 | # Platform or fallback drivers go here | 118 | # Platform or fallback drivers go here |
115 | obj-$(CONFIG_FB_VESA) += vesafb.o | 119 | obj-$(CONFIG_FB_VESA) += vesafb.o |
diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c index 6c9dc2e69c82..a7a1c891bfa2 100644 --- a/drivers/video/amba-clcd.c +++ b/drivers/video/amba-clcd.c | |||
@@ -447,13 +447,12 @@ static int clcdfb_probe(struct amba_device *dev, void *id) | |||
447 | goto out; | 447 | goto out; |
448 | } | 448 | } |
449 | 449 | ||
450 | fb = kmalloc(sizeof(struct clcd_fb), GFP_KERNEL); | 450 | fb = kzalloc(sizeof(struct clcd_fb), GFP_KERNEL); |
451 | if (!fb) { | 451 | if (!fb) { |
452 | printk(KERN_INFO "CLCD: could not allocate new clcd_fb struct\n"); | 452 | printk(KERN_INFO "CLCD: could not allocate new clcd_fb struct\n"); |
453 | ret = -ENOMEM; | 453 | ret = -ENOMEM; |
454 | goto free_region; | 454 | goto free_region; |
455 | } | 455 | } |
456 | memset(fb, 0, sizeof(struct clcd_fb)); | ||
457 | 456 | ||
458 | fb->dev = dev; | 457 | fb->dev = dev; |
459 | fb->board = board; | 458 | fb->board = board; |
diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c new file mode 100644 index 000000000000..8a1b07c74394 --- /dev/null +++ b/drivers/video/arkfb.c | |||
@@ -0,0 +1,1201 @@ | |||
1 | /* | ||
2 | * linux/drivers/video/arkfb.c -- Frame buffer device driver for ARK 2000PV | ||
3 | * with ICS 5342 dac (it is easy to add support for different dacs). | ||
4 | * | ||
5 | * Copyright (c) 2007 Ondrej Zajicek <santiago@crfreenet.org> | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General Public | ||
8 | * License. See the file COPYING in the main directory of this archive for | ||
9 | * more details. | ||
10 | * | ||
11 | * Code is based on s3fb | ||
12 | */ | ||
13 | |||
14 | #include <linux/version.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/errno.h> | ||
18 | #include <linux/string.h> | ||
19 | #include <linux/mm.h> | ||
20 | #include <linux/tty.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/fb.h> | ||
24 | #include <linux/svga.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/pci.h> | ||
27 | #include <linux/console.h> /* Why should fb driver call console functions? because acquire_console_sem() */ | ||
28 | #include <video/vga.h> | ||
29 | |||
30 | #ifdef CONFIG_MTRR | ||
31 | #include <asm/mtrr.h> | ||
32 | #endif | ||
33 | |||
34 | struct arkfb_info { | ||
35 | int mclk_freq; | ||
36 | int mtrr_reg; | ||
37 | |||
38 | struct dac_info *dac; | ||
39 | struct vgastate state; | ||
40 | struct mutex open_lock; | ||
41 | unsigned int ref_count; | ||
42 | u32 pseudo_palette[16]; | ||
43 | }; | ||
44 | |||
45 | |||
46 | /* ------------------------------------------------------------------------- */ | ||
47 | |||
48 | |||
49 | static const struct svga_fb_format arkfb_formats[] = { | ||
50 | { 0, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0, | ||
51 | FB_TYPE_TEXT, FB_AUX_TEXT_SVGA_STEP4, FB_VISUAL_PSEUDOCOLOR, 8, 8}, | ||
52 | { 4, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0, | ||
53 | FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 8, 16}, | ||
54 | { 4, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 1, | ||
55 | FB_TYPE_INTERLEAVED_PLANES, 1, FB_VISUAL_PSEUDOCOLOR, 8, 16}, | ||
56 | { 8, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0, | ||
57 | FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 8, 8}, | ||
58 | {16, {10, 5, 0}, {5, 5, 0}, {0, 5, 0}, {0, 0, 0}, 0, | ||
59 | FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 4, 4}, | ||
60 | {16, {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, 0, | ||
61 | FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 4, 4}, | ||
62 | {24, {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, | ||
63 | FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 8, 8}, | ||
64 | {32, {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, | ||
65 | FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 2, 2}, | ||
66 | SVGA_FORMAT_END | ||
67 | }; | ||
68 | |||
69 | |||
70 | /* CRT timing register sets */ | ||
71 | |||
72 | static const struct vga_regset ark_h_total_regs[] = {{0x00, 0, 7}, {0x41, 7, 7}, VGA_REGSET_END}; | ||
73 | static const struct vga_regset ark_h_display_regs[] = {{0x01, 0, 7}, {0x41, 6, 6}, VGA_REGSET_END}; | ||
74 | static const struct vga_regset ark_h_blank_start_regs[] = {{0x02, 0, 7}, {0x41, 5, 5}, VGA_REGSET_END}; | ||
75 | static const struct vga_regset ark_h_blank_end_regs[] = {{0x03, 0, 4}, {0x05, 7, 7 }, VGA_REGSET_END}; | ||
76 | static const struct vga_regset ark_h_sync_start_regs[] = {{0x04, 0, 7}, {0x41, 4, 4}, VGA_REGSET_END}; | ||
77 | static const struct vga_regset ark_h_sync_end_regs[] = {{0x05, 0, 4}, VGA_REGSET_END}; | ||
78 | |||
79 | static const struct vga_regset ark_v_total_regs[] = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x40, 7, 7}, VGA_REGSET_END}; | ||
80 | static const struct vga_regset ark_v_display_regs[] = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x40, 6, 6}, VGA_REGSET_END}; | ||
81 | static const struct vga_regset ark_v_blank_start_regs[] = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x40, 5, 5}, VGA_REGSET_END}; | ||
82 | // const struct vga_regset ark_v_blank_end_regs[] = {{0x16, 0, 6}, VGA_REGSET_END}; | ||
83 | static const struct vga_regset ark_v_blank_end_regs[] = {{0x16, 0, 7}, VGA_REGSET_END}; | ||
84 | static const struct vga_regset ark_v_sync_start_regs[] = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x40, 4, 4}, VGA_REGSET_END}; | ||
85 | static const struct vga_regset ark_v_sync_end_regs[] = {{0x11, 0, 3}, VGA_REGSET_END}; | ||
86 | |||
87 | static const struct vga_regset ark_line_compare_regs[] = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, VGA_REGSET_END}; | ||
88 | static const struct vga_regset ark_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x40, 0, 2}, VGA_REGSET_END}; | ||
89 | static const struct vga_regset ark_offset_regs[] = {{0x13, 0, 7}, {0x41, 3, 3}, VGA_REGSET_END}; | ||
90 | |||
91 | static const struct svga_timing_regs ark_timing_regs = { | ||
92 | ark_h_total_regs, ark_h_display_regs, ark_h_blank_start_regs, | ||
93 | ark_h_blank_end_regs, ark_h_sync_start_regs, ark_h_sync_end_regs, | ||
94 | ark_v_total_regs, ark_v_display_regs, ark_v_blank_start_regs, | ||
95 | ark_v_blank_end_regs, ark_v_sync_start_regs, ark_v_sync_end_regs, | ||
96 | }; | ||
97 | |||
98 | |||
99 | /* ------------------------------------------------------------------------- */ | ||
100 | |||
101 | |||
102 | /* Module parameters */ | ||
103 | |||
104 | static char *mode = "640x480-8@60"; | ||
105 | |||
106 | #ifdef CONFIG_MTRR | ||
107 | static int mtrr = 1; | ||
108 | #endif | ||
109 | |||
110 | MODULE_AUTHOR("(c) 2007 Ondrej Zajicek <santiago@crfreenet.org>"); | ||
111 | MODULE_LICENSE("GPL"); | ||
112 | MODULE_DESCRIPTION("fbdev driver for ARK 2000PV"); | ||
113 | |||
114 | module_param(mode, charp, 0444); | ||
115 | MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)"); | ||
116 | |||
117 | #ifdef CONFIG_MTRR | ||
118 | module_param(mtrr, int, 0444); | ||
119 | MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)"); | ||
120 | #endif | ||
121 | |||
122 | static int threshold = 4; | ||
123 | |||
124 | module_param(threshold, int, 0644); | ||
125 | MODULE_PARM_DESC(threshold, "FIFO threshold"); | ||
126 | |||
127 | |||
128 | /* ------------------------------------------------------------------------- */ | ||
129 | |||
130 | |||
131 | static void arkfb_settile(struct fb_info *info, struct fb_tilemap *map) | ||
132 | { | ||
133 | const u8 *font = map->data; | ||
134 | u8 __iomem *fb = (u8 __iomem *)info->screen_base; | ||
135 | int i, c; | ||
136 | |||
137 | if ((map->width != 8) || (map->height != 16) || | ||
138 | (map->depth != 1) || (map->length != 256)) { | ||
139 | printk(KERN_ERR "fb%d: unsupported font parameters: width %d, " | ||
140 | "height %d, depth %d, length %d\n", info->node, | ||
141 | map->width, map->height, map->depth, map->length); | ||
142 | return; | ||
143 | } | ||
144 | |||
145 | fb += 2; | ||
146 | for (c = 0; c < map->length; c++) { | ||
147 | for (i = 0; i < map->height; i++) { | ||
148 | fb_writeb(font[i], &fb[i * 4]); | ||
149 | fb_writeb(font[i], &fb[i * 4 + (128 * 8)]); | ||
150 | } | ||
151 | fb += 128; | ||
152 | |||
153 | if ((c % 8) == 7) | ||
154 | fb += 128*8; | ||
155 | |||
156 | font += map->height; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | static struct fb_tile_ops arkfb_tile_ops = { | ||
161 | .fb_settile = arkfb_settile, | ||
162 | .fb_tilecopy = svga_tilecopy, | ||
163 | .fb_tilefill = svga_tilefill, | ||
164 | .fb_tileblit = svga_tileblit, | ||
165 | .fb_tilecursor = svga_tilecursor, | ||
166 | .fb_get_tilemax = svga_get_tilemax, | ||
167 | }; | ||
168 | |||
169 | |||
170 | /* ------------------------------------------------------------------------- */ | ||
171 | |||
172 | |||
173 | /* image data is MSB-first, fb structure is MSB-first too */ | ||
174 | static inline u32 expand_color(u32 c) | ||
175 | { | ||
176 | return ((c & 1) | ((c & 2) << 7) | ((c & 4) << 14) | ((c & 8) << 21)) * 0xFF; | ||
177 | } | ||
178 | |||
179 | /* arkfb_iplan_imageblit silently assumes that almost everything is 8-pixel aligned */ | ||
180 | static void arkfb_iplan_imageblit(struct fb_info *info, const struct fb_image *image) | ||
181 | { | ||
182 | u32 fg = expand_color(image->fg_color); | ||
183 | u32 bg = expand_color(image->bg_color); | ||
184 | const u8 *src1, *src; | ||
185 | u8 __iomem *dst1; | ||
186 | u32 __iomem *dst; | ||
187 | u32 val; | ||
188 | int x, y; | ||
189 | |||
190 | src1 = image->data; | ||
191 | dst1 = info->screen_base + (image->dy * info->fix.line_length) | ||
192 | + ((image->dx / 8) * 4); | ||
193 | |||
194 | for (y = 0; y < image->height; y++) { | ||
195 | src = src1; | ||
196 | dst = (u32 __iomem *) dst1; | ||
197 | for (x = 0; x < image->width; x += 8) { | ||
198 | val = *(src++) * 0x01010101; | ||
199 | val = (val & fg) | (~val & bg); | ||
200 | fb_writel(val, dst++); | ||
201 | } | ||
202 | src1 += image->width / 8; | ||
203 | dst1 += info->fix.line_length; | ||
204 | } | ||
205 | |||
206 | } | ||
207 | |||
208 | /* arkfb_iplan_fillrect silently assumes that almost everything is 8-pixel aligned */ | ||
209 | static void arkfb_iplan_fillrect(struct fb_info *info, const struct fb_fillrect *rect) | ||
210 | { | ||
211 | u32 fg = expand_color(rect->color); | ||
212 | u8 __iomem *dst1; | ||
213 | u32 __iomem *dst; | ||
214 | int x, y; | ||
215 | |||
216 | dst1 = info->screen_base + (rect->dy * info->fix.line_length) | ||
217 | + ((rect->dx / 8) * 4); | ||
218 | |||
219 | for (y = 0; y < rect->height; y++) { | ||
220 | dst = (u32 __iomem *) dst1; | ||
221 | for (x = 0; x < rect->width; x += 8) { | ||
222 | fb_writel(fg, dst++); | ||
223 | } | ||
224 | dst1 += info->fix.line_length; | ||
225 | } | ||
226 | |||
227 | } | ||
228 | |||
229 | |||
230 | /* image data is MSB-first, fb structure is high-nibble-in-low-byte-first */ | ||
231 | static inline u32 expand_pixel(u32 c) | ||
232 | { | ||
233 | return (((c & 1) << 24) | ((c & 2) << 27) | ((c & 4) << 14) | ((c & 8) << 17) | | ||
234 | ((c & 16) << 4) | ((c & 32) << 7) | ((c & 64) >> 6) | ((c & 128) >> 3)) * 0xF; | ||
235 | } | ||
236 | |||
237 | /* arkfb_cfb4_imageblit silently assumes that almost everything is 8-pixel aligned */ | ||
238 | static void arkfb_cfb4_imageblit(struct fb_info *info, const struct fb_image *image) | ||
239 | { | ||
240 | u32 fg = image->fg_color * 0x11111111; | ||
241 | u32 bg = image->bg_color * 0x11111111; | ||
242 | const u8 *src1, *src; | ||
243 | u8 __iomem *dst1; | ||
244 | u32 __iomem *dst; | ||
245 | u32 val; | ||
246 | int x, y; | ||
247 | |||
248 | src1 = image->data; | ||
249 | dst1 = info->screen_base + (image->dy * info->fix.line_length) | ||
250 | + ((image->dx / 8) * 4); | ||
251 | |||
252 | for (y = 0; y < image->height; y++) { | ||
253 | src = src1; | ||
254 | dst = (u32 __iomem *) dst1; | ||
255 | for (x = 0; x < image->width; x += 8) { | ||
256 | val = expand_pixel(*(src++)); | ||
257 | val = (val & fg) | (~val & bg); | ||
258 | fb_writel(val, dst++); | ||
259 | } | ||
260 | src1 += image->width / 8; | ||
261 | dst1 += info->fix.line_length; | ||
262 | } | ||
263 | |||
264 | } | ||
265 | |||
266 | static void arkfb_imageblit(struct fb_info *info, const struct fb_image *image) | ||
267 | { | ||
268 | if ((info->var.bits_per_pixel == 4) && (image->depth == 1) | ||
269 | && ((image->width % 8) == 0) && ((image->dx % 8) == 0)) { | ||
270 | if (info->fix.type == FB_TYPE_INTERLEAVED_PLANES) | ||
271 | arkfb_iplan_imageblit(info, image); | ||
272 | else | ||
273 | arkfb_cfb4_imageblit(info, image); | ||
274 | } else | ||
275 | cfb_imageblit(info, image); | ||
276 | } | ||
277 | |||
278 | static void arkfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) | ||
279 | { | ||
280 | if ((info->var.bits_per_pixel == 4) | ||
281 | && ((rect->width % 8) == 0) && ((rect->dx % 8) == 0) | ||
282 | && (info->fix.type == FB_TYPE_INTERLEAVED_PLANES)) | ||
283 | arkfb_iplan_fillrect(info, rect); | ||
284 | else | ||
285 | cfb_fillrect(info, rect); | ||
286 | } | ||
287 | |||
288 | |||
289 | /* ------------------------------------------------------------------------- */ | ||
290 | |||
291 | |||
292 | enum | ||
293 | { | ||
294 | DAC_PSEUDO8_8, | ||
295 | DAC_RGB1555_8, | ||
296 | DAC_RGB0565_8, | ||
297 | DAC_RGB0888_8, | ||
298 | DAC_RGB8888_8, | ||
299 | DAC_PSEUDO8_16, | ||
300 | DAC_RGB1555_16, | ||
301 | DAC_RGB0565_16, | ||
302 | DAC_RGB0888_16, | ||
303 | DAC_RGB8888_16, | ||
304 | DAC_MAX | ||
305 | }; | ||
306 | |||
307 | struct dac_ops { | ||
308 | int (*dac_get_mode)(struct dac_info *info); | ||
309 | int (*dac_set_mode)(struct dac_info *info, int mode); | ||
310 | int (*dac_get_freq)(struct dac_info *info, int channel); | ||
311 | int (*dac_set_freq)(struct dac_info *info, int channel, u32 freq); | ||
312 | void (*dac_release)(struct dac_info *info); | ||
313 | }; | ||
314 | |||
315 | typedef void (*dac_read_regs_t)(void *data, u8 *code, int count); | ||
316 | typedef void (*dac_write_regs_t)(void *data, u8 *code, int count); | ||
317 | |||
318 | struct dac_info | ||
319 | { | ||
320 | struct dac_ops *dacops; | ||
321 | dac_read_regs_t dac_read_regs; | ||
322 | dac_write_regs_t dac_write_regs; | ||
323 | void *data; | ||
324 | }; | ||
325 | |||
326 | |||
327 | static inline u8 dac_read_reg(struct dac_info *info, u8 reg) | ||
328 | { | ||
329 | u8 code[2] = {reg, 0}; | ||
330 | info->dac_read_regs(info->data, code, 1); | ||
331 | return code[1]; | ||
332 | } | ||
333 | |||
334 | static inline void dac_read_regs(struct dac_info *info, u8 *code, int count) | ||
335 | { | ||
336 | info->dac_read_regs(info->data, code, count); | ||
337 | } | ||
338 | |||
339 | static inline void dac_write_reg(struct dac_info *info, u8 reg, u8 val) | ||
340 | { | ||
341 | u8 code[2] = {reg, val}; | ||
342 | info->dac_write_regs(info->data, code, 1); | ||
343 | } | ||
344 | |||
345 | static inline void dac_write_regs(struct dac_info *info, u8 *code, int count) | ||
346 | { | ||
347 | info->dac_write_regs(info->data, code, count); | ||
348 | } | ||
349 | |||
350 | static inline int dac_set_mode(struct dac_info *info, int mode) | ||
351 | { | ||
352 | return info->dacops->dac_set_mode(info, mode); | ||
353 | } | ||
354 | |||
355 | static inline int dac_set_freq(struct dac_info *info, int channel, u32 freq) | ||
356 | { | ||
357 | return info->dacops->dac_set_freq(info, channel, freq); | ||
358 | } | ||
359 | |||
360 | static inline void dac_release(struct dac_info *info) | ||
361 | { | ||
362 | info->dacops->dac_release(info); | ||
363 | } | ||
364 | |||
365 | |||
366 | /* ------------------------------------------------------------------------- */ | ||
367 | |||
368 | |||
369 | /* ICS5342 DAC */ | ||
370 | |||
371 | struct ics5342_info | ||
372 | { | ||
373 | struct dac_info dac; | ||
374 | u8 mode; | ||
375 | }; | ||
376 | |||
377 | #define DAC_PAR(info) ((struct ics5342_info *) info) | ||
378 | |||
379 | /* LSB is set to distinguish unused slots */ | ||
380 | static const u8 ics5342_mode_table[DAC_MAX] = { | ||
381 | [DAC_PSEUDO8_8] = 0x01, [DAC_RGB1555_8] = 0x21, [DAC_RGB0565_8] = 0x61, | ||
382 | [DAC_RGB0888_8] = 0x41, [DAC_PSEUDO8_16] = 0x11, [DAC_RGB1555_16] = 0x31, | ||
383 | [DAC_RGB0565_16] = 0x51, [DAC_RGB0888_16] = 0x91, [DAC_RGB8888_16] = 0x71 | ||
384 | }; | ||
385 | |||
386 | static int ics5342_set_mode(struct dac_info *info, int mode) | ||
387 | { | ||
388 | u8 code; | ||
389 | |||
390 | if (mode >= DAC_MAX) | ||
391 | return -EINVAL; | ||
392 | |||
393 | code = ics5342_mode_table[mode]; | ||
394 | |||
395 | if (! code) | ||
396 | return -EINVAL; | ||
397 | |||
398 | dac_write_reg(info, 6, code & 0xF0); | ||
399 | DAC_PAR(info)->mode = mode; | ||
400 | |||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | static const struct svga_pll ics5342_pll = {3, 129, 3, 33, 0, 3, | ||
405 | 60000, 250000, 14318}; | ||
406 | |||
407 | /* pd4 - allow only posdivider 4 (r=2) */ | ||
408 | static const struct svga_pll ics5342_pll_pd4 = {3, 129, 3, 33, 2, 2, | ||
409 | 60000, 335000, 14318}; | ||
410 | |||
411 | /* 270 MHz should be upper bound for VCO clock according to specs, | ||
412 | but that is too restrictive in pd4 case */ | ||
413 | |||
414 | static int ics5342_set_freq(struct dac_info *info, int channel, u32 freq) | ||
415 | { | ||
416 | u16 m, n, r; | ||
417 | |||
418 | /* only postdivider 4 (r=2) is valid in mode DAC_PSEUDO8_16 */ | ||
419 | int rv = svga_compute_pll((DAC_PAR(info)->mode == DAC_PSEUDO8_16) | ||
420 | ? &ics5342_pll_pd4 : &ics5342_pll, | ||
421 | freq, &m, &n, &r, 0); | ||
422 | |||
423 | if (rv < 0) { | ||
424 | return -EINVAL; | ||
425 | } else { | ||
426 | u8 code[6] = {4, 3, 5, m-2, 5, (n-2) | (r << 5)}; | ||
427 | dac_write_regs(info, code, 3); | ||
428 | return 0; | ||
429 | } | ||
430 | } | ||
431 | |||
432 | static void ics5342_release(struct dac_info *info) | ||
433 | { | ||
434 | ics5342_set_mode(info, DAC_PSEUDO8_8); | ||
435 | kfree(info); | ||
436 | } | ||
437 | |||
438 | static struct dac_ops ics5342_ops = { | ||
439 | .dac_set_mode = ics5342_set_mode, | ||
440 | .dac_set_freq = ics5342_set_freq, | ||
441 | .dac_release = ics5342_release | ||
442 | }; | ||
443 | |||
444 | |||
445 | static struct dac_info * ics5342_init(dac_read_regs_t drr, dac_write_regs_t dwr, void *data) | ||
446 | { | ||
447 | struct dac_info *info = kzalloc(sizeof(struct ics5342_info), GFP_KERNEL); | ||
448 | |||
449 | if (! info) | ||
450 | return NULL; | ||
451 | |||
452 | info->dacops = &ics5342_ops; | ||
453 | info->dac_read_regs = drr; | ||
454 | info->dac_write_regs = dwr; | ||
455 | info->data = data; | ||
456 | DAC_PAR(info)->mode = DAC_PSEUDO8_8; /* estimation */ | ||
457 | return info; | ||
458 | } | ||
459 | |||
460 | |||
461 | /* ------------------------------------------------------------------------- */ | ||
462 | |||
463 | |||
464 | static unsigned short dac_regs[4] = {0x3c8, 0x3c9, 0x3c6, 0x3c7}; | ||
465 | |||
466 | static void ark_dac_read_regs(void *data, u8 *code, int count) | ||
467 | { | ||
468 | u8 regval = vga_rseq(NULL, 0x1C); | ||
469 | |||
470 | while (count != 0) | ||
471 | { | ||
472 | vga_wseq(NULL, 0x1C, regval | (code[0] & 4) ? 0x80 : 0); | ||
473 | code[1] = vga_r(NULL, dac_regs[code[0] & 3]); | ||
474 | count--; | ||
475 | code += 2; | ||
476 | } | ||
477 | |||
478 | vga_wseq(NULL, 0x1C, regval); | ||
479 | } | ||
480 | |||
481 | static void ark_dac_write_regs(void *data, u8 *code, int count) | ||
482 | { | ||
483 | u8 regval = vga_rseq(NULL, 0x1C); | ||
484 | |||
485 | while (count != 0) | ||
486 | { | ||
487 | vga_wseq(NULL, 0x1C, regval | (code[0] & 4) ? 0x80 : 0); | ||
488 | vga_w(NULL, dac_regs[code[0] & 3], code[1]); | ||
489 | count--; | ||
490 | code += 2; | ||
491 | } | ||
492 | |||
493 | vga_wseq(NULL, 0x1C, regval); | ||
494 | } | ||
495 | |||
496 | |||
497 | static void ark_set_pixclock(struct fb_info *info, u32 pixclock) | ||
498 | { | ||
499 | struct arkfb_info *par = info->par; | ||
500 | u8 regval; | ||
501 | |||
502 | int rv = dac_set_freq(par->dac, 0, 1000000000 / pixclock); | ||
503 | if (rv < 0) { | ||
504 | printk(KERN_ERR "fb%d: cannot set requested pixclock, keeping old value\n", info->node); | ||
505 | return; | ||
506 | } | ||
507 | |||
508 | /* Set VGA misc register */ | ||
509 | regval = vga_r(NULL, VGA_MIS_R); | ||
510 | vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD); | ||
511 | } | ||
512 | |||
513 | |||
514 | /* Open framebuffer */ | ||
515 | |||
516 | static int arkfb_open(struct fb_info *info, int user) | ||
517 | { | ||
518 | struct arkfb_info *par = info->par; | ||
519 | |||
520 | mutex_lock(&(par->open_lock)); | ||
521 | if (par->ref_count == 0) { | ||
522 | memset(&(par->state), 0, sizeof(struct vgastate)); | ||
523 | par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP; | ||
524 | par->state.num_crtc = 0x60; | ||
525 | par->state.num_seq = 0x30; | ||
526 | save_vga(&(par->state)); | ||
527 | } | ||
528 | |||
529 | par->ref_count++; | ||
530 | mutex_unlock(&(par->open_lock)); | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | /* Close framebuffer */ | ||
536 | |||
537 | static int arkfb_release(struct fb_info *info, int user) | ||
538 | { | ||
539 | struct arkfb_info *par = info->par; | ||
540 | |||
541 | mutex_lock(&(par->open_lock)); | ||
542 | if (par->ref_count == 0) { | ||
543 | mutex_unlock(&(par->open_lock)); | ||
544 | return -EINVAL; | ||
545 | } | ||
546 | |||
547 | if (par->ref_count == 1) { | ||
548 | restore_vga(&(par->state)); | ||
549 | dac_set_mode(par->dac, DAC_PSEUDO8_8); | ||
550 | } | ||
551 | |||
552 | par->ref_count--; | ||
553 | mutex_unlock(&(par->open_lock)); | ||
554 | |||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | /* Validate passed in var */ | ||
559 | |||
560 | static int arkfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | ||
561 | { | ||
562 | int rv, mem, step; | ||
563 | |||
564 | /* Find appropriate format */ | ||
565 | rv = svga_match_format (arkfb_formats, var, NULL); | ||
566 | if (rv < 0) | ||
567 | { | ||
568 | printk(KERN_ERR "fb%d: unsupported mode requested\n", info->node); | ||
569 | return rv; | ||
570 | } | ||
571 | |||
572 | /* Do not allow to have real resoulution larger than virtual */ | ||
573 | if (var->xres > var->xres_virtual) | ||
574 | var->xres_virtual = var->xres; | ||
575 | |||
576 | if (var->yres > var->yres_virtual) | ||
577 | var->yres_virtual = var->yres; | ||
578 | |||
579 | /* Round up xres_virtual to have proper alignment of lines */ | ||
580 | step = arkfb_formats[rv].xresstep - 1; | ||
581 | var->xres_virtual = (var->xres_virtual+step) & ~step; | ||
582 | |||
583 | |||
584 | /* Check whether have enough memory */ | ||
585 | mem = ((var->bits_per_pixel * var->xres_virtual) >> 3) * var->yres_virtual; | ||
586 | if (mem > info->screen_size) | ||
587 | { | ||
588 | printk(KERN_ERR "fb%d: not enough framebuffer memory (%d kB requested , %d kB available)\n", info->node, mem >> 10, (unsigned int) (info->screen_size >> 10)); | ||
589 | return -EINVAL; | ||
590 | } | ||
591 | |||
592 | rv = svga_check_timings (&ark_timing_regs, var, info->node); | ||
593 | if (rv < 0) | ||
594 | { | ||
595 | printk(KERN_ERR "fb%d: invalid timings requested\n", info->node); | ||
596 | return rv; | ||
597 | } | ||
598 | |||
599 | /* Interlaced mode is broken */ | ||
600 | if (var->vmode & FB_VMODE_INTERLACED) | ||
601 | return -EINVAL; | ||
602 | |||
603 | return 0; | ||
604 | } | ||
605 | |||
606 | /* Set video mode from par */ | ||
607 | |||
608 | static int arkfb_set_par(struct fb_info *info) | ||
609 | { | ||
610 | struct arkfb_info *par = info->par; | ||
611 | u32 value, mode, hmul, hdiv, offset_value, screen_size; | ||
612 | u32 bpp = info->var.bits_per_pixel; | ||
613 | u8 regval; | ||
614 | |||
615 | if (bpp != 0) { | ||
616 | info->fix.ypanstep = 1; | ||
617 | info->fix.line_length = (info->var.xres_virtual * bpp) / 8; | ||
618 | |||
619 | info->flags &= ~FBINFO_MISC_TILEBLITTING; | ||
620 | info->tileops = NULL; | ||
621 | |||
622 | /* in 4bpp supports 8p wide tiles only, any tiles otherwise */ | ||
623 | info->pixmap.blit_x = (bpp == 4) ? (1 << (8 - 1)) : (~(u32)0); | ||
624 | info->pixmap.blit_y = ~(u32)0; | ||
625 | |||
626 | offset_value = (info->var.xres_virtual * bpp) / 64; | ||
627 | screen_size = info->var.yres_virtual * info->fix.line_length; | ||
628 | } else { | ||
629 | info->fix.ypanstep = 16; | ||
630 | info->fix.line_length = 0; | ||
631 | |||
632 | info->flags |= FBINFO_MISC_TILEBLITTING; | ||
633 | info->tileops = &arkfb_tile_ops; | ||
634 | |||
635 | /* supports 8x16 tiles only */ | ||
636 | info->pixmap.blit_x = 1 << (8 - 1); | ||
637 | info->pixmap.blit_y = 1 << (16 - 1); | ||
638 | |||
639 | offset_value = info->var.xres_virtual / 16; | ||
640 | screen_size = (info->var.xres_virtual * info->var.yres_virtual) / 64; | ||
641 | } | ||
642 | |||
643 | info->var.xoffset = 0; | ||
644 | info->var.yoffset = 0; | ||
645 | info->var.activate = FB_ACTIVATE_NOW; | ||
646 | |||
647 | /* Unlock registers */ | ||
648 | svga_wcrt_mask(0x11, 0x00, 0x80); | ||
649 | |||
650 | /* Blank screen and turn off sync */ | ||
651 | svga_wseq_mask(0x01, 0x20, 0x20); | ||
652 | svga_wcrt_mask(0x17, 0x00, 0x80); | ||
653 | |||
654 | /* Set default values */ | ||
655 | svga_set_default_gfx_regs(); | ||
656 | svga_set_default_atc_regs(); | ||
657 | svga_set_default_seq_regs(); | ||
658 | svga_set_default_crt_regs(); | ||
659 | svga_wcrt_multi(ark_line_compare_regs, 0xFFFFFFFF); | ||
660 | svga_wcrt_multi(ark_start_address_regs, 0); | ||
661 | |||
662 | /* ARK specific initialization */ | ||
663 | svga_wseq_mask(0x10, 0x1F, 0x1F); /* enable linear framebuffer and full memory access */ | ||
664 | svga_wseq_mask(0x12, 0x03, 0x03); /* 4 MB linear framebuffer size */ | ||
665 | |||
666 | vga_wseq(NULL, 0x13, info->fix.smem_start >> 16); | ||
667 | vga_wseq(NULL, 0x14, info->fix.smem_start >> 24); | ||
668 | vga_wseq(NULL, 0x15, 0); | ||
669 | vga_wseq(NULL, 0x16, 0); | ||
670 | |||
671 | /* Set the FIFO threshold register */ | ||
672 | /* It is fascinating way to store 5-bit value in 8-bit register */ | ||
673 | regval = 0x10 | ((threshold & 0x0E) >> 1) | (threshold & 0x01) << 7 | (threshold & 0x10) << 1; | ||
674 | vga_wseq(NULL, 0x18, regval); | ||
675 | |||
676 | /* Set the offset register */ | ||
677 | pr_debug("fb%d: offset register : %d\n", info->node, offset_value); | ||
678 | svga_wcrt_multi(ark_offset_regs, offset_value); | ||
679 | |||
680 | /* fix for hi-res textmode */ | ||
681 | svga_wcrt_mask(0x40, 0x08, 0x08); | ||
682 | |||
683 | if (info->var.vmode & FB_VMODE_DOUBLE) | ||
684 | svga_wcrt_mask(0x09, 0x80, 0x80); | ||
685 | else | ||
686 | svga_wcrt_mask(0x09, 0x00, 0x80); | ||
687 | |||
688 | if (info->var.vmode & FB_VMODE_INTERLACED) | ||
689 | svga_wcrt_mask(0x44, 0x04, 0x04); | ||
690 | else | ||
691 | svga_wcrt_mask(0x44, 0x00, 0x04); | ||
692 | |||
693 | hmul = 1; | ||
694 | hdiv = 1; | ||
695 | mode = svga_match_format(arkfb_formats, &(info->var), &(info->fix)); | ||
696 | |||
697 | /* Set mode-specific register values */ | ||
698 | switch (mode) { | ||
699 | case 0: | ||
700 | pr_debug("fb%d: text mode\n", info->node); | ||
701 | svga_set_textmode_vga_regs(); | ||
702 | |||
703 | vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */ | ||
704 | svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */ | ||
705 | dac_set_mode(par->dac, DAC_PSEUDO8_8); | ||
706 | |||
707 | break; | ||
708 | case 1: | ||
709 | pr_debug("fb%d: 4 bit pseudocolor\n", info->node); | ||
710 | vga_wgfx(NULL, VGA_GFX_MODE, 0x40); | ||
711 | |||
712 | vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */ | ||
713 | svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */ | ||
714 | dac_set_mode(par->dac, DAC_PSEUDO8_8); | ||
715 | break; | ||
716 | case 2: | ||
717 | pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node); | ||
718 | |||
719 | vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */ | ||
720 | svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */ | ||
721 | dac_set_mode(par->dac, DAC_PSEUDO8_8); | ||
722 | break; | ||
723 | case 3: | ||
724 | pr_debug("fb%d: 8 bit pseudocolor\n", info->node); | ||
725 | |||
726 | vga_wseq(NULL, 0x11, 0x16); /* 8bpp accel mode */ | ||
727 | |||
728 | if (info->var.pixclock > 20000) { | ||
729 | pr_debug("fb%d: not using multiplex\n", info->node); | ||
730 | svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */ | ||
731 | dac_set_mode(par->dac, DAC_PSEUDO8_8); | ||
732 | } else { | ||
733 | pr_debug("fb%d: using multiplex\n", info->node); | ||
734 | svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */ | ||
735 | dac_set_mode(par->dac, DAC_PSEUDO8_16); | ||
736 | hdiv = 2; | ||
737 | } | ||
738 | break; | ||
739 | case 4: | ||
740 | pr_debug("fb%d: 5/5/5 truecolor\n", info->node); | ||
741 | |||
742 | vga_wseq(NULL, 0x11, 0x1A); /* 16bpp accel mode */ | ||
743 | svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */ | ||
744 | dac_set_mode(par->dac, DAC_RGB1555_16); | ||
745 | break; | ||
746 | case 5: | ||
747 | pr_debug("fb%d: 5/6/5 truecolor\n", info->node); | ||
748 | |||
749 | vga_wseq(NULL, 0x11, 0x1A); /* 16bpp accel mode */ | ||
750 | svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */ | ||
751 | dac_set_mode(par->dac, DAC_RGB0565_16); | ||
752 | break; | ||
753 | case 6: | ||
754 | pr_debug("fb%d: 8/8/8 truecolor\n", info->node); | ||
755 | |||
756 | vga_wseq(NULL, 0x11, 0x16); /* 8bpp accel mode ??? */ | ||
757 | svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */ | ||
758 | dac_set_mode(par->dac, DAC_RGB0888_16); | ||
759 | hmul = 3; | ||
760 | hdiv = 2; | ||
761 | break; | ||
762 | case 7: | ||
763 | pr_debug("fb%d: 8/8/8/8 truecolor\n", info->node); | ||
764 | |||
765 | vga_wseq(NULL, 0x11, 0x1E); /* 32bpp accel mode */ | ||
766 | svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */ | ||
767 | dac_set_mode(par->dac, DAC_RGB8888_16); | ||
768 | hmul = 2; | ||
769 | break; | ||
770 | default: | ||
771 | printk(KERN_ERR "fb%d: unsupported mode - bug\n", info->node); | ||
772 | return -EINVAL; | ||
773 | } | ||
774 | |||
775 | ark_set_pixclock(info, (hdiv * info->var.pixclock) / hmul); | ||
776 | svga_set_timings(&ark_timing_regs, &(info->var), hmul, hdiv, | ||
777 | (info->var.vmode & FB_VMODE_DOUBLE) ? 2 : 1, | ||
778 | (info->var.vmode & FB_VMODE_INTERLACED) ? 2 : 1, | ||
779 | hmul, info->node); | ||
780 | |||
781 | /* Set interlaced mode start/end register */ | ||
782 | value = info->var.xres + info->var.left_margin + info->var.right_margin + info->var.hsync_len; | ||
783 | value = ((value * hmul / hdiv) / 8) - 5; | ||
784 | vga_wcrt(NULL, 0x42, (value + 1) / 2); | ||
785 | |||
786 | memset_io(info->screen_base, 0x00, screen_size); | ||
787 | /* Device and screen back on */ | ||
788 | svga_wcrt_mask(0x17, 0x80, 0x80); | ||
789 | svga_wseq_mask(0x01, 0x00, 0x20); | ||
790 | |||
791 | return 0; | ||
792 | } | ||
793 | |||
794 | /* Set a colour register */ | ||
795 | |||
796 | static int arkfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, | ||
797 | u_int transp, struct fb_info *fb) | ||
798 | { | ||
799 | switch (fb->var.bits_per_pixel) { | ||
800 | case 0: | ||
801 | case 4: | ||
802 | if (regno >= 16) | ||
803 | return -EINVAL; | ||
804 | |||
805 | if ((fb->var.bits_per_pixel == 4) && | ||
806 | (fb->var.nonstd == 0)) { | ||
807 | outb(0xF0, VGA_PEL_MSK); | ||
808 | outb(regno*16, VGA_PEL_IW); | ||
809 | } else { | ||
810 | outb(0x0F, VGA_PEL_MSK); | ||
811 | outb(regno, VGA_PEL_IW); | ||
812 | } | ||
813 | outb(red >> 10, VGA_PEL_D); | ||
814 | outb(green >> 10, VGA_PEL_D); | ||
815 | outb(blue >> 10, VGA_PEL_D); | ||
816 | break; | ||
817 | case 8: | ||
818 | if (regno >= 256) | ||
819 | return -EINVAL; | ||
820 | |||
821 | outb(0xFF, VGA_PEL_MSK); | ||
822 | outb(regno, VGA_PEL_IW); | ||
823 | outb(red >> 10, VGA_PEL_D); | ||
824 | outb(green >> 10, VGA_PEL_D); | ||
825 | outb(blue >> 10, VGA_PEL_D); | ||
826 | break; | ||
827 | case 16: | ||
828 | if (regno >= 16) | ||
829 | return 0; | ||
830 | |||
831 | if (fb->var.green.length == 5) | ||
832 | ((u32*)fb->pseudo_palette)[regno] = ((red & 0xF800) >> 1) | | ||
833 | ((green & 0xF800) >> 6) | ((blue & 0xF800) >> 11); | ||
834 | else if (fb->var.green.length == 6) | ||
835 | ((u32*)fb->pseudo_palette)[regno] = (red & 0xF800) | | ||
836 | ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11); | ||
837 | else | ||
838 | return -EINVAL; | ||
839 | break; | ||
840 | case 24: | ||
841 | case 32: | ||
842 | if (regno >= 16) | ||
843 | return 0; | ||
844 | |||
845 | ((u32*)fb->pseudo_palette)[regno] = ((red & 0xFF00) << 8) | | ||
846 | (green & 0xFF00) | ((blue & 0xFF00) >> 8); | ||
847 | break; | ||
848 | default: | ||
849 | return -EINVAL; | ||
850 | } | ||
851 | |||
852 | return 0; | ||
853 | } | ||
854 | |||
855 | /* Set the display blanking state */ | ||
856 | |||
857 | static int arkfb_blank(int blank_mode, struct fb_info *info) | ||
858 | { | ||
859 | switch (blank_mode) { | ||
860 | case FB_BLANK_UNBLANK: | ||
861 | pr_debug("fb%d: unblank\n", info->node); | ||
862 | svga_wseq_mask(0x01, 0x00, 0x20); | ||
863 | svga_wcrt_mask(0x17, 0x80, 0x80); | ||
864 | break; | ||
865 | case FB_BLANK_NORMAL: | ||
866 | pr_debug("fb%d: blank\n", info->node); | ||
867 | svga_wseq_mask(0x01, 0x20, 0x20); | ||
868 | svga_wcrt_mask(0x17, 0x80, 0x80); | ||
869 | break; | ||
870 | case FB_BLANK_POWERDOWN: | ||
871 | case FB_BLANK_HSYNC_SUSPEND: | ||
872 | case FB_BLANK_VSYNC_SUSPEND: | ||
873 | pr_debug("fb%d: sync down\n", info->node); | ||
874 | svga_wseq_mask(0x01, 0x20, 0x20); | ||
875 | svga_wcrt_mask(0x17, 0x00, 0x80); | ||
876 | break; | ||
877 | } | ||
878 | return 0; | ||
879 | } | ||
880 | |||
881 | |||
882 | /* Pan the display */ | ||
883 | |||
884 | static int arkfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) | ||
885 | { | ||
886 | unsigned int offset; | ||
887 | |||
888 | /* Calculate the offset */ | ||
889 | if (var->bits_per_pixel == 0) { | ||
890 | offset = (var->yoffset / 16) * (var->xres_virtual / 2) + (var->xoffset / 2); | ||
891 | offset = offset >> 2; | ||
892 | } else { | ||
893 | offset = (var->yoffset * info->fix.line_length) + | ||
894 | (var->xoffset * var->bits_per_pixel / 8); | ||
895 | offset = offset >> ((var->bits_per_pixel == 4) ? 2 : 3); | ||
896 | } | ||
897 | |||
898 | /* Set the offset */ | ||
899 | svga_wcrt_multi(ark_start_address_regs, offset); | ||
900 | |||
901 | return 0; | ||
902 | } | ||
903 | |||
904 | |||
905 | /* ------------------------------------------------------------------------- */ | ||
906 | |||
907 | |||
908 | /* Frame buffer operations */ | ||
909 | |||
910 | static struct fb_ops arkfb_ops = { | ||
911 | .owner = THIS_MODULE, | ||
912 | .fb_open = arkfb_open, | ||
913 | .fb_release = arkfb_release, | ||
914 | .fb_check_var = arkfb_check_var, | ||
915 | .fb_set_par = arkfb_set_par, | ||
916 | .fb_setcolreg = arkfb_setcolreg, | ||
917 | .fb_blank = arkfb_blank, | ||
918 | .fb_pan_display = arkfb_pan_display, | ||
919 | .fb_fillrect = arkfb_fillrect, | ||
920 | .fb_copyarea = cfb_copyarea, | ||
921 | .fb_imageblit = arkfb_imageblit, | ||
922 | .fb_get_caps = svga_get_caps, | ||
923 | }; | ||
924 | |||
925 | |||
926 | /* ------------------------------------------------------------------------- */ | ||
927 | |||
928 | |||
929 | /* PCI probe */ | ||
930 | static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) | ||
931 | { | ||
932 | struct fb_info *info; | ||
933 | struct arkfb_info *par; | ||
934 | int rc; | ||
935 | u8 regval; | ||
936 | |||
937 | /* Ignore secondary VGA device because there is no VGA arbitration */ | ||
938 | if (! svga_primary_device(dev)) { | ||
939 | dev_info(&(dev->dev), "ignoring secondary device\n"); | ||
940 | return -ENODEV; | ||
941 | } | ||
942 | |||
943 | /* Allocate and fill driver data structure */ | ||
944 | info = framebuffer_alloc(sizeof(struct arkfb_info), NULL); | ||
945 | if (! info) { | ||
946 | dev_err(&(dev->dev), "cannot allocate memory\n"); | ||
947 | return -ENOMEM; | ||
948 | } | ||
949 | |||
950 | par = info->par; | ||
951 | mutex_init(&par->open_lock); | ||
952 | |||
953 | info->flags = FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN; | ||
954 | info->fbops = &arkfb_ops; | ||
955 | |||
956 | /* Prepare PCI device */ | ||
957 | rc = pci_enable_device(dev); | ||
958 | if (rc < 0) { | ||
959 | dev_err(&(dev->dev), "cannot enable PCI device\n"); | ||
960 | goto err_enable_device; | ||
961 | } | ||
962 | |||
963 | rc = pci_request_regions(dev, "arkfb"); | ||
964 | if (rc < 0) { | ||
965 | dev_err(&(dev->dev), "cannot reserve framebuffer region\n"); | ||
966 | goto err_request_regions; | ||
967 | } | ||
968 | |||
969 | par->dac = ics5342_init(ark_dac_read_regs, ark_dac_write_regs, info); | ||
970 | if (! par->dac) { | ||
971 | rc = -ENOMEM; | ||
972 | dev_err(&(dev->dev), "RAMDAC initialization failed\n"); | ||
973 | goto err_dac; | ||
974 | } | ||
975 | |||
976 | info->fix.smem_start = pci_resource_start(dev, 0); | ||
977 | info->fix.smem_len = pci_resource_len(dev, 0); | ||
978 | |||
979 | /* Map physical IO memory address into kernel space */ | ||
980 | info->screen_base = pci_iomap(dev, 0, 0); | ||
981 | if (! info->screen_base) { | ||
982 | rc = -ENOMEM; | ||
983 | dev_err(&(dev->dev), "iomap for framebuffer failed\n"); | ||
984 | goto err_iomap; | ||
985 | } | ||
986 | |||
987 | /* FIXME get memsize */ | ||
988 | regval = vga_rseq(NULL, 0x10); | ||
989 | info->screen_size = (1 << (regval >> 6)) << 20; | ||
990 | info->fix.smem_len = info->screen_size; | ||
991 | |||
992 | strcpy(info->fix.id, "ARK 2000PV"); | ||
993 | info->fix.mmio_start = 0; | ||
994 | info->fix.mmio_len = 0; | ||
995 | info->fix.type = FB_TYPE_PACKED_PIXELS; | ||
996 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; | ||
997 | info->fix.ypanstep = 0; | ||
998 | info->fix.accel = FB_ACCEL_NONE; | ||
999 | info->pseudo_palette = (void*) (par->pseudo_palette); | ||
1000 | |||
1001 | /* Prepare startup mode */ | ||
1002 | rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8); | ||
1003 | if (! ((rc == 1) || (rc == 2))) { | ||
1004 | rc = -EINVAL; | ||
1005 | dev_err(&(dev->dev), "mode %s not found\n", mode); | ||
1006 | goto err_find_mode; | ||
1007 | } | ||
1008 | |||
1009 | rc = fb_alloc_cmap(&info->cmap, 256, 0); | ||
1010 | if (rc < 0) { | ||
1011 | dev_err(&(dev->dev), "cannot allocate colormap\n"); | ||
1012 | goto err_alloc_cmap; | ||
1013 | } | ||
1014 | |||
1015 | rc = register_framebuffer(info); | ||
1016 | if (rc < 0) { | ||
1017 | dev_err(&(dev->dev), "cannot register framebugger\n"); | ||
1018 | goto err_reg_fb; | ||
1019 | } | ||
1020 | |||
1021 | printk(KERN_INFO "fb%d: %s on %s, %d MB RAM\n", info->node, info->fix.id, | ||
1022 | pci_name(dev), info->fix.smem_len >> 20); | ||
1023 | |||
1024 | /* Record a reference to the driver data */ | ||
1025 | pci_set_drvdata(dev, info); | ||
1026 | |||
1027 | #ifdef CONFIG_MTRR | ||
1028 | if (mtrr) { | ||
1029 | par->mtrr_reg = -1; | ||
1030 | par->mtrr_reg = mtrr_add(info->fix.smem_start, info->fix.smem_len, MTRR_TYPE_WRCOMB, 1); | ||
1031 | } | ||
1032 | #endif | ||
1033 | |||
1034 | return 0; | ||
1035 | |||
1036 | /* Error handling */ | ||
1037 | err_reg_fb: | ||
1038 | fb_dealloc_cmap(&info->cmap); | ||
1039 | err_alloc_cmap: | ||
1040 | err_find_mode: | ||
1041 | pci_iounmap(dev, info->screen_base); | ||
1042 | err_iomap: | ||
1043 | dac_release(par->dac); | ||
1044 | err_dac: | ||
1045 | pci_release_regions(dev); | ||
1046 | err_request_regions: | ||
1047 | /* pci_disable_device(dev); */ | ||
1048 | err_enable_device: | ||
1049 | framebuffer_release(info); | ||
1050 | return rc; | ||
1051 | } | ||
1052 | |||
1053 | /* PCI remove */ | ||
1054 | |||
1055 | static void __devexit ark_pci_remove(struct pci_dev *dev) | ||
1056 | { | ||
1057 | struct fb_info *info = pci_get_drvdata(dev); | ||
1058 | |||
1059 | if (info) { | ||
1060 | struct arkfb_info *par = info->par; | ||
1061 | |||
1062 | #ifdef CONFIG_MTRR | ||
1063 | if (par->mtrr_reg >= 0) { | ||
1064 | mtrr_del(par->mtrr_reg, 0, 0); | ||
1065 | par->mtrr_reg = -1; | ||
1066 | } | ||
1067 | #endif | ||
1068 | |||
1069 | dac_release(par->dac); | ||
1070 | unregister_framebuffer(info); | ||
1071 | fb_dealloc_cmap(&info->cmap); | ||
1072 | |||
1073 | pci_iounmap(dev, info->screen_base); | ||
1074 | pci_release_regions(dev); | ||
1075 | /* pci_disable_device(dev); */ | ||
1076 | |||
1077 | pci_set_drvdata(dev, NULL); | ||
1078 | framebuffer_release(info); | ||
1079 | } | ||
1080 | } | ||
1081 | |||
1082 | |||
1083 | #ifdef CONFIG_PM | ||
1084 | /* PCI suspend */ | ||
1085 | |||
1086 | static int ark_pci_suspend (struct pci_dev* dev, pm_message_t state) | ||
1087 | { | ||
1088 | struct fb_info *info = pci_get_drvdata(dev); | ||
1089 | struct arkfb_info *par = info->par; | ||
1090 | |||
1091 | dev_info(&(dev->dev), "suspend\n"); | ||
1092 | |||
1093 | acquire_console_sem(); | ||
1094 | mutex_lock(&(par->open_lock)); | ||
1095 | |||
1096 | if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) { | ||
1097 | mutex_unlock(&(par->open_lock)); | ||
1098 | release_console_sem(); | ||
1099 | return 0; | ||
1100 | } | ||
1101 | |||
1102 | fb_set_suspend(info, 1); | ||
1103 | |||
1104 | pci_save_state(dev); | ||
1105 | pci_disable_device(dev); | ||
1106 | pci_set_power_state(dev, pci_choose_state(dev, state)); | ||
1107 | |||
1108 | mutex_unlock(&(par->open_lock)); | ||
1109 | release_console_sem(); | ||
1110 | |||
1111 | return 0; | ||
1112 | } | ||
1113 | |||
1114 | |||
1115 | /* PCI resume */ | ||
1116 | |||
1117 | static int ark_pci_resume (struct pci_dev* dev) | ||
1118 | { | ||
1119 | struct fb_info *info = pci_get_drvdata(dev); | ||
1120 | struct arkfb_info *par = info->par; | ||
1121 | |||
1122 | dev_info(&(dev->dev), "resume\n"); | ||
1123 | |||
1124 | acquire_console_sem(); | ||
1125 | mutex_lock(&(par->open_lock)); | ||
1126 | |||
1127 | if (par->ref_count == 0) { | ||
1128 | mutex_unlock(&(par->open_lock)); | ||
1129 | release_console_sem(); | ||
1130 | return 0; | ||
1131 | } | ||
1132 | |||
1133 | pci_set_power_state(dev, PCI_D0); | ||
1134 | pci_restore_state(dev); | ||
1135 | |||
1136 | if (pci_enable_device(dev)) | ||
1137 | goto fail; | ||
1138 | |||
1139 | pci_set_master(dev); | ||
1140 | |||
1141 | arkfb_set_par(info); | ||
1142 | fb_set_suspend(info, 0); | ||
1143 | |||
1144 | mutex_unlock(&(par->open_lock)); | ||
1145 | fail: | ||
1146 | release_console_sem(); | ||
1147 | return 0; | ||
1148 | } | ||
1149 | #else | ||
1150 | #define ark_pci_suspend NULL | ||
1151 | #define ark_pci_resume NULL | ||
1152 | #endif /* CONFIG_PM */ | ||
1153 | |||
1154 | /* List of boards that we are trying to support */ | ||
1155 | |||
1156 | static struct pci_device_id ark_devices[] __devinitdata = { | ||
1157 | {PCI_DEVICE(0xEDD8, 0xA099)}, | ||
1158 | {0, 0, 0, 0, 0, 0, 0} | ||
1159 | }; | ||
1160 | |||
1161 | |||
1162 | MODULE_DEVICE_TABLE(pci, ark_devices); | ||
1163 | |||
1164 | static struct pci_driver arkfb_pci_driver = { | ||
1165 | .name = "arkfb", | ||
1166 | .id_table = ark_devices, | ||
1167 | .probe = ark_pci_probe, | ||
1168 | .remove = __devexit_p(ark_pci_remove), | ||
1169 | .suspend = ark_pci_suspend, | ||
1170 | .resume = ark_pci_resume, | ||
1171 | }; | ||
1172 | |||
1173 | /* Cleanup */ | ||
1174 | |||
1175 | static void __exit arkfb_cleanup(void) | ||
1176 | { | ||
1177 | pr_debug("arkfb: cleaning up\n"); | ||
1178 | pci_unregister_driver(&arkfb_pci_driver); | ||
1179 | } | ||
1180 | |||
1181 | /* Driver Initialisation */ | ||
1182 | |||
1183 | static int __init arkfb_init(void) | ||
1184 | { | ||
1185 | |||
1186 | #ifndef MODULE | ||
1187 | char *option = NULL; | ||
1188 | |||
1189 | if (fb_get_options("arkfb", &option)) | ||
1190 | return -ENODEV; | ||
1191 | |||
1192 | if (option && *option) | ||
1193 | mode = option; | ||
1194 | #endif | ||
1195 | |||
1196 | pr_debug("arkfb: initializing\n"); | ||
1197 | return pci_register_driver(&arkfb_pci_driver); | ||
1198 | } | ||
1199 | |||
1200 | module_init(arkfb_init); | ||
1201 | module_exit(arkfb_cleanup); | ||
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c new file mode 100644 index 000000000000..235b618b4117 --- /dev/null +++ b/drivers/video/atmel_lcdfb.c | |||
@@ -0,0 +1,801 @@ | |||
1 | /* | ||
2 | * Driver for AT91/AT32 LCD Controller | ||
3 | * | ||
4 | * Copyright (C) 2007 Atmel Corporation | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file COPYING in the main directory of this archive for | ||
8 | * more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | #include <linux/dma-mapping.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/clk.h> | ||
16 | #include <linux/fb.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/delay.h> | ||
19 | |||
20 | #include <asm/arch/board.h> | ||
21 | #include <asm/arch/cpu.h> | ||
22 | #include <asm/arch/gpio.h> | ||
23 | |||
24 | #include <video/atmel_lcdc.h> | ||
25 | |||
26 | #define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg)) | ||
27 | #define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg)) | ||
28 | |||
29 | /* configurable parameters */ | ||
30 | #define ATMEL_LCDC_CVAL_DEFAULT 0xc8 | ||
31 | #define ATMEL_LCDC_DMA_BURST_LEN 8 | ||
32 | |||
33 | #if defined(CONFIG_ARCH_AT91SAM9263) | ||
34 | #define ATMEL_LCDC_FIFO_SIZE 2048 | ||
35 | #else | ||
36 | #define ATMEL_LCDC_FIFO_SIZE 512 | ||
37 | #endif | ||
38 | |||
39 | #if defined(CONFIG_ARCH_AT91) | ||
40 | #define ATMEL_LCDFB_FBINFO_DEFAULT FBINFO_DEFAULT | ||
41 | |||
42 | static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo, | ||
43 | struct fb_var_screeninfo *var) | ||
44 | { | ||
45 | |||
46 | } | ||
47 | #elif defined(CONFIG_AVR32) | ||
48 | #define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \ | ||
49 | | FBINFO_PARTIAL_PAN_OK \ | ||
50 | | FBINFO_HWACCEL_XPAN \ | ||
51 | | FBINFO_HWACCEL_YPAN) | ||
52 | |||
53 | static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo, | ||
54 | struct fb_var_screeninfo *var) | ||
55 | { | ||
56 | u32 dma2dcfg; | ||
57 | u32 pixeloff; | ||
58 | |||
59 | pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f; | ||
60 | |||
61 | dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8; | ||
62 | dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET; | ||
63 | lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg); | ||
64 | |||
65 | /* Update configuration */ | ||
66 | lcdc_writel(sinfo, ATMEL_LCDC_DMACON, | ||
67 | lcdc_readl(sinfo, ATMEL_LCDC_DMACON) | ||
68 | | ATMEL_LCDC_DMAUPDT); | ||
69 | } | ||
70 | #endif | ||
71 | |||
72 | |||
73 | static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = { | ||
74 | .type = FB_TYPE_PACKED_PIXELS, | ||
75 | .visual = FB_VISUAL_TRUECOLOR, | ||
76 | .xpanstep = 0, | ||
77 | .ypanstep = 0, | ||
78 | .ywrapstep = 0, | ||
79 | .accel = FB_ACCEL_NONE, | ||
80 | }; | ||
81 | |||
82 | static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2) | ||
83 | { | ||
84 | unsigned long value; | ||
85 | |||
86 | if (!(cpu_is_at91sam9261() || cpu_is_at32ap7000())) | ||
87 | return xres; | ||
88 | |||
89 | value = xres; | ||
90 | if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) { | ||
91 | /* STN display */ | ||
92 | if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR) { | ||
93 | value *= 3; | ||
94 | } | ||
95 | if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4 | ||
96 | || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8 | ||
97 | && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL )) | ||
98 | value = DIV_ROUND_UP(value, 4); | ||
99 | else | ||
100 | value = DIV_ROUND_UP(value, 8); | ||
101 | } | ||
102 | |||
103 | return value; | ||
104 | } | ||
105 | |||
106 | static void atmel_lcdfb_update_dma(struct fb_info *info, | ||
107 | struct fb_var_screeninfo *var) | ||
108 | { | ||
109 | struct atmel_lcdfb_info *sinfo = info->par; | ||
110 | struct fb_fix_screeninfo *fix = &info->fix; | ||
111 | unsigned long dma_addr; | ||
112 | |||
113 | dma_addr = (fix->smem_start + var->yoffset * fix->line_length | ||
114 | + var->xoffset * var->bits_per_pixel / 8); | ||
115 | |||
116 | dma_addr &= ~3UL; | ||
117 | |||
118 | /* Set framebuffer DMA base address and pixel offset */ | ||
119 | lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr); | ||
120 | |||
121 | atmel_lcdfb_update_dma2d(sinfo, var); | ||
122 | } | ||
123 | |||
124 | static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo) | ||
125 | { | ||
126 | struct fb_info *info = sinfo->info; | ||
127 | |||
128 | dma_free_writecombine(info->device, info->fix.smem_len, | ||
129 | info->screen_base, info->fix.smem_start); | ||
130 | } | ||
131 | |||
132 | /** | ||
133 | * atmel_lcdfb_alloc_video_memory - Allocate framebuffer memory | ||
134 | * @sinfo: the frame buffer to allocate memory for | ||
135 | */ | ||
136 | static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo) | ||
137 | { | ||
138 | struct fb_info *info = sinfo->info; | ||
139 | struct fb_var_screeninfo *var = &info->var; | ||
140 | |||
141 | info->fix.smem_len = (var->xres_virtual * var->yres_virtual | ||
142 | * ((var->bits_per_pixel + 7) / 8)); | ||
143 | |||
144 | info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len, | ||
145 | (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL); | ||
146 | |||
147 | if (!info->screen_base) { | ||
148 | return -ENOMEM; | ||
149 | } | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | /** | ||
155 | * atmel_lcdfb_check_var - Validates a var passed in. | ||
156 | * @var: frame buffer variable screen structure | ||
157 | * @info: frame buffer structure that represents a single frame buffer | ||
158 | * | ||
159 | * Checks to see if the hardware supports the state requested by | ||
160 | * var passed in. This function does not alter the hardware | ||
161 | * state!!! This means the data stored in struct fb_info and | ||
162 | * struct atmel_lcdfb_info do not change. This includes the var | ||
163 | * inside of struct fb_info. Do NOT change these. This function | ||
164 | * can be called on its own if we intent to only test a mode and | ||
165 | * not actually set it. The stuff in modedb.c is a example of | ||
166 | * this. If the var passed in is slightly off by what the | ||
167 | * hardware can support then we alter the var PASSED in to what | ||
168 | * we can do. If the hardware doesn't support mode change a | ||
169 | * -EINVAL will be returned by the upper layers. You don't need | ||
170 | * to implement this function then. If you hardware doesn't | ||
171 | * support changing the resolution then this function is not | ||
172 | * needed. In this case the driver would just provide a var that | ||
173 | * represents the static state the screen is in. | ||
174 | * | ||
175 | * Returns negative errno on error, or zero on success. | ||
176 | */ | ||
177 | static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, | ||
178 | struct fb_info *info) | ||
179 | { | ||
180 | struct device *dev = info->device; | ||
181 | struct atmel_lcdfb_info *sinfo = info->par; | ||
182 | unsigned long clk_value_khz; | ||
183 | |||
184 | clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; | ||
185 | |||
186 | dev_dbg(dev, "%s:\n", __func__); | ||
187 | dev_dbg(dev, " resolution: %ux%u\n", var->xres, var->yres); | ||
188 | dev_dbg(dev, " pixclk: %lu KHz\n", PICOS2KHZ(var->pixclock)); | ||
189 | dev_dbg(dev, " bpp: %u\n", var->bits_per_pixel); | ||
190 | dev_dbg(dev, " clk: %lu KHz\n", clk_value_khz); | ||
191 | |||
192 | if ((PICOS2KHZ(var->pixclock) * var->bits_per_pixel / 8) > clk_value_khz) { | ||
193 | dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(var->pixclock)); | ||
194 | return -EINVAL; | ||
195 | } | ||
196 | |||
197 | /* Force same alignment for each line */ | ||
198 | var->xres = (var->xres + 3) & ~3UL; | ||
199 | var->xres_virtual = (var->xres_virtual + 3) & ~3UL; | ||
200 | |||
201 | var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0; | ||
202 | var->transp.msb_right = 0; | ||
203 | var->transp.offset = var->transp.length = 0; | ||
204 | var->xoffset = var->yoffset = 0; | ||
205 | |||
206 | switch (var->bits_per_pixel) { | ||
207 | case 1: | ||
208 | case 2: | ||
209 | case 4: | ||
210 | case 8: | ||
211 | var->red.offset = var->green.offset = var->blue.offset = 0; | ||
212 | var->red.length = var->green.length = var->blue.length | ||
213 | = var->bits_per_pixel; | ||
214 | break; | ||
215 | case 15: | ||
216 | case 16: | ||
217 | var->red.offset = 0; | ||
218 | var->green.offset = 5; | ||
219 | var->blue.offset = 10; | ||
220 | var->red.length = var->green.length = var->blue.length = 5; | ||
221 | break; | ||
222 | case 32: | ||
223 | var->transp.offset = 24; | ||
224 | var->transp.length = 8; | ||
225 | /* fall through */ | ||
226 | case 24: | ||
227 | var->red.offset = 0; | ||
228 | var->green.offset = 8; | ||
229 | var->blue.offset = 16; | ||
230 | var->red.length = var->green.length = var->blue.length = 8; | ||
231 | break; | ||
232 | default: | ||
233 | dev_err(dev, "color depth %d not supported\n", | ||
234 | var->bits_per_pixel); | ||
235 | return -EINVAL; | ||
236 | } | ||
237 | |||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | /** | ||
242 | * atmel_lcdfb_set_par - Alters the hardware state. | ||
243 | * @info: frame buffer structure that represents a single frame buffer | ||
244 | * | ||
245 | * Using the fb_var_screeninfo in fb_info we set the resolution | ||
246 | * of the this particular framebuffer. This function alters the | ||
247 | * par AND the fb_fix_screeninfo stored in fb_info. It doesn't | ||
248 | * not alter var in fb_info since we are using that data. This | ||
249 | * means we depend on the data in var inside fb_info to be | ||
250 | * supported by the hardware. atmel_lcdfb_check_var is always called | ||
251 | * before atmel_lcdfb_set_par to ensure this. Again if you can't | ||
252 | * change the resolution you don't need this function. | ||
253 | * | ||
254 | */ | ||
255 | static int atmel_lcdfb_set_par(struct fb_info *info) | ||
256 | { | ||
257 | struct atmel_lcdfb_info *sinfo = info->par; | ||
258 | unsigned long hozval_linesz; | ||
259 | unsigned long value; | ||
260 | unsigned long clk_value_khz; | ||
261 | unsigned long bits_per_line; | ||
262 | |||
263 | dev_dbg(info->device, "%s:\n", __func__); | ||
264 | dev_dbg(info->device, " * resolution: %ux%u (%ux%u virtual)\n", | ||
265 | info->var.xres, info->var.yres, | ||
266 | info->var.xres_virtual, info->var.yres_virtual); | ||
267 | |||
268 | /* Turn off the LCD controller and the DMA controller */ | ||
269 | lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET); | ||
270 | |||
271 | lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0); | ||
272 | |||
273 | if (info->var.bits_per_pixel == 1) | ||
274 | info->fix.visual = FB_VISUAL_MONO01; | ||
275 | else if (info->var.bits_per_pixel <= 8) | ||
276 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; | ||
277 | else | ||
278 | info->fix.visual = FB_VISUAL_TRUECOLOR; | ||
279 | |||
280 | bits_per_line = info->var.xres_virtual * info->var.bits_per_pixel; | ||
281 | info->fix.line_length = DIV_ROUND_UP(bits_per_line, 8); | ||
282 | |||
283 | /* Re-initialize the DMA engine... */ | ||
284 | dev_dbg(info->device, " * update DMA engine\n"); | ||
285 | atmel_lcdfb_update_dma(info, &info->var); | ||
286 | |||
287 | /* ...set frame size and burst length = 8 words (?) */ | ||
288 | value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32; | ||
289 | value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET); | ||
290 | lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value); | ||
291 | |||
292 | /* Now, the LCDC core... */ | ||
293 | |||
294 | /* Set pixel clock */ | ||
295 | clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; | ||
296 | |||
297 | value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock)); | ||
298 | |||
299 | value = (value / 2) - 1; | ||
300 | dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n", value); | ||
301 | |||
302 | if (value <= 0) { | ||
303 | dev_notice(info->device, "Bypassing pixel clock divider\n"); | ||
304 | lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS); | ||
305 | } else { | ||
306 | lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, value << ATMEL_LCDC_CLKVAL_OFFSET); | ||
307 | info->var.pixclock = KHZ2PICOS(clk_value_khz / (2 * (value + 1))); | ||
308 | dev_dbg(info->device, " updated pixclk: %lu KHz\n", | ||
309 | PICOS2KHZ(info->var.pixclock)); | ||
310 | } | ||
311 | |||
312 | |||
313 | /* Initialize control register 2 */ | ||
314 | value = sinfo->default_lcdcon2; | ||
315 | |||
316 | if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) | ||
317 | value |= ATMEL_LCDC_INVLINE_INVERTED; | ||
318 | if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) | ||
319 | value |= ATMEL_LCDC_INVFRAME_INVERTED; | ||
320 | |||
321 | switch (info->var.bits_per_pixel) { | ||
322 | case 1: value |= ATMEL_LCDC_PIXELSIZE_1; break; | ||
323 | case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break; | ||
324 | case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break; | ||
325 | case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break; | ||
326 | case 15: /* fall through */ | ||
327 | case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break; | ||
328 | case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break; | ||
329 | case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break; | ||
330 | default: BUG(); break; | ||
331 | } | ||
332 | dev_dbg(info->device, " * LCDCON2 = %08lx\n", value); | ||
333 | lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value); | ||
334 | |||
335 | /* Vertical timing */ | ||
336 | value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET; | ||
337 | value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET; | ||
338 | value |= info->var.lower_margin; | ||
339 | dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value); | ||
340 | lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value); | ||
341 | |||
342 | /* Horizontal timing */ | ||
343 | value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET; | ||
344 | value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET; | ||
345 | value |= (info->var.left_margin - 1); | ||
346 | dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value); | ||
347 | lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value); | ||
348 | |||
349 | /* Horizontal value (aka line size) */ | ||
350 | hozval_linesz = compute_hozval(info->var.xres, | ||
351 | lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2)); | ||
352 | |||
353 | /* Display size */ | ||
354 | value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET; | ||
355 | value |= info->var.yres - 1; | ||
356 | dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value); | ||
357 | lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value); | ||
358 | |||
359 | /* FIFO Threshold: Use formula from data sheet */ | ||
360 | value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3); | ||
361 | lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value); | ||
362 | |||
363 | /* Toggle LCD_MODE every frame */ | ||
364 | lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0); | ||
365 | |||
366 | /* Disable all interrupts */ | ||
367 | lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); | ||
368 | |||
369 | /* Set contrast */ | ||
370 | value = ATMEL_LCDC_PS_DIV8 | ATMEL_LCDC_POL_POSITIVE | ATMEL_LCDC_ENA_PWMENABLE; | ||
371 | lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, value); | ||
372 | lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT); | ||
373 | /* ...wait for DMA engine to become idle... */ | ||
374 | while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) | ||
375 | msleep(10); | ||
376 | |||
377 | dev_dbg(info->device, " * re-enable DMA engine\n"); | ||
378 | /* ...and enable it with updated configuration */ | ||
379 | lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon); | ||
380 | |||
381 | dev_dbg(info->device, " * re-enable LCDC core\n"); | ||
382 | lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, | ||
383 | (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR); | ||
384 | |||
385 | dev_dbg(info->device, " * DONE\n"); | ||
386 | |||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | static inline unsigned int chan_to_field(unsigned int chan, const struct fb_bitfield *bf) | ||
391 | { | ||
392 | chan &= 0xffff; | ||
393 | chan >>= 16 - bf->length; | ||
394 | return chan << bf->offset; | ||
395 | } | ||
396 | |||
397 | /** | ||
398 | * atmel_lcdfb_setcolreg - Optional function. Sets a color register. | ||
399 | * @regno: Which register in the CLUT we are programming | ||
400 | * @red: The red value which can be up to 16 bits wide | ||
401 | * @green: The green value which can be up to 16 bits wide | ||
402 | * @blue: The blue value which can be up to 16 bits wide. | ||
403 | * @transp: If supported the alpha value which can be up to 16 bits wide. | ||
404 | * @info: frame buffer info structure | ||
405 | * | ||
406 | * Set a single color register. The values supplied have a 16 bit | ||
407 | * magnitude which needs to be scaled in this function for the hardware. | ||
408 | * Things to take into consideration are how many color registers, if | ||
409 | * any, are supported with the current color visual. With truecolor mode | ||
410 | * no color palettes are supported. Here a psuedo palette is created | ||
411 | * which we store the value in pseudo_palette in struct fb_info. For | ||
412 | * pseudocolor mode we have a limited color palette. To deal with this | ||
413 | * we can program what color is displayed for a particular pixel value. | ||
414 | * DirectColor is similar in that we can program each color field. If | ||
415 | * we have a static colormap we don't need to implement this function. | ||
416 | * | ||
417 | * Returns negative errno on error, or zero on success. In an | ||
418 | * ideal world, this would have been the case, but as it turns | ||
419 | * out, the other drivers return 1 on failure, so that's what | ||
420 | * we're going to do. | ||
421 | */ | ||
422 | static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red, | ||
423 | unsigned int green, unsigned int blue, | ||
424 | unsigned int transp, struct fb_info *info) | ||
425 | { | ||
426 | struct atmel_lcdfb_info *sinfo = info->par; | ||
427 | unsigned int val; | ||
428 | u32 *pal; | ||
429 | int ret = 1; | ||
430 | |||
431 | if (info->var.grayscale) | ||
432 | red = green = blue = (19595 * red + 38470 * green | ||
433 | + 7471 * blue) >> 16; | ||
434 | |||
435 | switch (info->fix.visual) { | ||
436 | case FB_VISUAL_TRUECOLOR: | ||
437 | if (regno < 16) { | ||
438 | pal = info->pseudo_palette; | ||
439 | |||
440 | val = chan_to_field(red, &info->var.red); | ||
441 | val |= chan_to_field(green, &info->var.green); | ||
442 | val |= chan_to_field(blue, &info->var.blue); | ||
443 | |||
444 | pal[regno] = val; | ||
445 | ret = 0; | ||
446 | } | ||
447 | break; | ||
448 | |||
449 | case FB_VISUAL_PSEUDOCOLOR: | ||
450 | if (regno < 256) { | ||
451 | val = ((red >> 11) & 0x001f); | ||
452 | val |= ((green >> 6) & 0x03e0); | ||
453 | val |= ((blue >> 1) & 0x7c00); | ||
454 | |||
455 | /* | ||
456 | * TODO: intensity bit. Maybe something like | ||
457 | * ~(red[10] ^ green[10] ^ blue[10]) & 1 | ||
458 | */ | ||
459 | |||
460 | lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val); | ||
461 | ret = 0; | ||
462 | } | ||
463 | break; | ||
464 | |||
465 | case FB_VISUAL_MONO01: | ||
466 | if (regno < 2) { | ||
467 | val = (regno == 0) ? 0x00 : 0x1F; | ||
468 | lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val); | ||
469 | ret = 0; | ||
470 | } | ||
471 | break; | ||
472 | |||
473 | } | ||
474 | |||
475 | return ret; | ||
476 | } | ||
477 | |||
478 | static int atmel_lcdfb_pan_display(struct fb_var_screeninfo *var, | ||
479 | struct fb_info *info) | ||
480 | { | ||
481 | dev_dbg(info->device, "%s\n", __func__); | ||
482 | |||
483 | atmel_lcdfb_update_dma(info, var); | ||
484 | |||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | static struct fb_ops atmel_lcdfb_ops = { | ||
489 | .owner = THIS_MODULE, | ||
490 | .fb_check_var = atmel_lcdfb_check_var, | ||
491 | .fb_set_par = atmel_lcdfb_set_par, | ||
492 | .fb_setcolreg = atmel_lcdfb_setcolreg, | ||
493 | .fb_pan_display = atmel_lcdfb_pan_display, | ||
494 | .fb_fillrect = cfb_fillrect, | ||
495 | .fb_copyarea = cfb_copyarea, | ||
496 | .fb_imageblit = cfb_imageblit, | ||
497 | }; | ||
498 | |||
499 | static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id) | ||
500 | { | ||
501 | struct fb_info *info = dev_id; | ||
502 | struct atmel_lcdfb_info *sinfo = info->par; | ||
503 | u32 status; | ||
504 | |||
505 | status = lcdc_readl(sinfo, ATMEL_LCDC_ISR); | ||
506 | lcdc_writel(sinfo, ATMEL_LCDC_IDR, status); | ||
507 | return IRQ_HANDLED; | ||
508 | } | ||
509 | |||
510 | static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo) | ||
511 | { | ||
512 | struct fb_info *info = sinfo->info; | ||
513 | int ret = 0; | ||
514 | |||
515 | memset_io(info->screen_base, 0, info->fix.smem_len); | ||
516 | info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW; | ||
517 | |||
518 | dev_info(info->device, | ||
519 | "%luKiB frame buffer at %08lx (mapped at %p)\n", | ||
520 | (unsigned long)info->fix.smem_len / 1024, | ||
521 | (unsigned long)info->fix.smem_start, | ||
522 | info->screen_base); | ||
523 | |||
524 | /* Allocate colormap */ | ||
525 | ret = fb_alloc_cmap(&info->cmap, 256, 0); | ||
526 | if (ret < 0) | ||
527 | dev_err(info->device, "Alloc color map failed\n"); | ||
528 | |||
529 | return ret; | ||
530 | } | ||
531 | |||
532 | static void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo) | ||
533 | { | ||
534 | if (sinfo->bus_clk) | ||
535 | clk_enable(sinfo->bus_clk); | ||
536 | clk_enable(sinfo->lcdc_clk); | ||
537 | } | ||
538 | |||
539 | static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo) | ||
540 | { | ||
541 | if (sinfo->bus_clk) | ||
542 | clk_disable(sinfo->bus_clk); | ||
543 | clk_disable(sinfo->lcdc_clk); | ||
544 | } | ||
545 | |||
546 | |||
547 | static int __init atmel_lcdfb_probe(struct platform_device *pdev) | ||
548 | { | ||
549 | struct device *dev = &pdev->dev; | ||
550 | struct fb_info *info; | ||
551 | struct atmel_lcdfb_info *sinfo; | ||
552 | struct atmel_lcdfb_info *pdata_sinfo; | ||
553 | struct resource *regs = NULL; | ||
554 | struct resource *map = NULL; | ||
555 | int ret; | ||
556 | |||
557 | dev_dbg(dev, "%s BEGIN\n", __func__); | ||
558 | |||
559 | ret = -ENOMEM; | ||
560 | info = framebuffer_alloc(sizeof(struct atmel_lcdfb_info), dev); | ||
561 | if (!info) { | ||
562 | dev_err(dev, "cannot allocate memory\n"); | ||
563 | goto out; | ||
564 | } | ||
565 | |||
566 | sinfo = info->par; | ||
567 | |||
568 | if (dev->platform_data) { | ||
569 | pdata_sinfo = (struct atmel_lcdfb_info *)dev->platform_data; | ||
570 | sinfo->default_bpp = pdata_sinfo->default_bpp; | ||
571 | sinfo->default_dmacon = pdata_sinfo->default_dmacon; | ||
572 | sinfo->default_lcdcon2 = pdata_sinfo->default_lcdcon2; | ||
573 | sinfo->default_monspecs = pdata_sinfo->default_monspecs; | ||
574 | sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control; | ||
575 | sinfo->guard_time = pdata_sinfo->guard_time; | ||
576 | } else { | ||
577 | dev_err(dev, "cannot get default configuration\n"); | ||
578 | goto free_info; | ||
579 | } | ||
580 | sinfo->info = info; | ||
581 | sinfo->pdev = pdev; | ||
582 | |||
583 | strcpy(info->fix.id, sinfo->pdev->name); | ||
584 | info->flags = ATMEL_LCDFB_FBINFO_DEFAULT; | ||
585 | info->pseudo_palette = sinfo->pseudo_palette; | ||
586 | info->fbops = &atmel_lcdfb_ops; | ||
587 | |||
588 | memcpy(&info->monspecs, sinfo->default_monspecs, sizeof(info->monspecs)); | ||
589 | info->fix = atmel_lcdfb_fix; | ||
590 | |||
591 | /* Enable LCDC Clocks */ | ||
592 | if (cpu_is_at91sam9261() || cpu_is_at32ap7000()) { | ||
593 | sinfo->bus_clk = clk_get(dev, "hck1"); | ||
594 | if (IS_ERR(sinfo->bus_clk)) { | ||
595 | ret = PTR_ERR(sinfo->bus_clk); | ||
596 | goto free_info; | ||
597 | } | ||
598 | } | ||
599 | sinfo->lcdc_clk = clk_get(dev, "lcdc_clk"); | ||
600 | if (IS_ERR(sinfo->lcdc_clk)) { | ||
601 | ret = PTR_ERR(sinfo->lcdc_clk); | ||
602 | goto put_bus_clk; | ||
603 | } | ||
604 | atmel_lcdfb_start_clock(sinfo); | ||
605 | |||
606 | ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb, | ||
607 | info->monspecs.modedb_len, info->monspecs.modedb, | ||
608 | sinfo->default_bpp); | ||
609 | if (!ret) { | ||
610 | dev_err(dev, "no suitable video mode found\n"); | ||
611 | goto stop_clk; | ||
612 | } | ||
613 | |||
614 | |||
615 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
616 | if (!regs) { | ||
617 | dev_err(dev, "resources unusable\n"); | ||
618 | ret = -ENXIO; | ||
619 | goto stop_clk; | ||
620 | } | ||
621 | |||
622 | sinfo->irq_base = platform_get_irq(pdev, 0); | ||
623 | if (sinfo->irq_base < 0) { | ||
624 | dev_err(dev, "unable to get irq\n"); | ||
625 | ret = sinfo->irq_base; | ||
626 | goto stop_clk; | ||
627 | } | ||
628 | |||
629 | /* Initialize video memory */ | ||
630 | map = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
631 | if (map) { | ||
632 | /* use a pre-allocated memory buffer */ | ||
633 | info->fix.smem_start = map->start; | ||
634 | info->fix.smem_len = map->end - map->start + 1; | ||
635 | if (!request_mem_region(info->fix.smem_start, | ||
636 | info->fix.smem_len, pdev->name)) { | ||
637 | ret = -EBUSY; | ||
638 | goto stop_clk; | ||
639 | } | ||
640 | |||
641 | info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); | ||
642 | if (!info->screen_base) | ||
643 | goto release_intmem; | ||
644 | } else { | ||
645 | /* alocate memory buffer */ | ||
646 | ret = atmel_lcdfb_alloc_video_memory(sinfo); | ||
647 | if (ret < 0) { | ||
648 | dev_err(dev, "cannot allocate framebuffer: %d\n", ret); | ||
649 | goto stop_clk; | ||
650 | } | ||
651 | } | ||
652 | |||
653 | /* LCDC registers */ | ||
654 | info->fix.mmio_start = regs->start; | ||
655 | info->fix.mmio_len = regs->end - regs->start + 1; | ||
656 | |||
657 | if (!request_mem_region(info->fix.mmio_start, | ||
658 | info->fix.mmio_len, pdev->name)) { | ||
659 | ret = -EBUSY; | ||
660 | goto free_fb; | ||
661 | } | ||
662 | |||
663 | sinfo->mmio = ioremap(info->fix.mmio_start, info->fix.mmio_len); | ||
664 | if (!sinfo->mmio) { | ||
665 | dev_err(dev, "cannot map LCDC registers\n"); | ||
666 | goto release_mem; | ||
667 | } | ||
668 | |||
669 | /* interrupt */ | ||
670 | ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info); | ||
671 | if (ret) { | ||
672 | dev_err(dev, "request_irq failed: %d\n", ret); | ||
673 | goto unmap_mmio; | ||
674 | } | ||
675 | |||
676 | ret = atmel_lcdfb_init_fbinfo(sinfo); | ||
677 | if (ret < 0) { | ||
678 | dev_err(dev, "init fbinfo failed: %d\n", ret); | ||
679 | goto unregister_irqs; | ||
680 | } | ||
681 | |||
682 | /* | ||
683 | * This makes sure that our colour bitfield | ||
684 | * descriptors are correctly initialised. | ||
685 | */ | ||
686 | atmel_lcdfb_check_var(&info->var, info); | ||
687 | |||
688 | ret = fb_set_var(info, &info->var); | ||
689 | if (ret) { | ||
690 | dev_warn(dev, "unable to set display parameters\n"); | ||
691 | goto free_cmap; | ||
692 | } | ||
693 | |||
694 | dev_set_drvdata(dev, info); | ||
695 | |||
696 | /* | ||
697 | * Tell the world that we're ready to go | ||
698 | */ | ||
699 | ret = register_framebuffer(info); | ||
700 | if (ret < 0) { | ||
701 | dev_err(dev, "failed to register framebuffer device: %d\n", ret); | ||
702 | goto free_cmap; | ||
703 | } | ||
704 | |||
705 | /* Power up the LCDC screen */ | ||
706 | if (sinfo->atmel_lcdfb_power_control) | ||
707 | sinfo->atmel_lcdfb_power_control(1); | ||
708 | |||
709 | dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %lu\n", | ||
710 | info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base); | ||
711 | |||
712 | return 0; | ||
713 | |||
714 | |||
715 | free_cmap: | ||
716 | fb_dealloc_cmap(&info->cmap); | ||
717 | unregister_irqs: | ||
718 | free_irq(sinfo->irq_base, info); | ||
719 | unmap_mmio: | ||
720 | iounmap(sinfo->mmio); | ||
721 | release_mem: | ||
722 | release_mem_region(info->fix.mmio_start, info->fix.mmio_len); | ||
723 | free_fb: | ||
724 | if (map) | ||
725 | iounmap(info->screen_base); | ||
726 | else | ||
727 | atmel_lcdfb_free_video_memory(sinfo); | ||
728 | |||
729 | release_intmem: | ||
730 | if (map) | ||
731 | release_mem_region(info->fix.smem_start, info->fix.smem_len); | ||
732 | stop_clk: | ||
733 | atmel_lcdfb_stop_clock(sinfo); | ||
734 | clk_put(sinfo->lcdc_clk); | ||
735 | put_bus_clk: | ||
736 | if (sinfo->bus_clk) | ||
737 | clk_put(sinfo->bus_clk); | ||
738 | free_info: | ||
739 | framebuffer_release(info); | ||
740 | out: | ||
741 | dev_dbg(dev, "%s FAILED\n", __func__); | ||
742 | return ret; | ||
743 | } | ||
744 | |||
745 | static int __exit atmel_lcdfb_remove(struct platform_device *pdev) | ||
746 | { | ||
747 | struct device *dev = &pdev->dev; | ||
748 | struct fb_info *info = dev_get_drvdata(dev); | ||
749 | struct atmel_lcdfb_info *sinfo = info->par; | ||
750 | |||
751 | if (!sinfo) | ||
752 | return 0; | ||
753 | |||
754 | if (sinfo->atmel_lcdfb_power_control) | ||
755 | sinfo->atmel_lcdfb_power_control(0); | ||
756 | unregister_framebuffer(info); | ||
757 | atmel_lcdfb_stop_clock(sinfo); | ||
758 | clk_put(sinfo->lcdc_clk); | ||
759 | if (sinfo->bus_clk) | ||
760 | clk_put(sinfo->bus_clk); | ||
761 | fb_dealloc_cmap(&info->cmap); | ||
762 | free_irq(sinfo->irq_base, info); | ||
763 | iounmap(sinfo->mmio); | ||
764 | release_mem_region(info->fix.mmio_start, info->fix.mmio_len); | ||
765 | if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) { | ||
766 | iounmap(info->screen_base); | ||
767 | release_mem_region(info->fix.smem_start, info->fix.smem_len); | ||
768 | } else { | ||
769 | atmel_lcdfb_free_video_memory(sinfo); | ||
770 | } | ||
771 | |||
772 | dev_set_drvdata(dev, NULL); | ||
773 | framebuffer_release(info); | ||
774 | |||
775 | return 0; | ||
776 | } | ||
777 | |||
778 | static struct platform_driver atmel_lcdfb_driver = { | ||
779 | .remove = __exit_p(atmel_lcdfb_remove), | ||
780 | .driver = { | ||
781 | .name = "atmel_lcdfb", | ||
782 | .owner = THIS_MODULE, | ||
783 | }, | ||
784 | }; | ||
785 | |||
786 | static int __init atmel_lcdfb_init(void) | ||
787 | { | ||
788 | return platform_driver_probe(&atmel_lcdfb_driver, atmel_lcdfb_probe); | ||
789 | } | ||
790 | |||
791 | static void __exit atmel_lcdfb_exit(void) | ||
792 | { | ||
793 | platform_driver_unregister(&atmel_lcdfb_driver); | ||
794 | } | ||
795 | |||
796 | module_init(atmel_lcdfb_init); | ||
797 | module_exit(atmel_lcdfb_exit); | ||
798 | |||
799 | MODULE_DESCRIPTION("AT91/AT32 LCD Controller framebuffer driver"); | ||
800 | MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@rfo.atmel.com>"); | ||
801 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/aty/ati_ids.h b/drivers/video/aty/ati_ids.h index 90e7df22f508..685a754991c6 100644 --- a/drivers/video/aty/ati_ids.h +++ b/drivers/video/aty/ati_ids.h | |||
@@ -204,6 +204,7 @@ | |||
204 | #define PCI_CHIP_RV280_5961 0x5961 | 204 | #define PCI_CHIP_RV280_5961 0x5961 |
205 | #define PCI_CHIP_RV280_5962 0x5962 | 205 | #define PCI_CHIP_RV280_5962 0x5962 |
206 | #define PCI_CHIP_RV280_5964 0x5964 | 206 | #define PCI_CHIP_RV280_5964 0x5964 |
207 | #define PCI_CHIP_RS485_5975 0x5975 | ||
207 | #define PCI_CHIP_RV280_5C61 0x5C61 | 208 | #define PCI_CHIP_RV280_5C61 0x5C61 |
208 | #define PCI_CHIP_RV280_5C63 0x5C63 | 209 | #define PCI_CHIP_RV280_5C63 0x5C63 |
209 | #define PCI_CHIP_R423_5D57 0x5D57 | 210 | #define PCI_CHIP_R423_5D57 0x5D57 |
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 8d3455da663a..13990697b5c1 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c | |||
@@ -541,7 +541,7 @@ static char ram_off[] __devinitdata = "OFF"; | |||
541 | #endif /* CONFIG_FB_ATY_CT */ | 541 | #endif /* CONFIG_FB_ATY_CT */ |
542 | 542 | ||
543 | 543 | ||
544 | static u32 pseudo_palette[17]; | 544 | static u32 pseudo_palette[16]; |
545 | 545 | ||
546 | #ifdef CONFIG_FB_ATY_GX | 546 | #ifdef CONFIG_FB_ATY_GX |
547 | static char *aty_gx_ram[8] __devinitdata = { | 547 | static char *aty_gx_ram[8] __devinitdata = { |
@@ -2290,15 +2290,6 @@ static int __devinit aty_init(struct fb_info *info) | |||
2290 | init_waitqueue_head(&par->vblank.wait); | 2290 | init_waitqueue_head(&par->vblank.wait); |
2291 | spin_lock_init(&par->int_lock); | 2291 | spin_lock_init(&par->int_lock); |
2292 | 2292 | ||
2293 | #ifdef CONFIG_PPC_PMAC | ||
2294 | /* The Apple iBook1 uses non-standard memory frequencies. We detect it | ||
2295 | * and set the frequency manually. */ | ||
2296 | if (machine_is_compatible("PowerBook2,1")) { | ||
2297 | par->pll_limits.mclk = 70; | ||
2298 | par->pll_limits.xclk = 53; | ||
2299 | } | ||
2300 | #endif | ||
2301 | |||
2302 | #ifdef CONFIG_FB_ATY_GX | 2293 | #ifdef CONFIG_FB_ATY_GX |
2303 | if (!M64_HAS(INTEGRATED)) { | 2294 | if (!M64_HAS(INTEGRATED)) { |
2304 | u32 stat0; | 2295 | u32 stat0; |
@@ -2383,6 +2374,14 @@ static int __devinit aty_init(struct fb_info *info) | |||
2383 | par->pll_limits.xclk = (par->pll_limits.xclk + 1) >> 1; | 2374 | par->pll_limits.xclk = (par->pll_limits.xclk + 1) >> 1; |
2384 | } | 2375 | } |
2385 | #endif | 2376 | #endif |
2377 | #ifdef CONFIG_PPC_PMAC | ||
2378 | /* The Apple iBook1 uses non-standard memory frequencies. We detect it | ||
2379 | * and set the frequency manually. */ | ||
2380 | if (machine_is_compatible("PowerBook2,1")) { | ||
2381 | par->pll_limits.mclk = 70; | ||
2382 | par->pll_limits.xclk = 53; | ||
2383 | } | ||
2384 | #endif | ||
2386 | 2385 | ||
2387 | /* Allow command line to override clocks. */ | 2386 | /* Allow command line to override clocks. */ |
2388 | if (pll) | 2387 | if (pll) |
@@ -2914,10 +2913,6 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev, | |||
2914 | int node, len, i, j, ret; | 2913 | int node, len, i, j, ret; |
2915 | u32 mem, chip_id; | 2914 | u32 mem, chip_id; |
2916 | 2915 | ||
2917 | /* Do not attach when we have a serial console. */ | ||
2918 | if (!con_is_present()) | ||
2919 | return -ENXIO; | ||
2920 | |||
2921 | /* | 2916 | /* |
2922 | * Map memory-mapped registers. | 2917 | * Map memory-mapped registers. |
2923 | */ | 2918 | */ |
@@ -2938,12 +2933,11 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev, | |||
2938 | /* nothing */ ; | 2933 | /* nothing */ ; |
2939 | j = i + 4; | 2934 | j = i + 4; |
2940 | 2935 | ||
2941 | par->mmap_map = kmalloc(j * sizeof(*par->mmap_map), GFP_ATOMIC); | 2936 | par->mmap_map = kcalloc(j, sizeof(*par->mmap_map), GFP_ATOMIC); |
2942 | if (!par->mmap_map) { | 2937 | if (!par->mmap_map) { |
2943 | PRINTKE("atyfb_setup_sparc() can't alloc mmap_map\n"); | 2938 | PRINTKE("atyfb_setup_sparc() can't alloc mmap_map\n"); |
2944 | return -ENOMEM; | 2939 | return -ENOMEM; |
2945 | } | 2940 | } |
2946 | memset(par->mmap_map, 0, j * sizeof(*par->mmap_map)); | ||
2947 | 2941 | ||
2948 | for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) { | 2942 | for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) { |
2949 | struct resource *rp = &pdev->resource[i]; | 2943 | struct resource *rp = &pdev->resource[i]; |
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index 2ce050193018..47ca62fe7c3e 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c | |||
@@ -153,6 +153,8 @@ static struct pci_device_id radeonfb_pci_table[] = { | |||
153 | /* Mobility 9200 (M9+) */ | 153 | /* Mobility 9200 (M9+) */ |
154 | CHIP_DEF(PCI_CHIP_RV280_5C61, RV280, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), | 154 | CHIP_DEF(PCI_CHIP_RV280_5C61, RV280, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), |
155 | CHIP_DEF(PCI_CHIP_RV280_5C63, RV280, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), | 155 | CHIP_DEF(PCI_CHIP_RV280_5C63, RV280, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY), |
156 | /*Mobility Xpress 200 */ | ||
157 | CHIP_DEF(PCI_CHIP_RS485_5975, R300, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), | ||
156 | /* 9200 */ | 158 | /* 9200 */ |
157 | CHIP_DEF(PCI_CHIP_RV280_5960, RV280, CHIP_HAS_CRTC2), | 159 | CHIP_DEF(PCI_CHIP_RV280_5960, RV280, CHIP_HAS_CRTC2), |
158 | CHIP_DEF(PCI_CHIP_RV280_5961, RV280, CHIP_HAS_CRTC2), | 160 | CHIP_DEF(PCI_CHIP_RV280_5961, RV280, CHIP_HAS_CRTC2), |
@@ -2102,7 +2104,9 @@ static ssize_t radeon_show_one_edid(char *buf, loff_t off, size_t count, const u | |||
2102 | } | 2104 | } |
2103 | 2105 | ||
2104 | 2106 | ||
2105 | static ssize_t radeon_show_edid1(struct kobject *kobj, char *buf, loff_t off, size_t count) | 2107 | static ssize_t radeon_show_edid1(struct kobject *kobj, |
2108 | struct bin_attribute *bin_attr, | ||
2109 | char *buf, loff_t off, size_t count) | ||
2106 | { | 2110 | { |
2107 | struct device *dev = container_of(kobj, struct device, kobj); | 2111 | struct device *dev = container_of(kobj, struct device, kobj); |
2108 | struct pci_dev *pdev = to_pci_dev(dev); | 2112 | struct pci_dev *pdev = to_pci_dev(dev); |
@@ -2113,7 +2117,9 @@ static ssize_t radeon_show_edid1(struct kobject *kobj, char *buf, loff_t off, si | |||
2113 | } | 2117 | } |
2114 | 2118 | ||
2115 | 2119 | ||
2116 | static ssize_t radeon_show_edid2(struct kobject *kobj, char *buf, loff_t off, size_t count) | 2120 | static ssize_t radeon_show_edid2(struct kobject *kobj, |
2121 | struct bin_attribute *bin_attr, | ||
2122 | char *buf, loff_t off, size_t count) | ||
2117 | { | 2123 | { |
2118 | struct device *dev = container_of(kobj, struct device, kobj); | 2124 | struct device *dev = container_of(kobj, struct device, kobj); |
2119 | struct pci_dev *pdev = to_pci_dev(dev); | 2125 | struct pci_dev *pdev = to_pci_dev(dev); |
@@ -2126,7 +2132,6 @@ static ssize_t radeon_show_edid2(struct kobject *kobj, char *buf, loff_t off, si | |||
2126 | static struct bin_attribute edid1_attr = { | 2132 | static struct bin_attribute edid1_attr = { |
2127 | .attr = { | 2133 | .attr = { |
2128 | .name = "edid1", | 2134 | .name = "edid1", |
2129 | .owner = THIS_MODULE, | ||
2130 | .mode = 0444, | 2135 | .mode = 0444, |
2131 | }, | 2136 | }, |
2132 | .size = EDID_LENGTH, | 2137 | .size = EDID_LENGTH, |
@@ -2136,7 +2141,6 @@ static struct bin_attribute edid1_attr = { | |||
2136 | static struct bin_attribute edid2_attr = { | 2141 | static struct bin_attribute edid2_attr = { |
2137 | .attr = { | 2142 | .attr = { |
2138 | .name = "edid2", | 2143 | .name = "edid2", |
2139 | .owner = THIS_MODULE, | ||
2140 | .mode = 0444, | 2144 | .mode = 0444, |
2141 | }, | 2145 | }, |
2142 | .size = EDID_LENGTH, | 2146 | .size = EDID_LENGTH, |
diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h index 7ebffcdfd1e3..7c922c7b460b 100644 --- a/drivers/video/aty/radeonfb.h +++ b/drivers/video/aty/radeonfb.h | |||
@@ -301,7 +301,7 @@ struct radeonfb_info { | |||
301 | void __iomem *bios_seg; | 301 | void __iomem *bios_seg; |
302 | int fp_bios_start; | 302 | int fp_bios_start; |
303 | 303 | ||
304 | u32 pseudo_palette[17]; | 304 | u32 pseudo_palette[16]; |
305 | struct { u8 red, green, blue, pad; } | 305 | struct { u8 red, green, blue, pad; } |
306 | palette[256]; | 306 | palette[256]; |
307 | 307 | ||
diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c index dbf4ec3f6d57..03e57ef88378 100644 --- a/drivers/video/au1200fb.c +++ b/drivers/video/au1200fb.c | |||
@@ -1589,11 +1589,10 @@ static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev) | |||
1589 | return -EFAULT; | 1589 | return -EFAULT; |
1590 | } | 1590 | } |
1591 | 1591 | ||
1592 | fbi->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); | 1592 | fbi->pseudo_palette = kcalloc(16, sizeof(u32), GFP_KERNEL); |
1593 | if (!fbi->pseudo_palette) { | 1593 | if (!fbi->pseudo_palette) { |
1594 | return -ENOMEM; | 1594 | return -ENOMEM; |
1595 | } | 1595 | } |
1596 | memset(fbi->pseudo_palette, 0, sizeof(u32) * 16); | ||
1597 | 1596 | ||
1598 | if (fb_alloc_cmap(&fbi->cmap, AU1200_LCD_NBR_PALETTE_ENTRIES, 0) < 0) { | 1597 | if (fb_alloc_cmap(&fbi->cmap, AU1200_LCD_NBR_PALETTE_ENTRIES, 0) < 0) { |
1599 | print_err("Fail to allocate colormap (%d entries)", | 1598 | print_err("Fail to allocate colormap (%d entries)", |
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index c65e81ff3578..7e06223bca94 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c | |||
@@ -172,7 +172,7 @@ static struct class backlight_class = { | |||
172 | 172 | ||
173 | #define DECLARE_ATTR(_name,_mode,_show,_store) \ | 173 | #define DECLARE_ATTR(_name,_mode,_show,_store) \ |
174 | { \ | 174 | { \ |
175 | .attr = { .name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \ | 175 | .attr = { .name = __stringify(_name), .mode = _mode }, \ |
176 | .show = _show, \ | 176 | .show = _show, \ |
177 | .store = _store, \ | 177 | .store = _store, \ |
178 | } | 178 | } |
diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c index e9bbc3455c94..1b3f6586bc9f 100644 --- a/drivers/video/backlight/cr_bllcd.c +++ b/drivers/video/backlight/cr_bllcd.c | |||
@@ -174,7 +174,7 @@ static int cr_backlight_probe(struct platform_device *pdev) | |||
174 | struct cr_panel *crp; | 174 | struct cr_panel *crp; |
175 | u8 dev_en; | 175 | u8 dev_en; |
176 | 176 | ||
177 | crp = kzalloc(sizeof(crp), GFP_KERNEL); | 177 | crp = kzalloc(sizeof(*crp), GFP_KERNEL); |
178 | if (crp == NULL) | 178 | if (crp == NULL) |
179 | return -ENOMEM; | 179 | return -ENOMEM; |
180 | 180 | ||
diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c index 6ef8f0a7a137..648b53c1fdea 100644 --- a/drivers/video/backlight/lcd.c +++ b/drivers/video/backlight/lcd.c | |||
@@ -157,7 +157,7 @@ static struct class lcd_class = { | |||
157 | 157 | ||
158 | #define DECLARE_ATTR(_name,_mode,_show,_store) \ | 158 | #define DECLARE_ATTR(_name,_mode,_show,_store) \ |
159 | { \ | 159 | { \ |
160 | .attr = { .name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \ | 160 | .attr = { .name = __stringify(_name), .mode = _mode }, \ |
161 | .show = _show, \ | 161 | .show = _show, \ |
162 | .store = _store, \ | 162 | .store = _store, \ |
163 | } | 163 | } |
diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c index af313bf1a2da..f48e8c534c87 100644 --- a/drivers/video/chipsfb.c +++ b/drivers/video/chipsfb.c | |||
@@ -292,7 +292,7 @@ static void __init chips_hw_init(void) | |||
292 | write_fr(chips_init_fr[i].addr, chips_init_fr[i].data); | 292 | write_fr(chips_init_fr[i].addr, chips_init_fr[i].data); |
293 | } | 293 | } |
294 | 294 | ||
295 | static struct fb_fix_screeninfo chipsfb_fix __initdata = { | 295 | static struct fb_fix_screeninfo chipsfb_fix __devinitdata = { |
296 | .id = "C&T 65550", | 296 | .id = "C&T 65550", |
297 | .type = FB_TYPE_PACKED_PIXELS, | 297 | .type = FB_TYPE_PACKED_PIXELS, |
298 | .visual = FB_VISUAL_PSEUDOCOLOR, | 298 | .visual = FB_VISUAL_PSEUDOCOLOR, |
@@ -309,7 +309,7 @@ static struct fb_fix_screeninfo chipsfb_fix __initdata = { | |||
309 | .smem_len = 0x100000, /* 1MB */ | 309 | .smem_len = 0x100000, /* 1MB */ |
310 | }; | 310 | }; |
311 | 311 | ||
312 | static struct fb_var_screeninfo chipsfb_var __initdata = { | 312 | static struct fb_var_screeninfo chipsfb_var __devinitdata = { |
313 | .xres = 800, | 313 | .xres = 800, |
314 | .yres = 600, | 314 | .yres = 600, |
315 | .xres_virtual = 800, | 315 | .xres_virtual = 800, |
@@ -330,7 +330,7 @@ static struct fb_var_screeninfo chipsfb_var __initdata = { | |||
330 | .vsync_len = 8, | 330 | .vsync_len = 8, |
331 | }; | 331 | }; |
332 | 332 | ||
333 | static void __init init_chips(struct fb_info *p, unsigned long addr) | 333 | static void __devinit init_chips(struct fb_info *p, unsigned long addr) |
334 | { | 334 | { |
335 | memset(p->screen_base, 0, 0x100000); | 335 | memset(p->screen_base, 0, 0x100000); |
336 | 336 | ||
diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c index 50b78af0fa24..dea6579941b7 100644 --- a/drivers/video/clps711xfb.c +++ b/drivers/video/clps711xfb.c | |||
@@ -366,11 +366,10 @@ int __init clps711xfb_init(void) | |||
366 | if (fb_get_options("clps711xfb", NULL)) | 366 | if (fb_get_options("clps711xfb", NULL)) |
367 | return -ENODEV; | 367 | return -ENODEV; |
368 | 368 | ||
369 | cfb = kmalloc(sizeof(*cfb), GFP_KERNEL); | 369 | cfb = kzalloc(sizeof(*cfb), GFP_KERNEL); |
370 | if (!cfb) | 370 | if (!cfb) |
371 | goto out; | 371 | goto out; |
372 | 372 | ||
373 | memset(cfb, 0, sizeof(*cfb)); | ||
374 | strcpy(cfb->fix.id, "clps711x"); | 373 | strcpy(cfb->fix.id, "clps711x"); |
375 | 374 | ||
376 | cfb->fbops = &clps7111fb_ops; | 375 | cfb->fbops = &clps7111fb_ops; |
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index aa3935df852a..49643969f9f8 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig | |||
@@ -6,7 +6,7 @@ menu "Console display driver support" | |||
6 | 6 | ||
7 | config VGA_CONSOLE | 7 | config VGA_CONSOLE |
8 | bool "VGA text console" if EMBEDDED || !X86 | 8 | bool "VGA text console" if EMBEDDED || !X86 |
9 | depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH | 9 | depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH && !BFIN |
10 | default y | 10 | default y |
11 | help | 11 | help |
12 | Saying Y here will allow you to use Linux in text mode through a | 12 | Saying Y here will allow you to use Linux in text mode through a |
@@ -19,13 +19,6 @@ config VGA_CONSOLE | |||
19 | 19 | ||
20 | Say Y. | 20 | Say Y. |
21 | 21 | ||
22 | # if [ "$CONFIG_PCI" = "y" -a "$CONFIG_VGA_CONSOLE" = "y" ]; then | ||
23 | # bool ' Allow VGA on any bus?' CONFIG_VGA_HOSE | ||
24 | # if [ "$CONFIG_VGA_HOSE" = "y" ]; then | ||
25 | # define_bool CONFIG_DUMMY_CONSOLE y | ||
26 | # fi | ||
27 | # fi | ||
28 | |||
29 | config VGACON_SOFT_SCROLLBACK | 22 | config VGACON_SOFT_SCROLLBACK |
30 | bool "Enable Scrollback Buffer in System RAM" | 23 | bool "Enable Scrollback Buffer in System RAM" |
31 | depends on VGA_CONSOLE | 24 | depends on VGA_CONSOLE |
@@ -125,6 +118,22 @@ config FRAMEBUFFER_CONSOLE | |||
125 | help | 118 | help |
126 | Low-level framebuffer-based console driver. | 119 | Low-level framebuffer-based console driver. |
127 | 120 | ||
121 | config FRAMEBUFFER_CONSOLE_DETECT_PRIMARY | ||
122 | bool "Map the console to the primary display device" | ||
123 | depends on FRAMEBUFFER_CONSOLE | ||
124 | default n | ||
125 | ---help--- | ||
126 | If this option is selected, the framebuffer console will | ||
127 | automatically select the primary display device (if the architecture | ||
128 | supports this feature). Otherwise, the framebuffer console will | ||
129 | always select the first framebuffer driver that is loaded. The latter | ||
130 | is the default behavior. | ||
131 | |||
132 | You can always override the automatic selection of the primary device | ||
133 | by using the fbcon=map: boot option. | ||
134 | |||
135 | If unsure, select n. | ||
136 | |||
128 | config FRAMEBUFFER_CONSOLE_ROTATION | 137 | config FRAMEBUFFER_CONSOLE_ROTATION |
129 | bool "Framebuffer Console Rotation" | 138 | bool "Framebuffer Console Rotation" |
130 | depends on FRAMEBUFFER_CONSOLE | 139 | depends on FRAMEBUFFER_CONSOLE |
diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile index 9b26dda18a38..ac46cc3f6a2a 100644 --- a/drivers/video/console/Makefile +++ b/drivers/video/console/Makefile | |||
@@ -47,7 +47,7 @@ targets := promcon_tbl.c | |||
47 | quiet_cmd_conmakehash = CNMKHSH $@ | 47 | quiet_cmd_conmakehash = CNMKHSH $@ |
48 | cmd_conmakehash = scripts/conmakehash $< | \ | 48 | cmd_conmakehash = scripts/conmakehash $< | \ |
49 | sed -e '/\#include <[^>]*>/p' -e 's/types/init/' \ | 49 | sed -e '/\#include <[^>]*>/p' -e 's/types/init/' \ |
50 | -e 's/dfont\(_uni.*\]\)/promfont\1 __initdata/' > $@ | 50 | -e 's/dfont\(_uni.*\]\)/promfont\1 /' > $@ |
51 | 51 | ||
52 | $(obj)/promcon_tbl.c: $(src)/prom.uni | 52 | $(obj)/promcon_tbl.c: $(src)/prom.uni |
53 | $(call cmd,conmakehash) | 53 | $(call cmd,conmakehash) |
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 73813c60d03a..decfdc8eb9cc 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c | |||
@@ -75,6 +75,7 @@ | |||
75 | #include <linux/init.h> | 75 | #include <linux/init.h> |
76 | #include <linux/interrupt.h> | 76 | #include <linux/interrupt.h> |
77 | #include <linux/crc32.h> /* For counting font checksums */ | 77 | #include <linux/crc32.h> /* For counting font checksums */ |
78 | #include <asm/fb.h> | ||
78 | #include <asm/irq.h> | 79 | #include <asm/irq.h> |
79 | #include <asm/system.h> | 80 | #include <asm/system.h> |
80 | #include <asm/uaccess.h> | 81 | #include <asm/uaccess.h> |
@@ -125,6 +126,8 @@ static int first_fb_vc; | |||
125 | static int last_fb_vc = MAX_NR_CONSOLES - 1; | 126 | static int last_fb_vc = MAX_NR_CONSOLES - 1; |
126 | static int fbcon_is_default = 1; | 127 | static int fbcon_is_default = 1; |
127 | static int fbcon_has_exited; | 128 | static int fbcon_has_exited; |
129 | static int primary_device = -1; | ||
130 | static int map_override; | ||
128 | 131 | ||
129 | /* font data */ | 132 | /* font data */ |
130 | static char fontname[40]; | 133 | static char fontname[40]; |
@@ -152,6 +155,7 @@ static int fbcon_set_origin(struct vc_data *); | |||
152 | #define DEFAULT_CURSOR_BLINK_RATE (20) | 155 | #define DEFAULT_CURSOR_BLINK_RATE (20) |
153 | 156 | ||
154 | static int vbl_cursor_cnt; | 157 | static int vbl_cursor_cnt; |
158 | static int fbcon_cursor_noblink; | ||
155 | 159 | ||
156 | #define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1) | 160 | #define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1) |
157 | 161 | ||
@@ -188,16 +192,14 @@ static __inline__ void ypan_down(struct vc_data *vc, int count); | |||
188 | static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx, | 192 | static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx, |
189 | int dy, int dx, int height, int width, u_int y_break); | 193 | int dy, int dx, int height, int width, u_int y_break); |
190 | static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, | 194 | static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, |
191 | struct vc_data *vc); | 195 | int unit); |
192 | static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *var, | ||
193 | int unit); | ||
194 | static void fbcon_redraw_move(struct vc_data *vc, struct display *p, | 196 | static void fbcon_redraw_move(struct vc_data *vc, struct display *p, |
195 | int line, int count, int dy); | 197 | int line, int count, int dy); |
196 | static void fbcon_modechanged(struct fb_info *info); | 198 | static void fbcon_modechanged(struct fb_info *info); |
197 | static void fbcon_set_all_vcs(struct fb_info *info); | 199 | static void fbcon_set_all_vcs(struct fb_info *info); |
198 | static void fbcon_start(void); | 200 | static void fbcon_start(void); |
199 | static void fbcon_exit(void); | 201 | static void fbcon_exit(void); |
200 | static struct class_device *fbcon_class_device; | 202 | static struct device *fbcon_device; |
201 | 203 | ||
202 | #ifdef CONFIG_MAC | 204 | #ifdef CONFIG_MAC |
203 | /* | 205 | /* |
@@ -441,7 +443,8 @@ static void fbcon_add_cursor_timer(struct fb_info *info) | |||
441 | struct fbcon_ops *ops = info->fbcon_par; | 443 | struct fbcon_ops *ops = info->fbcon_par; |
442 | 444 | ||
443 | if ((!info->queue.func || info->queue.func == fb_flashcursor) && | 445 | if ((!info->queue.func || info->queue.func == fb_flashcursor) && |
444 | !(ops->flags & FBCON_FLAGS_CURSOR_TIMER)) { | 446 | !(ops->flags & FBCON_FLAGS_CURSOR_TIMER) && |
447 | !fbcon_cursor_noblink) { | ||
445 | if (!info->queue.func) | 448 | if (!info->queue.func) |
446 | INIT_WORK(&info->queue, fb_flashcursor); | 449 | INIT_WORK(&info->queue, fb_flashcursor); |
447 | 450 | ||
@@ -495,13 +498,17 @@ static int __init fb_console_setup(char *this_opt) | |||
495 | 498 | ||
496 | if (!strncmp(options, "map:", 4)) { | 499 | if (!strncmp(options, "map:", 4)) { |
497 | options += 4; | 500 | options += 4; |
498 | if (*options) | 501 | if (*options) { |
499 | for (i = 0, j = 0; i < MAX_NR_CONSOLES; i++) { | 502 | for (i = 0, j = 0; i < MAX_NR_CONSOLES; i++) { |
500 | if (!options[j]) | 503 | if (!options[j]) |
501 | j = 0; | 504 | j = 0; |
502 | con2fb_map_boot[i] = | 505 | con2fb_map_boot[i] = |
503 | (options[j++]-'0') % FB_MAX; | 506 | (options[j++]-'0') % FB_MAX; |
504 | } | 507 | } |
508 | |||
509 | map_override = 1; | ||
510 | } | ||
511 | |||
505 | return 1; | 512 | return 1; |
506 | } | 513 | } |
507 | 514 | ||
@@ -736,7 +743,9 @@ static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info, | |||
736 | 743 | ||
737 | if (!err) { | 744 | if (!err) { |
738 | info->fbcon_par = ops; | 745 | info->fbcon_par = ops; |
739 | set_blitting_type(vc, info); | 746 | |
747 | if (vc) | ||
748 | set_blitting_type(vc, info); | ||
740 | } | 749 | } |
741 | 750 | ||
742 | if (err) { | 751 | if (err) { |
@@ -798,11 +807,7 @@ static void con2fb_init_display(struct vc_data *vc, struct fb_info *info, | |||
798 | 807 | ||
799 | ops->flags |= FBCON_FLAGS_INIT; | 808 | ops->flags |= FBCON_FLAGS_INIT; |
800 | ops->graphics = 0; | 809 | ops->graphics = 0; |
801 | 810 | fbcon_set_disp(info, &info->var, unit); | |
802 | if (vc) | ||
803 | fbcon_set_disp(info, &info->var, vc); | ||
804 | else | ||
805 | fbcon_preset_disp(info, &info->var, unit); | ||
806 | 811 | ||
807 | if (show_logo) { | 812 | if (show_logo) { |
808 | struct vc_data *fg_vc = vc_cons[fg_console].d; | 813 | struct vc_data *fg_vc = vc_cons[fg_console].d; |
@@ -1107,6 +1112,9 @@ static void fbcon_init(struct vc_data *vc, int init) | |||
1107 | if (var_to_display(p, &info->var, info)) | 1112 | if (var_to_display(p, &info->var, info)) |
1108 | return; | 1113 | return; |
1109 | 1114 | ||
1115 | if (!info->fbcon_par) | ||
1116 | con2fb_acquire_newinfo(vc, info, vc->vc_num, -1); | ||
1117 | |||
1110 | /* If we are not the first console on this | 1118 | /* If we are not the first console on this |
1111 | fb, copy the font from that console */ | 1119 | fb, copy the font from that console */ |
1112 | t = &fb_display[fg_console]; | 1120 | t = &fb_display[fg_console]; |
@@ -1349,6 +1357,11 @@ static void fbcon_cursor(struct vc_data *vc, int mode) | |||
1349 | if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1) | 1357 | if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1) |
1350 | return; | 1358 | return; |
1351 | 1359 | ||
1360 | if (vc->vc_cursor_type & 0x10) | ||
1361 | fbcon_del_cursor_timer(info); | ||
1362 | else | ||
1363 | fbcon_add_cursor_timer(info); | ||
1364 | |||
1352 | ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1; | 1365 | ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1; |
1353 | if (mode & CM_SOFTBACK) { | 1366 | if (mode & CM_SOFTBACK) { |
1354 | mode &= ~CM_SOFTBACK; | 1367 | mode &= ~CM_SOFTBACK; |
@@ -1368,36 +1381,29 @@ static int scrollback_phys_max = 0; | |||
1368 | static int scrollback_max = 0; | 1381 | static int scrollback_max = 0; |
1369 | static int scrollback_current = 0; | 1382 | static int scrollback_current = 0; |
1370 | 1383 | ||
1371 | /* | ||
1372 | * If no vc is existent yet, just set struct display | ||
1373 | */ | ||
1374 | static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *var, | ||
1375 | int unit) | ||
1376 | { | ||
1377 | struct display *p = &fb_display[unit]; | ||
1378 | struct display *t = &fb_display[fg_console]; | ||
1379 | |||
1380 | if (var_to_display(p, var, info)) | ||
1381 | return; | ||
1382 | |||
1383 | p->fontdata = t->fontdata; | ||
1384 | p->userfont = t->userfont; | ||
1385 | if (p->userfont) | ||
1386 | REFCOUNT(p->fontdata)++; | ||
1387 | } | ||
1388 | |||
1389 | static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, | 1384 | static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, |
1390 | struct vc_data *vc) | 1385 | int unit) |
1391 | { | 1386 | { |
1392 | struct display *p = &fb_display[vc->vc_num], *t; | 1387 | struct display *p, *t; |
1393 | struct vc_data **default_mode = vc->vc_display_fg; | 1388 | struct vc_data **default_mode, *vc; |
1394 | struct vc_data *svc = *default_mode; | 1389 | struct vc_data *svc; |
1395 | struct fbcon_ops *ops = info->fbcon_par; | 1390 | struct fbcon_ops *ops = info->fbcon_par; |
1396 | int rows, cols, charcnt = 256; | 1391 | int rows, cols, charcnt = 256; |
1397 | 1392 | ||
1393 | p = &fb_display[unit]; | ||
1394 | |||
1398 | if (var_to_display(p, var, info)) | 1395 | if (var_to_display(p, var, info)) |
1399 | return; | 1396 | return; |
1397 | |||
1398 | vc = vc_cons[unit].d; | ||
1399 | |||
1400 | if (!vc) | ||
1401 | return; | ||
1402 | |||
1403 | default_mode = vc->vc_display_fg; | ||
1404 | svc = *default_mode; | ||
1400 | t = &fb_display[svc->vc_num]; | 1405 | t = &fb_display[svc->vc_num]; |
1406 | |||
1401 | if (!vc->vc_font.data) { | 1407 | if (!vc->vc_font.data) { |
1402 | vc->vc_font.data = (void *)(p->fontdata = t->fontdata); | 1408 | vc->vc_font.data = (void *)(p->fontdata = t->fontdata); |
1403 | vc->vc_font.width = (*default_mode)->vc_font.width; | 1409 | vc->vc_font.width = (*default_mode)->vc_font.width; |
@@ -1704,6 +1710,56 @@ static void fbcon_redraw_move(struct vc_data *vc, struct display *p, | |||
1704 | } | 1710 | } |
1705 | } | 1711 | } |
1706 | 1712 | ||
1713 | static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info, | ||
1714 | struct display *p, int line, int count, int ycount) | ||
1715 | { | ||
1716 | int offset = ycount * vc->vc_cols; | ||
1717 | unsigned short *d = (unsigned short *) | ||
1718 | (vc->vc_origin + vc->vc_size_row * line); | ||
1719 | unsigned short *s = d + offset; | ||
1720 | struct fbcon_ops *ops = info->fbcon_par; | ||
1721 | |||
1722 | while (count--) { | ||
1723 | unsigned short *start = s; | ||
1724 | unsigned short *le = advance_row(s, 1); | ||
1725 | unsigned short c; | ||
1726 | int x = 0; | ||
1727 | |||
1728 | do { | ||
1729 | c = scr_readw(s); | ||
1730 | |||
1731 | if (c == scr_readw(d)) { | ||
1732 | if (s > start) { | ||
1733 | ops->bmove(vc, info, line + ycount, x, | ||
1734 | line, x, 1, s-start); | ||
1735 | x += s - start + 1; | ||
1736 | start = s + 1; | ||
1737 | } else { | ||
1738 | x++; | ||
1739 | start++; | ||
1740 | } | ||
1741 | } | ||
1742 | |||
1743 | scr_writew(c, d); | ||
1744 | console_conditional_schedule(); | ||
1745 | s++; | ||
1746 | d++; | ||
1747 | } while (s < le); | ||
1748 | if (s > start) | ||
1749 | ops->bmove(vc, info, line + ycount, x, line, x, 1, | ||
1750 | s-start); | ||
1751 | console_conditional_schedule(); | ||
1752 | if (ycount > 0) | ||
1753 | line++; | ||
1754 | else { | ||
1755 | line--; | ||
1756 | /* NOTE: We subtract two lines from these pointers */ | ||
1757 | s -= vc->vc_size_row; | ||
1758 | d -= vc->vc_size_row; | ||
1759 | } | ||
1760 | } | ||
1761 | } | ||
1762 | |||
1707 | static void fbcon_redraw(struct vc_data *vc, struct display *p, | 1763 | static void fbcon_redraw(struct vc_data *vc, struct display *p, |
1708 | int line, int count, int offset) | 1764 | int line, int count, int offset) |
1709 | { | 1765 | { |
@@ -1789,7 +1845,6 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, | |||
1789 | { | 1845 | { |
1790 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; | 1846 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
1791 | struct display *p = &fb_display[vc->vc_num]; | 1847 | struct display *p = &fb_display[vc->vc_num]; |
1792 | struct fbcon_ops *ops = info->fbcon_par; | ||
1793 | int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK; | 1848 | int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK; |
1794 | 1849 | ||
1795 | if (fbcon_is_inactive(vc, info)) | 1850 | if (fbcon_is_inactive(vc, info)) |
@@ -1813,10 +1868,15 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, | |||
1813 | goto redraw_up; | 1868 | goto redraw_up; |
1814 | switch (p->scrollmode) { | 1869 | switch (p->scrollmode) { |
1815 | case SCROLL_MOVE: | 1870 | case SCROLL_MOVE: |
1816 | ops->bmove(vc, info, t + count, 0, t, 0, | 1871 | fbcon_redraw_blit(vc, info, p, t, b - t - count, |
1817 | b - t - count, vc->vc_cols); | 1872 | count); |
1818 | ops->clear(vc, info, b - count, 0, count, | 1873 | fbcon_clear(vc, b - count, 0, count, vc->vc_cols); |
1819 | vc->vc_cols); | 1874 | scr_memsetw((unsigned short *) (vc->vc_origin + |
1875 | vc->vc_size_row * | ||
1876 | (b - count)), | ||
1877 | vc->vc_video_erase_char, | ||
1878 | vc->vc_size_row * count); | ||
1879 | return 1; | ||
1820 | break; | 1880 | break; |
1821 | 1881 | ||
1822 | case SCROLL_WRAP_MOVE: | 1882 | case SCROLL_WRAP_MOVE: |
@@ -1899,9 +1959,15 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, | |||
1899 | goto redraw_down; | 1959 | goto redraw_down; |
1900 | switch (p->scrollmode) { | 1960 | switch (p->scrollmode) { |
1901 | case SCROLL_MOVE: | 1961 | case SCROLL_MOVE: |
1902 | ops->bmove(vc, info, t, 0, t + count, 0, | 1962 | fbcon_redraw_blit(vc, info, p, b - 1, b - t - count, |
1903 | b - t - count, vc->vc_cols); | 1963 | -count); |
1904 | ops->clear(vc, info, t, 0, count, vc->vc_cols); | 1964 | fbcon_clear(vc, t, 0, count, vc->vc_cols); |
1965 | scr_memsetw((unsigned short *) (vc->vc_origin + | ||
1966 | vc->vc_size_row * | ||
1967 | t), | ||
1968 | vc->vc_video_erase_char, | ||
1969 | vc->vc_size_row * count); | ||
1970 | return 1; | ||
1905 | break; | 1971 | break; |
1906 | 1972 | ||
1907 | case SCROLL_WRAP_MOVE: | 1973 | case SCROLL_WRAP_MOVE: |
@@ -2937,9 +3003,48 @@ static int fbcon_mode_deleted(struct fb_info *info, | |||
2937 | return found; | 3003 | return found; |
2938 | } | 3004 | } |
2939 | 3005 | ||
2940 | static int fbcon_fb_unregistered(int idx) | 3006 | #ifdef CONFIG_VT_HW_CONSOLE_BINDING |
3007 | static int fbcon_unbind(void) | ||
2941 | { | 3008 | { |
2942 | int i; | 3009 | int ret; |
3010 | |||
3011 | ret = unbind_con_driver(&fb_con, first_fb_vc, last_fb_vc, | ||
3012 | fbcon_is_default); | ||
3013 | return ret; | ||
3014 | } | ||
3015 | #else | ||
3016 | static inline int fbcon_unbind(void) | ||
3017 | { | ||
3018 | return -EINVAL; | ||
3019 | } | ||
3020 | #endif /* CONFIG_VT_HW_CONSOLE_BINDING */ | ||
3021 | |||
3022 | static int fbcon_fb_unbind(int idx) | ||
3023 | { | ||
3024 | int i, new_idx = -1, ret = 0; | ||
3025 | |||
3026 | for (i = first_fb_vc; i <= last_fb_vc; i++) { | ||
3027 | if (con2fb_map[i] != idx && | ||
3028 | con2fb_map[i] != -1) { | ||
3029 | new_idx = i; | ||
3030 | break; | ||
3031 | } | ||
3032 | } | ||
3033 | |||
3034 | if (new_idx != -1) { | ||
3035 | for (i = first_fb_vc; i <= last_fb_vc; i++) { | ||
3036 | if (con2fb_map[i] == idx) | ||
3037 | set_con2fb_map(i, new_idx, 0); | ||
3038 | } | ||
3039 | } else | ||
3040 | ret = fbcon_unbind(); | ||
3041 | |||
3042 | return ret; | ||
3043 | } | ||
3044 | |||
3045 | static int fbcon_fb_unregistered(struct fb_info *info) | ||
3046 | { | ||
3047 | int i, idx = info->node; | ||
2943 | 3048 | ||
2944 | for (i = first_fb_vc; i <= last_fb_vc; i++) { | 3049 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
2945 | if (con2fb_map[i] == idx) | 3050 | if (con2fb_map[i] == idx) |
@@ -2967,12 +3072,48 @@ static int fbcon_fb_unregistered(int idx) | |||
2967 | if (!num_registered_fb) | 3072 | if (!num_registered_fb) |
2968 | unregister_con_driver(&fb_con); | 3073 | unregister_con_driver(&fb_con); |
2969 | 3074 | ||
3075 | |||
3076 | if (primary_device == idx) | ||
3077 | primary_device = -1; | ||
3078 | |||
2970 | return 0; | 3079 | return 0; |
2971 | } | 3080 | } |
2972 | 3081 | ||
2973 | static int fbcon_fb_registered(int idx) | 3082 | #ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY |
3083 | static void fbcon_select_primary(struct fb_info *info) | ||
2974 | { | 3084 | { |
2975 | int ret = 0, i; | 3085 | if (!map_override && primary_device == -1 && |
3086 | fb_is_primary_device(info)) { | ||
3087 | int i; | ||
3088 | |||
3089 | printk(KERN_INFO "fbcon: %s (fb%i) is primary device\n", | ||
3090 | info->fix.id, info->node); | ||
3091 | primary_device = info->node; | ||
3092 | |||
3093 | for (i = first_fb_vc; i <= last_fb_vc; i++) | ||
3094 | con2fb_map_boot[i] = primary_device; | ||
3095 | |||
3096 | if (con_is_bound(&fb_con)) { | ||
3097 | printk(KERN_INFO "fbcon: Remapping primary device, " | ||
3098 | "fb%i, to tty %i-%i\n", info->node, | ||
3099 | first_fb_vc + 1, last_fb_vc + 1); | ||
3100 | info_idx = primary_device; | ||
3101 | } | ||
3102 | } | ||
3103 | |||
3104 | } | ||
3105 | #else | ||
3106 | static inline void fbcon_select_primary(struct fb_info *info) | ||
3107 | { | ||
3108 | return; | ||
3109 | } | ||
3110 | #endif /* CONFIG_FRAMEBUFFER_DETECT_PRIMARY */ | ||
3111 | |||
3112 | static int fbcon_fb_registered(struct fb_info *info) | ||
3113 | { | ||
3114 | int ret = 0, i, idx = info->node; | ||
3115 | |||
3116 | fbcon_select_primary(info); | ||
2976 | 3117 | ||
2977 | if (info_idx == -1) { | 3118 | if (info_idx == -1) { |
2978 | for (i = first_fb_vc; i <= last_fb_vc; i++) { | 3119 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
@@ -2986,8 +3127,7 @@ static int fbcon_fb_registered(int idx) | |||
2986 | ret = fbcon_takeover(1); | 3127 | ret = fbcon_takeover(1); |
2987 | } else { | 3128 | } else { |
2988 | for (i = first_fb_vc; i <= last_fb_vc; i++) { | 3129 | for (i = first_fb_vc; i <= last_fb_vc; i++) { |
2989 | if (con2fb_map_boot[i] == idx && | 3130 | if (con2fb_map_boot[i] == idx) |
2990 | con2fb_map[i] == -1) | ||
2991 | set_con2fb_map(i, idx, 0); | 3131 | set_con2fb_map(i, idx, 0); |
2992 | } | 3132 | } |
2993 | } | 3133 | } |
@@ -3034,12 +3174,7 @@ static void fbcon_new_modelist(struct fb_info *info) | |||
3034 | mode = fb_find_nearest_mode(fb_display[i].mode, | 3174 | mode = fb_find_nearest_mode(fb_display[i].mode, |
3035 | &info->modelist); | 3175 | &info->modelist); |
3036 | fb_videomode_to_var(&var, mode); | 3176 | fb_videomode_to_var(&var, mode); |
3037 | 3177 | fbcon_set_disp(info, &var, vc->vc_num); | |
3038 | if (vc) | ||
3039 | fbcon_set_disp(info, &var, vc); | ||
3040 | else | ||
3041 | fbcon_preset_disp(info, &var, i); | ||
3042 | |||
3043 | } | 3178 | } |
3044 | } | 3179 | } |
3045 | 3180 | ||
@@ -3114,11 +3249,14 @@ static int fbcon_event_notify(struct notifier_block *self, | |||
3114 | mode = event->data; | 3249 | mode = event->data; |
3115 | ret = fbcon_mode_deleted(info, mode); | 3250 | ret = fbcon_mode_deleted(info, mode); |
3116 | break; | 3251 | break; |
3252 | case FB_EVENT_FB_UNBIND: | ||
3253 | ret = fbcon_fb_unbind(info->node); | ||
3254 | break; | ||
3117 | case FB_EVENT_FB_REGISTERED: | 3255 | case FB_EVENT_FB_REGISTERED: |
3118 | ret = fbcon_fb_registered(info->node); | 3256 | ret = fbcon_fb_registered(info); |
3119 | break; | 3257 | break; |
3120 | case FB_EVENT_FB_UNREGISTERED: | 3258 | case FB_EVENT_FB_UNREGISTERED: |
3121 | ret = fbcon_fb_unregistered(info->node); | 3259 | ret = fbcon_fb_unregistered(info); |
3122 | break; | 3260 | break; |
3123 | case FB_EVENT_SET_CONSOLE_MAP: | 3261 | case FB_EVENT_SET_CONSOLE_MAP: |
3124 | con2fb = event->data; | 3262 | con2fb = event->data; |
@@ -3179,8 +3317,9 @@ static struct notifier_block fbcon_event_notifier = { | |||
3179 | .notifier_call = fbcon_event_notify, | 3317 | .notifier_call = fbcon_event_notify, |
3180 | }; | 3318 | }; |
3181 | 3319 | ||
3182 | static ssize_t store_rotate(struct class_device *class_device, | 3320 | static ssize_t store_rotate(struct device *device, |
3183 | const char *buf, size_t count) | 3321 | struct device_attribute *attr, const char *buf, |
3322 | size_t count) | ||
3184 | { | 3323 | { |
3185 | struct fb_info *info; | 3324 | struct fb_info *info; |
3186 | int rotate, idx; | 3325 | int rotate, idx; |
@@ -3203,8 +3342,9 @@ err: | |||
3203 | return count; | 3342 | return count; |
3204 | } | 3343 | } |
3205 | 3344 | ||
3206 | static ssize_t store_rotate_all(struct class_device *class_device, | 3345 | static ssize_t store_rotate_all(struct device *device, |
3207 | const char *buf, size_t count) | 3346 | struct device_attribute *attr,const char *buf, |
3347 | size_t count) | ||
3208 | { | 3348 | { |
3209 | struct fb_info *info; | 3349 | struct fb_info *info; |
3210 | int rotate, idx; | 3350 | int rotate, idx; |
@@ -3227,7 +3367,8 @@ err: | |||
3227 | return count; | 3367 | return count; |
3228 | } | 3368 | } |
3229 | 3369 | ||
3230 | static ssize_t show_rotate(struct class_device *class_device, char *buf) | 3370 | static ssize_t show_rotate(struct device *device, |
3371 | struct device_attribute *attr,char *buf) | ||
3231 | { | 3372 | { |
3232 | struct fb_info *info; | 3373 | struct fb_info *info; |
3233 | int rotate = 0, idx; | 3374 | int rotate = 0, idx; |
@@ -3248,20 +3389,86 @@ err: | |||
3248 | return snprintf(buf, PAGE_SIZE, "%d\n", rotate); | 3389 | return snprintf(buf, PAGE_SIZE, "%d\n", rotate); |
3249 | } | 3390 | } |
3250 | 3391 | ||
3251 | static struct class_device_attribute class_device_attrs[] = { | 3392 | static ssize_t show_cursor_blink(struct device *device, |
3393 | struct device_attribute *attr, char *buf) | ||
3394 | { | ||
3395 | struct fb_info *info; | ||
3396 | struct fbcon_ops *ops; | ||
3397 | int idx, blink = -1; | ||
3398 | |||
3399 | if (fbcon_has_exited) | ||
3400 | return 0; | ||
3401 | |||
3402 | acquire_console_sem(); | ||
3403 | idx = con2fb_map[fg_console]; | ||
3404 | |||
3405 | if (idx == -1 || registered_fb[idx] == NULL) | ||
3406 | goto err; | ||
3407 | |||
3408 | info = registered_fb[idx]; | ||
3409 | ops = info->fbcon_par; | ||
3410 | |||
3411 | if (!ops) | ||
3412 | goto err; | ||
3413 | |||
3414 | blink = (ops->flags & FBCON_FLAGS_CURSOR_TIMER) ? 1 : 0; | ||
3415 | err: | ||
3416 | release_console_sem(); | ||
3417 | return snprintf(buf, PAGE_SIZE, "%d\n", blink); | ||
3418 | } | ||
3419 | |||
3420 | static ssize_t store_cursor_blink(struct device *device, | ||
3421 | struct device_attribute *attr, | ||
3422 | const char *buf, size_t count) | ||
3423 | { | ||
3424 | struct fb_info *info; | ||
3425 | int blink, idx; | ||
3426 | char **last = NULL; | ||
3427 | |||
3428 | if (fbcon_has_exited) | ||
3429 | return count; | ||
3430 | |||
3431 | acquire_console_sem(); | ||
3432 | idx = con2fb_map[fg_console]; | ||
3433 | |||
3434 | if (idx == -1 || registered_fb[idx] == NULL) | ||
3435 | goto err; | ||
3436 | |||
3437 | info = registered_fb[idx]; | ||
3438 | |||
3439 | if (!info->fbcon_par) | ||
3440 | goto err; | ||
3441 | |||
3442 | blink = simple_strtoul(buf, last, 0); | ||
3443 | |||
3444 | if (blink) { | ||
3445 | fbcon_cursor_noblink = 0; | ||
3446 | fbcon_add_cursor_timer(info); | ||
3447 | } else { | ||
3448 | fbcon_cursor_noblink = 1; | ||
3449 | fbcon_del_cursor_timer(info); | ||
3450 | } | ||
3451 | |||
3452 | err: | ||
3453 | release_console_sem(); | ||
3454 | return count; | ||
3455 | } | ||
3456 | |||
3457 | static struct device_attribute device_attrs[] = { | ||
3252 | __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate), | 3458 | __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate), |
3253 | __ATTR(rotate_all, S_IWUSR, NULL, store_rotate_all), | 3459 | __ATTR(rotate_all, S_IWUSR, NULL, store_rotate_all), |
3460 | __ATTR(cursor_blink, S_IRUGO|S_IWUSR, show_cursor_blink, | ||
3461 | store_cursor_blink), | ||
3254 | }; | 3462 | }; |
3255 | 3463 | ||
3256 | static int fbcon_init_class_device(void) | 3464 | static int fbcon_init_device(void) |
3257 | { | 3465 | { |
3258 | int i, error = 0; | 3466 | int i, error = 0; |
3259 | 3467 | ||
3260 | fbcon_has_sysfs = 1; | 3468 | fbcon_has_sysfs = 1; |
3261 | 3469 | ||
3262 | for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) { | 3470 | for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { |
3263 | error = class_device_create_file(fbcon_class_device, | 3471 | error = device_create_file(fbcon_device, &device_attrs[i]); |
3264 | &class_device_attrs[i]); | ||
3265 | 3472 | ||
3266 | if (error) | 3473 | if (error) |
3267 | break; | 3474 | break; |
@@ -3269,8 +3476,7 @@ static int fbcon_init_class_device(void) | |||
3269 | 3476 | ||
3270 | if (error) { | 3477 | if (error) { |
3271 | while (--i >= 0) | 3478 | while (--i >= 0) |
3272 | class_device_remove_file(fbcon_class_device, | 3479 | device_remove_file(fbcon_device, &device_attrs[i]); |
3273 | &class_device_attrs[i]); | ||
3274 | 3480 | ||
3275 | fbcon_has_sysfs = 0; | 3481 | fbcon_has_sysfs = 0; |
3276 | } | 3482 | } |
@@ -3356,16 +3562,15 @@ static int __init fb_console_init(void) | |||
3356 | 3562 | ||
3357 | acquire_console_sem(); | 3563 | acquire_console_sem(); |
3358 | fb_register_client(&fbcon_event_notifier); | 3564 | fb_register_client(&fbcon_event_notifier); |
3359 | fbcon_class_device = | 3565 | fbcon_device = device_create(fb_class, NULL, MKDEV(0, 0), "fbcon"); |
3360 | class_device_create(fb_class, NULL, MKDEV(0, 0), NULL, "fbcon"); | ||
3361 | 3566 | ||
3362 | if (IS_ERR(fbcon_class_device)) { | 3567 | if (IS_ERR(fbcon_device)) { |
3363 | printk(KERN_WARNING "Unable to create class_device " | 3568 | printk(KERN_WARNING "Unable to create device " |
3364 | "for fbcon; errno = %ld\n", | 3569 | "for fbcon; errno = %ld\n", |
3365 | PTR_ERR(fbcon_class_device)); | 3570 | PTR_ERR(fbcon_device)); |
3366 | fbcon_class_device = NULL; | 3571 | fbcon_device = NULL; |
3367 | } else | 3572 | } else |
3368 | fbcon_init_class_device(); | 3573 | fbcon_init_device(); |
3369 | 3574 | ||
3370 | for (i = 0; i < MAX_NR_CONSOLES; i++) | 3575 | for (i = 0; i < MAX_NR_CONSOLES; i++) |
3371 | con2fb_map[i] = -1; | 3576 | con2fb_map[i] = -1; |
@@ -3379,14 +3584,13 @@ module_init(fb_console_init); | |||
3379 | 3584 | ||
3380 | #ifdef MODULE | 3585 | #ifdef MODULE |
3381 | 3586 | ||
3382 | static void __exit fbcon_deinit_class_device(void) | 3587 | static void __exit fbcon_deinit_device(void) |
3383 | { | 3588 | { |
3384 | int i; | 3589 | int i; |
3385 | 3590 | ||
3386 | if (fbcon_has_sysfs) { | 3591 | if (fbcon_has_sysfs) { |
3387 | for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) | 3592 | for (i = 0; i < ARRAY_SIZE(device_attrs); i++) |
3388 | class_device_remove_file(fbcon_class_device, | 3593 | device_remove_file(fbcon_device, &device_attrs[i]); |
3389 | &class_device_attrs[i]); | ||
3390 | 3594 | ||
3391 | fbcon_has_sysfs = 0; | 3595 | fbcon_has_sysfs = 0; |
3392 | } | 3596 | } |
@@ -3396,8 +3600,8 @@ static void __exit fb_console_exit(void) | |||
3396 | { | 3600 | { |
3397 | acquire_console_sem(); | 3601 | acquire_console_sem(); |
3398 | fb_unregister_client(&fbcon_event_notifier); | 3602 | fb_unregister_client(&fbcon_event_notifier); |
3399 | fbcon_deinit_class_device(); | 3603 | fbcon_deinit_device(); |
3400 | class_device_destroy(fb_class, MKDEV(0, 0)); | 3604 | device_destroy(fb_class, MKDEV(0, 0)); |
3401 | fbcon_exit(); | 3605 | fbcon_exit(); |
3402 | release_console_sem(); | 3606 | release_console_sem(); |
3403 | unregister_con_driver(&fb_con); | 3607 | unregister_con_driver(&fb_con); |
diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h index 71f24e00fcd0..8e6ef4bc7a5c 100644 --- a/drivers/video/console/fbcon.h +++ b/drivers/video/console/fbcon.h | |||
@@ -176,7 +176,6 @@ extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info); | |||
176 | #endif | 176 | #endif |
177 | extern void fbcon_set_bitops(struct fbcon_ops *ops); | 177 | extern void fbcon_set_bitops(struct fbcon_ops *ops); |
178 | extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor); | 178 | extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor); |
179 | extern struct class *fb_class; | ||
180 | 179 | ||
181 | #define FBCON_ATTRIBUTE_UNDERLINE 1 | 180 | #define FBCON_ATTRIBUTE_UNDERLINE 1 |
182 | #define FBCON_ATTRIBUTE_REVERSE 2 | 181 | #define FBCON_ATTRIBUTE_REVERSE 2 |
diff --git a/drivers/video/console/softcursor.c b/drivers/video/console/softcursor.c index f577bd80e020..03cfb7ac5733 100644 --- a/drivers/video/console/softcursor.c +++ b/drivers/video/console/softcursor.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/video/softcursor.c | 2 | * linux/drivers/video/console/softcursor.c |
3 | * | 3 | * |
4 | * Generic software cursor for frame buffer devices | 4 | * Generic software cursor for frame buffer devices |
5 | * | 5 | * |
diff --git a/drivers/video/console/sticore.c b/drivers/video/console/sticore.c index 717b360d0415..870017d44970 100644 --- a/drivers/video/console/sticore.c +++ b/drivers/video/console/sticore.c | |||
@@ -240,7 +240,7 @@ static void sti_flush(unsigned long from, unsigned long len) | |||
240 | flush_icache_range(from, from+len); | 240 | flush_icache_range(from, from+len); |
241 | } | 241 | } |
242 | 242 | ||
243 | void __init | 243 | void __devinit |
244 | sti_rom_copy(unsigned long base, unsigned long count, void *dest) | 244 | sti_rom_copy(unsigned long base, unsigned long count, void *dest) |
245 | { | 245 | { |
246 | unsigned long dest_len = count; | 246 | unsigned long dest_len = count; |
@@ -269,7 +269,7 @@ sti_rom_copy(unsigned long base, unsigned long count, void *dest) | |||
269 | static char default_sti_path[21] __read_mostly; | 269 | static char default_sti_path[21] __read_mostly; |
270 | 270 | ||
271 | #ifndef MODULE | 271 | #ifndef MODULE |
272 | static int __init sti_setup(char *str) | 272 | static int __devinit sti_setup(char *str) |
273 | { | 273 | { |
274 | if (str) | 274 | if (str) |
275 | strlcpy (default_sti_path, str, sizeof (default_sti_path)); | 275 | strlcpy (default_sti_path, str, sizeof (default_sti_path)); |
@@ -288,12 +288,12 @@ __setup("sti=", sti_setup); | |||
288 | 288 | ||
289 | 289 | ||
290 | 290 | ||
291 | static char __initdata *font_name[MAX_STI_ROMS] = { "VGA8x16", }; | 291 | static char __devinitdata *font_name[MAX_STI_ROMS] = { "VGA8x16", }; |
292 | static int __initdata font_index[MAX_STI_ROMS], | 292 | static int __devinitdata font_index[MAX_STI_ROMS], |
293 | font_height[MAX_STI_ROMS], | 293 | font_height[MAX_STI_ROMS], |
294 | font_width[MAX_STI_ROMS]; | 294 | font_width[MAX_STI_ROMS]; |
295 | #ifndef MODULE | 295 | #ifndef MODULE |
296 | static int __init sti_font_setup(char *str) | 296 | static int __devinit sti_font_setup(char *str) |
297 | { | 297 | { |
298 | char *x; | 298 | char *x; |
299 | int i = 0; | 299 | int i = 0; |
@@ -346,7 +346,7 @@ __setup("sti_font=", sti_font_setup); | |||
346 | 346 | ||
347 | 347 | ||
348 | 348 | ||
349 | static void __init | 349 | static void __devinit |
350 | sti_dump_globcfg(struct sti_glob_cfg *glob_cfg, unsigned int sti_mem_request) | 350 | sti_dump_globcfg(struct sti_glob_cfg *glob_cfg, unsigned int sti_mem_request) |
351 | { | 351 | { |
352 | struct sti_glob_cfg_ext *cfg; | 352 | struct sti_glob_cfg_ext *cfg; |
@@ -386,7 +386,7 @@ sti_dump_globcfg(struct sti_glob_cfg *glob_cfg, unsigned int sti_mem_request) | |||
386 | cfg->sti_mem_addr, sti_mem_request)); | 386 | cfg->sti_mem_addr, sti_mem_request)); |
387 | } | 387 | } |
388 | 388 | ||
389 | static void __init | 389 | static void __devinit |
390 | sti_dump_outptr(struct sti_struct *sti) | 390 | sti_dump_outptr(struct sti_struct *sti) |
391 | { | 391 | { |
392 | DPRINTK((KERN_INFO | 392 | DPRINTK((KERN_INFO |
@@ -400,7 +400,7 @@ sti_dump_outptr(struct sti_struct *sti) | |||
400 | sti->outptr.attributes)); | 400 | sti->outptr.attributes)); |
401 | } | 401 | } |
402 | 402 | ||
403 | static int __init | 403 | static int __devinit |
404 | sti_init_glob_cfg(struct sti_struct *sti, | 404 | sti_init_glob_cfg(struct sti_struct *sti, |
405 | unsigned long rom_address, unsigned long hpa) | 405 | unsigned long rom_address, unsigned long hpa) |
406 | { | 406 | { |
@@ -482,7 +482,7 @@ sti_init_glob_cfg(struct sti_struct *sti, | |||
482 | } | 482 | } |
483 | 483 | ||
484 | #ifdef CONFIG_FB | 484 | #ifdef CONFIG_FB |
485 | struct sti_cooked_font * __init | 485 | struct sti_cooked_font * __devinit |
486 | sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name) | 486 | sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name) |
487 | { | 487 | { |
488 | const struct font_desc *fbfont; | 488 | const struct font_desc *fbfont; |
@@ -538,14 +538,14 @@ sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name) | |||
538 | return cooked_font; | 538 | return cooked_font; |
539 | } | 539 | } |
540 | #else | 540 | #else |
541 | struct sti_cooked_font * __init | 541 | struct sti_cooked_font * __devinit |
542 | sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name) | 542 | sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name) |
543 | { | 543 | { |
544 | return NULL; | 544 | return NULL; |
545 | } | 545 | } |
546 | #endif | 546 | #endif |
547 | 547 | ||
548 | struct sti_cooked_font * __init | 548 | struct sti_cooked_font * __devinit |
549 | sti_select_font(struct sti_cooked_rom *rom, | 549 | sti_select_font(struct sti_cooked_rom *rom, |
550 | int (*search_font_fnc) (struct sti_cooked_rom *,int,int) ) | 550 | int (*search_font_fnc) (struct sti_cooked_rom *,int,int) ) |
551 | { | 551 | { |
@@ -572,7 +572,7 @@ sti_select_font(struct sti_cooked_rom *rom, | |||
572 | } | 572 | } |
573 | 573 | ||
574 | 574 | ||
575 | static void __init | 575 | static void __devinit |
576 | sti_dump_rom(struct sti_rom *rom) | 576 | sti_dump_rom(struct sti_rom *rom) |
577 | { | 577 | { |
578 | printk(KERN_INFO " id %04x-%04x, conforms to spec rev. %d.%02x\n", | 578 | printk(KERN_INFO " id %04x-%04x, conforms to spec rev. %d.%02x\n", |
@@ -590,7 +590,7 @@ sti_dump_rom(struct sti_rom *rom) | |||
590 | } | 590 | } |
591 | 591 | ||
592 | 592 | ||
593 | static int __init | 593 | static int __devinit |
594 | sti_cook_fonts(struct sti_cooked_rom *cooked_rom, | 594 | sti_cook_fonts(struct sti_cooked_rom *cooked_rom, |
595 | struct sti_rom *raw_rom) | 595 | struct sti_rom *raw_rom) |
596 | { | 596 | { |
@@ -625,7 +625,7 @@ sti_cook_fonts(struct sti_cooked_rom *cooked_rom, | |||
625 | } | 625 | } |
626 | 626 | ||
627 | 627 | ||
628 | static int __init | 628 | static int __devinit |
629 | sti_search_font(struct sti_cooked_rom *rom, int height, int width) | 629 | sti_search_font(struct sti_cooked_rom *rom, int height, int width) |
630 | { | 630 | { |
631 | struct sti_cooked_font *font; | 631 | struct sti_cooked_font *font; |
@@ -642,7 +642,7 @@ sti_search_font(struct sti_cooked_rom *rom, int height, int width) | |||
642 | #define BMODE_RELOCATE(offset) offset = (offset) / 4; | 642 | #define BMODE_RELOCATE(offset) offset = (offset) / 4; |
643 | #define BMODE_LAST_ADDR_OFFS 0x50 | 643 | #define BMODE_LAST_ADDR_OFFS 0x50 |
644 | 644 | ||
645 | static void * __init | 645 | static void * __devinit |
646 | sti_bmode_font_raw(struct sti_cooked_font *f) | 646 | sti_bmode_font_raw(struct sti_cooked_font *f) |
647 | { | 647 | { |
648 | unsigned char *n, *p, *q; | 648 | unsigned char *n, *p, *q; |
@@ -660,7 +660,7 @@ sti_bmode_font_raw(struct sti_cooked_font *f) | |||
660 | return n + 3; | 660 | return n + 3; |
661 | } | 661 | } |
662 | 662 | ||
663 | static void __init | 663 | static void __devinit |
664 | sti_bmode_rom_copy(unsigned long base, unsigned long count, void *dest) | 664 | sti_bmode_rom_copy(unsigned long base, unsigned long count, void *dest) |
665 | { | 665 | { |
666 | unsigned long dest_len = count; | 666 | unsigned long dest_len = count; |
@@ -675,7 +675,7 @@ sti_bmode_rom_copy(unsigned long base, unsigned long count, void *dest) | |||
675 | sti_flush(dest_start, dest_len); | 675 | sti_flush(dest_start, dest_len); |
676 | } | 676 | } |
677 | 677 | ||
678 | static struct sti_rom * __init | 678 | static struct sti_rom * __devinit |
679 | sti_get_bmode_rom (unsigned long address) | 679 | sti_get_bmode_rom (unsigned long address) |
680 | { | 680 | { |
681 | struct sti_rom *raw; | 681 | struct sti_rom *raw; |
@@ -711,7 +711,7 @@ sti_get_bmode_rom (unsigned long address) | |||
711 | return raw; | 711 | return raw; |
712 | } | 712 | } |
713 | 713 | ||
714 | struct sti_rom * __init | 714 | struct sti_rom * __devinit |
715 | sti_get_wmode_rom (unsigned long address) | 715 | sti_get_wmode_rom (unsigned long address) |
716 | { | 716 | { |
717 | struct sti_rom *raw; | 717 | struct sti_rom *raw; |
@@ -727,7 +727,7 @@ sti_get_wmode_rom (unsigned long address) | |||
727 | return raw; | 727 | return raw; |
728 | } | 728 | } |
729 | 729 | ||
730 | int __init | 730 | int __devinit |
731 | sti_read_rom(int wordmode, struct sti_struct *sti, unsigned long address) | 731 | sti_read_rom(int wordmode, struct sti_struct *sti, unsigned long address) |
732 | { | 732 | { |
733 | struct sti_cooked_rom *cooked; | 733 | struct sti_cooked_rom *cooked; |
@@ -783,7 +783,7 @@ out_err: | |||
783 | return 0; | 783 | return 0; |
784 | } | 784 | } |
785 | 785 | ||
786 | static struct sti_struct * __init | 786 | static struct sti_struct * __devinit |
787 | sti_try_rom_generic(unsigned long address, unsigned long hpa, struct pci_dev *pd) | 787 | sti_try_rom_generic(unsigned long address, unsigned long hpa, struct pci_dev *pd) |
788 | { | 788 | { |
789 | struct sti_struct *sti; | 789 | struct sti_struct *sti; |
@@ -898,7 +898,7 @@ out_err: | |||
898 | return NULL; | 898 | return NULL; |
899 | } | 899 | } |
900 | 900 | ||
901 | static void __init sticore_check_for_default_sti(struct sti_struct *sti, char *path) | 901 | static void __devinit sticore_check_for_default_sti(struct sti_struct *sti, char *path) |
902 | { | 902 | { |
903 | if (strcmp (path, default_sti_path) == 0) | 903 | if (strcmp (path, default_sti_path) == 0) |
904 | default_sti = sti; | 904 | default_sti = sti; |
@@ -909,7 +909,7 @@ static void __init sticore_check_for_default_sti(struct sti_struct *sti, char *p | |||
909 | * in the additional address field addr[1] while on | 909 | * in the additional address field addr[1] while on |
910 | * older Systems the PDC stores it in page0->proc_sti | 910 | * older Systems the PDC stores it in page0->proc_sti |
911 | */ | 911 | */ |
912 | static int __init sticore_pa_init(struct parisc_device *dev) | 912 | static int __devinit sticore_pa_init(struct parisc_device *dev) |
913 | { | 913 | { |
914 | char pa_path[21]; | 914 | char pa_path[21]; |
915 | struct sti_struct *sti = NULL; | 915 | struct sti_struct *sti = NULL; |
@@ -1015,7 +1015,7 @@ static struct parisc_driver pa_sti_driver = { | |||
1015 | 1015 | ||
1016 | static int sticore_initialized __read_mostly; | 1016 | static int sticore_initialized __read_mostly; |
1017 | 1017 | ||
1018 | static void __init sti_init_roms(void) | 1018 | static void __devinit sti_init_roms(void) |
1019 | { | 1019 | { |
1020 | if (sticore_initialized) | 1020 | if (sticore_initialized) |
1021 | return; | 1021 | return; |
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 2460b82a1d93..d18b73aafa0d 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c | |||
@@ -187,7 +187,11 @@ static void vgacon_scrollback_init(int pitch) | |||
187 | } | 187 | } |
188 | } | 188 | } |
189 | 189 | ||
190 | static void vgacon_scrollback_startup(void) | 190 | /* |
191 | * Called only duing init so call of alloc_bootmen is ok. | ||
192 | * Marked __init_refok to silence modpost. | ||
193 | */ | ||
194 | static void __init_refok vgacon_scrollback_startup(void) | ||
191 | { | 195 | { |
192 | vgacon_scrollback = alloc_bootmem(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE | 196 | vgacon_scrollback = alloc_bootmem(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE |
193 | * 1024); | 197 | * 1024); |
@@ -368,9 +372,14 @@ static const char *vgacon_startup(void) | |||
368 | #endif | 372 | #endif |
369 | } | 373 | } |
370 | 374 | ||
375 | /* SCREEN_INFO initialized? */ | ||
376 | if ((ORIG_VIDEO_MODE == 0) && | ||
377 | (ORIG_VIDEO_LINES == 0) && | ||
378 | (ORIG_VIDEO_COLS == 0)) | ||
379 | goto no_vga; | ||
380 | |||
371 | /* VGA16 modes are not handled by VGACON */ | 381 | /* VGA16 modes are not handled by VGACON */ |
372 | if ((ORIG_VIDEO_MODE == 0x00) || /* SCREEN_INFO not initialized */ | 382 | if ((ORIG_VIDEO_MODE == 0x0D) || /* 320x200/4 */ |
373 | (ORIG_VIDEO_MODE == 0x0D) || /* 320x200/4 */ | ||
374 | (ORIG_VIDEO_MODE == 0x0E) || /* 640x200/4 */ | 383 | (ORIG_VIDEO_MODE == 0x0E) || /* 640x200/4 */ |
375 | (ORIG_VIDEO_MODE == 0x10) || /* 640x350/4 */ | 384 | (ORIG_VIDEO_MODE == 0x10) || /* 640x350/4 */ |
376 | (ORIG_VIDEO_MODE == 0x12) || /* 640x480/4 */ | 385 | (ORIG_VIDEO_MODE == 0x12) || /* 640x480/4 */ |
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c index 8b762739b1e0..b0be7eac32d8 100644 --- a/drivers/video/controlfb.c +++ b/drivers/video/controlfb.c | |||
@@ -94,7 +94,7 @@ static inline int VAR_MATCH(struct fb_var_screeninfo *x, struct fb_var_screeninf | |||
94 | struct fb_info_control { | 94 | struct fb_info_control { |
95 | struct fb_info info; | 95 | struct fb_info info; |
96 | struct fb_par_control par; | 96 | struct fb_par_control par; |
97 | u32 pseudo_palette[17]; | 97 | u32 pseudo_palette[16]; |
98 | 98 | ||
99 | struct cmap_regs __iomem *cmap_regs; | 99 | struct cmap_regs __iomem *cmap_regs; |
100 | unsigned long cmap_regs_phys; | 100 | unsigned long cmap_regs_phys; |
diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c index 7a6eeda5ae9a..30ede6e8830f 100644 --- a/drivers/video/cyber2000fb.c +++ b/drivers/video/cyber2000fb.c | |||
@@ -1221,11 +1221,10 @@ cyberpro_alloc_fb_info(unsigned int id, char *name) | |||
1221 | { | 1221 | { |
1222 | struct cfb_info *cfb; | 1222 | struct cfb_info *cfb; |
1223 | 1223 | ||
1224 | cfb = kmalloc(sizeof(struct cfb_info), GFP_KERNEL); | 1224 | cfb = kzalloc(sizeof(struct cfb_info), GFP_KERNEL); |
1225 | if (!cfb) | 1225 | if (!cfb) |
1226 | return NULL; | 1226 | return NULL; |
1227 | 1227 | ||
1228 | memset(cfb, 0, sizeof(struct cfb_info)); | ||
1229 | 1228 | ||
1230 | cfb->id = id; | 1229 | cfb->id = id; |
1231 | 1230 | ||
diff --git a/drivers/video/cyblafb.c b/drivers/video/cyblafb.c index 94a66c2d2cf5..e23324d10be2 100644 --- a/drivers/video/cyblafb.c +++ b/drivers/video/cyblafb.c | |||
@@ -1068,15 +1068,18 @@ static int cyblafb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
1068 | out8(0x3C9, green >> 10); | 1068 | out8(0x3C9, green >> 10); |
1069 | out8(0x3C9, blue >> 10); | 1069 | out8(0x3C9, blue >> 10); |
1070 | 1070 | ||
1071 | } else if (bpp == 16) // RGB 565 | 1071 | } else if (regno < 16) { |
1072 | ((u32 *) info->pseudo_palette)[regno] = | 1072 | if (bpp == 16) // RGB 565 |
1073 | (red & 0xF800) | | 1073 | ((u32 *) info->pseudo_palette)[regno] = |
1074 | ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11); | 1074 | (red & 0xF800) | |
1075 | else if (bpp == 32) // ARGB 8888 | 1075 | ((green & 0xFC00) >> 5) | |
1076 | ((u32 *) info->pseudo_palette)[regno] = | 1076 | ((blue & 0xF800) >> 11); |
1077 | ((transp & 0xFF00) << 16) | | 1077 | else if (bpp == 32) // ARGB 8888 |
1078 | ((red & 0xFF00) << 8) | | 1078 | ((u32 *) info->pseudo_palette)[regno] = |
1079 | ((green & 0xFF00)) | ((blue & 0xFF00) >> 8); | 1079 | ((transp & 0xFF00) << 16) | |
1080 | ((red & 0xFF00) << 8) | | ||
1081 | ((green & 0xFF00)) | ((blue & 0xFF00) >> 8); | ||
1082 | } | ||
1080 | 1083 | ||
1081 | return 0; | 1084 | return 0; |
1082 | } | 1085 | } |
diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c index ca2c54ce508e..33be46ccb54f 100644 --- a/drivers/video/epson1355fb.c +++ b/drivers/video/epson1355fb.c | |||
@@ -63,23 +63,12 @@ | |||
63 | 63 | ||
64 | struct epson1355_par { | 64 | struct epson1355_par { |
65 | unsigned long reg_addr; | 65 | unsigned long reg_addr; |
66 | u32 pseudo_palette[16]; | ||
66 | }; | 67 | }; |
67 | 68 | ||
68 | /* ------------------------------------------------------------------------- */ | 69 | /* ------------------------------------------------------------------------- */ |
69 | 70 | ||
70 | #ifdef CONFIG_SUPERH | 71 | #if defined(CONFIG_ARM) |
71 | |||
72 | static inline u8 epson1355_read_reg(int index) | ||
73 | { | ||
74 | return ctrl_inb(par.reg_addr + index); | ||
75 | } | ||
76 | |||
77 | static inline void epson1355_write_reg(u8 data, int index) | ||
78 | { | ||
79 | ctrl_outb(data, par.reg_addr + index); | ||
80 | } | ||
81 | |||
82 | #elif defined(CONFIG_ARM) | ||
83 | 72 | ||
84 | # ifdef CONFIG_ARCH_CEIVA | 73 | # ifdef CONFIG_ARCH_CEIVA |
85 | # include <asm/arch/hardware.h> | 74 | # include <asm/arch/hardware.h> |
@@ -289,7 +278,7 @@ static int epson1355fb_blank(int blank_mode, struct fb_info *info) | |||
289 | struct epson1355_par *par = info->par; | 278 | struct epson1355_par *par = info->par; |
290 | 279 | ||
291 | switch (blank_mode) { | 280 | switch (blank_mode) { |
292 | case FB_BLANK_UNBLANKING: | 281 | case FB_BLANK_UNBLANK: |
293 | case FB_BLANK_NORMAL: | 282 | case FB_BLANK_NORMAL: |
294 | lcd_enable(par, 1); | 283 | lcd_enable(par, 1); |
295 | backlight_enable(1); | 284 | backlight_enable(1); |
@@ -635,7 +624,7 @@ int __init epson1355fb_probe(struct platform_device *dev) | |||
635 | goto bail; | 624 | goto bail; |
636 | } | 625 | } |
637 | 626 | ||
638 | info = framebuffer_alloc(sizeof(struct epson1355_par) + sizeof(u32) * 256, &dev->dev); | 627 | info = framebuffer_alloc(sizeof(struct epson1355_par), &dev->dev); |
639 | if (!info) { | 628 | if (!info) { |
640 | rc = -ENOMEM; | 629 | rc = -ENOMEM; |
641 | goto bail; | 630 | goto bail; |
@@ -648,7 +637,7 @@ int __init epson1355fb_probe(struct platform_device *dev) | |||
648 | rc = -ENOMEM; | 637 | rc = -ENOMEM; |
649 | goto bail; | 638 | goto bail; |
650 | } | 639 | } |
651 | info->pseudo_palette = (void *)(default_par + 1); | 640 | info->pseudo_palette = default_par->pseudo_palette; |
652 | 641 | ||
653 | info->screen_base = ioremap(EPSON1355FB_FB_PHYS, EPSON1355FB_FB_LEN); | 642 | info->screen_base = ioremap(EPSON1355FB_FB_PHYS, EPSON1355FB_FB_LEN); |
654 | if (!info->screen_base) { | 643 | if (!info->screen_base) { |
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 08d4e11d9121..215ac579f901 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c | |||
@@ -33,17 +33,10 @@ | |||
33 | #include <linux/err.h> | 33 | #include <linux/err.h> |
34 | #include <linux/device.h> | 34 | #include <linux/device.h> |
35 | #include <linux/efi.h> | 35 | #include <linux/efi.h> |
36 | #include <linux/fb.h> | ||
36 | 37 | ||
37 | #if defined(__mc68000__) || defined(CONFIG_APUS) | 38 | #include <asm/fb.h> |
38 | #include <asm/setup.h> | ||
39 | #endif | ||
40 | 39 | ||
41 | #include <asm/io.h> | ||
42 | #include <asm/uaccess.h> | ||
43 | #include <asm/page.h> | ||
44 | #include <asm/pgtable.h> | ||
45 | |||
46 | #include <linux/fb.h> | ||
47 | 40 | ||
48 | /* | 41 | /* |
49 | * Frame buffer device initialization and setup routines | 42 | * Frame buffer device initialization and setup routines |
@@ -411,10 +404,146 @@ static void fb_do_show_logo(struct fb_info *info, struct fb_image *image, | |||
411 | } | 404 | } |
412 | } | 405 | } |
413 | 406 | ||
407 | static int fb_show_logo_line(struct fb_info *info, int rotate, | ||
408 | const struct linux_logo *logo, int y, | ||
409 | unsigned int n) | ||
410 | { | ||
411 | u32 *palette = NULL, *saved_pseudo_palette = NULL; | ||
412 | unsigned char *logo_new = NULL, *logo_rotate = NULL; | ||
413 | struct fb_image image; | ||
414 | |||
415 | /* Return if the frame buffer is not mapped or suspended */ | ||
416 | if (logo == NULL || info->state != FBINFO_STATE_RUNNING || | ||
417 | info->flags & FBINFO_MODULE) | ||
418 | return 0; | ||
419 | |||
420 | image.depth = 8; | ||
421 | image.data = logo->data; | ||
422 | |||
423 | if (fb_logo.needs_cmapreset) | ||
424 | fb_set_logocmap(info, logo); | ||
425 | |||
426 | if (fb_logo.needs_truepalette || | ||
427 | fb_logo.needs_directpalette) { | ||
428 | palette = kmalloc(256 * 4, GFP_KERNEL); | ||
429 | if (palette == NULL) | ||
430 | return 0; | ||
431 | |||
432 | if (fb_logo.needs_truepalette) | ||
433 | fb_set_logo_truepalette(info, logo, palette); | ||
434 | else | ||
435 | fb_set_logo_directpalette(info, logo, palette); | ||
436 | |||
437 | saved_pseudo_palette = info->pseudo_palette; | ||
438 | info->pseudo_palette = palette; | ||
439 | } | ||
440 | |||
441 | if (fb_logo.depth <= 4) { | ||
442 | logo_new = kmalloc(logo->width * logo->height, GFP_KERNEL); | ||
443 | if (logo_new == NULL) { | ||
444 | kfree(palette); | ||
445 | if (saved_pseudo_palette) | ||
446 | info->pseudo_palette = saved_pseudo_palette; | ||
447 | return 0; | ||
448 | } | ||
449 | image.data = logo_new; | ||
450 | fb_set_logo(info, logo, logo_new, fb_logo.depth); | ||
451 | } | ||
452 | |||
453 | image.dx = 0; | ||
454 | image.dy = y; | ||
455 | image.width = logo->width; | ||
456 | image.height = logo->height; | ||
457 | |||
458 | if (rotate) { | ||
459 | logo_rotate = kmalloc(logo->width * | ||
460 | logo->height, GFP_KERNEL); | ||
461 | if (logo_rotate) | ||
462 | fb_rotate_logo(info, logo_rotate, &image, rotate); | ||
463 | } | ||
464 | |||
465 | fb_do_show_logo(info, &image, rotate, n); | ||
466 | |||
467 | kfree(palette); | ||
468 | if (saved_pseudo_palette != NULL) | ||
469 | info->pseudo_palette = saved_pseudo_palette; | ||
470 | kfree(logo_new); | ||
471 | kfree(logo_rotate); | ||
472 | return logo->height; | ||
473 | } | ||
474 | |||
475 | |||
476 | #ifdef CONFIG_FB_LOGO_EXTRA | ||
477 | |||
478 | #define FB_LOGO_EX_NUM_MAX 10 | ||
479 | static struct logo_data_extra { | ||
480 | const struct linux_logo *logo; | ||
481 | unsigned int n; | ||
482 | } fb_logo_ex[FB_LOGO_EX_NUM_MAX]; | ||
483 | static unsigned int fb_logo_ex_num; | ||
484 | |||
485 | void fb_append_extra_logo(const struct linux_logo *logo, unsigned int n) | ||
486 | { | ||
487 | if (!n || fb_logo_ex_num == FB_LOGO_EX_NUM_MAX) | ||
488 | return; | ||
489 | |||
490 | fb_logo_ex[fb_logo_ex_num].logo = logo; | ||
491 | fb_logo_ex[fb_logo_ex_num].n = n; | ||
492 | fb_logo_ex_num++; | ||
493 | } | ||
494 | |||
495 | static int fb_prepare_extra_logos(struct fb_info *info, unsigned int height, | ||
496 | unsigned int yres) | ||
497 | { | ||
498 | unsigned int i; | ||
499 | |||
500 | /* FIXME: logo_ex supports only truecolor fb. */ | ||
501 | if (info->fix.visual != FB_VISUAL_TRUECOLOR) | ||
502 | fb_logo_ex_num = 0; | ||
503 | |||
504 | for (i = 0; i < fb_logo_ex_num; i++) { | ||
505 | height += fb_logo_ex[i].logo->height; | ||
506 | if (height > yres) { | ||
507 | height -= fb_logo_ex[i].logo->height; | ||
508 | fb_logo_ex_num = i; | ||
509 | break; | ||
510 | } | ||
511 | } | ||
512 | return height; | ||
513 | } | ||
514 | |||
515 | static int fb_show_extra_logos(struct fb_info *info, int y, int rotate) | ||
516 | { | ||
517 | unsigned int i; | ||
518 | |||
519 | for (i = 0; i < fb_logo_ex_num; i++) | ||
520 | y += fb_show_logo_line(info, rotate, | ||
521 | fb_logo_ex[i].logo, y, fb_logo_ex[i].n); | ||
522 | |||
523 | return y; | ||
524 | } | ||
525 | |||
526 | #else /* !CONFIG_FB_LOGO_EXTRA */ | ||
527 | |||
528 | static inline int fb_prepare_extra_logos(struct fb_info *info, | ||
529 | unsigned int height, | ||
530 | unsigned int yres) | ||
531 | { | ||
532 | return height; | ||
533 | } | ||
534 | |||
535 | static inline int fb_show_extra_logos(struct fb_info *info, int y, int rotate) | ||
536 | { | ||
537 | return y; | ||
538 | } | ||
539 | |||
540 | #endif /* CONFIG_FB_LOGO_EXTRA */ | ||
541 | |||
542 | |||
414 | int fb_prepare_logo(struct fb_info *info, int rotate) | 543 | int fb_prepare_logo(struct fb_info *info, int rotate) |
415 | { | 544 | { |
416 | int depth = fb_get_color_depth(&info->var, &info->fix); | 545 | int depth = fb_get_color_depth(&info->var, &info->fix); |
417 | int yres; | 546 | unsigned int yres; |
418 | 547 | ||
419 | memset(&fb_logo, 0, sizeof(struct logo_data)); | 548 | memset(&fb_logo, 0, sizeof(struct logo_data)); |
420 | 549 | ||
@@ -456,7 +585,7 @@ int fb_prepare_logo(struct fb_info *info, int rotate) | |||
456 | if (!fb_logo.logo) { | 585 | if (!fb_logo.logo) { |
457 | return 0; | 586 | return 0; |
458 | } | 587 | } |
459 | 588 | ||
460 | if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD) | 589 | if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD) |
461 | yres = info->var.yres; | 590 | yres = info->var.yres; |
462 | else | 591 | else |
@@ -473,75 +602,20 @@ int fb_prepare_logo(struct fb_info *info, int rotate) | |||
473 | else if (fb_logo.logo->type == LINUX_LOGO_VGA16) | 602 | else if (fb_logo.logo->type == LINUX_LOGO_VGA16) |
474 | fb_logo.depth = 4; | 603 | fb_logo.depth = 4; |
475 | else | 604 | else |
476 | fb_logo.depth = 1; | 605 | fb_logo.depth = 1; |
477 | return fb_logo.logo->height; | 606 | |
607 | return fb_prepare_extra_logos(info, fb_logo.logo->height, yres); | ||
478 | } | 608 | } |
479 | 609 | ||
480 | int fb_show_logo(struct fb_info *info, int rotate) | 610 | int fb_show_logo(struct fb_info *info, int rotate) |
481 | { | 611 | { |
482 | u32 *palette = NULL, *saved_pseudo_palette = NULL; | 612 | int y; |
483 | unsigned char *logo_new = NULL, *logo_rotate = NULL; | ||
484 | struct fb_image image; | ||
485 | |||
486 | /* Return if the frame buffer is not mapped or suspended */ | ||
487 | if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING || | ||
488 | info->flags & FBINFO_MODULE) | ||
489 | return 0; | ||
490 | |||
491 | image.depth = 8; | ||
492 | image.data = fb_logo.logo->data; | ||
493 | |||
494 | if (fb_logo.needs_cmapreset) | ||
495 | fb_set_logocmap(info, fb_logo.logo); | ||
496 | |||
497 | if (fb_logo.needs_truepalette || | ||
498 | fb_logo.needs_directpalette) { | ||
499 | palette = kmalloc(256 * 4, GFP_KERNEL); | ||
500 | if (palette == NULL) | ||
501 | return 0; | ||
502 | |||
503 | if (fb_logo.needs_truepalette) | ||
504 | fb_set_logo_truepalette(info, fb_logo.logo, palette); | ||
505 | else | ||
506 | fb_set_logo_directpalette(info, fb_logo.logo, palette); | ||
507 | |||
508 | saved_pseudo_palette = info->pseudo_palette; | ||
509 | info->pseudo_palette = palette; | ||
510 | } | ||
511 | |||
512 | if (fb_logo.depth <= 4) { | ||
513 | logo_new = kmalloc(fb_logo.logo->width * fb_logo.logo->height, | ||
514 | GFP_KERNEL); | ||
515 | if (logo_new == NULL) { | ||
516 | kfree(palette); | ||
517 | if (saved_pseudo_palette) | ||
518 | info->pseudo_palette = saved_pseudo_palette; | ||
519 | return 0; | ||
520 | } | ||
521 | image.data = logo_new; | ||
522 | fb_set_logo(info, fb_logo.logo, logo_new, fb_logo.depth); | ||
523 | } | ||
524 | 613 | ||
525 | image.dx = 0; | 614 | y = fb_show_logo_line(info, rotate, fb_logo.logo, 0, |
526 | image.dy = 0; | 615 | num_online_cpus()); |
527 | image.width = fb_logo.logo->width; | 616 | y = fb_show_extra_logos(info, y, rotate); |
528 | image.height = fb_logo.logo->height; | ||
529 | 617 | ||
530 | if (rotate) { | 618 | return y; |
531 | logo_rotate = kmalloc(fb_logo.logo->width * | ||
532 | fb_logo.logo->height, GFP_KERNEL); | ||
533 | if (logo_rotate) | ||
534 | fb_rotate_logo(info, logo_rotate, &image, rotate); | ||
535 | } | ||
536 | |||
537 | fb_do_show_logo(info, &image, rotate, num_online_cpus()); | ||
538 | |||
539 | kfree(palette); | ||
540 | if (saved_pseudo_palette != NULL) | ||
541 | info->pseudo_palette = saved_pseudo_palette; | ||
542 | kfree(logo_new); | ||
543 | kfree(logo_rotate); | ||
544 | return fb_logo.logo->height; | ||
545 | } | 619 | } |
546 | #else | 620 | #else |
547 | int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; } | 621 | int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; } |
@@ -1155,17 +1229,15 @@ fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
1155 | } | 1229 | } |
1156 | #endif | 1230 | #endif |
1157 | 1231 | ||
1158 | static int | 1232 | static int |
1159 | fb_mmap(struct file *file, struct vm_area_struct * vma) | 1233 | fb_mmap(struct file *file, struct vm_area_struct * vma) |
1160 | { | 1234 | { |
1161 | int fbidx = iminor(file->f_path.dentry->d_inode); | 1235 | int fbidx = iminor(file->f_path.dentry->d_inode); |
1162 | struct fb_info *info = registered_fb[fbidx]; | 1236 | struct fb_info *info = registered_fb[fbidx]; |
1163 | struct fb_ops *fb = info->fbops; | 1237 | struct fb_ops *fb = info->fbops; |
1164 | unsigned long off; | 1238 | unsigned long off; |
1165 | #if !defined(__sparc__) || defined(__sparc_v9__) | ||
1166 | unsigned long start; | 1239 | unsigned long start; |
1167 | u32 len; | 1240 | u32 len; |
1168 | #endif | ||
1169 | 1241 | ||
1170 | if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) | 1242 | if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) |
1171 | return -EINVAL; | 1243 | return -EINVAL; |
@@ -1180,12 +1252,6 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) | |||
1180 | return res; | 1252 | return res; |
1181 | } | 1253 | } |
1182 | 1254 | ||
1183 | #if defined(__sparc__) && !defined(__sparc_v9__) | ||
1184 | /* Should never get here, all fb drivers should have their own | ||
1185 | mmap routines */ | ||
1186 | return -EINVAL; | ||
1187 | #else | ||
1188 | /* !sparc32... */ | ||
1189 | lock_kernel(); | 1255 | lock_kernel(); |
1190 | 1256 | ||
1191 | /* frame buffer memory */ | 1257 | /* frame buffer memory */ |
@@ -1209,46 +1275,11 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) | |||
1209 | vma->vm_pgoff = off >> PAGE_SHIFT; | 1275 | vma->vm_pgoff = off >> PAGE_SHIFT; |
1210 | /* This is an IO map - tell maydump to skip this VMA */ | 1276 | /* This is an IO map - tell maydump to skip this VMA */ |
1211 | vma->vm_flags |= VM_IO | VM_RESERVED; | 1277 | vma->vm_flags |= VM_IO | VM_RESERVED; |
1212 | #if defined(__mc68000__) | 1278 | fb_pgprotect(file, vma, off); |
1213 | #if defined(CONFIG_SUN3) | ||
1214 | pgprot_val(vma->vm_page_prot) |= SUN3_PAGE_NOCACHE; | ||
1215 | #elif defined(CONFIG_MMU) | ||
1216 | if (CPU_IS_020_OR_030) | ||
1217 | pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030; | ||
1218 | if (CPU_IS_040_OR_060) { | ||
1219 | pgprot_val(vma->vm_page_prot) &= _CACHEMASK040; | ||
1220 | /* Use no-cache mode, serialized */ | ||
1221 | pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE_S; | ||
1222 | } | ||
1223 | #endif | ||
1224 | #elif defined(__powerpc__) | ||
1225 | vma->vm_page_prot = phys_mem_access_prot(file, off >> PAGE_SHIFT, | ||
1226 | vma->vm_end - vma->vm_start, | ||
1227 | vma->vm_page_prot); | ||
1228 | #elif defined(__alpha__) | ||
1229 | /* Caching is off in the I/O space quadrant by design. */ | ||
1230 | #elif defined(__i386__) || defined(__x86_64__) | ||
1231 | if (boot_cpu_data.x86 > 3) | ||
1232 | pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; | ||
1233 | #elif defined(__mips__) || defined(__sparc_v9__) | ||
1234 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | ||
1235 | #elif defined(__hppa__) | ||
1236 | pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; | ||
1237 | #elif defined(__arm__) || defined(__sh__) || defined(__m32r__) | ||
1238 | vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); | ||
1239 | #elif defined(__ia64__) | ||
1240 | if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start)) | ||
1241 | vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); | ||
1242 | else | ||
1243 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | ||
1244 | #else | ||
1245 | #warning What do we have to do here?? | ||
1246 | #endif | ||
1247 | if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, | 1279 | if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, |
1248 | vma->vm_end - vma->vm_start, vma->vm_page_prot)) | 1280 | vma->vm_end - vma->vm_start, vma->vm_page_prot)) |
1249 | return -EAGAIN; | 1281 | return -EAGAIN; |
1250 | return 0; | 1282 | return 0; |
1251 | #endif /* !sparc32 */ | ||
1252 | } | 1283 | } |
1253 | 1284 | ||
1254 | static int | 1285 | static int |
@@ -1384,17 +1415,34 @@ register_framebuffer(struct fb_info *fb_info) | |||
1384 | * | 1415 | * |
1385 | * Returns negative errno on error, or zero for success. | 1416 | * Returns negative errno on error, or zero for success. |
1386 | * | 1417 | * |
1418 | * This function will also notify the framebuffer console | ||
1419 | * to release the driver. | ||
1420 | * | ||
1421 | * This is meant to be called within a driver's module_exit() | ||
1422 | * function. If this is called outside module_exit(), ensure | ||
1423 | * that the driver implements fb_open() and fb_release() to | ||
1424 | * check that no processes are using the device. | ||
1387 | */ | 1425 | */ |
1388 | 1426 | ||
1389 | int | 1427 | int |
1390 | unregister_framebuffer(struct fb_info *fb_info) | 1428 | unregister_framebuffer(struct fb_info *fb_info) |
1391 | { | 1429 | { |
1392 | struct fb_event event; | 1430 | struct fb_event event; |
1393 | int i; | 1431 | int i, ret = 0; |
1394 | 1432 | ||
1395 | i = fb_info->node; | 1433 | i = fb_info->node; |
1396 | if (!registered_fb[i]) | 1434 | if (!registered_fb[i]) { |
1397 | return -EINVAL; | 1435 | ret = -EINVAL; |
1436 | goto done; | ||
1437 | } | ||
1438 | |||
1439 | event.info = fb_info; | ||
1440 | ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event); | ||
1441 | |||
1442 | if (ret) { | ||
1443 | ret = -EINVAL; | ||
1444 | goto done; | ||
1445 | } | ||
1398 | 1446 | ||
1399 | if (fb_info->pixmap.addr && | 1447 | if (fb_info->pixmap.addr && |
1400 | (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) | 1448 | (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) |
@@ -1406,7 +1454,8 @@ unregister_framebuffer(struct fb_info *fb_info) | |||
1406 | device_destroy(fb_class, MKDEV(FB_MAJOR, i)); | 1454 | device_destroy(fb_class, MKDEV(FB_MAJOR, i)); |
1407 | event.info = fb_info; | 1455 | event.info = fb_info; |
1408 | fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); | 1456 | fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); |
1409 | return 0; | 1457 | done: |
1458 | return ret; | ||
1410 | } | 1459 | } |
1411 | 1460 | ||
1412 | /** | 1461 | /** |
diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c index 1d4e8354b561..3f6c98fad437 100644 --- a/drivers/video/ffb.c +++ b/drivers/video/ffb.c | |||
@@ -656,7 +656,7 @@ static int ffb_setcolreg(unsigned regno, | |||
656 | { | 656 | { |
657 | u32 value; | 657 | u32 value; |
658 | 658 | ||
659 | if (regno >= 256) | 659 | if (regno >= 16) |
660 | return 1; | 660 | return 1; |
661 | 661 | ||
662 | red >>= 8; | 662 | red >>= 8; |
@@ -903,7 +903,7 @@ ffb_init_fix(struct fb_info *info) | |||
903 | struct all_info { | 903 | struct all_info { |
904 | struct fb_info info; | 904 | struct fb_info info; |
905 | struct ffb_par par; | 905 | struct ffb_par par; |
906 | u32 pseudo_palette[256]; | 906 | u32 pseudo_palette[16]; |
907 | }; | 907 | }; |
908 | 908 | ||
909 | static int ffb_init_one(struct of_device *op) | 909 | static int ffb_init_one(struct of_device *op) |
diff --git a/drivers/video/fm2fb.c b/drivers/video/fm2fb.c index 70ff55b14596..6c91c61cdb63 100644 --- a/drivers/video/fm2fb.c +++ b/drivers/video/fm2fb.c | |||
@@ -195,13 +195,15 @@ static int fm2fb_blank(int blank, struct fb_info *info) | |||
195 | static int fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, | 195 | static int fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, |
196 | u_int transp, struct fb_info *info) | 196 | u_int transp, struct fb_info *info) |
197 | { | 197 | { |
198 | if (regno > info->cmap.len) | 198 | if (regno < 16) { |
199 | return 1; | 199 | red >>= 8; |
200 | red >>= 8; | 200 | green >>= 8; |
201 | green >>= 8; | 201 | blue >>= 8; |
202 | blue >>= 8; | 202 | |
203 | ((u32*)(info->pseudo_palette))[regno] = (red << 16) | | ||
204 | (green << 8) | blue; | ||
205 | } | ||
203 | 206 | ||
204 | ((u32*)(info->pseudo_palette))[regno] = (red << 16) | (green << 8) | blue; | ||
205 | return 0; | 207 | return 0; |
206 | } | 208 | } |
207 | 209 | ||
@@ -237,7 +239,7 @@ static int __devinit fm2fb_probe(struct zorro_dev *z, | |||
237 | if (!zorro_request_device(z,"fm2fb")) | 239 | if (!zorro_request_device(z,"fm2fb")) |
238 | return -ENXIO; | 240 | return -ENXIO; |
239 | 241 | ||
240 | info = framebuffer_alloc(256 * sizeof(u32), &z->dev); | 242 | info = framebuffer_alloc(16 * sizeof(u32), &z->dev); |
241 | if (!info) { | 243 | if (!info) { |
242 | zorro_release_device(z); | 244 | zorro_release_device(z); |
243 | return -ENOMEM; | 245 | return -ENOMEM; |
diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c index bf0e60b5a3b6..b9b572b293d4 100644 --- a/drivers/video/gbefb.c +++ b/drivers/video/gbefb.c | |||
@@ -86,7 +86,7 @@ static int gbe_revision; | |||
86 | 86 | ||
87 | static int ypan, ywrap; | 87 | static int ypan, ywrap; |
88 | 88 | ||
89 | static uint32_t pseudo_palette[256]; | 89 | static uint32_t pseudo_palette[16]; |
90 | 90 | ||
91 | static char *mode_option __initdata = NULL; | 91 | static char *mode_option __initdata = NULL; |
92 | 92 | ||
@@ -854,8 +854,7 @@ static int gbefb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
854 | green >>= 8; | 854 | green >>= 8; |
855 | blue >>= 8; | 855 | blue >>= 8; |
856 | 856 | ||
857 | switch (info->var.bits_per_pixel) { | 857 | if (info->var.bits_per_pixel <= 8) { |
858 | case 8: | ||
859 | /* wait for the color map FIFO to have a free entry */ | 858 | /* wait for the color map FIFO to have a free entry */ |
860 | for (i = 0; i < 1000 && gbe->cm_fifo >= 63; i++) | 859 | for (i = 0; i < 1000 && gbe->cm_fifo >= 63; i++) |
861 | udelay(10); | 860 | udelay(10); |
@@ -864,23 +863,25 @@ static int gbefb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
864 | return 1; | 863 | return 1; |
865 | } | 864 | } |
866 | gbe->cmap[regno] = (red << 24) | (green << 16) | (blue << 8); | 865 | gbe->cmap[regno] = (red << 24) | (green << 16) | (blue << 8); |
867 | break; | 866 | } else if (regno < 16) { |
868 | case 15: | 867 | switch (info->var.bits_per_pixel) { |
869 | case 16: | 868 | case 15: |
870 | red >>= 3; | 869 | case 16: |
871 | green >>= 3; | 870 | red >>= 3; |
872 | blue >>= 3; | 871 | green >>= 3; |
873 | pseudo_palette[regno] = | 872 | blue >>= 3; |
874 | (red << info->var.red.offset) | | 873 | pseudo_palette[regno] = |
875 | (green << info->var.green.offset) | | 874 | (red << info->var.red.offset) | |
876 | (blue << info->var.blue.offset); | 875 | (green << info->var.green.offset) | |
877 | break; | 876 | (blue << info->var.blue.offset); |
878 | case 32: | 877 | break; |
879 | pseudo_palette[regno] = | 878 | case 32: |
880 | (red << info->var.red.offset) | | 879 | pseudo_palette[regno] = |
881 | (green << info->var.green.offset) | | 880 | (red << info->var.red.offset) | |
882 | (blue << info->var.blue.offset); | 881 | (green << info->var.green.offset) | |
883 | break; | 882 | (blue << info->var.blue.offset); |
883 | break; | ||
884 | } | ||
884 | } | 885 | } |
885 | 886 | ||
886 | return 0; | 887 | return 0; |
diff --git a/drivers/video/i810/i810.h b/drivers/video/i810/i810.h index 889e4ea5edc1..328ae6c673ec 100644 --- a/drivers/video/i810/i810.h +++ b/drivers/video/i810/i810.h | |||
@@ -266,7 +266,7 @@ struct i810fb_par { | |||
266 | struct i810fb_i2c_chan chan[3]; | 266 | struct i810fb_i2c_chan chan[3]; |
267 | struct mutex open_lock; | 267 | struct mutex open_lock; |
268 | unsigned int use_count; | 268 | unsigned int use_count; |
269 | u32 pseudo_palette[17]; | 269 | u32 pseudo_palette[16]; |
270 | unsigned long mmio_start_phys; | 270 | unsigned long mmio_start_phys; |
271 | u8 __iomem *mmio_start_virtual; | 271 | u8 __iomem *mmio_start_virtual; |
272 | u8 *edid; | 272 | u8 *edid; |
diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index 7e760197cf29..1a7d7789d877 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c | |||
@@ -1717,7 +1717,7 @@ static int __devinit i810_alloc_agp_mem(struct fb_info *info) | |||
1717 | * @info: pointer to device specific info structure | 1717 | * @info: pointer to device specific info structure |
1718 | * | 1718 | * |
1719 | * DESCRIPTION: | 1719 | * DESCRIPTION: |
1720 | * Sets the the user monitor's horizontal and vertical | 1720 | * Sets the user monitor's horizontal and vertical |
1721 | * frequency limits | 1721 | * frequency limits |
1722 | */ | 1722 | */ |
1723 | static void __devinit i810_init_monspecs(struct fb_info *info) | 1723 | static void __devinit i810_init_monspecs(struct fb_info *info) |
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c index eb1a4812ad1d..b87ea21d3d78 100644 --- a/drivers/video/igafb.c +++ b/drivers/video/igafb.c | |||
@@ -379,10 +379,6 @@ int __init igafb_init(void) | |||
379 | if (fb_get_options("igafb", NULL)) | 379 | if (fb_get_options("igafb", NULL)) |
380 | return -ENODEV; | 380 | return -ENODEV; |
381 | 381 | ||
382 | /* Do not attach when we have a serial console. */ | ||
383 | if (!con_is_present()) | ||
384 | return -ENXIO; | ||
385 | |||
386 | pdev = pci_get_device(PCI_VENDOR_ID_INTERG, | 382 | pdev = pci_get_device(PCI_VENDOR_ID_INTERG, |
387 | PCI_DEVICE_ID_INTERG_1682, 0); | 383 | PCI_DEVICE_ID_INTERG_1682, 0); |
388 | if (pdev == NULL) { | 384 | if (pdev == NULL) { |
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 267c1ff9ebd9..a12589898597 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c | |||
@@ -394,26 +394,18 @@ static void imxfb_setup_gpio(struct imxfb_info *fbi) | |||
394 | 394 | ||
395 | /* initialize GPIOs */ | 395 | /* initialize GPIOs */ |
396 | imx_gpio_mode(PD6_PF_LSCLK); | 396 | imx_gpio_mode(PD6_PF_LSCLK); |
397 | imx_gpio_mode(PD10_PF_SPL_SPR); | ||
398 | imx_gpio_mode(PD11_PF_CONTRAST); | 397 | imx_gpio_mode(PD11_PF_CONTRAST); |
399 | imx_gpio_mode(PD14_PF_FLM_VSYNC); | 398 | imx_gpio_mode(PD14_PF_FLM_VSYNC); |
400 | imx_gpio_mode(PD13_PF_LP_HSYNC); | 399 | imx_gpio_mode(PD13_PF_LP_HSYNC); |
401 | imx_gpio_mode(PD7_PF_REV); | ||
402 | imx_gpio_mode(PD8_PF_CLS); | ||
403 | |||
404 | #ifndef CONFIG_MACH_PIMX1 | ||
405 | /* on PiMX1 used as buffers enable signal | ||
406 | */ | ||
407 | imx_gpio_mode(PD9_PF_PS); | ||
408 | #endif | ||
409 | |||
410 | #ifndef CONFIG_MACH_MX1FS2 | ||
411 | /* on mx1fs2 this pin is used to (de)activate the display, so we need | ||
412 | * it as a normal gpio | ||
413 | */ | ||
414 | imx_gpio_mode(PD12_PF_ACD_OE); | 400 | imx_gpio_mode(PD12_PF_ACD_OE); |
415 | #endif | ||
416 | 401 | ||
402 | /* These are only needed for Sharp HR TFT displays */ | ||
403 | if (fbi->pcr & PCR_SHARP) { | ||
404 | imx_gpio_mode(PD7_PF_REV); | ||
405 | imx_gpio_mode(PD8_PF_CLS); | ||
406 | imx_gpio_mode(PD9_PF_PS); | ||
407 | imx_gpio_mode(PD10_PF_SPL_SPR); | ||
408 | } | ||
417 | } | 409 | } |
418 | 410 | ||
419 | #ifdef CONFIG_PM | 411 | #ifdef CONFIG_PM |
@@ -476,7 +468,6 @@ static int __init imxfb_init_fbinfo(struct device *dev) | |||
476 | 468 | ||
477 | info->fbops = &imxfb_ops; | 469 | info->fbops = &imxfb_ops; |
478 | info->flags = FBINFO_FLAG_DEFAULT; | 470 | info->flags = FBINFO_FLAG_DEFAULT; |
479 | info->pseudo_palette = (fbi + 1); | ||
480 | 471 | ||
481 | fbi->rgb[RGB_16] = &def_rgb_16; | 472 | fbi->rgb[RGB_16] = &def_rgb_16; |
482 | fbi->rgb[RGB_8] = &def_rgb_8; | 473 | fbi->rgb[RGB_8] = &def_rgb_8; |
@@ -499,6 +490,7 @@ static int __init imxfb_init_fbinfo(struct device *dev) | |||
499 | info->var.sync = inf->sync; | 490 | info->var.sync = inf->sync; |
500 | info->var.grayscale = inf->cmap_greyscale; | 491 | info->var.grayscale = inf->cmap_greyscale; |
501 | fbi->cmap_inverse = inf->cmap_inverse; | 492 | fbi->cmap_inverse = inf->cmap_inverse; |
493 | fbi->cmap_static = inf->cmap_static; | ||
502 | fbi->pcr = inf->pcr; | 494 | fbi->pcr = inf->pcr; |
503 | fbi->lscr1 = inf->lscr1; | 495 | fbi->lscr1 = inf->lscr1; |
504 | fbi->dmacr = inf->dmacr; | 496 | fbi->dmacr = inf->dmacr; |
diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index 80b94c19a9fa..6148300fadd6 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/drivers/video/intelfb/intelfb.h | |||
@@ -302,7 +302,7 @@ struct intelfb_info { | |||
302 | u32 ring_lockup; | 302 | u32 ring_lockup; |
303 | 303 | ||
304 | /* palette */ | 304 | /* palette */ |
305 | u32 pseudo_palette[17]; | 305 | u32 pseudo_palette[16]; |
306 | 306 | ||
307 | /* chip info */ | 307 | /* chip info */ |
308 | int pci_chipset; | 308 | int pci_chipset; |
diff --git a/drivers/video/kyro/STG4000InitDevice.c b/drivers/video/kyro/STG4000InitDevice.c index ab5285a7f1d6..1d3f2080aa6f 100644 --- a/drivers/video/kyro/STG4000InitDevice.c +++ b/drivers/video/kyro/STG4000InitDevice.c | |||
@@ -247,7 +247,6 @@ int SetCoreClockPLL(volatile STG4000REG __iomem *pSTGReg, struct pci_dev *pDev) | |||
247 | u32 ulCoreClock; | 247 | u32 ulCoreClock; |
248 | u32 tmp; | 248 | u32 tmp; |
249 | u32 ulChipSpeed; | 249 | u32 ulChipSpeed; |
250 | u8 rev; | ||
251 | 250 | ||
252 | STG_WRITE_REG(IntMask, 0xFFFF); | 251 | STG_WRITE_REG(IntMask, 0xFFFF); |
253 | 252 | ||
@@ -276,9 +275,9 @@ int SetCoreClockPLL(volatile STG4000REG __iomem *pSTGReg, struct pci_dev *pDev) | |||
276 | PMX2_SOFTRESET_ROM_RST); | 275 | PMX2_SOFTRESET_ROM_RST); |
277 | 276 | ||
278 | pci_read_config_word(pDev, PCI_CONFIG_SUBSYS_ID, &sub); | 277 | pci_read_config_word(pDev, PCI_CONFIG_SUBSYS_ID, &sub); |
279 | pci_read_config_byte(pDev, PCI_REVISION_ID, &rev); | ||
280 | 278 | ||
281 | ulChipSpeed = InitSDRAMRegisters(pSTGReg, (u32)sub, (u32)rev); | 279 | ulChipSpeed = InitSDRAMRegisters(pSTGReg, (u32)sub, |
280 | (u32)pDev->revision); | ||
282 | 281 | ||
283 | if (ulChipSpeed == 0) | 282 | if (ulChipSpeed == 0) |
284 | return -EINVAL; | 283 | return -EINVAL; |
diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig index 9397bcef3018..9de1c114f809 100644 --- a/drivers/video/logo/Kconfig +++ b/drivers/video/logo/Kconfig | |||
@@ -10,6 +10,11 @@ menuconfig LOGO | |||
10 | 10 | ||
11 | if LOGO | 11 | if LOGO |
12 | 12 | ||
13 | config FB_LOGO_EXTRA | ||
14 | bool | ||
15 | depends on FB=y | ||
16 | default y if SPU_BASE | ||
17 | |||
13 | config LOGO_LINUX_MONO | 18 | config LOGO_LINUX_MONO |
14 | bool "Standard black and white Linux logo" | 19 | bool "Standard black and white Linux logo" |
15 | default y | 20 | default y |
diff --git a/drivers/video/logo/Makefile b/drivers/video/logo/Makefile index b985dfad6c63..a5fc4edf84e6 100644 --- a/drivers/video/logo/Makefile +++ b/drivers/video/logo/Makefile | |||
@@ -14,6 +14,8 @@ obj-$(CONFIG_LOGO_SUPERH_VGA16) += logo_superh_vga16.o | |||
14 | obj-$(CONFIG_LOGO_SUPERH_CLUT224) += logo_superh_clut224.o | 14 | obj-$(CONFIG_LOGO_SUPERH_CLUT224) += logo_superh_clut224.o |
15 | obj-$(CONFIG_LOGO_M32R_CLUT224) += logo_m32r_clut224.o | 15 | obj-$(CONFIG_LOGO_M32R_CLUT224) += logo_m32r_clut224.o |
16 | 16 | ||
17 | obj-$(CONFIG_SPU_BASE) += logo_spe_clut224.o | ||
18 | |||
17 | # How to generate logo's | 19 | # How to generate logo's |
18 | 20 | ||
19 | # Use logo-cfiles to retrieve list of .c files to be built | 21 | # Use logo-cfiles to retrieve list of .c files to be built |
diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c index 80c03618eb53..2b0f799aa8da 100644 --- a/drivers/video/logo/logo.c +++ b/drivers/video/logo/logo.c | |||
@@ -34,8 +34,11 @@ extern const struct linux_logo logo_superh_vga16; | |||
34 | extern const struct linux_logo logo_superh_clut224; | 34 | extern const struct linux_logo logo_superh_clut224; |
35 | extern const struct linux_logo logo_m32r_clut224; | 35 | extern const struct linux_logo logo_m32r_clut224; |
36 | 36 | ||
37 | 37 | /* logo's are marked __initdata. Use __init_refok to tell | |
38 | const struct linux_logo *fb_find_logo(int depth) | 38 | * modpost that it is intended that this function uses data |
39 | * marked __initdata. | ||
40 | */ | ||
41 | const struct linux_logo * __init_refok fb_find_logo(int depth) | ||
39 | { | 42 | { |
40 | const struct linux_logo *logo = NULL; | 43 | const struct linux_logo *logo = NULL; |
41 | 44 | ||
diff --git a/drivers/video/logo/logo_spe_clut224.ppm b/drivers/video/logo/logo_spe_clut224.ppm new file mode 100644 index 000000000000..d36ad624a79c --- /dev/null +++ b/drivers/video/logo/logo_spe_clut224.ppm | |||
@@ -0,0 +1,283 @@ | |||
1 | P3 | ||
2 | 40 40 | ||
3 | 255 | ||
4 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
5 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
6 | 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 6 6 6 | ||
7 | 15 15 15 21 21 21 19 19 19 14 14 14 6 6 6 2 2 2 | ||
8 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
9 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
10 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
11 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
12 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
13 | 0 0 0 0 0 0 0 0 0 2 2 2 21 21 21 55 55 55 | ||
14 | 56 56 56 54 54 54 53 53 53 60 60 60 56 56 56 25 25 25 | ||
15 | 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
16 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
17 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
18 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
19 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
20 | 0 0 0 0 0 0 2 2 2 27 27 27 62 62 62 17 17 19 | ||
21 | 2 2 6 2 2 6 2 2 6 2 2 6 16 16 18 57 57 57 | ||
22 | 45 45 45 8 8 8 0 0 0 0 0 0 0 0 0 0 0 0 | ||
23 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
24 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
25 | 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 | ||
26 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
27 | 0 0 0 0 0 0 16 16 16 62 62 62 8 8 10 2 2 6 | ||
28 | 2 2 6 2 2 6 2 2 6 12 12 14 67 67 67 16 16 17 | ||
29 | 45 45 45 41 41 41 4 4 4 0 0 0 0 0 0 0 0 0 | ||
30 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
31 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
32 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
33 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
34 | 0 0 0 2 2 2 35 35 35 40 40 40 2 2 6 2 2 6 | ||
35 | 2 2 6 2 2 6 2 2 6 15 15 17 70 70 70 27 27 27 | ||
36 | 3 3 6 62 62 62 20 20 20 0 0 0 0 0 0 0 0 0 | ||
37 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
38 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
39 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
40 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
41 | 0 0 0 4 4 4 58 58 58 12 12 14 2 2 6 2 2 6 | ||
42 | 2 2 6 2 2 6 2 2 6 4 4 7 4 4 7 2 2 6 | ||
43 | 2 2 6 34 34 36 40 40 40 3 3 3 0 0 0 0 0 0 | ||
44 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
45 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
46 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
47 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
48 | 0 0 0 7 7 7 64 64 64 2 2 6 5 5 5 17 17 17 | ||
49 | 3 3 6 2 2 6 2 2 6 15 15 15 21 21 21 7 7 10 | ||
50 | 2 2 6 8 8 10 62 62 62 6 6 6 0 0 0 0 0 0 | ||
51 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
52 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
53 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
54 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
55 | 0 0 0 7 7 7 66 66 66 5 5 8 122 122 122 122 122 122 | ||
56 | 9 9 11 3 3 6 104 96 81 179 179 179 122 122 122 13 13 13 | ||
57 | 2 2 6 2 2 6 67 67 67 10 10 10 0 0 0 0 0 0 | ||
58 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
59 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
60 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
61 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
62 | 0 0 0 7 7 7 65 65 65 41 41 43 152 149 142 192 191 189 | ||
63 | 48 48 49 23 23 24 228 210 210 86 86 86 192 191 189 59 59 61 | ||
64 | 2 2 6 2 2 6 64 64 64 14 14 14 0 0 0 0 0 0 | ||
65 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
66 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
67 | 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 | ||
68 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
69 | 0 0 0 7 7 7 66 66 66 59 59 59 59 59 61 86 86 86 | ||
70 | 99 84 50 78 66 28 152 149 142 5 5 8 122 122 122 104 96 81 | ||
71 | 2 2 6 2 2 6 67 67 67 14 14 14 0 0 0 0 0 0 | ||
72 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
73 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
74 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
75 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
76 | 0 0 0 5 5 5 63 63 63 24 24 24 152 149 142 175 122 13 | ||
77 | 238 184 12 220 170 13 226 181 52 112 86 32 194 165 151 46 46 47 | ||
78 | 2 2 6 2 2 6 65 65 65 17 17 17 0 0 0 0 0 0 | ||
79 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
80 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
81 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
82 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
83 | 0 0 0 5 5 5 59 59 59 21 21 21 175 122 13 231 174 11 | ||
84 | 240 192 13 237 183 61 240 192 13 240 192 13 234 179 16 81 64 9 | ||
85 | 2 2 6 2 2 6 63 63 63 25 25 25 0 0 0 0 0 0 | ||
86 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
87 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
88 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
89 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
90 | 0 0 0 5 5 5 54 54 54 51 48 39 189 138 9 238 184 12 | ||
91 | 240 192 13 240 192 13 240 192 13 215 161 11 207 152 19 81 64 9 | ||
92 | 16 16 18 5 5 8 40 40 40 44 44 44 4 4 4 0 0 0 | ||
93 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
94 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
95 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
96 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
97 | 0 0 0 5 5 5 59 59 59 27 27 27 126 107 64 187 136 12 | ||
98 | 220 170 13 201 147 20 189 138 9 198 154 46 199 182 125 70 70 70 | ||
99 | 27 27 27 104 96 81 12 12 14 70 70 70 16 16 16 0 0 0 | ||
100 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
101 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
102 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
103 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
104 | 0 0 0 17 17 17 70 70 70 12 12 12 168 168 168 174 135 135 | ||
105 | 175 122 13 175 122 13 178 151 83 192 191 189 233 233 233 179 179 179 | ||
106 | 3 3 6 29 29 31 3 3 6 41 41 41 44 44 44 5 5 5 | ||
107 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
108 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
109 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
110 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
111 | 8 8 8 53 53 53 44 44 44 59 59 59 238 238 238 192 191 189 | ||
112 | 192 191 189 192 191 189 221 205 205 240 240 240 253 253 253 253 253 253 | ||
113 | 70 70 70 2 2 6 2 2 6 5 5 8 67 67 67 22 22 22 | ||
114 | 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
115 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
116 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
117 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 | ||
118 | 38 38 38 56 56 56 7 7 9 221 205 205 253 253 253 233 233 233 | ||
119 | 221 205 205 233 233 233 251 251 251 253 253 253 253 253 253 253 253 253 | ||
120 | 192 191 189 2 2 6 2 2 6 2 2 6 25 25 25 64 64 64 | ||
121 | 15 15 15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
122 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
123 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
124 | 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 27 27 27 | ||
125 | 66 66 66 7 7 9 86 86 86 252 252 252 253 253 253 253 253 253 | ||
126 | 252 252 252 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 | ||
127 | 244 244 244 19 19 21 2 2 6 2 2 6 2 2 6 38 38 38 | ||
128 | 54 54 54 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 | ||
129 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
130 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
131 | 0 0 0 0 0 0 0 0 0 0 0 0 14 14 14 62 62 62 | ||
132 | 10 10 12 3 3 6 122 122 122 235 235 235 251 251 251 248 248 248 | ||
133 | 235 235 235 248 248 248 252 252 252 246 246 246 233 233 233 237 228 228 | ||
134 | 223 207 207 70 70 70 2 2 6 2 2 6 2 2 6 2 2 6 | ||
135 | 46 46 47 38 38 38 4 4 4 0 0 0 0 0 0 0 0 0 | ||
136 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
137 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
138 | 0 0 0 0 0 0 0 0 0 2 2 2 33 33 33 44 44 44 | ||
139 | 4 4 7 9 9 11 168 168 168 240 240 240 252 252 252 252 252 252 | ||
140 | 246 246 246 253 253 253 253 253 253 251 251 251 245 241 241 233 233 233 | ||
141 | 221 205 205 192 191 189 29 29 31 27 27 27 9 9 12 2 2 6 | ||
142 | 3 3 6 65 65 65 15 15 15 0 0 0 0 0 0 0 0 0 | ||
143 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
144 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
145 | 0 0 0 0 0 0 0 0 0 6 6 6 59 59 59 19 19 21 | ||
146 | 24 24 24 86 86 86 249 249 249 253 253 253 253 253 253 253 253 253 | ||
147 | 253 253 253 228 210 210 241 230 230 253 253 253 253 253 253 253 253 253 | ||
148 | 251 251 251 228 210 210 152 149 142 5 5 8 27 27 27 4 4 7 | ||
149 | 2 2 6 46 46 47 34 34 34 2 2 2 0 0 0 0 0 0 | ||
150 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
151 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
152 | 0 0 0 0 0 0 0 0 0 16 16 16 67 67 67 19 19 21 | ||
153 | 12 12 14 223 207 207 254 20 20 254 20 20 253 127 127 242 223 223 | ||
154 | 254 20 20 253 127 127 254 48 48 242 223 223 254 86 86 254 20 20 | ||
155 | 254 20 20 253 137 137 233 233 233 32 32 32 35 35 35 23 23 24 | ||
156 | 2 2 6 15 15 15 60 60 60 6 6 6 0 0 0 0 0 0 | ||
157 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
158 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
159 | 0 0 0 0 0 0 4 4 4 38 38 38 48 48 49 22 22 22 | ||
160 | 86 86 86 253 253 253 254 20 20 241 230 230 227 216 186 253 137 137 | ||
161 | 253 137 137 253 253 253 253 137 137 253 137 137 254 48 48 253 253 253 | ||
162 | 253 253 253 253 253 253 253 253 253 62 62 62 2 2 6 23 23 24 | ||
163 | 2 2 6 2 2 6 62 62 62 17 17 17 0 0 0 0 0 0 | ||
164 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
165 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
166 | 0 0 0 0 0 0 14 14 14 70 70 70 14 14 14 16 16 18 | ||
167 | 179 179 179 253 253 253 227 216 186 254 48 48 240 219 160 253 127 127 | ||
168 | 254 20 20 253 137 137 254 86 86 231 203 141 254 20 20 254 20 20 | ||
169 | 253 137 137 253 253 253 253 253 253 104 96 81 2 2 6 23 23 24 | ||
170 | 2 2 6 2 2 6 46 46 47 27 27 27 0 0 0 0 0 0 | ||
171 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
172 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
173 | 0 0 0 4 4 4 39 39 39 42 42 43 19 19 21 13 13 13 | ||
174 | 228 210 210 242 223 223 253 253 253 242 223 223 253 127 127 253 127 127 | ||
175 | 253 127 127 253 127 127 253 137 137 253 253 253 254 48 48 253 253 253 | ||
176 | 228 210 210 253 253 253 253 253 253 122 122 122 2 2 6 19 19 19 | ||
177 | 2 2 6 2 2 6 39 39 39 38 38 38 3 3 3 0 0 0 | ||
178 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
179 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
180 | 0 0 0 8 8 8 60 60 60 3 3 6 33 33 33 38 38 38 | ||
181 | 253 137 137 254 86 86 253 137 137 254 86 86 253 137 137 209 197 168 | ||
182 | 253 127 127 253 253 253 253 253 253 253 253 253 253 127 127 254 86 86 | ||
183 | 254 86 86 253 137 137 253 253 253 122 122 122 2 2 6 17 17 17 | ||
184 | 2 2 6 2 2 6 34 34 36 42 42 43 3 3 3 0 0 0 | ||
185 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
186 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
187 | 0 0 0 13 13 13 59 59 59 2 2 6 9 9 12 56 56 56 | ||
188 | 252 252 252 240 219 160 253 137 137 240 219 160 253 253 253 237 228 228 | ||
189 | 254 86 86 253 253 253 253 253 253 253 253 253 253 253 253 242 223 223 | ||
190 | 227 216 186 249 249 249 253 253 253 122 122 122 16 16 17 17 17 17 | ||
191 | 12 12 14 3 3 6 39 39 39 38 38 38 3 3 3 0 0 0 | ||
192 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
193 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 | ||
194 | 5 5 5 22 22 22 104 96 81 187 136 12 207 152 19 51 48 39 | ||
195 | 221 205 205 253 253 253 253 253 253 253 253 253 253 253 253 240 240 240 | ||
196 | 250 247 243 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 | ||
197 | 253 253 253 250 247 243 240 219 160 99 84 50 5 5 8 2 2 6 | ||
198 | 7 7 9 46 46 47 58 58 58 35 35 35 3 3 3 0 0 0 | ||
199 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
200 | 0 0 0 0 0 0 0 0 0 0 0 0 8 8 8 33 33 33 | ||
201 | 58 58 58 86 86 86 170 136 53 239 182 13 246 190 14 220 170 13 | ||
202 | 44 38 29 179 179 179 253 253 253 253 253 253 253 253 253 240 240 240 | ||
203 | 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 | ||
204 | 253 253 253 240 219 160 240 192 13 112 86 32 2 2 6 2 2 6 | ||
205 | 3 3 6 41 33 20 220 170 13 53 53 53 4 4 4 0 0 0 | ||
206 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
207 | 0 0 0 0 0 0 0 0 0 2 2 2 32 32 32 150 116 44 | ||
208 | 215 161 11 215 161 11 228 170 11 245 188 14 246 190 14 246 190 14 | ||
209 | 187 136 12 9 9 11 122 122 122 251 251 251 253 253 253 253 253 253 | ||
210 | 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 | ||
211 | 248 248 248 211 196 135 239 182 13 175 122 13 6 5 6 2 2 6 | ||
212 | 16 14 12 187 136 12 238 184 12 84 78 65 10 10 10 0 0 0 | ||
213 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
214 | 0 0 0 0 0 0 0 0 0 4 4 4 53 53 53 207 152 19 | ||
215 | 242 185 13 245 188 14 246 190 14 246 190 14 246 190 14 246 190 14 | ||
216 | 240 192 13 81 64 9 2 2 6 86 86 86 244 244 244 253 253 253 | ||
217 | 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 | ||
218 | 233 233 233 199 182 125 231 174 11 207 152 19 175 122 13 175 122 13 | ||
219 | 201 147 20 239 182 13 244 187 14 150 116 44 35 35 35 6 6 6 | ||
220 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
221 | 0 0 0 0 0 0 0 0 0 5 5 5 53 53 53 201 147 20 | ||
222 | 242 185 13 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 | ||
223 | 246 190 14 220 170 13 13 11 10 2 2 6 152 149 142 253 253 253 | ||
224 | 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 | ||
225 | 235 235 235 199 182 125 228 170 11 234 177 12 226 168 11 226 168 11 | ||
226 | 234 177 12 246 190 14 246 190 14 234 179 16 126 107 64 36 36 36 | ||
227 | 6 6 6 0 0 0 0 0 0 0 0 0 | ||
228 | 0 0 0 0 0 0 0 0 0 3 3 3 48 48 49 189 142 35 | ||
229 | 242 185 13 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 | ||
230 | 246 190 14 246 190 14 140 112 39 36 36 36 192 191 189 253 253 253 | ||
231 | 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 | ||
232 | 192 191 189 112 86 32 226 168 11 244 187 14 244 187 14 244 187 14 | ||
233 | 245 188 14 246 190 14 246 190 14 246 190 14 242 185 13 150 116 44 | ||
234 | 27 27 27 2 2 2 0 0 0 0 0 0 | ||
235 | 0 0 0 0 0 0 0 0 0 6 6 6 58 58 58 189 142 35 | ||
236 | 239 182 13 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 | ||
237 | 246 190 14 246 190 14 239 188 14 209 197 168 253 253 253 253 253 253 | ||
238 | 253 253 253 253 253 253 253 253 253 253 253 253 252 252 252 168 168 168 | ||
239 | 16 16 18 97 67 8 228 170 11 245 188 14 246 190 14 246 190 14 | ||
240 | 246 190 14 246 190 14 246 190 14 246 190 14 244 187 14 198 154 46 | ||
241 | 35 35 35 3 3 3 0 0 0 0 0 0 | ||
242 | 0 0 0 0 0 0 0 0 0 13 13 13 84 78 65 215 161 11 | ||
243 | 244 187 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 | ||
244 | 246 190 14 246 190 14 238 184 12 187 136 12 168 168 168 244 244 244 | ||
245 | 253 253 253 252 252 252 240 240 240 179 179 179 67 67 67 2 2 6 | ||
246 | 2 2 6 97 67 8 228 170 11 246 190 14 246 190 14 246 190 14 | ||
247 | 246 190 14 246 190 14 245 188 14 234 177 12 189 142 35 86 77 61 | ||
248 | 16 16 16 0 0 0 0 0 0 0 0 0 | ||
249 | 0 0 0 0 0 0 0 0 0 13 13 13 103 92 56 207 152 19 | ||
250 | 228 170 11 234 177 12 239 182 13 242 186 14 245 188 14 246 190 14 | ||
251 | 246 190 14 246 190 14 239 182 13 189 138 9 41 33 20 10 10 12 | ||
252 | 30 30 31 23 23 24 5 5 8 2 2 6 2 2 6 2 2 6 | ||
253 | 4 4 6 112 86 32 215 161 11 245 188 14 246 190 14 245 188 14 | ||
254 | 239 182 13 228 170 11 189 142 35 104 96 81 48 48 49 17 17 17 | ||
255 | 2 2 2 0 0 0 0 0 0 0 0 0 | ||
256 | 0 0 0 0 0 0 0 0 0 5 5 5 39 39 39 103 92 56 | ||
257 | 141 109 44 175 122 13 187 136 12 189 138 9 207 152 19 228 170 11 | ||
258 | 239 182 13 239 182 13 215 161 11 175 122 13 41 33 20 2 2 6 | ||
259 | 15 15 17 20 20 22 20 20 22 20 20 22 20 20 22 8 8 10 | ||
260 | 4 4 6 97 67 8 189 138 9 231 174 11 239 182 13 226 168 11 | ||
261 | 189 138 9 126 107 64 59 59 59 21 21 21 5 5 5 0 0 0 | ||
262 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
263 | 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 17 17 17 | ||
264 | 34 34 34 57 57 57 84 78 65 103 92 56 125 101 41 140 112 39 | ||
265 | 175 122 13 175 122 13 175 122 13 97 67 8 72 67 58 84 78 65 | ||
266 | 60 60 60 56 56 56 56 56 56 56 56 56 57 57 57 65 65 65 | ||
267 | 86 86 86 95 73 34 175 122 13 187 136 12 187 136 12 175 122 13 | ||
268 | 103 92 56 41 41 41 10 10 10 0 0 0 0 0 0 0 0 0 | ||
269 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
270 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
271 | 2 2 2 4 4 4 12 12 12 24 24 24 40 40 40 70 70 70 | ||
272 | 86 77 61 95 73 34 88 72 41 72 67 58 36 36 36 10 10 10 | ||
273 | 5 5 5 5 5 5 5 5 5 4 4 4 5 5 5 6 6 6 | ||
274 | 22 22 22 61 61 59 88 72 41 112 86 32 112 86 32 84 78 65 | ||
275 | 32 32 32 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 | ||
276 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
277 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
278 | 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 10 10 10 | ||
279 | 21 21 21 33 33 33 31 31 31 16 16 16 2 2 2 0 0 0 | ||
280 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
281 | 2 2 2 12 12 12 30 30 31 40 40 40 32 32 32 16 16 16 | ||
282 | 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||
283 | 0 0 0 0 0 0 0 0 0 0 0 0 | ||
diff --git a/drivers/video/macfb.c b/drivers/video/macfb.c index f7d647dda978..aa8c714d6245 100644 --- a/drivers/video/macfb.c +++ b/drivers/video/macfb.c | |||
@@ -170,7 +170,7 @@ static struct fb_fix_screeninfo macfb_fix = { | |||
170 | }; | 170 | }; |
171 | 171 | ||
172 | static struct fb_info fb_info; | 172 | static struct fb_info fb_info; |
173 | static u32 pseudo_palette[17]; | 173 | static u32 pseudo_palette[16]; |
174 | static int inverse = 0; | 174 | static int inverse = 0; |
175 | static int vidtest = 0; | 175 | static int vidtest = 0; |
176 | 176 | ||
@@ -529,56 +529,63 @@ static int macfb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
529 | if (regno >= fb_info->cmap.len) | 529 | if (regno >= fb_info->cmap.len) |
530 | return 1; | 530 | return 1; |
531 | 531 | ||
532 | switch (fb_info->var.bits_per_pixel) { | 532 | if (fb_info->var.bits_per_pixel <= 8) { |
533 | case 1: | 533 | switch (fb_info->var.bits_per_pixel) { |
534 | /* We shouldn't get here */ | 534 | case 1: |
535 | break; | 535 | /* We shouldn't get here */ |
536 | case 2: | 536 | break; |
537 | case 4: | 537 | case 2: |
538 | case 8: | 538 | case 4: |
539 | if (macfb_setpalette) | 539 | case 8: |
540 | macfb_setpalette(regno, red, green, blue, fb_info); | 540 | if (macfb_setpalette) |
541 | else | 541 | macfb_setpalette(regno, red, green, blue, |
542 | return 1; | 542 | fb_info); |
543 | break; | 543 | else |
544 | case 16: | 544 | return 1; |
545 | if (fb_info->var.red.offset == 10) { | 545 | break; |
546 | /* 1:5:5:5 */ | 546 | } |
547 | ((u32*) (fb_info->pseudo_palette))[regno] = | 547 | } else if (regno < 16) { |
548 | switch (fb_info->var.bits_per_pixel) { | ||
549 | case 16: | ||
550 | if (fb_info->var.red.offset == 10) { | ||
551 | /* 1:5:5:5 */ | ||
552 | ((u32*) (fb_info->pseudo_palette))[regno] = | ||
548 | ((red & 0xf800) >> 1) | | 553 | ((red & 0xf800) >> 1) | |
549 | ((green & 0xf800) >> 6) | | 554 | ((green & 0xf800) >> 6) | |
550 | ((blue & 0xf800) >> 11) | | 555 | ((blue & 0xf800) >> 11) | |
551 | ((transp != 0) << 15); | 556 | ((transp != 0) << 15); |
552 | } else { | 557 | } else { |
553 | /* 0:5:6:5 */ | 558 | /* 0:5:6:5 */ |
554 | ((u32*) (fb_info->pseudo_palette))[regno] = | 559 | ((u32*) (fb_info->pseudo_palette))[regno] = |
555 | ((red & 0xf800) ) | | 560 | ((red & 0xf800) ) | |
556 | ((green & 0xfc00) >> 5) | | 561 | ((green & 0xfc00) >> 5) | |
557 | ((blue & 0xf800) >> 11); | 562 | ((blue & 0xf800) >> 11); |
563 | } | ||
564 | break; | ||
565 | /* I'm pretty sure that one or the other of these | ||
566 | doesn't exist on 68k Macs */ | ||
567 | case 24: | ||
568 | red >>= 8; | ||
569 | green >>= 8; | ||
570 | blue >>= 8; | ||
571 | ((u32 *)(fb_info->pseudo_palette))[regno] = | ||
572 | (red << fb_info->var.red.offset) | | ||
573 | (green << fb_info->var.green.offset) | | ||
574 | (blue << fb_info->var.blue.offset); | ||
575 | break; | ||
576 | case 32: | ||
577 | red >>= 8; | ||
578 | green >>= 8; | ||
579 | blue >>= 8; | ||
580 | ((u32 *)(fb_info->pseudo_palette))[regno] = | ||
581 | (red << fb_info->var.red.offset) | | ||
582 | (green << fb_info->var.green.offset) | | ||
583 | (blue << fb_info->var.blue.offset); | ||
584 | break; | ||
558 | } | 585 | } |
559 | break; | 586 | } |
560 | /* I'm pretty sure that one or the other of these | 587 | |
561 | doesn't exist on 68k Macs */ | 588 | return 0; |
562 | case 24: | ||
563 | red >>= 8; | ||
564 | green >>= 8; | ||
565 | blue >>= 8; | ||
566 | ((u32 *)(fb_info->pseudo_palette))[regno] = | ||
567 | (red << fb_info->var.red.offset) | | ||
568 | (green << fb_info->var.green.offset) | | ||
569 | (blue << fb_info->var.blue.offset); | ||
570 | break; | ||
571 | case 32: | ||
572 | red >>= 8; | ||
573 | green >>= 8; | ||
574 | blue >>= 8; | ||
575 | ((u32 *)(fb_info->pseudo_palette))[regno] = | ||
576 | (red << fb_info->var.red.offset) | | ||
577 | (green << fb_info->var.green.offset) | | ||
578 | (blue << fb_info->var.blue.offset); | ||
579 | break; | ||
580 | } | ||
581 | return 0; | ||
582 | } | 589 | } |
583 | 590 | ||
584 | static struct fb_ops macfb_ops = { | 591 | static struct fb_ops macfb_ops = { |
diff --git a/drivers/video/macmodes.c b/drivers/video/macmodes.c index ab2149531a04..083f60321ed8 100644 --- a/drivers/video/macmodes.c +++ b/drivers/video/macmodes.c | |||
@@ -369,9 +369,8 @@ EXPORT_SYMBOL(mac_map_monitor_sense); | |||
369 | * | 369 | * |
370 | */ | 370 | */ |
371 | 371 | ||
372 | int __devinit mac_find_mode(struct fb_var_screeninfo *var, | 372 | int mac_find_mode(struct fb_var_screeninfo *var, struct fb_info *info, |
373 | struct fb_info *info, const char *mode_option, | 373 | const char *mode_option, unsigned int default_bpp) |
374 | unsigned int default_bpp) | ||
375 | { | 374 | { |
376 | const struct fb_videomode *db = NULL; | 375 | const struct fb_videomode *db = NULL; |
377 | unsigned int dbsize = 0; | 376 | unsigned int dbsize = 0; |
diff --git a/drivers/video/macmodes.h b/drivers/video/macmodes.h index babeb81f467d..b86ba08aac9e 100644 --- a/drivers/video/macmodes.h +++ b/drivers/video/macmodes.h | |||
@@ -55,10 +55,10 @@ extern int mac_vmode_to_var(int vmode, int cmode, | |||
55 | extern int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode, | 55 | extern int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode, |
56 | int *cmode); | 56 | int *cmode); |
57 | extern int mac_map_monitor_sense(int sense); | 57 | extern int mac_map_monitor_sense(int sense); |
58 | extern int __devinit mac_find_mode(struct fb_var_screeninfo *var, | 58 | extern int mac_find_mode(struct fb_var_screeninfo *var, |
59 | struct fb_info *info, | 59 | struct fb_info *info, |
60 | const char *mode_option, | 60 | const char *mode_option, |
61 | unsigned int default_bpp); | 61 | unsigned int default_bpp); |
62 | 62 | ||
63 | 63 | ||
64 | /* | 64 | /* |
diff --git a/drivers/video/matrox/matroxfb_Ti3026.c b/drivers/video/matrox/matroxfb_Ti3026.c index a5690a5f29d5..9445cdb759b1 100644 --- a/drivers/video/matrox/matroxfb_Ti3026.c +++ b/drivers/video/matrox/matroxfb_Ti3026.c | |||
@@ -72,7 +72,7 @@ | |||
72 | * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> | 72 | * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> |
73 | * | 73 | * |
74 | * (following author is not in any relation with this code, but his ideas | 74 | * (following author is not in any relation with this code, but his ideas |
75 | * were used when writting this driver) | 75 | * were used when writing this driver) |
76 | * | 76 | * |
77 | * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> | 77 | * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> |
78 | * | 78 | * |
diff --git a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c index a5c825d99466..3660d2673bdc 100644 --- a/drivers/video/matrox/matroxfb_accel.c +++ b/drivers/video/matrox/matroxfb_accel.c | |||
@@ -70,7 +70,7 @@ | |||
70 | * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> | 70 | * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> |
71 | * | 71 | * |
72 | * (following author is not in any relation with this code, but his ideas | 72 | * (following author is not in any relation with this code, but his ideas |
73 | * were used when writting this driver) | 73 | * were used when writing this driver) |
74 | * | 74 | * |
75 | * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> | 75 | * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> |
76 | * | 76 | * |
@@ -91,7 +91,6 @@ static inline void matrox_cfb4_pal(u_int32_t* pal) { | |||
91 | for (i = 0; i < 16; i++) { | 91 | for (i = 0; i < 16; i++) { |
92 | pal[i] = i * 0x11111111U; | 92 | pal[i] = i * 0x11111111U; |
93 | } | 93 | } |
94 | pal[i] = 0xFFFFFFFF; | ||
95 | } | 94 | } |
96 | 95 | ||
97 | static inline void matrox_cfb8_pal(u_int32_t* pal) { | 96 | static inline void matrox_cfb8_pal(u_int32_t* pal) { |
@@ -100,7 +99,6 @@ static inline void matrox_cfb8_pal(u_int32_t* pal) { | |||
100 | for (i = 0; i < 16; i++) { | 99 | for (i = 0; i < 16; i++) { |
101 | pal[i] = i * 0x01010101U; | 100 | pal[i] = i * 0x01010101U; |
102 | } | 101 | } |
103 | pal[i] = 0x0F0F0F0F; | ||
104 | } | 102 | } |
105 | 103 | ||
106 | static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area); | 104 | static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area); |
@@ -145,13 +143,10 @@ void matrox_cfbX_init(WPMINFO2) { | |||
145 | ACCESS_FBINFO(fbops).fb_imageblit = matroxfb_imageblit; | 143 | ACCESS_FBINFO(fbops).fb_imageblit = matroxfb_imageblit; |
146 | } | 144 | } |
147 | break; | 145 | break; |
148 | case 16: if (ACCESS_FBINFO(fbcon).var.green.length == 5) { | 146 | case 16: if (ACCESS_FBINFO(fbcon).var.green.length == 5) |
149 | maccess = 0xC0000001; | 147 | maccess = 0xC0000001; |
150 | ACCESS_FBINFO(cmap[16]) = 0x7FFF7FFF; | 148 | else |
151 | } else { | ||
152 | maccess = 0x40000001; | 149 | maccess = 0x40000001; |
153 | ACCESS_FBINFO(cmap[16]) = 0xFFFFFFFF; | ||
154 | } | ||
155 | mopmode = M_OPMODE_16BPP; | 150 | mopmode = M_OPMODE_16BPP; |
156 | if (accel) { | 151 | if (accel) { |
157 | ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea; | 152 | ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea; |
@@ -161,7 +156,6 @@ void matrox_cfbX_init(WPMINFO2) { | |||
161 | break; | 156 | break; |
162 | case 24: maccess = 0x00000003; | 157 | case 24: maccess = 0x00000003; |
163 | mopmode = M_OPMODE_24BPP; | 158 | mopmode = M_OPMODE_24BPP; |
164 | ACCESS_FBINFO(cmap[16]) = 0xFFFFFFFF; | ||
165 | if (accel) { | 159 | if (accel) { |
166 | ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea; | 160 | ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea; |
167 | ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect; | 161 | ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect; |
@@ -170,7 +164,6 @@ void matrox_cfbX_init(WPMINFO2) { | |||
170 | break; | 164 | break; |
171 | case 32: maccess = 0x00000002; | 165 | case 32: maccess = 0x00000002; |
172 | mopmode = M_OPMODE_32BPP; | 166 | mopmode = M_OPMODE_32BPP; |
173 | ACCESS_FBINFO(cmap[16]) = 0xFFFFFFFF; | ||
174 | if (accel) { | 167 | if (accel) { |
175 | ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea; | 168 | ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea; |
176 | ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect; | 169 | ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect; |
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index cb2aa402ddfd..86ca7b179000 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c | |||
@@ -93,7 +93,7 @@ | |||
93 | * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> | 93 | * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> |
94 | * | 94 | * |
95 | * (following author is not in any relation with this code, but his ideas | 95 | * (following author is not in any relation with this code, but his ideas |
96 | * were used when writting this driver) | 96 | * were used when writing this driver) |
97 | * | 97 | * |
98 | * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> | 98 | * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> |
99 | * | 99 | * |
@@ -679,6 +679,8 @@ static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
679 | mga_outb(M_DAC_VAL, blue); | 679 | mga_outb(M_DAC_VAL, blue); |
680 | break; | 680 | break; |
681 | case 16: | 681 | case 16: |
682 | if (regno >= 16) | ||
683 | break; | ||
682 | { | 684 | { |
683 | u_int16_t col = | 685 | u_int16_t col = |
684 | (red << ACCESS_FBINFO(fbcon).var.red.offset) | | 686 | (red << ACCESS_FBINFO(fbcon).var.red.offset) | |
@@ -690,6 +692,8 @@ static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
690 | break; | 692 | break; |
691 | case 24: | 693 | case 24: |
692 | case 32: | 694 | case 32: |
695 | if (regno >= 16) | ||
696 | break; | ||
693 | ACCESS_FBINFO(cmap[regno]) = | 697 | ACCESS_FBINFO(cmap[regno]) = |
694 | (red << ACCESS_FBINFO(fbcon).var.red.offset) | | 698 | (red << ACCESS_FBINFO(fbcon).var.red.offset) | |
695 | (green << ACCESS_FBINFO(fbcon).var.green.offset) | | 699 | (green << ACCESS_FBINFO(fbcon).var.green.offset) | |
@@ -1994,7 +1998,6 @@ static void matroxfb_unregister_device(struct matrox_fb_info* minfo) { | |||
1994 | 1998 | ||
1995 | static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dummy) { | 1999 | static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dummy) { |
1996 | struct board* b; | 2000 | struct board* b; |
1997 | u_int8_t rev; | ||
1998 | u_int16_t svid; | 2001 | u_int16_t svid; |
1999 | u_int16_t sid; | 2002 | u_int16_t sid; |
2000 | struct matrox_fb_info* minfo; | 2003 | struct matrox_fb_info* minfo; |
@@ -2005,11 +2008,10 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm | |||
2005 | #endif | 2008 | #endif |
2006 | DBG(__FUNCTION__) | 2009 | DBG(__FUNCTION__) |
2007 | 2010 | ||
2008 | pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); | ||
2009 | svid = pdev->subsystem_vendor; | 2011 | svid = pdev->subsystem_vendor; |
2010 | sid = pdev->subsystem_device; | 2012 | sid = pdev->subsystem_device; |
2011 | for (b = dev_list; b->vendor; b++) { | 2013 | for (b = dev_list; b->vendor; b++) { |
2012 | if ((b->vendor != pdev->vendor) || (b->device != pdev->device) || (b->rev < rev)) continue; | 2014 | if ((b->vendor != pdev->vendor) || (b->device != pdev->device) || (b->rev < pdev->revision)) continue; |
2013 | if (b->svid) | 2015 | if (b->svid) |
2014 | if ((b->svid != svid) || (b->sid != sid)) continue; | 2016 | if ((b->svid != svid) || (b->sid != sid)) continue; |
2015 | break; | 2017 | break; |
diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h index 9c25c2f7966b..d59577c8de86 100644 --- a/drivers/video/matrox/matroxfb_base.h +++ b/drivers/video/matrox/matroxfb_base.h | |||
@@ -518,7 +518,7 @@ struct matrox_fb_info { | |||
518 | dll:1; | 518 | dll:1; |
519 | } memory; | 519 | } memory; |
520 | } values; | 520 | } values; |
521 | u_int32_t cmap[17]; | 521 | u_int32_t cmap[16]; |
522 | }; | 522 | }; |
523 | 523 | ||
524 | #define info2minfo(info) container_of(info, struct matrox_fb_info, fbcon) | 524 | #define info2minfo(info) container_of(info, struct matrox_fb_info, fbcon) |
diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c index 03ae55b168ff..4b3344e03695 100644 --- a/drivers/video/matrox/matroxfb_crtc2.c +++ b/drivers/video/matrox/matroxfb_crtc2.c | |||
@@ -163,11 +163,6 @@ static void matroxfb_dh_disable(struct matroxfb_dh_fb_info* m2info) { | |||
163 | ACCESS_FBINFO(hw).crtc2.ctl = 0x00000004; | 163 | ACCESS_FBINFO(hw).crtc2.ctl = 0x00000004; |
164 | } | 164 | } |
165 | 165 | ||
166 | static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info) { | ||
167 | /* no acceleration for secondary head... */ | ||
168 | m2info->cmap[16] = 0xFFFFFFFF; | ||
169 | } | ||
170 | |||
171 | static void matroxfb_dh_pan_var(struct matroxfb_dh_fb_info* m2info, | 166 | static void matroxfb_dh_pan_var(struct matroxfb_dh_fb_info* m2info, |
172 | struct fb_var_screeninfo* var) { | 167 | struct fb_var_screeninfo* var) { |
173 | unsigned int pos; | 168 | unsigned int pos; |
@@ -385,7 +380,6 @@ static int matroxfb_dh_set_par(struct fb_info* info) { | |||
385 | } | 380 | } |
386 | } | 381 | } |
387 | up_read(&ACCESS_FBINFO(altout).lock); | 382 | up_read(&ACCESS_FBINFO(altout).lock); |
388 | matroxfb_dh_cfbX_init(m2info); | ||
389 | } | 383 | } |
390 | m2info->initialized = 1; | 384 | m2info->initialized = 1; |
391 | return 0; | 385 | return 0; |
diff --git a/drivers/video/matrox/matroxfb_crtc2.h b/drivers/video/matrox/matroxfb_crtc2.h index 608e40bb20e9..1005582e843e 100644 --- a/drivers/video/matrox/matroxfb_crtc2.h +++ b/drivers/video/matrox/matroxfb_crtc2.h | |||
@@ -2,8 +2,6 @@ | |||
2 | #define __MATROXFB_CRTC2_H__ | 2 | #define __MATROXFB_CRTC2_H__ |
3 | 3 | ||
4 | #include <linux/ioctl.h> | 4 | #include <linux/ioctl.h> |
5 | #include <linux/i2c.h> | ||
6 | #include <linux/i2c-algo-bit.h> | ||
7 | #include "matroxfb_base.h" | 5 | #include "matroxfb_base.h" |
8 | 6 | ||
9 | struct matroxfb_dh_fb_info { | 7 | struct matroxfb_dh_fb_info { |
@@ -30,7 +28,7 @@ struct matroxfb_dh_fb_info { | |||
30 | 28 | ||
31 | unsigned int interlaced:1; | 29 | unsigned int interlaced:1; |
32 | 30 | ||
33 | u_int32_t cmap[17]; | 31 | u_int32_t cmap[16]; |
34 | }; | 32 | }; |
35 | 33 | ||
36 | #endif /* __MATROXFB_CRTC2_H__ */ | 34 | #endif /* __MATROXFB_CRTC2_H__ */ |
diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c index 5d29a26b8cdf..de0d755f9019 100644 --- a/drivers/video/matrox/matroxfb_maven.c +++ b/drivers/video/matrox/matroxfb_maven.c | |||
@@ -273,8 +273,11 @@ static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll, | |||
273 | } | 273 | } |
274 | } | 274 | } |
275 | } | 275 | } |
276 | |||
277 | /* if h2/post/in/feed have not been assigned, return zero (error) */ | ||
276 | if (besth2 < 2) | 278 | if (besth2 < 2) |
277 | return 0; | 279 | return 0; |
280 | |||
278 | dprintk(KERN_ERR "clk: %02X %02X %02X %d %d\n", *in, *feed, *post, fxtal, fwant); | 281 | dprintk(KERN_ERR "clk: %02X %02X %02X %d %d\n", *in, *feed, *post, fxtal, fwant); |
279 | return fxtal * (*feed) / (*in) * ctl->den; | 282 | return fxtal * (*feed) / (*in) * ctl->den; |
280 | } | 283 | } |
@@ -284,7 +287,7 @@ static unsigned int matroxfb_mavenclock(const struct matrox_pll_ctl* ctl, | |||
284 | unsigned int* in, unsigned int* feed, unsigned int* post, | 287 | unsigned int* in, unsigned int* feed, unsigned int* post, |
285 | unsigned int* htotal2) { | 288 | unsigned int* htotal2) { |
286 | unsigned int fvco; | 289 | unsigned int fvco; |
287 | unsigned int p; | 290 | unsigned int uninitialized_var(p); |
288 | 291 | ||
289 | fvco = matroxfb_PLL_mavenclock(&maven1000_pll, ctl, htotal, vtotal, in, feed, &p, htotal2); | 292 | fvco = matroxfb_PLL_mavenclock(&maven1000_pll, ctl, htotal, vtotal, in, feed, &p, htotal2); |
290 | if (!fvco) | 293 | if (!fvco) |
@@ -715,7 +718,9 @@ static int maven_find_exact_clocks(unsigned int ht, unsigned int vt, | |||
715 | m->regs[0x82] = 0x81; | 718 | m->regs[0x82] = 0x81; |
716 | 719 | ||
717 | for (x = 0; x < 8; x++) { | 720 | for (x = 0; x < 8; x++) { |
718 | unsigned int a, b, c, h2; | 721 | unsigned int c; |
722 | unsigned int uninitialized_var(a), uninitialized_var(b), | ||
723 | uninitialized_var(h2); | ||
719 | unsigned int h = ht + 2 + x; | 724 | unsigned int h = ht + 2 + x; |
720 | 725 | ||
721 | if (!matroxfb_mavenclock((m->mode == MATROXFB_OUTPUT_MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) { | 726 | if (!matroxfb_mavenclock((m->mode == MATROXFB_OUTPUT_MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) { |
diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c index 18886b629cb1..5948e54b9ef9 100644 --- a/drivers/video/matrox/matroxfb_misc.c +++ b/drivers/video/matrox/matroxfb_misc.c | |||
@@ -78,7 +78,7 @@ | |||
78 | * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> | 78 | * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> |
79 | * | 79 | * |
80 | * (following author is not in any relation with this code, but his ideas | 80 | * (following author is not in any relation with this code, but his ideas |
81 | * were used when writting this driver) | 81 | * were used when writing this driver) |
82 | * | 82 | * |
83 | * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> | 83 | * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> |
84 | * | 84 | * |
diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c index bd30aba242d0..731d7a5c5aa2 100644 --- a/drivers/video/neofb.c +++ b/drivers/video/neofb.c | |||
@@ -1286,34 +1286,36 @@ static int neofb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, | |||
1286 | if (regno >= fb->cmap.len || regno > 255) | 1286 | if (regno >= fb->cmap.len || regno > 255) |
1287 | return -EINVAL; | 1287 | return -EINVAL; |
1288 | 1288 | ||
1289 | switch (fb->var.bits_per_pixel) { | 1289 | if (fb->var.bits_per_pixel <= 8) { |
1290 | case 8: | ||
1291 | outb(regno, 0x3c8); | 1290 | outb(regno, 0x3c8); |
1292 | 1291 | ||
1293 | outb(red >> 10, 0x3c9); | 1292 | outb(red >> 10, 0x3c9); |
1294 | outb(green >> 10, 0x3c9); | 1293 | outb(green >> 10, 0x3c9); |
1295 | outb(blue >> 10, 0x3c9); | 1294 | outb(blue >> 10, 0x3c9); |
1296 | break; | 1295 | } else if (regno < 16) { |
1297 | case 16: | 1296 | switch (fb->var.bits_per_pixel) { |
1298 | ((u32 *) fb->pseudo_palette)[regno] = | 1297 | case 16: |
1298 | ((u32 *) fb->pseudo_palette)[regno] = | ||
1299 | ((red & 0xf800)) | ((green & 0xfc00) >> 5) | | 1299 | ((red & 0xf800)) | ((green & 0xfc00) >> 5) | |
1300 | ((blue & 0xf800) >> 11); | 1300 | ((blue & 0xf800) >> 11); |
1301 | break; | 1301 | break; |
1302 | case 24: | 1302 | case 24: |
1303 | ((u32 *) fb->pseudo_palette)[regno] = | 1303 | ((u32 *) fb->pseudo_palette)[regno] = |
1304 | ((red & 0xff00) << 8) | ((green & 0xff00)) | | 1304 | ((red & 0xff00) << 8) | ((green & 0xff00)) | |
1305 | ((blue & 0xff00) >> 8); | 1305 | ((blue & 0xff00) >> 8); |
1306 | break; | 1306 | break; |
1307 | #ifdef NO_32BIT_SUPPORT_YET | 1307 | #ifdef NO_32BIT_SUPPORT_YET |
1308 | case 32: | 1308 | case 32: |
1309 | ((u32 *) fb->pseudo_palette)[regno] = | 1309 | ((u32 *) fb->pseudo_palette)[regno] = |
1310 | ((transp & 0xff00) << 16) | ((red & 0xff00) << 8) | | 1310 | ((transp & 0xff00) << 16) | ((red & 0xff00) << 8) | |
1311 | ((green & 0xff00)) | ((blue & 0xff00) >> 8); | 1311 | ((green & 0xff00)) | ((blue & 0xff00) >> 8); |
1312 | break; | 1312 | break; |
1313 | #endif | 1313 | #endif |
1314 | default: | 1314 | default: |
1315 | return 1; | 1315 | return 1; |
1316 | } | ||
1316 | } | 1317 | } |
1318 | |||
1317 | return 0; | 1319 | return 0; |
1318 | } | 1320 | } |
1319 | 1321 | ||
diff --git a/drivers/video/nvidia/nv_hw.c b/drivers/video/nvidia/nv_hw.c index f297c7b14a41..d1a10549f543 100644 --- a/drivers/video/nvidia/nv_hw.c +++ b/drivers/video/nvidia/nv_hw.c | |||
@@ -150,7 +150,7 @@ static void nvGetClocks(struct nvidia_par *par, unsigned int *MClk, | |||
150 | M = pll & 0xFF; | 150 | M = pll & 0xFF; |
151 | N = (pll >> 8) & 0xFF; | 151 | N = (pll >> 8) & 0xFF; |
152 | if (((par->Chipset & 0xfff0) == 0x0290) || | 152 | if (((par->Chipset & 0xfff0) == 0x0290) || |
153 | ((par->Chipset & 0xfff0) == 0x0390)) { | 153 | ((par->Chipset & 0xfff0) == 0x0390)) { |
154 | MB = 1; | 154 | MB = 1; |
155 | NB = 1; | 155 | NB = 1; |
156 | } else { | 156 | } else { |
@@ -160,7 +160,7 @@ static void nvGetClocks(struct nvidia_par *par, unsigned int *MClk, | |||
160 | *MClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P; | 160 | *MClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P; |
161 | 161 | ||
162 | pll = NV_RD32(par->PMC, 0x4000); | 162 | pll = NV_RD32(par->PMC, 0x4000); |
163 | P = (pll >> 16) & 0x03; | 163 | P = (pll >> 16) & 0x07; |
164 | pll = NV_RD32(par->PMC, 0x4004); | 164 | pll = NV_RD32(par->PMC, 0x4004); |
165 | M = pll & 0xFF; | 165 | M = pll & 0xFF; |
166 | N = (pll >> 8) & 0xFF; | 166 | N = (pll >> 8) & 0xFF; |
@@ -891,11 +891,17 @@ void NVCalcStateExt(struct nvidia_par *par, | |||
891 | state->general = bpp == 16 ? 0x00101100 : 0x00100100; | 891 | state->general = bpp == 16 ? 0x00101100 : 0x00100100; |
892 | state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00; | 892 | state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00; |
893 | break; | 893 | break; |
894 | case NV_ARCH_40: | ||
895 | if (!par->FlatPanel) | ||
896 | state->control = NV_RD32(par->PRAMDAC0, 0x0580) & | ||
897 | 0xeffffeff; | ||
898 | /* fallthrough */ | ||
894 | case NV_ARCH_10: | 899 | case NV_ARCH_10: |
895 | case NV_ARCH_20: | 900 | case NV_ARCH_20: |
896 | case NV_ARCH_30: | 901 | case NV_ARCH_30: |
897 | default: | 902 | default: |
898 | if ((par->Chipset & 0xfff0) == 0x0240) { | 903 | if ((par->Chipset & 0xfff0) == 0x0240 || |
904 | (par->Chipset & 0xfff0) == 0x03d0) { | ||
899 | state->arbitration0 = 256; | 905 | state->arbitration0 = 256; |
900 | state->arbitration1 = 0x0480; | 906 | state->arbitration1 = 0x0480; |
901 | } else if (((par->Chipset & 0xffff) == 0x01A0) || | 907 | } else if (((par->Chipset & 0xffff) == 0x01A0) || |
@@ -938,7 +944,7 @@ void NVCalcStateExt(struct nvidia_par *par, | |||
938 | 944 | ||
939 | void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | 945 | void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) |
940 | { | 946 | { |
941 | int i; | 947 | int i, j; |
942 | 948 | ||
943 | NV_WR32(par->PMC, 0x0140, 0x00000000); | 949 | NV_WR32(par->PMC, 0x0140, 0x00000000); |
944 | NV_WR32(par->PMC, 0x0200, 0xFFFF00FF); | 950 | NV_WR32(par->PMC, 0x0200, 0xFFFF00FF); |
@@ -950,7 +956,8 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | |||
950 | NV_WR32(par->PTIMER, 0x0100 * 4, 0xFFFFFFFF); | 956 | NV_WR32(par->PTIMER, 0x0100 * 4, 0xFFFFFFFF); |
951 | 957 | ||
952 | if (par->Architecture == NV_ARCH_04) { | 958 | if (par->Architecture == NV_ARCH_04) { |
953 | NV_WR32(par->PFB, 0x0200, state->config); | 959 | if (state) |
960 | NV_WR32(par->PFB, 0x0200, state->config); | ||
954 | } else if ((par->Architecture < NV_ARCH_40) || | 961 | } else if ((par->Architecture < NV_ARCH_40) || |
955 | (par->Chipset & 0xfff0) == 0x0040) { | 962 | (par->Chipset & 0xfff0) == 0x0040) { |
956 | for (i = 0; i < 8; i++) { | 963 | for (i = 0; i < 8; i++) { |
@@ -963,7 +970,9 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | |||
963 | 970 | ||
964 | if (((par->Chipset & 0xfff0) == 0x0090) || | 971 | if (((par->Chipset & 0xfff0) == 0x0090) || |
965 | ((par->Chipset & 0xfff0) == 0x01D0) || | 972 | ((par->Chipset & 0xfff0) == 0x01D0) || |
966 | ((par->Chipset & 0xfff0) == 0x0290)) | 973 | ((par->Chipset & 0xfff0) == 0x0290) || |
974 | ((par->Chipset & 0xfff0) == 0x0390) || | ||
975 | ((par->Chipset & 0xfff0) == 0x03D0)) | ||
967 | regions = 15; | 976 | regions = 15; |
968 | for(i = 0; i < regions; i++) { | 977 | for(i = 0; i < regions; i++) { |
969 | NV_WR32(par->PFB, 0x0600 + (i * 0x10), 0); | 978 | NV_WR32(par->PFB, 0x0600 + (i * 0x10), 0); |
@@ -1204,16 +1213,20 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | |||
1204 | NV_WR32(par->PGRAPH, 0x0608, 0xFFFFFFFF); | 1213 | NV_WR32(par->PGRAPH, 0x0608, 0xFFFFFFFF); |
1205 | } else { | 1214 | } else { |
1206 | if (par->Architecture >= NV_ARCH_40) { | 1215 | if (par->Architecture >= NV_ARCH_40) { |
1207 | u32 tmp; | ||
1208 | |||
1209 | NV_WR32(par->PGRAPH, 0x0084, 0x401287c0); | 1216 | NV_WR32(par->PGRAPH, 0x0084, 0x401287c0); |
1210 | NV_WR32(par->PGRAPH, 0x008C, 0x60de8051); | 1217 | NV_WR32(par->PGRAPH, 0x008C, 0x60de8051); |
1211 | NV_WR32(par->PGRAPH, 0x0090, 0x00008000); | 1218 | NV_WR32(par->PGRAPH, 0x0090, 0x00008000); |
1212 | NV_WR32(par->PGRAPH, 0x0610, 0x00be3c5f); | 1219 | NV_WR32(par->PGRAPH, 0x0610, 0x00be3c5f); |
1220 | NV_WR32(par->PGRAPH, 0x0bc4, | ||
1221 | NV_RD32(par->PGRAPH, 0x0bc4) | | ||
1222 | 0x00008000); | ||
1213 | 1223 | ||
1214 | tmp = NV_RD32(par->REGS, 0x1540) & 0xff; | 1224 | j = NV_RD32(par->REGS, 0x1540) & 0xff; |
1215 | for(i = 0; tmp && !(tmp & 1); tmp >>= 1, i++); | 1225 | |
1216 | NV_WR32(par->PGRAPH, 0x5000, i); | 1226 | if (j) { |
1227 | for (i = 0; !(j & 1); j >>= 1, i++); | ||
1228 | NV_WR32(par->PGRAPH, 0x5000, i); | ||
1229 | } | ||
1217 | 1230 | ||
1218 | if ((par->Chipset & 0xfff0) == 0x0040) { | 1231 | if ((par->Chipset & 0xfff0) == 0x0040) { |
1219 | NV_WR32(par->PGRAPH, 0x09b0, | 1232 | NV_WR32(par->PGRAPH, 0x09b0, |
@@ -1248,6 +1261,7 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | |||
1248 | case 0x0160: | 1261 | case 0x0160: |
1249 | case 0x01D0: | 1262 | case 0x01D0: |
1250 | case 0x0240: | 1263 | case 0x0240: |
1264 | case 0x03D0: | ||
1251 | NV_WR32(par->PMC, 0x1700, | 1265 | NV_WR32(par->PMC, 0x1700, |
1252 | NV_RD32(par->PFB, 0x020C)); | 1266 | NV_RD32(par->PFB, 0x020C)); |
1253 | NV_WR32(par->PMC, 0x1704, 0); | 1267 | NV_WR32(par->PMC, 0x1704, 0); |
@@ -1267,7 +1281,6 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | |||
1267 | 0x00000108); | 1281 | 0x00000108); |
1268 | break; | 1282 | break; |
1269 | case 0x0220: | 1283 | case 0x0220: |
1270 | case 0x0230: | ||
1271 | NV_WR32(par->PGRAPH, 0x0860, 0); | 1284 | NV_WR32(par->PGRAPH, 0x0860, 0); |
1272 | NV_WR32(par->PGRAPH, 0x0864, 0); | 1285 | NV_WR32(par->PGRAPH, 0x0864, 0); |
1273 | NV_WR32(par->PRAMDAC, 0x0608, | 1286 | NV_WR32(par->PRAMDAC, 0x0608, |
@@ -1276,6 +1289,7 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | |||
1276 | break; | 1289 | break; |
1277 | case 0x0090: | 1290 | case 0x0090: |
1278 | case 0x0290: | 1291 | case 0x0290: |
1292 | case 0x0390: | ||
1279 | NV_WR32(par->PRAMDAC, 0x0608, | 1293 | NV_WR32(par->PRAMDAC, 0x0608, |
1280 | NV_RD32(par->PRAMDAC, 0x0608) | | 1294 | NV_RD32(par->PRAMDAC, 0x0608) | |
1281 | 0x00100000); | 1295 | 0x00100000); |
@@ -1352,7 +1366,9 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | |||
1352 | } else { | 1366 | } else { |
1353 | if (((par->Chipset & 0xfff0) == 0x0090) || | 1367 | if (((par->Chipset & 0xfff0) == 0x0090) || |
1354 | ((par->Chipset & 0xfff0) == 0x01D0) || | 1368 | ((par->Chipset & 0xfff0) == 0x01D0) || |
1355 | ((par->Chipset & 0xfff0) == 0x0290)) { | 1369 | ((par->Chipset & 0xfff0) == 0x0290) || |
1370 | ((par->Chipset & 0xfff0) == 0x0390) || | ||
1371 | ((par->Chipset & 0xfff0) == 0x03D0)) { | ||
1356 | for (i = 0; i < 60; i++) { | 1372 | for (i = 0; i < 60; i++) { |
1357 | NV_WR32(par->PGRAPH, | 1373 | NV_WR32(par->PGRAPH, |
1358 | 0x0D00 + i*4, | 1374 | 0x0D00 + i*4, |
@@ -1403,7 +1419,8 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | |||
1403 | } else { | 1419 | } else { |
1404 | if ((par->Chipset & 0xfff0) == 0x0090 || | 1420 | if ((par->Chipset & 0xfff0) == 0x0090 || |
1405 | (par->Chipset & 0xfff0) == 0x01D0 || | 1421 | (par->Chipset & 0xfff0) == 0x01D0 || |
1406 | (par->Chipset & 0xfff0) == 0x0290) { | 1422 | (par->Chipset & 0xfff0) == 0x0290 || |
1423 | (par->Chipset & 0xfff0) == 0x0390) { | ||
1407 | NV_WR32(par->PGRAPH, 0x0DF0, | 1424 | NV_WR32(par->PGRAPH, 0x0DF0, |
1408 | NV_RD32(par->PFB, 0x0200)); | 1425 | NV_RD32(par->PFB, 0x0200)); |
1409 | NV_WR32(par->PGRAPH, 0x0DF4, | 1426 | NV_WR32(par->PGRAPH, 0x0DF4, |
@@ -1490,6 +1507,12 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | |||
1490 | NV_WR32(par->PFIFO, 0x0494 * 4, 0x00000001); | 1507 | NV_WR32(par->PFIFO, 0x0494 * 4, 0x00000001); |
1491 | NV_WR32(par->PFIFO, 0x0495 * 4, 0x00000001); | 1508 | NV_WR32(par->PFIFO, 0x0495 * 4, 0x00000001); |
1492 | NV_WR32(par->PFIFO, 0x0140 * 4, 0x00000001); | 1509 | NV_WR32(par->PFIFO, 0x0140 * 4, 0x00000001); |
1510 | |||
1511 | if (!state) { | ||
1512 | par->CurrentState = NULL; | ||
1513 | return; | ||
1514 | } | ||
1515 | |||
1493 | if (par->Architecture >= NV_ARCH_10) { | 1516 | if (par->Architecture >= NV_ARCH_10) { |
1494 | if (par->twoHeads) { | 1517 | if (par->twoHeads) { |
1495 | NV_WR32(par->PCRTC0, 0x0860, state->head); | 1518 | NV_WR32(par->PCRTC0, 0x0860, state->head); |
@@ -1561,6 +1584,9 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) | |||
1561 | VGA_WR08(par->PCIO, 0x03D5, state->interlace); | 1584 | VGA_WR08(par->PCIO, 0x03D5, state->interlace); |
1562 | 1585 | ||
1563 | if (!par->FlatPanel) { | 1586 | if (!par->FlatPanel) { |
1587 | if (par->Architecture >= NV_ARCH_40) | ||
1588 | NV_WR32(par->PRAMDAC0, 0x0580, state->control); | ||
1589 | |||
1564 | NV_WR32(par->PRAMDAC0, 0x050C, state->pllsel); | 1590 | NV_WR32(par->PRAMDAC0, 0x050C, state->pllsel); |
1565 | NV_WR32(par->PRAMDAC0, 0x0508, state->vpll); | 1591 | NV_WR32(par->PRAMDAC0, 0x0508, state->vpll); |
1566 | if (par->twoHeads) | 1592 | if (par->twoHeads) |
@@ -1626,6 +1652,9 @@ void NVUnloadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) { | |||
1626 | state->scale = NV_RD32(par->PRAMDAC, 0x0848); | 1652 | state->scale = NV_RD32(par->PRAMDAC, 0x0848); |
1627 | state->config = NV_RD32(par->PFB, 0x0200); | 1653 | state->config = NV_RD32(par->PFB, 0x0200); |
1628 | 1654 | ||
1655 | if (par->Architecture >= NV_ARCH_40 && !par->FlatPanel) | ||
1656 | state->control = NV_RD32(par->PRAMDAC0, 0x0580); | ||
1657 | |||
1629 | if (par->Architecture >= NV_ARCH_10) { | 1658 | if (par->Architecture >= NV_ARCH_10) { |
1630 | if (par->twoHeads) { | 1659 | if (par->twoHeads) { |
1631 | state->head = NV_RD32(par->PCRTC0, 0x0860); | 1660 | state->head = NV_RD32(par->PCRTC0, 0x0860); |
diff --git a/drivers/video/nvidia/nv_setup.c b/drivers/video/nvidia/nv_setup.c index 707e2c8a13ed..82579d3a9970 100644 --- a/drivers/video/nvidia/nv_setup.c +++ b/drivers/video/nvidia/nv_setup.c | |||
@@ -166,11 +166,13 @@ u8 NVReadDacData(struct nvidia_par *par) | |||
166 | static int NVIsConnected(struct nvidia_par *par, int output) | 166 | static int NVIsConnected(struct nvidia_par *par, int output) |
167 | { | 167 | { |
168 | volatile u32 __iomem *PRAMDAC = par->PRAMDAC0; | 168 | volatile u32 __iomem *PRAMDAC = par->PRAMDAC0; |
169 | u32 reg52C, reg608; | 169 | u32 reg52C, reg608, dac0_reg608 = 0; |
170 | int present; | 170 | int present; |
171 | 171 | ||
172 | if (output) | 172 | if (output) { |
173 | PRAMDAC += 0x800; | 173 | dac0_reg608 = NV_RD32(PRAMDAC, 0x0608); |
174 | PRAMDAC += 0x800; | ||
175 | } | ||
174 | 176 | ||
175 | reg52C = NV_RD32(PRAMDAC, 0x052C); | 177 | reg52C = NV_RD32(PRAMDAC, 0x052C); |
176 | reg608 = NV_RD32(PRAMDAC, 0x0608); | 178 | reg608 = NV_RD32(PRAMDAC, 0x0608); |
@@ -194,8 +196,8 @@ static int NVIsConnected(struct nvidia_par *par, int output) | |||
194 | else | 196 | else |
195 | printk("nvidiafb: CRTC%i analog not found\n", output); | 197 | printk("nvidiafb: CRTC%i analog not found\n", output); |
196 | 198 | ||
197 | NV_WR32(par->PRAMDAC0, 0x0608, NV_RD32(par->PRAMDAC0, 0x0608) & | 199 | if (output) |
198 | 0x0000EFFF); | 200 | NV_WR32(par->PRAMDAC0, 0x0608, dac0_reg608); |
199 | 201 | ||
200 | NV_WR32(PRAMDAC, 0x052C, reg52C); | 202 | NV_WR32(PRAMDAC, 0x052C, reg52C); |
201 | NV_WR32(PRAMDAC, 0x0608, reg608); | 203 | NV_WR32(PRAMDAC, 0x0608, reg608); |
diff --git a/drivers/video/nvidia/nv_type.h b/drivers/video/nvidia/nv_type.h index 38f7cc0a2331..2fdf77ec39fc 100644 --- a/drivers/video/nvidia/nv_type.h +++ b/drivers/video/nvidia/nv_type.h | |||
@@ -86,6 +86,7 @@ typedef struct _riva_hw_state { | |||
86 | u32 timingV; | 86 | u32 timingV; |
87 | u32 displayV; | 87 | u32 displayV; |
88 | u32 crtcSync; | 88 | u32 crtcSync; |
89 | u32 control; | ||
89 | } RIVA_HW_STATE; | 90 | } RIVA_HW_STATE; |
90 | 91 | ||
91 | struct riva_regs { | 92 | struct riva_regs { |
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index 7c36b5fe582e..a7fe214f0f77 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c | |||
@@ -37,7 +37,6 @@ | |||
37 | #include "nv_proto.h" | 37 | #include "nv_proto.h" |
38 | #include "nv_dma.h" | 38 | #include "nv_dma.h" |
39 | 39 | ||
40 | #undef CONFIG_FB_NVIDIA_DEBUG | ||
41 | #ifdef CONFIG_FB_NVIDIA_DEBUG | 40 | #ifdef CONFIG_FB_NVIDIA_DEBUG |
42 | #define NVTRACE printk | 41 | #define NVTRACE printk |
43 | #else | 42 | #else |
@@ -675,6 +674,7 @@ static int nvidiafb_set_par(struct fb_info *info) | |||
675 | info->fbops->fb_sync = nvidiafb_sync; | 674 | info->fbops->fb_sync = nvidiafb_sync; |
676 | info->pixmap.scan_align = 4; | 675 | info->pixmap.scan_align = 4; |
677 | info->flags &= ~FBINFO_HWACCEL_DISABLED; | 676 | info->flags &= ~FBINFO_HWACCEL_DISABLED; |
677 | info->flags |= FBINFO_READS_FAST; | ||
678 | NVResetGraphics(info); | 678 | NVResetGraphics(info); |
679 | } else { | 679 | } else { |
680 | info->fbops->fb_imageblit = cfb_imageblit; | 680 | info->fbops->fb_imageblit = cfb_imageblit; |
@@ -683,6 +683,7 @@ static int nvidiafb_set_par(struct fb_info *info) | |||
683 | info->fbops->fb_sync = NULL; | 683 | info->fbops->fb_sync = NULL; |
684 | info->pixmap.scan_align = 1; | 684 | info->pixmap.scan_align = 1; |
685 | info->flags |= FBINFO_HWACCEL_DISABLED; | 685 | info->flags |= FBINFO_HWACCEL_DISABLED; |
686 | info->flags &= ~FBINFO_READS_FAST; | ||
686 | } | 687 | } |
687 | 688 | ||
688 | par->cursor_reset = 1; | 689 | par->cursor_reset = 1; |
@@ -1194,7 +1195,8 @@ static u32 __devinit nvidia_get_chipset(struct fb_info *info) | |||
1194 | 1195 | ||
1195 | printk(KERN_INFO PFX "Device ID: %x \n", id); | 1196 | printk(KERN_INFO PFX "Device ID: %x \n", id); |
1196 | 1197 | ||
1197 | if ((id & 0xfff0) == 0x00f0) { | 1198 | if ((id & 0xfff0) == 0x00f0 || |
1199 | (id & 0xfff0) == 0x02e0) { | ||
1198 | /* pci-e */ | 1200 | /* pci-e */ |
1199 | id = NV_RD32(par->REGS, 0x1800); | 1201 | id = NV_RD32(par->REGS, 0x1800); |
1200 | 1202 | ||
@@ -1239,17 +1241,16 @@ static u32 __devinit nvidia_get_arch(struct fb_info *info) | |||
1239 | case 0x0040: /* GeForce 6800 */ | 1241 | case 0x0040: /* GeForce 6800 */ |
1240 | case 0x00C0: /* GeForce 6800 */ | 1242 | case 0x00C0: /* GeForce 6800 */ |
1241 | case 0x0120: /* GeForce 6800 */ | 1243 | case 0x0120: /* GeForce 6800 */ |
1242 | case 0x0130: | ||
1243 | case 0x0140: /* GeForce 6600 */ | 1244 | case 0x0140: /* GeForce 6600 */ |
1244 | case 0x0160: /* GeForce 6200 */ | 1245 | case 0x0160: /* GeForce 6200 */ |
1245 | case 0x01D0: /* GeForce 7200, 7300, 7400 */ | 1246 | case 0x01D0: /* GeForce 7200, 7300, 7400 */ |
1246 | case 0x0090: /* GeForce 7800 */ | 1247 | case 0x0090: /* GeForce 7800 */ |
1247 | case 0x0210: /* GeForce 6800 */ | 1248 | case 0x0210: /* GeForce 6800 */ |
1248 | case 0x0220: /* GeForce 6200 */ | 1249 | case 0x0220: /* GeForce 6200 */ |
1249 | case 0x0230: | ||
1250 | case 0x0240: /* GeForce 6100 */ | 1250 | case 0x0240: /* GeForce 6100 */ |
1251 | case 0x0290: /* GeForce 7900 */ | 1251 | case 0x0290: /* GeForce 7900 */ |
1252 | case 0x0390: /* GeForce 7600 */ | 1252 | case 0x0390: /* GeForce 7600 */ |
1253 | case 0x03D0: | ||
1253 | arch = NV_ARCH_40; | 1254 | arch = NV_ARCH_40; |
1254 | break; | 1255 | break; |
1255 | case 0x0020: /* TNT, TNT2 */ | 1256 | case 0x0020: /* TNT, TNT2 */ |
diff --git a/drivers/video/offb.c b/drivers/video/offb.c index 885b42836cbb..452433d46973 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c | |||
@@ -271,7 +271,7 @@ static void __init offb_init_fb(const char *name, const char *full_name, | |||
271 | return; | 271 | return; |
272 | } | 272 | } |
273 | 273 | ||
274 | size = sizeof(struct fb_info) + sizeof(u32) * 17; | 274 | size = sizeof(struct fb_info) + sizeof(u32) * 16; |
275 | 275 | ||
276 | info = kmalloc(size, GFP_ATOMIC); | 276 | info = kmalloc(size, GFP_ATOMIC); |
277 | 277 | ||
diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig new file mode 100644 index 000000000000..7f4d25b8a184 --- /dev/null +++ b/drivers/video/omap/Kconfig | |||
@@ -0,0 +1,58 @@ | |||
1 | config FB_OMAP | ||
2 | tristate "OMAP frame buffer support (EXPERIMENTAL)" | ||
3 | depends on FB | ||
4 | select FB_CFB_FILLRECT | ||
5 | select FB_CFB_COPYAREA | ||
6 | select FB_CFB_IMAGEBLIT | ||
7 | help | ||
8 | Frame buffer driver for OMAP based boards. | ||
9 | |||
10 | config FB_OMAP_BOOTLOADER_INIT | ||
11 | bool "Check bootloader initializaion" | ||
12 | depends on FB_OMAP | ||
13 | help | ||
14 | Say Y here if you want to enable checking if the bootloader has | ||
15 | already initialized the display controller. In this case the | ||
16 | driver will skip the initialization. | ||
17 | |||
18 | config FB_OMAP_CONSISTENT_DMA_SIZE | ||
19 | int "Consistent DMA memory size (MB)" | ||
20 | depends on FB_OMAP | ||
21 | range 1 14 | ||
22 | default 2 | ||
23 | help | ||
24 | Increase the DMA consistent memory size according to your video | ||
25 | memory needs, for example if you want to use multiple planes. | ||
26 | The size must be 2MB aligned. | ||
27 | If unsure say 1. | ||
28 | |||
29 | config FB_OMAP_DMA_TUNE | ||
30 | bool "Set DMA SDRAM access priority high" | ||
31 | depends on FB_OMAP && ARCH_OMAP1 | ||
32 | help | ||
33 | On systems in which video memory is in system memory | ||
34 | (SDRAM) this will speed up graphics DMA operations. | ||
35 | If you have such a system and want to use rotation | ||
36 | answer yes. Answer no if you have a dedicated video | ||
37 | memory, or don't use any of the accelerated features. | ||
38 | |||
39 | config FB_OMAP_LCDC_EXTERNAL | ||
40 | bool "External LCD controller support" | ||
41 | depends on FB_OMAP | ||
42 | help | ||
43 | Say Y here, if you want to have support for boards with an | ||
44 | external LCD controller connected to the SoSSI/RFBI interface. | ||
45 | |||
46 | config FB_OMAP_LCDC_HWA742 | ||
47 | bool "Epson HWA742 LCD controller support" | ||
48 | depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL | ||
49 | help | ||
50 | Say Y here if you want to have support for the external | ||
51 | Epson HWA742 LCD controller. | ||
52 | |||
53 | config FB_OMAP_LCDC_BLIZZARD | ||
54 | bool "Epson Blizzard LCD controller support" | ||
55 | depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL | ||
56 | help | ||
57 | Say Y here if you want to have support for the external | ||
58 | Epson Blizzard LCD controller. | ||
diff --git a/drivers/video/omap/Makefile b/drivers/video/omap/Makefile new file mode 100644 index 000000000000..99da8b6d2c36 --- /dev/null +++ b/drivers/video/omap/Makefile | |||
@@ -0,0 +1,29 @@ | |||
1 | # | ||
2 | # Makefile for the new OMAP framebuffer device driver | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_FB_OMAP) += omapfb.o | ||
6 | |||
7 | objs-yy := omapfb_main.o | ||
8 | |||
9 | objs-y$(CONFIG_ARCH_OMAP1) += lcdc.o | ||
10 | objs-y$(CONFIG_ARCH_OMAP2) += dispc.o | ||
11 | |||
12 | objs-$(CONFIG_ARCH_OMAP1)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += sossi.o | ||
13 | objs-$(CONFIG_ARCH_OMAP2)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += rfbi.o | ||
14 | |||
15 | objs-y$(CONFIG_FB_OMAP_LCDC_HWA742) += hwa742.o | ||
16 | objs-y$(CONFIG_FB_OMAP_LCDC_BLIZZARD) += blizzard.o | ||
17 | |||
18 | objs-y$(CONFIG_MACH_OMAP_H4) += lcd_h4.o | ||
19 | objs-y$(CONFIG_MACH_OMAP_H3) += lcd_h3.o | ||
20 | objs-y$(CONFIG_MACH_OMAP_PALMTE) += lcd_palmte.o | ||
21 | objs-y$(CONFIG_MACH_OMAP_PALMTT) += lcd_palmtt.o | ||
22 | objs-y$(CONFIG_MACH_OMAP_PALMZ71) += lcd_palmz71.o | ||
23 | objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1610.o | ||
24 | objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1510.o | ||
25 | objs-y$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o | ||
26 | objs-y$(CONFIG_MACH_SX1) += lcd_sx1.o | ||
27 | |||
28 | omapfb-objs := $(objs-yy) | ||
29 | |||
diff --git a/drivers/video/omap/blizzard.c b/drivers/video/omap/blizzard.c new file mode 100644 index 000000000000..e682940a97a4 --- /dev/null +++ b/drivers/video/omap/blizzard.c | |||
@@ -0,0 +1,1568 @@ | |||
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 <asm/arch/dma.h> | ||
30 | #include <asm/arch/omapfb.h> | ||
31 | #include <asm/arch/blizzard.h> | ||
32 | |||
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_HDISP 0x2a | ||
48 | #define BLIZZARD_HNDP 0x2c | ||
49 | #define BLIZZARD_VDISP0 0x2e | ||
50 | #define BLIZZARD_VDISP1 0x30 | ||
51 | #define BLIZZARD_VNDP 0x32 | ||
52 | #define BLIZZARD_HSW 0x34 | ||
53 | #define BLIZZARD_VSW 0x38 | ||
54 | #define BLIZZARD_DISPLAY_MODE 0x68 | ||
55 | #define BLIZZARD_INPUT_WIN_X_START_0 0x6c | ||
56 | #define BLIZZARD_DATA_SOURCE_SELECT 0x8e | ||
57 | #define BLIZZARD_DISP_MEM_DATA_PORT 0x90 | ||
58 | #define BLIZZARD_DISP_MEM_READ_ADDR0 0x92 | ||
59 | #define BLIZZARD_POWER_SAVE 0xE6 | ||
60 | #define BLIZZARD_NDISP_CTRL_STATUS 0xE8 | ||
61 | |||
62 | /* Data source select */ | ||
63 | /* For S1D13745 */ | ||
64 | #define BLIZZARD_SRC_WRITE_LCD_BACKGROUND 0x00 | ||
65 | #define BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE 0x01 | ||
66 | #define BLIZZARD_SRC_WRITE_OVERLAY_ENABLE 0x04 | ||
67 | #define BLIZZARD_SRC_DISABLE_OVERLAY 0x05 | ||
68 | /* For S1D13744 */ | ||
69 | #define BLIZZARD_SRC_WRITE_LCD 0x00 | ||
70 | #define BLIZZARD_SRC_BLT_LCD 0x06 | ||
71 | |||
72 | #define BLIZZARD_COLOR_RGB565 0x01 | ||
73 | #define BLIZZARD_COLOR_YUV420 0x09 | ||
74 | |||
75 | #define BLIZZARD_VERSION_S1D13745 0x01 /* Hailstorm */ | ||
76 | #define BLIZZARD_VERSION_S1D13744 0x02 /* Blizzard */ | ||
77 | |||
78 | #define BLIZZARD_AUTO_UPDATE_TIME (HZ / 20) | ||
79 | |||
80 | /* Reserve 4 request slots for requests in irq context */ | ||
81 | #define REQ_POOL_SIZE 24 | ||
82 | #define IRQ_REQ_POOL_SIZE 4 | ||
83 | |||
84 | #define REQ_FROM_IRQ_POOL 0x01 | ||
85 | |||
86 | #define REQ_COMPLETE 0 | ||
87 | #define REQ_PENDING 1 | ||
88 | |||
89 | struct blizzard_reg_list { | ||
90 | int start; | ||
91 | int end; | ||
92 | }; | ||
93 | |||
94 | /* These need to be saved / restored separately from the rest. */ | ||
95 | static struct blizzard_reg_list blizzard_pll_regs[] = { | ||
96 | { | ||
97 | .start = 0x04, /* Don't save PLL ctrl (0x0C) */ | ||
98 | .end = 0x0a, | ||
99 | }, | ||
100 | { | ||
101 | .start = 0x0e, /* Clock configuration */ | ||
102 | .end = 0x0e, | ||
103 | }, | ||
104 | }; | ||
105 | |||
106 | static struct blizzard_reg_list blizzard_gen_regs[] = { | ||
107 | { | ||
108 | .start = 0x18, /* SDRAM control */ | ||
109 | .end = 0x20, | ||
110 | }, | ||
111 | { | ||
112 | .start = 0x28, /* LCD Panel configuration */ | ||
113 | .end = 0x5a, /* HSSI interface, TV configuration */ | ||
114 | }, | ||
115 | }; | ||
116 | |||
117 | static u8 blizzard_reg_cache[0x5a / 2]; | ||
118 | |||
119 | struct update_param { | ||
120 | int plane; | ||
121 | int x, y, width, height; | ||
122 | int out_x, out_y; | ||
123 | int out_width, out_height; | ||
124 | int color_mode; | ||
125 | int bpp; | ||
126 | int flags; | ||
127 | }; | ||
128 | |||
129 | struct blizzard_request { | ||
130 | struct list_head entry; | ||
131 | unsigned int flags; | ||
132 | |||
133 | int (*handler)(struct blizzard_request *req); | ||
134 | void (*complete)(void *data); | ||
135 | void *complete_data; | ||
136 | |||
137 | union { | ||
138 | struct update_param update; | ||
139 | struct completion *sync; | ||
140 | } par; | ||
141 | }; | ||
142 | |||
143 | struct plane_info { | ||
144 | unsigned long offset; | ||
145 | int pos_x, pos_y; | ||
146 | int width, height; | ||
147 | int out_width, out_height; | ||
148 | int scr_width; | ||
149 | int color_mode; | ||
150 | int bpp; | ||
151 | }; | ||
152 | |||
153 | struct blizzard_struct { | ||
154 | enum omapfb_update_mode update_mode; | ||
155 | enum omapfb_update_mode update_mode_before_suspend; | ||
156 | |||
157 | struct timer_list auto_update_timer; | ||
158 | int stop_auto_update; | ||
159 | struct omapfb_update_window auto_update_window; | ||
160 | int enabled_planes; | ||
161 | int vid_nonstd_color; | ||
162 | int vid_scaled; | ||
163 | int last_color_mode; | ||
164 | int zoom_on; | ||
165 | int screen_width; | ||
166 | int screen_height; | ||
167 | unsigned te_connected:1; | ||
168 | unsigned vsync_only:1; | ||
169 | |||
170 | struct plane_info plane[OMAPFB_PLANE_NUM]; | ||
171 | |||
172 | struct blizzard_request req_pool[REQ_POOL_SIZE]; | ||
173 | struct list_head pending_req_list; | ||
174 | struct list_head free_req_list; | ||
175 | struct semaphore req_sema; | ||
176 | spinlock_t req_lock; | ||
177 | |||
178 | unsigned long sys_ck_rate; | ||
179 | struct extif_timings reg_timings, lut_timings; | ||
180 | |||
181 | u32 max_transmit_size; | ||
182 | u32 extif_clk_period; | ||
183 | int extif_clk_div; | ||
184 | unsigned long pix_tx_time; | ||
185 | unsigned long line_upd_time; | ||
186 | |||
187 | struct omapfb_device *fbdev; | ||
188 | struct lcd_ctrl_extif *extif; | ||
189 | struct lcd_ctrl *int_ctrl; | ||
190 | |||
191 | void (*power_up)(struct device *dev); | ||
192 | void (*power_down)(struct device *dev); | ||
193 | |||
194 | int version; | ||
195 | } blizzard; | ||
196 | |||
197 | struct lcd_ctrl blizzard_ctrl; | ||
198 | |||
199 | static u8 blizzard_read_reg(u8 reg) | ||
200 | { | ||
201 | u8 data; | ||
202 | |||
203 | blizzard.extif->set_bits_per_cycle(8); | ||
204 | blizzard.extif->write_command(®, 1); | ||
205 | blizzard.extif->read_data(&data, 1); | ||
206 | |||
207 | return data; | ||
208 | } | ||
209 | |||
210 | static void blizzard_write_reg(u8 reg, u8 val) | ||
211 | { | ||
212 | blizzard.extif->set_bits_per_cycle(8); | ||
213 | blizzard.extif->write_command(®, 1); | ||
214 | blizzard.extif->write_data(&val, 1); | ||
215 | } | ||
216 | |||
217 | static void blizzard_restart_sdram(void) | ||
218 | { | ||
219 | unsigned long tmo; | ||
220 | |||
221 | blizzard_write_reg(BLIZZARD_MEM_BANK0_ACTIVATE, 0); | ||
222 | udelay(50); | ||
223 | blizzard_write_reg(BLIZZARD_MEM_BANK0_ACTIVATE, 1); | ||
224 | tmo = jiffies + msecs_to_jiffies(200); | ||
225 | while (!(blizzard_read_reg(BLIZZARD_MEM_BANK0_STATUS) & 0x01)) { | ||
226 | if (time_after(jiffies, tmo)) { | ||
227 | dev_err(blizzard.fbdev->dev, | ||
228 | "s1d1374x: SDRAM not ready"); | ||
229 | break; | ||
230 | } | ||
231 | msleep(1); | ||
232 | } | ||
233 | } | ||
234 | |||
235 | static void blizzard_stop_sdram(void) | ||
236 | { | ||
237 | blizzard_write_reg(BLIZZARD_MEM_BANK0_ACTIVATE, 0); | ||
238 | } | ||
239 | |||
240 | /* Wait until the last window was completely written into the controllers | ||
241 | * SDRAM and we can start transferring the next window. | ||
242 | */ | ||
243 | static void blizzard_wait_line_buffer(void) | ||
244 | { | ||
245 | unsigned long tmo = jiffies + msecs_to_jiffies(30); | ||
246 | |||
247 | while (blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS) & (1 << 7)) { | ||
248 | if (time_after(jiffies, tmo)) { | ||
249 | if (printk_ratelimit()) | ||
250 | dev_err(blizzard.fbdev->dev, | ||
251 | "s1d1374x: line buffer not ready\n"); | ||
252 | break; | ||
253 | } | ||
254 | } | ||
255 | } | ||
256 | |||
257 | /* Wait until the YYC color space converter is idle. */ | ||
258 | static void blizzard_wait_yyc(void) | ||
259 | { | ||
260 | unsigned long tmo = jiffies + msecs_to_jiffies(30); | ||
261 | |||
262 | while (blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS) & (1 << 4)) { | ||
263 | if (time_after(jiffies, tmo)) { | ||
264 | if (printk_ratelimit()) | ||
265 | dev_err(blizzard.fbdev->dev, | ||
266 | "s1d1374x: YYC not ready\n"); | ||
267 | break; | ||
268 | } | ||
269 | } | ||
270 | } | ||
271 | |||
272 | static void disable_overlay(void) | ||
273 | { | ||
274 | blizzard_write_reg(BLIZZARD_DATA_SOURCE_SELECT, | ||
275 | BLIZZARD_SRC_DISABLE_OVERLAY); | ||
276 | } | ||
277 | |||
278 | static void set_window_regs(int x_start, int y_start, int x_end, int y_end, | ||
279 | int x_out_start, int y_out_start, | ||
280 | int x_out_end, int y_out_end, int color_mode, | ||
281 | int zoom_off, int flags) | ||
282 | { | ||
283 | u8 tmp[18]; | ||
284 | u8 cmd; | ||
285 | |||
286 | x_end--; | ||
287 | y_end--; | ||
288 | tmp[0] = x_start; | ||
289 | tmp[1] = x_start >> 8; | ||
290 | tmp[2] = y_start; | ||
291 | tmp[3] = y_start >> 8; | ||
292 | tmp[4] = x_end; | ||
293 | tmp[5] = x_end >> 8; | ||
294 | tmp[6] = y_end; | ||
295 | tmp[7] = y_end >> 8; | ||
296 | |||
297 | x_out_end--; | ||
298 | y_out_end--; | ||
299 | tmp[8] = x_out_start; | ||
300 | tmp[9] = x_out_start >> 8; | ||
301 | tmp[10] = y_out_start; | ||
302 | tmp[11] = y_out_start >> 8; | ||
303 | tmp[12] = x_out_end; | ||
304 | tmp[13] = x_out_end >> 8; | ||
305 | tmp[14] = y_out_end; | ||
306 | tmp[15] = y_out_end >> 8; | ||
307 | |||
308 | tmp[16] = color_mode; | ||
309 | if (zoom_off && blizzard.version == BLIZZARD_VERSION_S1D13745) | ||
310 | tmp[17] = BLIZZARD_SRC_WRITE_LCD_BACKGROUND; | ||
311 | else if (flags & OMAPFB_FORMAT_FLAG_ENABLE_OVERLAY) | ||
312 | tmp[17] = BLIZZARD_SRC_WRITE_OVERLAY_ENABLE; | ||
313 | else | ||
314 | tmp[17] = blizzard.version == BLIZZARD_VERSION_S1D13744 ? | ||
315 | BLIZZARD_SRC_WRITE_LCD : | ||
316 | BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE; | ||
317 | |||
318 | blizzard.extif->set_bits_per_cycle(8); | ||
319 | cmd = BLIZZARD_INPUT_WIN_X_START_0; | ||
320 | blizzard.extif->write_command(&cmd, 1); | ||
321 | blizzard.extif->write_data(tmp, 18); | ||
322 | } | ||
323 | |||
324 | static void enable_tearsync(int y, int width, int height, int screen_height, | ||
325 | int out_height, int force_vsync) | ||
326 | { | ||
327 | u8 b; | ||
328 | |||
329 | b = blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS); | ||
330 | b |= 1 << 3; | ||
331 | blizzard_write_reg(BLIZZARD_NDISP_CTRL_STATUS, b); | ||
332 | |||
333 | if (likely(blizzard.vsync_only || force_vsync)) { | ||
334 | blizzard.extif->enable_tearsync(1, 0); | ||
335 | return; | ||
336 | } | ||
337 | |||
338 | if (width * blizzard.pix_tx_time < blizzard.line_upd_time) { | ||
339 | blizzard.extif->enable_tearsync(1, 0); | ||
340 | return; | ||
341 | } | ||
342 | |||
343 | if ((width * blizzard.pix_tx_time / 1000) * height < | ||
344 | (y + out_height) * (blizzard.line_upd_time / 1000)) { | ||
345 | blizzard.extif->enable_tearsync(1, 0); | ||
346 | return; | ||
347 | } | ||
348 | |||
349 | blizzard.extif->enable_tearsync(1, y + 1); | ||
350 | } | ||
351 | |||
352 | static void disable_tearsync(void) | ||
353 | { | ||
354 | u8 b; | ||
355 | |||
356 | blizzard.extif->enable_tearsync(0, 0); | ||
357 | b = blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS); | ||
358 | b &= ~(1 << 3); | ||
359 | blizzard_write_reg(BLIZZARD_NDISP_CTRL_STATUS, b); | ||
360 | b = blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS); | ||
361 | } | ||
362 | |||
363 | static inline void set_extif_timings(const struct extif_timings *t); | ||
364 | |||
365 | static inline struct blizzard_request *alloc_req(void) | ||
366 | { | ||
367 | unsigned long flags; | ||
368 | struct blizzard_request *req; | ||
369 | int req_flags = 0; | ||
370 | |||
371 | if (!in_interrupt()) | ||
372 | down(&blizzard.req_sema); | ||
373 | else | ||
374 | req_flags = REQ_FROM_IRQ_POOL; | ||
375 | |||
376 | spin_lock_irqsave(&blizzard.req_lock, flags); | ||
377 | BUG_ON(list_empty(&blizzard.free_req_list)); | ||
378 | req = list_entry(blizzard.free_req_list.next, | ||
379 | struct blizzard_request, entry); | ||
380 | list_del(&req->entry); | ||
381 | spin_unlock_irqrestore(&blizzard.req_lock, flags); | ||
382 | |||
383 | INIT_LIST_HEAD(&req->entry); | ||
384 | req->flags = req_flags; | ||
385 | |||
386 | return req; | ||
387 | } | ||
388 | |||
389 | static inline void free_req(struct blizzard_request *req) | ||
390 | { | ||
391 | unsigned long flags; | ||
392 | |||
393 | spin_lock_irqsave(&blizzard.req_lock, flags); | ||
394 | |||
395 | list_del(&req->entry); | ||
396 | list_add(&req->entry, &blizzard.free_req_list); | ||
397 | if (!(req->flags & REQ_FROM_IRQ_POOL)) | ||
398 | up(&blizzard.req_sema); | ||
399 | |||
400 | spin_unlock_irqrestore(&blizzard.req_lock, flags); | ||
401 | } | ||
402 | |||
403 | static void process_pending_requests(void) | ||
404 | { | ||
405 | unsigned long flags; | ||
406 | |||
407 | spin_lock_irqsave(&blizzard.req_lock, flags); | ||
408 | |||
409 | while (!list_empty(&blizzard.pending_req_list)) { | ||
410 | struct blizzard_request *req; | ||
411 | void (*complete)(void *); | ||
412 | void *complete_data; | ||
413 | |||
414 | req = list_entry(blizzard.pending_req_list.next, | ||
415 | struct blizzard_request, entry); | ||
416 | spin_unlock_irqrestore(&blizzard.req_lock, flags); | ||
417 | |||
418 | if (req->handler(req) == REQ_PENDING) | ||
419 | return; | ||
420 | |||
421 | complete = req->complete; | ||
422 | complete_data = req->complete_data; | ||
423 | free_req(req); | ||
424 | |||
425 | if (complete) | ||
426 | complete(complete_data); | ||
427 | |||
428 | spin_lock_irqsave(&blizzard.req_lock, flags); | ||
429 | } | ||
430 | |||
431 | spin_unlock_irqrestore(&blizzard.req_lock, flags); | ||
432 | } | ||
433 | |||
434 | static void submit_req_list(struct list_head *head) | ||
435 | { | ||
436 | unsigned long flags; | ||
437 | int process = 1; | ||
438 | |||
439 | spin_lock_irqsave(&blizzard.req_lock, flags); | ||
440 | if (likely(!list_empty(&blizzard.pending_req_list))) | ||
441 | process = 0; | ||
442 | list_splice_init(head, blizzard.pending_req_list.prev); | ||
443 | spin_unlock_irqrestore(&blizzard.req_lock, flags); | ||
444 | |||
445 | if (process) | ||
446 | process_pending_requests(); | ||
447 | } | ||
448 | |||
449 | static void request_complete(void *data) | ||
450 | { | ||
451 | struct blizzard_request *req = (struct blizzard_request *)data; | ||
452 | void (*complete)(void *); | ||
453 | void *complete_data; | ||
454 | |||
455 | complete = req->complete; | ||
456 | complete_data = req->complete_data; | ||
457 | |||
458 | free_req(req); | ||
459 | |||
460 | if (complete) | ||
461 | complete(complete_data); | ||
462 | |||
463 | process_pending_requests(); | ||
464 | } | ||
465 | |||
466 | |||
467 | static int do_full_screen_update(struct blizzard_request *req) | ||
468 | { | ||
469 | int i; | ||
470 | int flags; | ||
471 | |||
472 | for (i = 0; i < 3; i++) { | ||
473 | struct plane_info *p = &blizzard.plane[i]; | ||
474 | if (!(blizzard.enabled_planes & (1 << i))) { | ||
475 | blizzard.int_ctrl->enable_plane(i, 0); | ||
476 | continue; | ||
477 | } | ||
478 | dev_dbg(blizzard.fbdev->dev, "pw %d ph %d\n", | ||
479 | p->width, p->height); | ||
480 | blizzard.int_ctrl->setup_plane(i, | ||
481 | OMAPFB_CHANNEL_OUT_LCD, p->offset, | ||
482 | p->scr_width, p->pos_x, p->pos_y, | ||
483 | p->width, p->height, | ||
484 | p->color_mode); | ||
485 | blizzard.int_ctrl->enable_plane(i, 1); | ||
486 | } | ||
487 | |||
488 | dev_dbg(blizzard.fbdev->dev, "sw %d sh %d\n", | ||
489 | blizzard.screen_width, blizzard.screen_height); | ||
490 | blizzard_wait_line_buffer(); | ||
491 | flags = req->par.update.flags; | ||
492 | if (flags & OMAPFB_FORMAT_FLAG_TEARSYNC) | ||
493 | enable_tearsync(0, blizzard.screen_width, | ||
494 | blizzard.screen_height, | ||
495 | blizzard.screen_height, | ||
496 | blizzard.screen_height, | ||
497 | flags & OMAPFB_FORMAT_FLAG_FORCE_VSYNC); | ||
498 | else | ||
499 | disable_tearsync(); | ||
500 | |||
501 | set_window_regs(0, 0, blizzard.screen_width, blizzard.screen_height, | ||
502 | 0, 0, blizzard.screen_width, blizzard.screen_height, | ||
503 | BLIZZARD_COLOR_RGB565, blizzard.zoom_on, flags); | ||
504 | blizzard.zoom_on = 0; | ||
505 | |||
506 | blizzard.extif->set_bits_per_cycle(16); | ||
507 | /* set_window_regs has left the register index at the right | ||
508 | * place, so no need to set it here. | ||
509 | */ | ||
510 | blizzard.extif->transfer_area(blizzard.screen_width, | ||
511 | blizzard.screen_height, | ||
512 | request_complete, req); | ||
513 | return REQ_PENDING; | ||
514 | } | ||
515 | |||
516 | /* Setup all planes with an overlapping area with the update window. */ | ||
517 | static int do_partial_update(struct blizzard_request *req, int plane, | ||
518 | int x, int y, int w, int h, | ||
519 | int x_out, int y_out, int w_out, int h_out, | ||
520 | int wnd_color_mode, int bpp) | ||
521 | { | ||
522 | int i; | ||
523 | int gx1, gy1, gx2, gy2; | ||
524 | int gx1_out, gy1_out, gx2_out, gy2_out; | ||
525 | int color_mode; | ||
526 | int flags; | ||
527 | int zoom_off; | ||
528 | |||
529 | /* Global coordinates, relative to pixel 0,0 of the LCD */ | ||
530 | gx1 = x + blizzard.plane[plane].pos_x; | ||
531 | gy1 = y + blizzard.plane[plane].pos_y; | ||
532 | gx2 = gx1 + w; | ||
533 | gy2 = gy1 + h; | ||
534 | |||
535 | flags = req->par.update.flags; | ||
536 | if (flags & OMAPFB_FORMAT_FLAG_DOUBLE) { | ||
537 | gx1_out = gx1; | ||
538 | gy1_out = gy1; | ||
539 | gx2_out = gx1 + w * 2; | ||
540 | gy2_out = gy1 + h * 2; | ||
541 | } else { | ||
542 | gx1_out = x_out + blizzard.plane[plane].pos_x; | ||
543 | gy1_out = y_out + blizzard.plane[plane].pos_y; | ||
544 | gx2_out = gx1_out + w_out; | ||
545 | gy2_out = gy1_out + h_out; | ||
546 | } | ||
547 | zoom_off = blizzard.zoom_on && gx1 == 0 && gy1 == 0 && | ||
548 | w == blizzard.screen_width && h == blizzard.screen_height; | ||
549 | blizzard.zoom_on = (!zoom_off && blizzard.zoom_on) || | ||
550 | (w < w_out || h < h_out); | ||
551 | |||
552 | for (i = 0; i < OMAPFB_PLANE_NUM; i++) { | ||
553 | struct plane_info *p = &blizzard.plane[i]; | ||
554 | int px1, py1; | ||
555 | int px2, py2; | ||
556 | int pw, ph; | ||
557 | int pposx, pposy; | ||
558 | unsigned long offset; | ||
559 | |||
560 | if (!(blizzard.enabled_planes & (1 << i)) || | ||
561 | (wnd_color_mode && i != plane)) { | ||
562 | blizzard.int_ctrl->enable_plane(i, 0); | ||
563 | continue; | ||
564 | } | ||
565 | /* Plane coordinates */ | ||
566 | if (i == plane) { | ||
567 | /* Plane in which we are doing the update. | ||
568 | * Local coordinates are the one in the update | ||
569 | * request. | ||
570 | */ | ||
571 | px1 = x; | ||
572 | py1 = y; | ||
573 | px2 = x + w; | ||
574 | py2 = y + h; | ||
575 | pposx = 0; | ||
576 | pposy = 0; | ||
577 | } else { | ||
578 | /* Check if this plane has an overlapping part */ | ||
579 | px1 = gx1 - p->pos_x; | ||
580 | py1 = gy1 - p->pos_y; | ||
581 | px2 = gx2 - p->pos_x; | ||
582 | py2 = gy2 - p->pos_y; | ||
583 | if (px1 >= p->width || py1 >= p->height || | ||
584 | px2 <= 0 || py2 <= 0) { | ||
585 | blizzard.int_ctrl->enable_plane(i, 0); | ||
586 | continue; | ||
587 | } | ||
588 | /* Calculate the coordinates for the overlapping | ||
589 | * part in the plane's local coordinates. | ||
590 | */ | ||
591 | pposx = -px1; | ||
592 | pposy = -py1; | ||
593 | if (px1 < 0) | ||
594 | px1 = 0; | ||
595 | if (py1 < 0) | ||
596 | py1 = 0; | ||
597 | if (px2 > p->width) | ||
598 | px2 = p->width; | ||
599 | if (py2 > p->height) | ||
600 | py2 = p->height; | ||
601 | if (pposx < 0) | ||
602 | pposx = 0; | ||
603 | if (pposy < 0) | ||
604 | pposy = 0; | ||
605 | } | ||
606 | pw = px2 - px1; | ||
607 | ph = py2 - py1; | ||
608 | offset = p->offset + (p->scr_width * py1 + px1) * p->bpp / 8; | ||
609 | if (wnd_color_mode) | ||
610 | /* Window embedded in the plane with a differing | ||
611 | * color mode / bpp. Calculate the number of DMA | ||
612 | * transfer elements in terms of the plane's bpp. | ||
613 | */ | ||
614 | pw = (pw + 1) * bpp / p->bpp; | ||
615 | #ifdef VERBOSE | ||
616 | dev_dbg(blizzard.fbdev->dev, | ||
617 | "plane %d offset %#08lx pposx %d pposy %d " | ||
618 | "px1 %d py1 %d pw %d ph %d\n", | ||
619 | i, offset, pposx, pposy, px1, py1, pw, ph); | ||
620 | #endif | ||
621 | blizzard.int_ctrl->setup_plane(i, | ||
622 | OMAPFB_CHANNEL_OUT_LCD, offset, | ||
623 | p->scr_width, | ||
624 | pposx, pposy, pw, ph, | ||
625 | p->color_mode); | ||
626 | |||
627 | blizzard.int_ctrl->enable_plane(i, 1); | ||
628 | } | ||
629 | |||
630 | switch (wnd_color_mode) { | ||
631 | case OMAPFB_COLOR_YUV420: | ||
632 | color_mode = BLIZZARD_COLOR_YUV420; | ||
633 | /* Currently only the 16 bits/pixel cycle format is | ||
634 | * supported on the external interface. Adjust the number | ||
635 | * of transfer elements per line for 12bpp format. | ||
636 | */ | ||
637 | w = (w + 1) * 3 / 4; | ||
638 | break; | ||
639 | default: | ||
640 | color_mode = BLIZZARD_COLOR_RGB565; | ||
641 | break; | ||
642 | } | ||
643 | |||
644 | blizzard_wait_line_buffer(); | ||
645 | if (blizzard.last_color_mode == BLIZZARD_COLOR_YUV420) | ||
646 | blizzard_wait_yyc(); | ||
647 | blizzard.last_color_mode = color_mode; | ||
648 | if (flags & OMAPFB_FORMAT_FLAG_TEARSYNC) | ||
649 | enable_tearsync(gy1, w, h, | ||
650 | blizzard.screen_height, | ||
651 | h_out, | ||
652 | flags & OMAPFB_FORMAT_FLAG_FORCE_VSYNC); | ||
653 | else | ||
654 | disable_tearsync(); | ||
655 | |||
656 | set_window_regs(gx1, gy1, gx2, gy2, gx1_out, gy1_out, gx2_out, gy2_out, | ||
657 | color_mode, zoom_off, flags); | ||
658 | |||
659 | blizzard.extif->set_bits_per_cycle(16); | ||
660 | /* set_window_regs has left the register index at the right | ||
661 | * place, so no need to set it here. | ||
662 | */ | ||
663 | blizzard.extif->transfer_area(w, h, request_complete, req); | ||
664 | |||
665 | return REQ_PENDING; | ||
666 | } | ||
667 | |||
668 | static int send_frame_handler(struct blizzard_request *req) | ||
669 | { | ||
670 | struct update_param *par = &req->par.update; | ||
671 | int plane = par->plane; | ||
672 | |||
673 | #ifdef VERBOSE | ||
674 | dev_dbg(blizzard.fbdev->dev, | ||
675 | "send_frame: x %d y %d w %d h %d " | ||
676 | "x_out %d y_out %d w_out %d h_out %d " | ||
677 | "color_mode %04x flags %04x planes %01x\n", | ||
678 | par->x, par->y, par->width, par->height, | ||
679 | par->out_x, par->out_y, par->out_width, par->out_height, | ||
680 | par->color_mode, par->flags, blizzard.enabled_planes); | ||
681 | #endif | ||
682 | if (par->flags & OMAPFB_FORMAT_FLAG_DISABLE_OVERLAY) | ||
683 | disable_overlay(); | ||
684 | |||
685 | if ((blizzard.enabled_planes & blizzard.vid_nonstd_color) || | ||
686 | (blizzard.enabled_planes & blizzard.vid_scaled)) | ||
687 | return do_full_screen_update(req); | ||
688 | |||
689 | return do_partial_update(req, plane, par->x, par->y, | ||
690 | par->width, par->height, | ||
691 | par->out_x, par->out_y, | ||
692 | par->out_width, par->out_height, | ||
693 | par->color_mode, par->bpp); | ||
694 | } | ||
695 | |||
696 | static void send_frame_complete(void *data) | ||
697 | { | ||
698 | } | ||
699 | |||
700 | #define ADD_PREQ(_x, _y, _w, _h, _x_out, _y_out, _w_out, _h_out) do { \ | ||
701 | req = alloc_req(); \ | ||
702 | req->handler = send_frame_handler; \ | ||
703 | req->complete = send_frame_complete; \ | ||
704 | req->par.update.plane = plane_idx; \ | ||
705 | req->par.update.x = _x; \ | ||
706 | req->par.update.y = _y; \ | ||
707 | req->par.update.width = _w; \ | ||
708 | req->par.update.height = _h; \ | ||
709 | req->par.update.out_x = _x_out; \ | ||
710 | req->par.update.out_y = _y_out; \ | ||
711 | req->par.update.out_width = _w_out; \ | ||
712 | req->par.update.out_height = _h_out; \ | ||
713 | req->par.update.bpp = bpp; \ | ||
714 | req->par.update.color_mode = color_mode;\ | ||
715 | req->par.update.flags = flags; \ | ||
716 | list_add_tail(&req->entry, req_head); \ | ||
717 | } while(0) | ||
718 | |||
719 | static void create_req_list(int plane_idx, | ||
720 | struct omapfb_update_window *win, | ||
721 | struct list_head *req_head) | ||
722 | { | ||
723 | struct blizzard_request *req; | ||
724 | int x = win->x; | ||
725 | int y = win->y; | ||
726 | int width = win->width; | ||
727 | int height = win->height; | ||
728 | int x_out = win->out_x; | ||
729 | int y_out = win->out_y; | ||
730 | int width_out = win->out_width; | ||
731 | int height_out = win->out_height; | ||
732 | int color_mode; | ||
733 | int bpp; | ||
734 | int flags; | ||
735 | unsigned int ystart = y; | ||
736 | unsigned int yspan = height; | ||
737 | unsigned int ystart_out = y_out; | ||
738 | unsigned int yspan_out = height_out; | ||
739 | |||
740 | flags = win->format & ~OMAPFB_FORMAT_MASK; | ||
741 | color_mode = win->format & OMAPFB_FORMAT_MASK; | ||
742 | switch (color_mode) { | ||
743 | case OMAPFB_COLOR_YUV420: | ||
744 | /* Embedded window with different color mode */ | ||
745 | bpp = 12; | ||
746 | /* X, Y, height must be aligned at 2, width at 4 pixels */ | ||
747 | x &= ~1; | ||
748 | y &= ~1; | ||
749 | height = yspan = height & ~1; | ||
750 | width = width & ~3; | ||
751 | break; | ||
752 | default: | ||
753 | /* Same as the plane color mode */ | ||
754 | bpp = blizzard.plane[plane_idx].bpp; | ||
755 | break; | ||
756 | } | ||
757 | if (width * height * bpp / 8 > blizzard.max_transmit_size) { | ||
758 | yspan = blizzard.max_transmit_size / (width * bpp / 8); | ||
759 | yspan_out = yspan * height_out / height; | ||
760 | ADD_PREQ(x, ystart, width, yspan, x_out, ystart_out, | ||
761 | width_out, yspan_out); | ||
762 | ystart += yspan; | ||
763 | ystart_out += yspan_out; | ||
764 | yspan = height - yspan; | ||
765 | yspan_out = height_out - yspan_out; | ||
766 | flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC; | ||
767 | } | ||
768 | |||
769 | ADD_PREQ(x, ystart, width, yspan, x_out, ystart_out, | ||
770 | width_out, yspan_out); | ||
771 | } | ||
772 | |||
773 | static void auto_update_complete(void *data) | ||
774 | { | ||
775 | if (!blizzard.stop_auto_update) | ||
776 | mod_timer(&blizzard.auto_update_timer, | ||
777 | jiffies + BLIZZARD_AUTO_UPDATE_TIME); | ||
778 | } | ||
779 | |||
780 | static void blizzard_update_window_auto(unsigned long arg) | ||
781 | { | ||
782 | LIST_HEAD(req_list); | ||
783 | struct blizzard_request *last; | ||
784 | struct omapfb_plane_struct *plane; | ||
785 | |||
786 | plane = blizzard.fbdev->fb_info[0]->par; | ||
787 | create_req_list(plane->idx, | ||
788 | &blizzard.auto_update_window, &req_list); | ||
789 | last = list_entry(req_list.prev, struct blizzard_request, entry); | ||
790 | |||
791 | last->complete = auto_update_complete; | ||
792 | last->complete_data = NULL; | ||
793 | |||
794 | submit_req_list(&req_list); | ||
795 | } | ||
796 | |||
797 | int blizzard_update_window_async(struct fb_info *fbi, | ||
798 | struct omapfb_update_window *win, | ||
799 | void (*complete_callback)(void *arg), | ||
800 | void *complete_callback_data) | ||
801 | { | ||
802 | LIST_HEAD(req_list); | ||
803 | struct blizzard_request *last; | ||
804 | struct omapfb_plane_struct *plane = fbi->par; | ||
805 | |||
806 | if (unlikely(blizzard.update_mode != OMAPFB_MANUAL_UPDATE)) | ||
807 | return -EINVAL; | ||
808 | if (unlikely(!blizzard.te_connected && | ||
809 | (win->format & OMAPFB_FORMAT_FLAG_TEARSYNC))) | ||
810 | return -EINVAL; | ||
811 | |||
812 | create_req_list(plane->idx, win, &req_list); | ||
813 | last = list_entry(req_list.prev, struct blizzard_request, entry); | ||
814 | |||
815 | last->complete = complete_callback; | ||
816 | last->complete_data = (void *)complete_callback_data; | ||
817 | |||
818 | submit_req_list(&req_list); | ||
819 | |||
820 | return 0; | ||
821 | } | ||
822 | EXPORT_SYMBOL(blizzard_update_window_async); | ||
823 | |||
824 | static int update_full_screen(void) | ||
825 | { | ||
826 | return blizzard_update_window_async(blizzard.fbdev->fb_info[0], | ||
827 | &blizzard.auto_update_window, NULL, NULL); | ||
828 | |||
829 | } | ||
830 | |||
831 | static int blizzard_setup_plane(int plane, int channel_out, | ||
832 | unsigned long offset, int screen_width, | ||
833 | int pos_x, int pos_y, int width, int height, | ||
834 | int color_mode) | ||
835 | { | ||
836 | struct plane_info *p; | ||
837 | |||
838 | #ifdef VERBOSE | ||
839 | dev_dbg(blizzard.fbdev->dev, | ||
840 | "plane %d ch_out %d offset %#08lx scr_width %d " | ||
841 | "pos_x %d pos_y %d width %d height %d color_mode %d\n", | ||
842 | plane, channel_out, offset, screen_width, | ||
843 | pos_x, pos_y, width, height, color_mode); | ||
844 | #endif | ||
845 | if ((unsigned)plane > OMAPFB_PLANE_NUM) | ||
846 | return -EINVAL; | ||
847 | p = &blizzard.plane[plane]; | ||
848 | |||
849 | switch (color_mode) { | ||
850 | case OMAPFB_COLOR_YUV422: | ||
851 | case OMAPFB_COLOR_YUY422: | ||
852 | p->bpp = 16; | ||
853 | blizzard.vid_nonstd_color &= ~(1 << plane); | ||
854 | break; | ||
855 | case OMAPFB_COLOR_YUV420: | ||
856 | p->bpp = 12; | ||
857 | blizzard.vid_nonstd_color |= 1 << plane; | ||
858 | break; | ||
859 | case OMAPFB_COLOR_RGB565: | ||
860 | p->bpp = 16; | ||
861 | blizzard.vid_nonstd_color &= ~(1 << plane); | ||
862 | break; | ||
863 | default: | ||
864 | return -EINVAL; | ||
865 | } | ||
866 | |||
867 | p->offset = offset; | ||
868 | p->pos_x = pos_x; | ||
869 | p->pos_y = pos_y; | ||
870 | p->width = width; | ||
871 | p->height = height; | ||
872 | p->scr_width = screen_width; | ||
873 | if (!p->out_width) | ||
874 | p->out_width = width; | ||
875 | if (!p->out_height) | ||
876 | p->out_height = height; | ||
877 | |||
878 | p->color_mode = color_mode; | ||
879 | |||
880 | return 0; | ||
881 | } | ||
882 | |||
883 | static int blizzard_set_scale(int plane, int orig_w, int orig_h, | ||
884 | int out_w, int out_h) | ||
885 | { | ||
886 | struct plane_info *p = &blizzard.plane[plane]; | ||
887 | int r; | ||
888 | |||
889 | dev_dbg(blizzard.fbdev->dev, | ||
890 | "plane %d orig_w %d orig_h %d out_w %d out_h %d\n", | ||
891 | plane, orig_w, orig_h, out_w, out_h); | ||
892 | if ((unsigned)plane > OMAPFB_PLANE_NUM) | ||
893 | return -ENODEV; | ||
894 | |||
895 | r = blizzard.int_ctrl->set_scale(plane, orig_w, orig_h, out_w, out_h); | ||
896 | if (r < 0) | ||
897 | return r; | ||
898 | |||
899 | p->width = orig_w; | ||
900 | p->height = orig_h; | ||
901 | p->out_width = out_w; | ||
902 | p->out_height = out_h; | ||
903 | if (orig_w == out_w && orig_h == out_h) | ||
904 | blizzard.vid_scaled &= ~(1 << plane); | ||
905 | else | ||
906 | blizzard.vid_scaled |= 1 << plane; | ||
907 | |||
908 | return 0; | ||
909 | } | ||
910 | |||
911 | static int blizzard_enable_plane(int plane, int enable) | ||
912 | { | ||
913 | if (enable) | ||
914 | blizzard.enabled_planes |= 1 << plane; | ||
915 | else | ||
916 | blizzard.enabled_planes &= ~(1 << plane); | ||
917 | |||
918 | return 0; | ||
919 | } | ||
920 | |||
921 | static int sync_handler(struct blizzard_request *req) | ||
922 | { | ||
923 | complete(req->par.sync); | ||
924 | return REQ_COMPLETE; | ||
925 | } | ||
926 | |||
927 | static void blizzard_sync(void) | ||
928 | { | ||
929 | LIST_HEAD(req_list); | ||
930 | struct blizzard_request *req; | ||
931 | struct completion comp; | ||
932 | |||
933 | req = alloc_req(); | ||
934 | |||
935 | req->handler = sync_handler; | ||
936 | req->complete = NULL; | ||
937 | init_completion(&comp); | ||
938 | req->par.sync = ∁ | ||
939 | |||
940 | list_add(&req->entry, &req_list); | ||
941 | submit_req_list(&req_list); | ||
942 | |||
943 | wait_for_completion(&comp); | ||
944 | } | ||
945 | |||
946 | |||
947 | static void blizzard_bind_client(struct omapfb_notifier_block *nb) | ||
948 | { | ||
949 | if (blizzard.update_mode == OMAPFB_MANUAL_UPDATE) { | ||
950 | omapfb_notify_clients(blizzard.fbdev, OMAPFB_EVENT_READY); | ||
951 | } | ||
952 | } | ||
953 | |||
954 | static int blizzard_set_update_mode(enum omapfb_update_mode mode) | ||
955 | { | ||
956 | if (unlikely(mode != OMAPFB_MANUAL_UPDATE && | ||
957 | mode != OMAPFB_AUTO_UPDATE && | ||
958 | mode != OMAPFB_UPDATE_DISABLED)) | ||
959 | return -EINVAL; | ||
960 | |||
961 | if (mode == blizzard.update_mode) | ||
962 | return 0; | ||
963 | |||
964 | dev_info(blizzard.fbdev->dev, "s1d1374x: setting update mode to %s\n", | ||
965 | mode == OMAPFB_UPDATE_DISABLED ? "disabled" : | ||
966 | (mode == OMAPFB_AUTO_UPDATE ? "auto" : "manual")); | ||
967 | |||
968 | switch (blizzard.update_mode) { | ||
969 | case OMAPFB_MANUAL_UPDATE: | ||
970 | omapfb_notify_clients(blizzard.fbdev, OMAPFB_EVENT_DISABLED); | ||
971 | break; | ||
972 | case OMAPFB_AUTO_UPDATE: | ||
973 | blizzard.stop_auto_update = 1; | ||
974 | del_timer_sync(&blizzard.auto_update_timer); | ||
975 | break; | ||
976 | case OMAPFB_UPDATE_DISABLED: | ||
977 | break; | ||
978 | } | ||
979 | |||
980 | blizzard.update_mode = mode; | ||
981 | blizzard_sync(); | ||
982 | blizzard.stop_auto_update = 0; | ||
983 | |||
984 | switch (mode) { | ||
985 | case OMAPFB_MANUAL_UPDATE: | ||
986 | omapfb_notify_clients(blizzard.fbdev, OMAPFB_EVENT_READY); | ||
987 | break; | ||
988 | case OMAPFB_AUTO_UPDATE: | ||
989 | blizzard_update_window_auto(0); | ||
990 | break; | ||
991 | case OMAPFB_UPDATE_DISABLED: | ||
992 | break; | ||
993 | } | ||
994 | |||
995 | return 0; | ||
996 | } | ||
997 | |||
998 | static enum omapfb_update_mode blizzard_get_update_mode(void) | ||
999 | { | ||
1000 | return blizzard.update_mode; | ||
1001 | } | ||
1002 | |||
1003 | static inline void set_extif_timings(const struct extif_timings *t) | ||
1004 | { | ||
1005 | blizzard.extif->set_timings(t); | ||
1006 | } | ||
1007 | |||
1008 | static inline unsigned long round_to_extif_ticks(unsigned long ps, int div) | ||
1009 | { | ||
1010 | int bus_tick = blizzard.extif_clk_period * div; | ||
1011 | return (ps + bus_tick - 1) / bus_tick * bus_tick; | ||
1012 | } | ||
1013 | |||
1014 | static int calc_reg_timing(unsigned long sysclk, int div) | ||
1015 | { | ||
1016 | struct extif_timings *t; | ||
1017 | unsigned long systim; | ||
1018 | |||
1019 | /* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns, | ||
1020 | * AccessTime 2 ns + 12.2 ns (regs), | ||
1021 | * WEOffTime = WEOnTime + 1 ns, | ||
1022 | * REOffTime = REOnTime + 12 ns (regs), | ||
1023 | * CSOffTime = REOffTime + 1 ns | ||
1024 | * ReadCycle = 2ns + 2*SYSCLK (regs), | ||
1025 | * WriteCycle = 2*SYSCLK + 2 ns, | ||
1026 | * CSPulseWidth = 10 ns */ | ||
1027 | |||
1028 | systim = 1000000000 / (sysclk / 1000); | ||
1029 | dev_dbg(blizzard.fbdev->dev, | ||
1030 | "Blizzard systim %lu ps extif_clk_period %u div %d\n", | ||
1031 | systim, blizzard.extif_clk_period, div); | ||
1032 | |||
1033 | t = &blizzard.reg_timings; | ||
1034 | memset(t, 0, sizeof(*t)); | ||
1035 | |||
1036 | t->clk_div = div; | ||
1037 | |||
1038 | t->cs_on_time = 0; | ||
1039 | t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
1040 | t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
1041 | t->access_time = round_to_extif_ticks(t->re_on_time + 12200, div); | ||
1042 | t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div); | ||
1043 | t->re_off_time = round_to_extif_ticks(t->re_on_time + 13000, div); | ||
1044 | t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div); | ||
1045 | t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div); | ||
1046 | if (t->we_cycle_time < t->we_off_time) | ||
1047 | t->we_cycle_time = t->we_off_time; | ||
1048 | t->re_cycle_time = round_to_extif_ticks(2 * systim + 2000, div); | ||
1049 | if (t->re_cycle_time < t->re_off_time) | ||
1050 | t->re_cycle_time = t->re_off_time; | ||
1051 | t->cs_pulse_width = 0; | ||
1052 | |||
1053 | dev_dbg(blizzard.fbdev->dev, "[reg]cson %d csoff %d reon %d reoff %d\n", | ||
1054 | t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time); | ||
1055 | dev_dbg(blizzard.fbdev->dev, "[reg]weon %d weoff %d recyc %d wecyc %d\n", | ||
1056 | t->we_on_time, t->we_off_time, t->re_cycle_time, | ||
1057 | t->we_cycle_time); | ||
1058 | dev_dbg(blizzard.fbdev->dev, "[reg]rdaccess %d cspulse %d\n", | ||
1059 | t->access_time, t->cs_pulse_width); | ||
1060 | |||
1061 | return blizzard.extif->convert_timings(t); | ||
1062 | } | ||
1063 | |||
1064 | static int calc_lut_timing(unsigned long sysclk, int div) | ||
1065 | { | ||
1066 | struct extif_timings *t; | ||
1067 | unsigned long systim; | ||
1068 | |||
1069 | /* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns, | ||
1070 | * AccessTime 2 ns + 4 * SYSCLK + 26 (lut), | ||
1071 | * WEOffTime = WEOnTime + 1 ns, | ||
1072 | * REOffTime = REOnTime + 4*SYSCLK + 26 ns (lut), | ||
1073 | * CSOffTime = REOffTime + 1 ns | ||
1074 | * ReadCycle = 2ns + 4*SYSCLK + 26 ns (lut), | ||
1075 | * WriteCycle = 2*SYSCLK + 2 ns, | ||
1076 | * CSPulseWidth = 10 ns */ | ||
1077 | |||
1078 | systim = 1000000000 / (sysclk / 1000); | ||
1079 | dev_dbg(blizzard.fbdev->dev, | ||
1080 | "Blizzard systim %lu ps extif_clk_period %u div %d\n", | ||
1081 | systim, blizzard.extif_clk_period, div); | ||
1082 | |||
1083 | t = &blizzard.lut_timings; | ||
1084 | memset(t, 0, sizeof(*t)); | ||
1085 | |||
1086 | t->clk_div = div; | ||
1087 | |||
1088 | t->cs_on_time = 0; | ||
1089 | t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
1090 | t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
1091 | t->access_time = round_to_extif_ticks(t->re_on_time + 4 * systim + | ||
1092 | 26000, div); | ||
1093 | t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div); | ||
1094 | t->re_off_time = round_to_extif_ticks(t->re_on_time + 4 * systim + | ||
1095 | 26000, div); | ||
1096 | t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div); | ||
1097 | t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div); | ||
1098 | if (t->we_cycle_time < t->we_off_time) | ||
1099 | t->we_cycle_time = t->we_off_time; | ||
1100 | t->re_cycle_time = round_to_extif_ticks(2000 + 4 * systim + 26000, div); | ||
1101 | if (t->re_cycle_time < t->re_off_time) | ||
1102 | t->re_cycle_time = t->re_off_time; | ||
1103 | t->cs_pulse_width = 0; | ||
1104 | |||
1105 | dev_dbg(blizzard.fbdev->dev, | ||
1106 | "[lut]cson %d csoff %d reon %d reoff %d\n", | ||
1107 | t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time); | ||
1108 | dev_dbg(blizzard.fbdev->dev, | ||
1109 | "[lut]weon %d weoff %d recyc %d wecyc %d\n", | ||
1110 | t->we_on_time, t->we_off_time, t->re_cycle_time, | ||
1111 | t->we_cycle_time); | ||
1112 | dev_dbg(blizzard.fbdev->dev, "[lut]rdaccess %d cspulse %d\n", | ||
1113 | t->access_time, t->cs_pulse_width); | ||
1114 | |||
1115 | return blizzard.extif->convert_timings(t); | ||
1116 | } | ||
1117 | |||
1118 | static int calc_extif_timings(unsigned long sysclk, int *extif_mem_div) | ||
1119 | { | ||
1120 | int max_clk_div; | ||
1121 | int div; | ||
1122 | |||
1123 | blizzard.extif->get_clk_info(&blizzard.extif_clk_period, &max_clk_div); | ||
1124 | for (div = 1; div <= max_clk_div; div++) { | ||
1125 | if (calc_reg_timing(sysclk, div) == 0) | ||
1126 | break; | ||
1127 | } | ||
1128 | if (div > max_clk_div) { | ||
1129 | dev_dbg(blizzard.fbdev->dev, "reg timing failed\n"); | ||
1130 | goto err; | ||
1131 | } | ||
1132 | *extif_mem_div = div; | ||
1133 | |||
1134 | for (div = 1; div <= max_clk_div; div++) { | ||
1135 | if (calc_lut_timing(sysclk, div) == 0) | ||
1136 | break; | ||
1137 | } | ||
1138 | |||
1139 | if (div > max_clk_div) | ||
1140 | goto err; | ||
1141 | |||
1142 | blizzard.extif_clk_div = div; | ||
1143 | |||
1144 | return 0; | ||
1145 | err: | ||
1146 | dev_err(blizzard.fbdev->dev, "can't setup timings\n"); | ||
1147 | return -1; | ||
1148 | } | ||
1149 | |||
1150 | static void calc_blizzard_clk_rates(unsigned long ext_clk, | ||
1151 | unsigned long *sys_clk, unsigned long *pix_clk) | ||
1152 | { | ||
1153 | int pix_clk_src; | ||
1154 | int sys_div = 0, sys_mul = 0; | ||
1155 | int pix_div; | ||
1156 | |||
1157 | pix_clk_src = blizzard_read_reg(BLIZZARD_CLK_SRC); | ||
1158 | pix_div = ((pix_clk_src >> 3) & 0x1f) + 1; | ||
1159 | if ((pix_clk_src & (0x3 << 1)) == 0) { | ||
1160 | /* Source is the PLL */ | ||
1161 | sys_div = (blizzard_read_reg(BLIZZARD_PLL_DIV) & 0x3f) + 1; | ||
1162 | sys_mul = blizzard_read_reg(BLIZZARD_PLL_CLOCK_SYNTH_0); | ||
1163 | sys_mul |= ((blizzard_read_reg(BLIZZARD_PLL_CLOCK_SYNTH_1) | ||
1164 | & 0x0f) << 11); | ||
1165 | *sys_clk = ext_clk * sys_mul / sys_div; | ||
1166 | } else /* else source is ext clk, or oscillator */ | ||
1167 | *sys_clk = ext_clk; | ||
1168 | |||
1169 | *pix_clk = *sys_clk / pix_div; /* HZ */ | ||
1170 | dev_dbg(blizzard.fbdev->dev, | ||
1171 | "ext_clk %ld pix_src %d pix_div %d sys_div %d sys_mul %d\n", | ||
1172 | ext_clk, pix_clk_src & (0x3 << 1), pix_div, sys_div, sys_mul); | ||
1173 | dev_dbg(blizzard.fbdev->dev, "sys_clk %ld pix_clk %ld\n", | ||
1174 | *sys_clk, *pix_clk); | ||
1175 | } | ||
1176 | |||
1177 | static int setup_tearsync(unsigned long pix_clk, int extif_div) | ||
1178 | { | ||
1179 | int hdisp, vdisp; | ||
1180 | int hndp, vndp; | ||
1181 | int hsw, vsw; | ||
1182 | int hs, vs; | ||
1183 | int hs_pol_inv, vs_pol_inv; | ||
1184 | int use_hsvs, use_ndp; | ||
1185 | u8 b; | ||
1186 | |||
1187 | hsw = blizzard_read_reg(BLIZZARD_HSW); | ||
1188 | vsw = blizzard_read_reg(BLIZZARD_VSW); | ||
1189 | hs_pol_inv = !(hsw & 0x80); | ||
1190 | vs_pol_inv = !(vsw & 0x80); | ||
1191 | hsw = hsw & 0x7f; | ||
1192 | vsw = vsw & 0x3f; | ||
1193 | |||
1194 | hdisp = blizzard_read_reg(BLIZZARD_HDISP) * 8; | ||
1195 | vdisp = blizzard_read_reg(BLIZZARD_VDISP0) + | ||
1196 | ((blizzard_read_reg(BLIZZARD_VDISP1) & 0x3) << 8); | ||
1197 | |||
1198 | hndp = blizzard_read_reg(BLIZZARD_HNDP) & 0x3f; | ||
1199 | vndp = blizzard_read_reg(BLIZZARD_VNDP); | ||
1200 | |||
1201 | /* time to transfer one pixel (16bpp) in ps */ | ||
1202 | blizzard.pix_tx_time = blizzard.reg_timings.we_cycle_time; | ||
1203 | if (blizzard.extif->get_max_tx_rate != NULL) { | ||
1204 | /* The external interface might have a rate limitation, | ||
1205 | * if so, we have to maximize our transfer rate. | ||
1206 | */ | ||
1207 | unsigned long min_tx_time; | ||
1208 | unsigned long max_tx_rate = blizzard.extif->get_max_tx_rate(); | ||
1209 | |||
1210 | dev_dbg(blizzard.fbdev->dev, "max_tx_rate %ld HZ\n", | ||
1211 | max_tx_rate); | ||
1212 | min_tx_time = 1000000000 / (max_tx_rate / 1000); /* ps */ | ||
1213 | if (blizzard.pix_tx_time < min_tx_time) | ||
1214 | blizzard.pix_tx_time = min_tx_time; | ||
1215 | } | ||
1216 | |||
1217 | /* time to update one line in ps */ | ||
1218 | blizzard.line_upd_time = (hdisp + hndp) * 1000000 / (pix_clk / 1000); | ||
1219 | blizzard.line_upd_time *= 1000; | ||
1220 | if (hdisp * blizzard.pix_tx_time > blizzard.line_upd_time) | ||
1221 | /* transfer speed too low, we might have to use both | ||
1222 | * HS and VS */ | ||
1223 | use_hsvs = 1; | ||
1224 | else | ||
1225 | /* decent transfer speed, we'll always use only VS */ | ||
1226 | use_hsvs = 0; | ||
1227 | |||
1228 | if (use_hsvs && (hs_pol_inv || vs_pol_inv)) { | ||
1229 | /* HS or'ed with VS doesn't work, use the active high | ||
1230 | * TE signal based on HNDP / VNDP */ | ||
1231 | use_ndp = 1; | ||
1232 | hs_pol_inv = 0; | ||
1233 | vs_pol_inv = 0; | ||
1234 | hs = hndp; | ||
1235 | vs = vndp; | ||
1236 | } else { | ||
1237 | /* Use HS or'ed with VS as a TE signal if both are needed | ||
1238 | * or VNDP if only vsync is needed. */ | ||
1239 | use_ndp = 0; | ||
1240 | hs = hsw; | ||
1241 | vs = vsw; | ||
1242 | if (!use_hsvs) { | ||
1243 | hs_pol_inv = 0; | ||
1244 | vs_pol_inv = 0; | ||
1245 | } | ||
1246 | } | ||
1247 | |||
1248 | hs = hs * 1000000 / (pix_clk / 1000); /* ps */ | ||
1249 | hs *= 1000; | ||
1250 | |||
1251 | vs = vs * (hdisp + hndp) * 1000000 / (pix_clk / 1000); /* ps */ | ||
1252 | vs *= 1000; | ||
1253 | |||
1254 | if (vs <= hs) | ||
1255 | return -EDOM; | ||
1256 | /* set VS to 120% of HS to minimize VS detection time */ | ||
1257 | vs = hs * 12 / 10; | ||
1258 | /* minimize HS too */ | ||
1259 | if (hs > 10000) | ||
1260 | hs = 10000; | ||
1261 | |||
1262 | b = blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS); | ||
1263 | b &= ~0x3; | ||
1264 | b |= use_hsvs ? 1 : 0; | ||
1265 | b |= (use_ndp && use_hsvs) ? 0 : 2; | ||
1266 | blizzard_write_reg(BLIZZARD_NDISP_CTRL_STATUS, b); | ||
1267 | |||
1268 | blizzard.vsync_only = !use_hsvs; | ||
1269 | |||
1270 | dev_dbg(blizzard.fbdev->dev, | ||
1271 | "pix_clk %ld HZ pix_tx_time %ld ps line_upd_time %ld ps\n", | ||
1272 | pix_clk, blizzard.pix_tx_time, blizzard.line_upd_time); | ||
1273 | dev_dbg(blizzard.fbdev->dev, | ||
1274 | "hs %d ps vs %d ps mode %d vsync_only %d\n", | ||
1275 | hs, vs, b & 0x3, !use_hsvs); | ||
1276 | |||
1277 | return blizzard.extif->setup_tearsync(1, hs, vs, | ||
1278 | hs_pol_inv, vs_pol_inv, | ||
1279 | extif_div); | ||
1280 | } | ||
1281 | |||
1282 | static void blizzard_get_caps(int plane, struct omapfb_caps *caps) | ||
1283 | { | ||
1284 | blizzard.int_ctrl->get_caps(plane, caps); | ||
1285 | caps->ctrl |= OMAPFB_CAPS_MANUAL_UPDATE | | ||
1286 | OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE | | ||
1287 | OMAPFB_CAPS_WINDOW_SCALE | | ||
1288 | OMAPFB_CAPS_WINDOW_OVERLAY; | ||
1289 | if (blizzard.te_connected) | ||
1290 | caps->ctrl |= OMAPFB_CAPS_TEARSYNC; | ||
1291 | caps->wnd_color |= (1 << OMAPFB_COLOR_RGB565) | | ||
1292 | (1 << OMAPFB_COLOR_YUV420); | ||
1293 | } | ||
1294 | |||
1295 | static void _save_regs(struct blizzard_reg_list *list, int cnt) | ||
1296 | { | ||
1297 | int i; | ||
1298 | |||
1299 | for (i = 0; i < cnt; i++, list++) { | ||
1300 | int reg; | ||
1301 | for (reg = list->start; reg <= list->end; reg += 2) | ||
1302 | blizzard_reg_cache[reg / 2] = blizzard_read_reg(reg); | ||
1303 | } | ||
1304 | } | ||
1305 | |||
1306 | static void _restore_regs(struct blizzard_reg_list *list, int cnt) | ||
1307 | { | ||
1308 | int i; | ||
1309 | |||
1310 | for (i = 0; i < cnt; i++, list++) { | ||
1311 | int reg; | ||
1312 | for (reg = list->start; reg <= list->end; reg += 2) | ||
1313 | blizzard_write_reg(reg, blizzard_reg_cache[reg / 2]); | ||
1314 | } | ||
1315 | } | ||
1316 | |||
1317 | static void blizzard_save_all_regs(void) | ||
1318 | { | ||
1319 | _save_regs(blizzard_pll_regs, ARRAY_SIZE(blizzard_pll_regs)); | ||
1320 | _save_regs(blizzard_gen_regs, ARRAY_SIZE(blizzard_gen_regs)); | ||
1321 | } | ||
1322 | |||
1323 | static void blizzard_restore_pll_regs(void) | ||
1324 | { | ||
1325 | _restore_regs(blizzard_pll_regs, ARRAY_SIZE(blizzard_pll_regs)); | ||
1326 | } | ||
1327 | |||
1328 | static void blizzard_restore_gen_regs(void) | ||
1329 | { | ||
1330 | _restore_regs(blizzard_gen_regs, ARRAY_SIZE(blizzard_gen_regs)); | ||
1331 | } | ||
1332 | |||
1333 | static void blizzard_suspend(void) | ||
1334 | { | ||
1335 | u32 l; | ||
1336 | unsigned long tmo; | ||
1337 | |||
1338 | if (blizzard.last_color_mode) { | ||
1339 | update_full_screen(); | ||
1340 | blizzard_sync(); | ||
1341 | } | ||
1342 | blizzard.update_mode_before_suspend = blizzard.update_mode; | ||
1343 | /* the following will disable clocks as well */ | ||
1344 | blizzard_set_update_mode(OMAPFB_UPDATE_DISABLED); | ||
1345 | |||
1346 | blizzard_save_all_regs(); | ||
1347 | |||
1348 | blizzard_stop_sdram(); | ||
1349 | |||
1350 | l = blizzard_read_reg(BLIZZARD_POWER_SAVE); | ||
1351 | /* Standby, Sleep. We assume we use an external clock. */ | ||
1352 | l |= 0x03; | ||
1353 | blizzard_write_reg(BLIZZARD_POWER_SAVE, l); | ||
1354 | |||
1355 | tmo = jiffies + msecs_to_jiffies(100); | ||
1356 | while (!(blizzard_read_reg(BLIZZARD_PLL_MODE) & (1 << 1))) { | ||
1357 | if (time_after(jiffies, tmo)) { | ||
1358 | dev_err(blizzard.fbdev->dev, | ||
1359 | "s1d1374x: sleep timeout, stopping PLL manually\n"); | ||
1360 | l = blizzard_read_reg(BLIZZARD_PLL_MODE); | ||
1361 | l &= ~0x03; | ||
1362 | /* Disable PLL, counter function */ | ||
1363 | l |= 0x2; | ||
1364 | blizzard_write_reg(BLIZZARD_PLL_MODE, l); | ||
1365 | break; | ||
1366 | } | ||
1367 | msleep(1); | ||
1368 | } | ||
1369 | |||
1370 | if (blizzard.power_down != NULL) | ||
1371 | blizzard.power_down(blizzard.fbdev->dev); | ||
1372 | } | ||
1373 | |||
1374 | static void blizzard_resume(void) | ||
1375 | { | ||
1376 | u32 l; | ||
1377 | |||
1378 | if (blizzard.power_up != NULL) | ||
1379 | blizzard.power_up(blizzard.fbdev->dev); | ||
1380 | |||
1381 | l = blizzard_read_reg(BLIZZARD_POWER_SAVE); | ||
1382 | /* Standby, Sleep */ | ||
1383 | l &= ~0x03; | ||
1384 | blizzard_write_reg(BLIZZARD_POWER_SAVE, l); | ||
1385 | |||
1386 | blizzard_restore_pll_regs(); | ||
1387 | l = blizzard_read_reg(BLIZZARD_PLL_MODE); | ||
1388 | l &= ~0x03; | ||
1389 | /* Enable PLL, counter function */ | ||
1390 | l |= 0x1; | ||
1391 | blizzard_write_reg(BLIZZARD_PLL_MODE, l); | ||
1392 | |||
1393 | while (!(blizzard_read_reg(BLIZZARD_PLL_DIV) & (1 << 7))) | ||
1394 | msleep(1); | ||
1395 | |||
1396 | blizzard_restart_sdram(); | ||
1397 | |||
1398 | blizzard_restore_gen_regs(); | ||
1399 | |||
1400 | /* Enable display */ | ||
1401 | blizzard_write_reg(BLIZZARD_DISPLAY_MODE, 0x01); | ||
1402 | |||
1403 | /* the following will enable clocks as necessary */ | ||
1404 | blizzard_set_update_mode(blizzard.update_mode_before_suspend); | ||
1405 | |||
1406 | /* Force a background update */ | ||
1407 | blizzard.zoom_on = 1; | ||
1408 | update_full_screen(); | ||
1409 | blizzard_sync(); | ||
1410 | } | ||
1411 | |||
1412 | static int blizzard_init(struct omapfb_device *fbdev, int ext_mode, | ||
1413 | struct omapfb_mem_desc *req_vram) | ||
1414 | { | ||
1415 | int r = 0, i; | ||
1416 | u8 rev, conf; | ||
1417 | unsigned long ext_clk; | ||
1418 | int extif_div; | ||
1419 | unsigned long sys_clk, pix_clk; | ||
1420 | struct omapfb_platform_data *omapfb_conf; | ||
1421 | struct blizzard_platform_data *ctrl_conf; | ||
1422 | |||
1423 | blizzard.fbdev = fbdev; | ||
1424 | |||
1425 | BUG_ON(!fbdev->ext_if || !fbdev->int_ctrl); | ||
1426 | |||
1427 | blizzard.fbdev = fbdev; | ||
1428 | blizzard.extif = fbdev->ext_if; | ||
1429 | blizzard.int_ctrl = fbdev->int_ctrl; | ||
1430 | |||
1431 | omapfb_conf = fbdev->dev->platform_data; | ||
1432 | ctrl_conf = omapfb_conf->ctrl_platform_data; | ||
1433 | if (ctrl_conf == NULL || ctrl_conf->get_clock_rate == NULL) { | ||
1434 | dev_err(fbdev->dev, "s1d1374x: missing platform data\n"); | ||
1435 | r = -ENOENT; | ||
1436 | goto err1; | ||
1437 | } | ||
1438 | |||
1439 | blizzard.power_down = ctrl_conf->power_down; | ||
1440 | blizzard.power_up = ctrl_conf->power_up; | ||
1441 | |||
1442 | spin_lock_init(&blizzard.req_lock); | ||
1443 | |||
1444 | if ((r = blizzard.int_ctrl->init(fbdev, 1, req_vram)) < 0) | ||
1445 | goto err1; | ||
1446 | |||
1447 | if ((r = blizzard.extif->init(fbdev)) < 0) | ||
1448 | goto err2; | ||
1449 | |||
1450 | blizzard_ctrl.set_color_key = blizzard.int_ctrl->set_color_key; | ||
1451 | blizzard_ctrl.get_color_key = blizzard.int_ctrl->get_color_key; | ||
1452 | blizzard_ctrl.setup_mem = blizzard.int_ctrl->setup_mem; | ||
1453 | blizzard_ctrl.mmap = blizzard.int_ctrl->mmap; | ||
1454 | |||
1455 | ext_clk = ctrl_conf->get_clock_rate(fbdev->dev); | ||
1456 | if ((r = calc_extif_timings(ext_clk, &extif_div)) < 0) | ||
1457 | goto err3; | ||
1458 | |||
1459 | set_extif_timings(&blizzard.reg_timings); | ||
1460 | |||
1461 | if (blizzard.power_up != NULL) | ||
1462 | blizzard.power_up(fbdev->dev); | ||
1463 | |||
1464 | calc_blizzard_clk_rates(ext_clk, &sys_clk, &pix_clk); | ||
1465 | |||
1466 | if ((r = calc_extif_timings(sys_clk, &extif_div)) < 0) | ||
1467 | goto err3; | ||
1468 | set_extif_timings(&blizzard.reg_timings); | ||
1469 | |||
1470 | if (!(blizzard_read_reg(BLIZZARD_PLL_DIV) & 0x80)) { | ||
1471 | dev_err(fbdev->dev, | ||
1472 | "controller not initialized by the bootloader\n"); | ||
1473 | r = -ENODEV; | ||
1474 | goto err3; | ||
1475 | } | ||
1476 | |||
1477 | if (ctrl_conf->te_connected) { | ||
1478 | if ((r = setup_tearsync(pix_clk, extif_div)) < 0) | ||
1479 | goto err3; | ||
1480 | blizzard.te_connected = 1; | ||
1481 | } | ||
1482 | |||
1483 | rev = blizzard_read_reg(BLIZZARD_REV_CODE); | ||
1484 | conf = blizzard_read_reg(BLIZZARD_CONFIG); | ||
1485 | |||
1486 | switch (rev & 0xfc) { | ||
1487 | case 0x9c: | ||
1488 | blizzard.version = BLIZZARD_VERSION_S1D13744; | ||
1489 | pr_info("omapfb: s1d13744 LCD controller rev %d " | ||
1490 | "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07); | ||
1491 | break; | ||
1492 | case 0xa4: | ||
1493 | blizzard.version = BLIZZARD_VERSION_S1D13745; | ||
1494 | pr_info("omapfb: s1d13745 LCD controller rev %d " | ||
1495 | "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07); | ||
1496 | break; | ||
1497 | default: | ||
1498 | dev_err(fbdev->dev, "invalid s1d1374x revision %02x\n", | ||
1499 | rev); | ||
1500 | r = -ENODEV; | ||
1501 | goto err3; | ||
1502 | } | ||
1503 | |||
1504 | blizzard.max_transmit_size = blizzard.extif->max_transmit_size; | ||
1505 | |||
1506 | blizzard.update_mode = OMAPFB_UPDATE_DISABLED; | ||
1507 | |||
1508 | blizzard.auto_update_window.x = 0; | ||
1509 | blizzard.auto_update_window.y = 0; | ||
1510 | blizzard.auto_update_window.width = fbdev->panel->x_res; | ||
1511 | blizzard.auto_update_window.height = fbdev->panel->y_res; | ||
1512 | blizzard.auto_update_window.out_x = 0; | ||
1513 | blizzard.auto_update_window.out_x = 0; | ||
1514 | blizzard.auto_update_window.out_width = fbdev->panel->x_res; | ||
1515 | blizzard.auto_update_window.out_height = fbdev->panel->y_res; | ||
1516 | blizzard.auto_update_window.format = 0; | ||
1517 | |||
1518 | blizzard.screen_width = fbdev->panel->x_res; | ||
1519 | blizzard.screen_height = fbdev->panel->y_res; | ||
1520 | |||
1521 | init_timer(&blizzard.auto_update_timer); | ||
1522 | blizzard.auto_update_timer.function = blizzard_update_window_auto; | ||
1523 | blizzard.auto_update_timer.data = 0; | ||
1524 | |||
1525 | INIT_LIST_HEAD(&blizzard.free_req_list); | ||
1526 | INIT_LIST_HEAD(&blizzard.pending_req_list); | ||
1527 | for (i = 0; i < ARRAY_SIZE(blizzard.req_pool); i++) | ||
1528 | list_add(&blizzard.req_pool[i].entry, &blizzard.free_req_list); | ||
1529 | BUG_ON(i <= IRQ_REQ_POOL_SIZE); | ||
1530 | sema_init(&blizzard.req_sema, i - IRQ_REQ_POOL_SIZE); | ||
1531 | |||
1532 | return 0; | ||
1533 | err3: | ||
1534 | if (blizzard.power_down != NULL) | ||
1535 | blizzard.power_down(fbdev->dev); | ||
1536 | blizzard.extif->cleanup(); | ||
1537 | err2: | ||
1538 | blizzard.int_ctrl->cleanup(); | ||
1539 | err1: | ||
1540 | return r; | ||
1541 | } | ||
1542 | |||
1543 | static void blizzard_cleanup(void) | ||
1544 | { | ||
1545 | blizzard_set_update_mode(OMAPFB_UPDATE_DISABLED); | ||
1546 | blizzard.extif->cleanup(); | ||
1547 | blizzard.int_ctrl->cleanup(); | ||
1548 | if (blizzard.power_down != NULL) | ||
1549 | blizzard.power_down(blizzard.fbdev->dev); | ||
1550 | } | ||
1551 | |||
1552 | struct lcd_ctrl blizzard_ctrl = { | ||
1553 | .name = "blizzard", | ||
1554 | .init = blizzard_init, | ||
1555 | .cleanup = blizzard_cleanup, | ||
1556 | .bind_client = blizzard_bind_client, | ||
1557 | .get_caps = blizzard_get_caps, | ||
1558 | .set_update_mode = blizzard_set_update_mode, | ||
1559 | .get_update_mode = blizzard_get_update_mode, | ||
1560 | .setup_plane = blizzard_setup_plane, | ||
1561 | .set_scale = blizzard_set_scale, | ||
1562 | .enable_plane = blizzard_enable_plane, | ||
1563 | .update_window = blizzard_update_window_async, | ||
1564 | .sync = blizzard_sync, | ||
1565 | .suspend = blizzard_suspend, | ||
1566 | .resume = blizzard_resume, | ||
1567 | }; | ||
1568 | |||
diff --git a/drivers/video/omap/dispc.c b/drivers/video/omap/dispc.c new file mode 100644 index 000000000000..f4c23434de6f --- /dev/null +++ b/drivers/video/omap/dispc.c | |||
@@ -0,0 +1,1502 @@ | |||
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/dma-mapping.h> | ||
23 | #include <linux/vmalloc.h> | ||
24 | #include <linux/clk.h> | ||
25 | #include <linux/io.h> | ||
26 | |||
27 | #include <asm/arch/sram.h> | ||
28 | #include <asm/arch/omapfb.h> | ||
29 | #include <asm/arch/board.h> | ||
30 | |||
31 | #include "dispc.h" | ||
32 | |||
33 | #define MODULE_NAME "dispc" | ||
34 | |||
35 | #define DSS_BASE 0x48050000 | ||
36 | #define DSS_SYSCONFIG 0x0010 | ||
37 | |||
38 | #define DISPC_BASE 0x48050400 | ||
39 | |||
40 | /* DISPC common */ | ||
41 | #define DISPC_REVISION 0x0000 | ||
42 | #define DISPC_SYSCONFIG 0x0010 | ||
43 | #define DISPC_SYSSTATUS 0x0014 | ||
44 | #define DISPC_IRQSTATUS 0x0018 | ||
45 | #define DISPC_IRQENABLE 0x001C | ||
46 | #define DISPC_CONTROL 0x0040 | ||
47 | #define DISPC_CONFIG 0x0044 | ||
48 | #define DISPC_CAPABLE 0x0048 | ||
49 | #define DISPC_DEFAULT_COLOR0 0x004C | ||
50 | #define DISPC_DEFAULT_COLOR1 0x0050 | ||
51 | #define DISPC_TRANS_COLOR0 0x0054 | ||
52 | #define DISPC_TRANS_COLOR1 0x0058 | ||
53 | #define DISPC_LINE_STATUS 0x005C | ||
54 | #define DISPC_LINE_NUMBER 0x0060 | ||
55 | #define DISPC_TIMING_H 0x0064 | ||
56 | #define DISPC_TIMING_V 0x0068 | ||
57 | #define DISPC_POL_FREQ 0x006C | ||
58 | #define DISPC_DIVISOR 0x0070 | ||
59 | #define DISPC_SIZE_DIG 0x0078 | ||
60 | #define DISPC_SIZE_LCD 0x007C | ||
61 | |||
62 | #define DISPC_DATA_CYCLE1 0x01D4 | ||
63 | #define DISPC_DATA_CYCLE2 0x01D8 | ||
64 | #define DISPC_DATA_CYCLE3 0x01DC | ||
65 | |||
66 | /* DISPC GFX plane */ | ||
67 | #define DISPC_GFX_BA0 0x0080 | ||
68 | #define DISPC_GFX_BA1 0x0084 | ||
69 | #define DISPC_GFX_POSITION 0x0088 | ||
70 | #define DISPC_GFX_SIZE 0x008C | ||
71 | #define DISPC_GFX_ATTRIBUTES 0x00A0 | ||
72 | #define DISPC_GFX_FIFO_THRESHOLD 0x00A4 | ||
73 | #define DISPC_GFX_FIFO_SIZE_STATUS 0x00A8 | ||
74 | #define DISPC_GFX_ROW_INC 0x00AC | ||
75 | #define DISPC_GFX_PIXEL_INC 0x00B0 | ||
76 | #define DISPC_GFX_WINDOW_SKIP 0x00B4 | ||
77 | #define DISPC_GFX_TABLE_BA 0x00B8 | ||
78 | |||
79 | /* DISPC Video plane 1/2 */ | ||
80 | #define DISPC_VID1_BASE 0x00BC | ||
81 | #define DISPC_VID2_BASE 0x014C | ||
82 | |||
83 | /* Offsets into DISPC_VID1/2_BASE */ | ||
84 | #define DISPC_VID_BA0 0x0000 | ||
85 | #define DISPC_VID_BA1 0x0004 | ||
86 | #define DISPC_VID_POSITION 0x0008 | ||
87 | #define DISPC_VID_SIZE 0x000C | ||
88 | #define DISPC_VID_ATTRIBUTES 0x0010 | ||
89 | #define DISPC_VID_FIFO_THRESHOLD 0x0014 | ||
90 | #define DISPC_VID_FIFO_SIZE_STATUS 0x0018 | ||
91 | #define DISPC_VID_ROW_INC 0x001C | ||
92 | #define DISPC_VID_PIXEL_INC 0x0020 | ||
93 | #define DISPC_VID_FIR 0x0024 | ||
94 | #define DISPC_VID_PICTURE_SIZE 0x0028 | ||
95 | #define DISPC_VID_ACCU0 0x002C | ||
96 | #define DISPC_VID_ACCU1 0x0030 | ||
97 | |||
98 | /* 8 elements in 8 byte increments */ | ||
99 | #define DISPC_VID_FIR_COEF_H0 0x0034 | ||
100 | /* 8 elements in 8 byte increments */ | ||
101 | #define DISPC_VID_FIR_COEF_HV0 0x0038 | ||
102 | /* 5 elements in 4 byte increments */ | ||
103 | #define DISPC_VID_CONV_COEF0 0x0074 | ||
104 | |||
105 | #define DISPC_IRQ_FRAMEMASK 0x0001 | ||
106 | #define DISPC_IRQ_VSYNC 0x0002 | ||
107 | #define DISPC_IRQ_EVSYNC_EVEN 0x0004 | ||
108 | #define DISPC_IRQ_EVSYNC_ODD 0x0008 | ||
109 | #define DISPC_IRQ_ACBIAS_COUNT_STAT 0x0010 | ||
110 | #define DISPC_IRQ_PROG_LINE_NUM 0x0020 | ||
111 | #define DISPC_IRQ_GFX_FIFO_UNDERFLOW 0x0040 | ||
112 | #define DISPC_IRQ_GFX_END_WIN 0x0080 | ||
113 | #define DISPC_IRQ_PAL_GAMMA_MASK 0x0100 | ||
114 | #define DISPC_IRQ_OCP_ERR 0x0200 | ||
115 | #define DISPC_IRQ_VID1_FIFO_UNDERFLOW 0x0400 | ||
116 | #define DISPC_IRQ_VID1_END_WIN 0x0800 | ||
117 | #define DISPC_IRQ_VID2_FIFO_UNDERFLOW 0x1000 | ||
118 | #define DISPC_IRQ_VID2_END_WIN 0x2000 | ||
119 | #define DISPC_IRQ_SYNC_LOST 0x4000 | ||
120 | |||
121 | #define DISPC_IRQ_MASK_ALL 0x7fff | ||
122 | |||
123 | #define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \ | ||
124 | DISPC_IRQ_VID1_FIFO_UNDERFLOW | \ | ||
125 | DISPC_IRQ_VID2_FIFO_UNDERFLOW | \ | ||
126 | DISPC_IRQ_SYNC_LOST) | ||
127 | |||
128 | #define RFBI_CONTROL 0x48050040 | ||
129 | |||
130 | #define MAX_PALETTE_SIZE (256 * 16) | ||
131 | |||
132 | #define FLD_MASK(pos, len) (((1 << len) - 1) << pos) | ||
133 | |||
134 | #define MOD_REG_FLD(reg, mask, val) \ | ||
135 | dispc_write_reg((reg), (dispc_read_reg(reg) & ~(mask)) | (val)); | ||
136 | |||
137 | #define OMAP2_SRAM_START 0x40200000 | ||
138 | /* Maximum size, in reality this is smaller if SRAM is partially locked. */ | ||
139 | #define OMAP2_SRAM_SIZE 0xa0000 /* 640k */ | ||
140 | |||
141 | /* We support the SDRAM / SRAM types. See OMAPFB_PLANE_MEMTYPE_* in omapfb.h */ | ||
142 | #define DISPC_MEMTYPE_NUM 2 | ||
143 | |||
144 | #define RESMAP_SIZE(_page_cnt) \ | ||
145 | ((_page_cnt + (sizeof(unsigned long) * 8) - 1) / 8) | ||
146 | #define RESMAP_PTR(_res_map, _page_nr) \ | ||
147 | (((_res_map)->map) + (_page_nr) / (sizeof(unsigned long) * 8)) | ||
148 | #define RESMAP_MASK(_page_nr) \ | ||
149 | (1 << ((_page_nr) & (sizeof(unsigned long) * 8 - 1))) | ||
150 | |||
151 | struct resmap { | ||
152 | unsigned long start; | ||
153 | unsigned page_cnt; | ||
154 | unsigned long *map; | ||
155 | }; | ||
156 | |||
157 | static struct { | ||
158 | u32 base; | ||
159 | |||
160 | struct omapfb_mem_desc mem_desc; | ||
161 | struct resmap *res_map[DISPC_MEMTYPE_NUM]; | ||
162 | atomic_t map_count[OMAPFB_PLANE_NUM]; | ||
163 | |||
164 | dma_addr_t palette_paddr; | ||
165 | void *palette_vaddr; | ||
166 | |||
167 | int ext_mode; | ||
168 | |||
169 | unsigned long enabled_irqs; | ||
170 | void (*irq_callback)(void *); | ||
171 | void *irq_callback_data; | ||
172 | struct completion frame_done; | ||
173 | |||
174 | int fir_hinc[OMAPFB_PLANE_NUM]; | ||
175 | int fir_vinc[OMAPFB_PLANE_NUM]; | ||
176 | |||
177 | struct clk *dss_ick, *dss1_fck; | ||
178 | struct clk *dss_54m_fck; | ||
179 | |||
180 | enum omapfb_update_mode update_mode; | ||
181 | struct omapfb_device *fbdev; | ||
182 | |||
183 | struct omapfb_color_key color_key; | ||
184 | } dispc; | ||
185 | |||
186 | static void enable_lcd_clocks(int enable); | ||
187 | |||
188 | static void inline dispc_write_reg(int idx, u32 val) | ||
189 | { | ||
190 | __raw_writel(val, dispc.base + idx); | ||
191 | } | ||
192 | |||
193 | static u32 inline dispc_read_reg(int idx) | ||
194 | { | ||
195 | u32 l = __raw_readl(dispc.base + idx); | ||
196 | return l; | ||
197 | } | ||
198 | |||
199 | /* Select RFBI or bypass mode */ | ||
200 | static void enable_rfbi_mode(int enable) | ||
201 | { | ||
202 | u32 l; | ||
203 | |||
204 | l = dispc_read_reg(DISPC_CONTROL); | ||
205 | /* Enable RFBI, GPIO0/1 */ | ||
206 | l &= ~((1 << 11) | (1 << 15) | (1 << 16)); | ||
207 | l |= enable ? (1 << 11) : 0; | ||
208 | /* RFBI En: GPIO0/1=10 RFBI Dis: GPIO0/1=11 */ | ||
209 | l |= 1 << 15; | ||
210 | l |= enable ? 0 : (1 << 16); | ||
211 | dispc_write_reg(DISPC_CONTROL, l); | ||
212 | |||
213 | /* Set bypass mode in RFBI module */ | ||
214 | l = __raw_readl(io_p2v(RFBI_CONTROL)); | ||
215 | l |= enable ? 0 : (1 << 1); | ||
216 | __raw_writel(l, io_p2v(RFBI_CONTROL)); | ||
217 | } | ||
218 | |||
219 | static void set_lcd_data_lines(int data_lines) | ||
220 | { | ||
221 | u32 l; | ||
222 | int code = 0; | ||
223 | |||
224 | switch (data_lines) { | ||
225 | case 12: | ||
226 | code = 0; | ||
227 | break; | ||
228 | case 16: | ||
229 | code = 1; | ||
230 | break; | ||
231 | case 18: | ||
232 | code = 2; | ||
233 | break; | ||
234 | case 24: | ||
235 | code = 3; | ||
236 | break; | ||
237 | default: | ||
238 | BUG(); | ||
239 | } | ||
240 | |||
241 | l = dispc_read_reg(DISPC_CONTROL); | ||
242 | l &= ~(0x03 << 8); | ||
243 | l |= code << 8; | ||
244 | dispc_write_reg(DISPC_CONTROL, l); | ||
245 | } | ||
246 | |||
247 | static void set_load_mode(int mode) | ||
248 | { | ||
249 | BUG_ON(mode & ~(DISPC_LOAD_CLUT_ONLY | DISPC_LOAD_FRAME_ONLY | | ||
250 | DISPC_LOAD_CLUT_ONCE_FRAME)); | ||
251 | MOD_REG_FLD(DISPC_CONFIG, 0x03 << 1, mode << 1); | ||
252 | } | ||
253 | |||
254 | void omap_dispc_set_lcd_size(int x, int y) | ||
255 | { | ||
256 | BUG_ON((x > (1 << 11)) || (y > (1 << 11))); | ||
257 | enable_lcd_clocks(1); | ||
258 | MOD_REG_FLD(DISPC_SIZE_LCD, FLD_MASK(16, 11) | FLD_MASK(0, 11), | ||
259 | ((y - 1) << 16) | (x - 1)); | ||
260 | enable_lcd_clocks(0); | ||
261 | } | ||
262 | EXPORT_SYMBOL(omap_dispc_set_lcd_size); | ||
263 | |||
264 | void omap_dispc_set_digit_size(int x, int y) | ||
265 | { | ||
266 | BUG_ON((x > (1 << 11)) || (y > (1 << 11))); | ||
267 | enable_lcd_clocks(1); | ||
268 | MOD_REG_FLD(DISPC_SIZE_DIG, FLD_MASK(16, 11) | FLD_MASK(0, 11), | ||
269 | ((y - 1) << 16) | (x - 1)); | ||
270 | enable_lcd_clocks(0); | ||
271 | } | ||
272 | EXPORT_SYMBOL(omap_dispc_set_digit_size); | ||
273 | |||
274 | static void setup_plane_fifo(int plane, int ext_mode) | ||
275 | { | ||
276 | const u32 ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD, | ||
277 | DISPC_VID1_BASE + DISPC_VID_FIFO_THRESHOLD, | ||
278 | DISPC_VID2_BASE + DISPC_VID_FIFO_THRESHOLD }; | ||
279 | const u32 fsz_reg[] = { DISPC_GFX_FIFO_SIZE_STATUS, | ||
280 | DISPC_VID1_BASE + DISPC_VID_FIFO_SIZE_STATUS, | ||
281 | DISPC_VID2_BASE + DISPC_VID_FIFO_SIZE_STATUS }; | ||
282 | int low, high; | ||
283 | u32 l; | ||
284 | |||
285 | BUG_ON(plane > 2); | ||
286 | |||
287 | l = dispc_read_reg(fsz_reg[plane]); | ||
288 | l &= FLD_MASK(0, 9); | ||
289 | if (ext_mode) { | ||
290 | low = l * 3 / 4; | ||
291 | high = l; | ||
292 | } else { | ||
293 | low = l / 4; | ||
294 | high = l * 3 / 4; | ||
295 | } | ||
296 | MOD_REG_FLD(ftrs_reg[plane], FLD_MASK(16, 9) | FLD_MASK(0, 9), | ||
297 | (high << 16) | low); | ||
298 | } | ||
299 | |||
300 | void omap_dispc_enable_lcd_out(int enable) | ||
301 | { | ||
302 | enable_lcd_clocks(1); | ||
303 | MOD_REG_FLD(DISPC_CONTROL, 1, enable ? 1 : 0); | ||
304 | enable_lcd_clocks(0); | ||
305 | } | ||
306 | EXPORT_SYMBOL(omap_dispc_enable_lcd_out); | ||
307 | |||
308 | void omap_dispc_enable_digit_out(int enable) | ||
309 | { | ||
310 | enable_lcd_clocks(1); | ||
311 | MOD_REG_FLD(DISPC_CONTROL, 1 << 1, enable ? 1 << 1 : 0); | ||
312 | enable_lcd_clocks(0); | ||
313 | } | ||
314 | EXPORT_SYMBOL(omap_dispc_enable_digit_out); | ||
315 | |||
316 | static inline int _setup_plane(int plane, int channel_out, | ||
317 | u32 paddr, int screen_width, | ||
318 | int pos_x, int pos_y, int width, int height, | ||
319 | int color_mode) | ||
320 | { | ||
321 | const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES, | ||
322 | DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES, | ||
323 | DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES }; | ||
324 | const u32 ba_reg[] = { DISPC_GFX_BA0, DISPC_VID1_BASE + DISPC_VID_BA0, | ||
325 | DISPC_VID2_BASE + DISPC_VID_BA0 }; | ||
326 | const u32 ps_reg[] = { DISPC_GFX_POSITION, | ||
327 | DISPC_VID1_BASE + DISPC_VID_POSITION, | ||
328 | DISPC_VID2_BASE + DISPC_VID_POSITION }; | ||
329 | const u32 sz_reg[] = { DISPC_GFX_SIZE, | ||
330 | DISPC_VID1_BASE + DISPC_VID_PICTURE_SIZE, | ||
331 | DISPC_VID2_BASE + DISPC_VID_PICTURE_SIZE }; | ||
332 | const u32 ri_reg[] = { DISPC_GFX_ROW_INC, | ||
333 | DISPC_VID1_BASE + DISPC_VID_ROW_INC, | ||
334 | DISPC_VID2_BASE + DISPC_VID_ROW_INC }; | ||
335 | const u32 vs_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_SIZE, | ||
336 | DISPC_VID2_BASE + DISPC_VID_SIZE }; | ||
337 | |||
338 | int chout_shift, burst_shift; | ||
339 | int chout_val; | ||
340 | int color_code; | ||
341 | int bpp; | ||
342 | int cconv_en; | ||
343 | int set_vsize; | ||
344 | u32 l; | ||
345 | |||
346 | #ifdef VERBOSE | ||
347 | dev_dbg(dispc.fbdev->dev, "plane %d channel %d paddr %#08x scr_width %d" | ||
348 | " pos_x %d pos_y %d width %d height %d color_mode %d\n", | ||
349 | plane, channel_out, paddr, screen_width, pos_x, pos_y, | ||
350 | width, height, color_mode); | ||
351 | #endif | ||
352 | |||
353 | set_vsize = 0; | ||
354 | switch (plane) { | ||
355 | case OMAPFB_PLANE_GFX: | ||
356 | burst_shift = 6; | ||
357 | chout_shift = 8; | ||
358 | break; | ||
359 | case OMAPFB_PLANE_VID1: | ||
360 | case OMAPFB_PLANE_VID2: | ||
361 | burst_shift = 14; | ||
362 | chout_shift = 16; | ||
363 | set_vsize = 1; | ||
364 | break; | ||
365 | default: | ||
366 | return -EINVAL; | ||
367 | } | ||
368 | |||
369 | switch (channel_out) { | ||
370 | case OMAPFB_CHANNEL_OUT_LCD: | ||
371 | chout_val = 0; | ||
372 | break; | ||
373 | case OMAPFB_CHANNEL_OUT_DIGIT: | ||
374 | chout_val = 1; | ||
375 | break; | ||
376 | default: | ||
377 | return -EINVAL; | ||
378 | } | ||
379 | |||
380 | cconv_en = 0; | ||
381 | switch (color_mode) { | ||
382 | case OMAPFB_COLOR_RGB565: | ||
383 | color_code = DISPC_RGB_16_BPP; | ||
384 | bpp = 16; | ||
385 | break; | ||
386 | case OMAPFB_COLOR_YUV422: | ||
387 | if (plane == 0) | ||
388 | return -EINVAL; | ||
389 | color_code = DISPC_UYVY_422; | ||
390 | cconv_en = 1; | ||
391 | bpp = 16; | ||
392 | break; | ||
393 | case OMAPFB_COLOR_YUY422: | ||
394 | if (plane == 0) | ||
395 | return -EINVAL; | ||
396 | color_code = DISPC_YUV2_422; | ||
397 | cconv_en = 1; | ||
398 | bpp = 16; | ||
399 | break; | ||
400 | default: | ||
401 | return -EINVAL; | ||
402 | } | ||
403 | |||
404 | l = dispc_read_reg(at_reg[plane]); | ||
405 | |||
406 | l &= ~(0x0f << 1); | ||
407 | l |= color_code << 1; | ||
408 | l &= ~(1 << 9); | ||
409 | l |= cconv_en << 9; | ||
410 | |||
411 | l &= ~(0x03 << burst_shift); | ||
412 | l |= DISPC_BURST_8x32 << burst_shift; | ||
413 | |||
414 | l &= ~(1 << chout_shift); | ||
415 | l |= chout_val << chout_shift; | ||
416 | |||
417 | dispc_write_reg(at_reg[plane], l); | ||
418 | |||
419 | dispc_write_reg(ba_reg[plane], paddr); | ||
420 | MOD_REG_FLD(ps_reg[plane], | ||
421 | FLD_MASK(16, 11) | FLD_MASK(0, 11), (pos_y << 16) | pos_x); | ||
422 | |||
423 | MOD_REG_FLD(sz_reg[plane], FLD_MASK(16, 11) | FLD_MASK(0, 11), | ||
424 | ((height - 1) << 16) | (width - 1)); | ||
425 | |||
426 | if (set_vsize) { | ||
427 | /* Set video size if set_scale hasn't set it */ | ||
428 | if (!dispc.fir_vinc[plane]) | ||
429 | MOD_REG_FLD(vs_reg[plane], | ||
430 | FLD_MASK(16, 11), (height - 1) << 16); | ||
431 | if (!dispc.fir_hinc[plane]) | ||
432 | MOD_REG_FLD(vs_reg[plane], | ||
433 | FLD_MASK(0, 11), width - 1); | ||
434 | } | ||
435 | |||
436 | dispc_write_reg(ri_reg[plane], (screen_width - width) * bpp / 8 + 1); | ||
437 | |||
438 | return height * screen_width * bpp / 8; | ||
439 | } | ||
440 | |||
441 | static int omap_dispc_setup_plane(int plane, int channel_out, | ||
442 | unsigned long offset, | ||
443 | int screen_width, | ||
444 | int pos_x, int pos_y, int width, int height, | ||
445 | int color_mode) | ||
446 | { | ||
447 | u32 paddr; | ||
448 | int r; | ||
449 | |||
450 | if ((unsigned)plane > dispc.mem_desc.region_cnt) | ||
451 | return -EINVAL; | ||
452 | paddr = dispc.mem_desc.region[plane].paddr + offset; | ||
453 | enable_lcd_clocks(1); | ||
454 | r = _setup_plane(plane, channel_out, paddr, | ||
455 | screen_width, | ||
456 | pos_x, pos_y, width, height, color_mode); | ||
457 | enable_lcd_clocks(0); | ||
458 | return r; | ||
459 | } | ||
460 | |||
461 | static void write_firh_reg(int plane, int reg, u32 value) | ||
462 | { | ||
463 | u32 base; | ||
464 | |||
465 | if (plane == 1) | ||
466 | base = DISPC_VID1_BASE + DISPC_VID_FIR_COEF_H0; | ||
467 | else | ||
468 | base = DISPC_VID2_BASE + DISPC_VID_FIR_COEF_H0; | ||
469 | dispc_write_reg(base + reg * 8, value); | ||
470 | } | ||
471 | |||
472 | static void write_firhv_reg(int plane, int reg, u32 value) | ||
473 | { | ||
474 | u32 base; | ||
475 | |||
476 | if (plane == 1) | ||
477 | base = DISPC_VID1_BASE + DISPC_VID_FIR_COEF_HV0; | ||
478 | else | ||
479 | base = DISPC_VID2_BASE + DISPC_VID_FIR_COEF_HV0; | ||
480 | dispc_write_reg(base + reg * 8, value); | ||
481 | } | ||
482 | |||
483 | static void set_upsampling_coef_table(int plane) | ||
484 | { | ||
485 | const u32 coef[][2] = { | ||
486 | { 0x00800000, 0x00800000 }, | ||
487 | { 0x0D7CF800, 0x037B02FF }, | ||
488 | { 0x1E70F5FF, 0x0C6F05FE }, | ||
489 | { 0x335FF5FE, 0x205907FB }, | ||
490 | { 0xF74949F7, 0x00404000 }, | ||
491 | { 0xF55F33FB, 0x075920FE }, | ||
492 | { 0xF5701EFE, 0x056F0CFF }, | ||
493 | { 0xF87C0DFF, 0x027B0300 }, | ||
494 | }; | ||
495 | int i; | ||
496 | |||
497 | for (i = 0; i < 8; i++) { | ||
498 | write_firh_reg(plane, i, coef[i][0]); | ||
499 | write_firhv_reg(plane, i, coef[i][1]); | ||
500 | } | ||
501 | } | ||
502 | |||
503 | static int omap_dispc_set_scale(int plane, | ||
504 | int orig_width, int orig_height, | ||
505 | int out_width, int out_height) | ||
506 | { | ||
507 | const u32 at_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES, | ||
508 | DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES }; | ||
509 | const u32 vs_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_SIZE, | ||
510 | DISPC_VID2_BASE + DISPC_VID_SIZE }; | ||
511 | const u32 fir_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_FIR, | ||
512 | DISPC_VID2_BASE + DISPC_VID_FIR }; | ||
513 | |||
514 | u32 l; | ||
515 | int fir_hinc; | ||
516 | int fir_vinc; | ||
517 | |||
518 | if ((unsigned)plane > OMAPFB_PLANE_NUM) | ||
519 | return -ENODEV; | ||
520 | |||
521 | if (plane == OMAPFB_PLANE_GFX && | ||
522 | (out_width != orig_width || out_height != orig_height)) | ||
523 | return -EINVAL; | ||
524 | |||
525 | enable_lcd_clocks(1); | ||
526 | if (orig_width < out_width) { | ||
527 | /* | ||
528 | * Upsampling. | ||
529 | * Currently you can only scale both dimensions in one way. | ||
530 | */ | ||
531 | if (orig_height > out_height || | ||
532 | orig_width * 8 < out_width || | ||
533 | orig_height * 8 < out_height) { | ||
534 | enable_lcd_clocks(0); | ||
535 | return -EINVAL; | ||
536 | } | ||
537 | set_upsampling_coef_table(plane); | ||
538 | } else if (orig_width > out_width) { | ||
539 | /* Downsampling not yet supported | ||
540 | */ | ||
541 | |||
542 | enable_lcd_clocks(0); | ||
543 | return -EINVAL; | ||
544 | } | ||
545 | if (!orig_width || orig_width == out_width) | ||
546 | fir_hinc = 0; | ||
547 | else | ||
548 | fir_hinc = 1024 * orig_width / out_width; | ||
549 | if (!orig_height || orig_height == out_height) | ||
550 | fir_vinc = 0; | ||
551 | else | ||
552 | fir_vinc = 1024 * orig_height / out_height; | ||
553 | dispc.fir_hinc[plane] = fir_hinc; | ||
554 | dispc.fir_vinc[plane] = fir_vinc; | ||
555 | |||
556 | MOD_REG_FLD(fir_reg[plane], | ||
557 | FLD_MASK(16, 12) | FLD_MASK(0, 12), | ||
558 | ((fir_vinc & 4095) << 16) | | ||
559 | (fir_hinc & 4095)); | ||
560 | |||
561 | dev_dbg(dispc.fbdev->dev, "out_width %d out_height %d orig_width %d " | ||
562 | "orig_height %d fir_hinc %d fir_vinc %d\n", | ||
563 | out_width, out_height, orig_width, orig_height, | ||
564 | fir_hinc, fir_vinc); | ||
565 | |||
566 | MOD_REG_FLD(vs_reg[plane], | ||
567 | FLD_MASK(16, 11) | FLD_MASK(0, 11), | ||
568 | ((out_height - 1) << 16) | (out_width - 1)); | ||
569 | |||
570 | l = dispc_read_reg(at_reg[plane]); | ||
571 | l &= ~(0x03 << 5); | ||
572 | l |= fir_hinc ? (1 << 5) : 0; | ||
573 | l |= fir_vinc ? (1 << 6) : 0; | ||
574 | dispc_write_reg(at_reg[plane], l); | ||
575 | |||
576 | enable_lcd_clocks(0); | ||
577 | return 0; | ||
578 | } | ||
579 | |||
580 | static int omap_dispc_enable_plane(int plane, int enable) | ||
581 | { | ||
582 | const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES, | ||
583 | DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES, | ||
584 | DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES }; | ||
585 | if ((unsigned int)plane > dispc.mem_desc.region_cnt) | ||
586 | return -EINVAL; | ||
587 | |||
588 | enable_lcd_clocks(1); | ||
589 | MOD_REG_FLD(at_reg[plane], 1, enable ? 1 : 0); | ||
590 | enable_lcd_clocks(0); | ||
591 | |||
592 | return 0; | ||
593 | } | ||
594 | |||
595 | static int omap_dispc_set_color_key(struct omapfb_color_key *ck) | ||
596 | { | ||
597 | u32 df_reg, tr_reg; | ||
598 | int shift, val; | ||
599 | |||
600 | switch (ck->channel_out) { | ||
601 | case OMAPFB_CHANNEL_OUT_LCD: | ||
602 | df_reg = DISPC_DEFAULT_COLOR0; | ||
603 | tr_reg = DISPC_TRANS_COLOR0; | ||
604 | shift = 10; | ||
605 | break; | ||
606 | case OMAPFB_CHANNEL_OUT_DIGIT: | ||
607 | df_reg = DISPC_DEFAULT_COLOR1; | ||
608 | tr_reg = DISPC_TRANS_COLOR1; | ||
609 | shift = 12; | ||
610 | break; | ||
611 | default: | ||
612 | return -EINVAL; | ||
613 | } | ||
614 | switch (ck->key_type) { | ||
615 | case OMAPFB_COLOR_KEY_DISABLED: | ||
616 | val = 0; | ||
617 | break; | ||
618 | case OMAPFB_COLOR_KEY_GFX_DST: | ||
619 | val = 1; | ||
620 | break; | ||
621 | case OMAPFB_COLOR_KEY_VID_SRC: | ||
622 | val = 3; | ||
623 | break; | ||
624 | default: | ||
625 | return -EINVAL; | ||
626 | } | ||
627 | enable_lcd_clocks(1); | ||
628 | MOD_REG_FLD(DISPC_CONFIG, FLD_MASK(shift, 2), val << shift); | ||
629 | |||
630 | if (val != 0) | ||
631 | dispc_write_reg(tr_reg, ck->trans_key); | ||
632 | dispc_write_reg(df_reg, ck->background); | ||
633 | enable_lcd_clocks(0); | ||
634 | |||
635 | dispc.color_key = *ck; | ||
636 | |||
637 | return 0; | ||
638 | } | ||
639 | |||
640 | static int omap_dispc_get_color_key(struct omapfb_color_key *ck) | ||
641 | { | ||
642 | *ck = dispc.color_key; | ||
643 | return 0; | ||
644 | } | ||
645 | |||
646 | static void load_palette(void) | ||
647 | { | ||
648 | } | ||
649 | |||
650 | static int omap_dispc_set_update_mode(enum omapfb_update_mode mode) | ||
651 | { | ||
652 | int r = 0; | ||
653 | |||
654 | if (mode != dispc.update_mode) { | ||
655 | switch (mode) { | ||
656 | case OMAPFB_AUTO_UPDATE: | ||
657 | case OMAPFB_MANUAL_UPDATE: | ||
658 | enable_lcd_clocks(1); | ||
659 | omap_dispc_enable_lcd_out(1); | ||
660 | dispc.update_mode = mode; | ||
661 | break; | ||
662 | case OMAPFB_UPDATE_DISABLED: | ||
663 | init_completion(&dispc.frame_done); | ||
664 | omap_dispc_enable_lcd_out(0); | ||
665 | if (!wait_for_completion_timeout(&dispc.frame_done, | ||
666 | msecs_to_jiffies(500))) { | ||
667 | dev_err(dispc.fbdev->dev, | ||
668 | "timeout waiting for FRAME DONE\n"); | ||
669 | } | ||
670 | dispc.update_mode = mode; | ||
671 | enable_lcd_clocks(0); | ||
672 | break; | ||
673 | default: | ||
674 | r = -EINVAL; | ||
675 | } | ||
676 | } | ||
677 | |||
678 | return r; | ||
679 | } | ||
680 | |||
681 | static void omap_dispc_get_caps(int plane, struct omapfb_caps *caps) | ||
682 | { | ||
683 | caps->ctrl |= OMAPFB_CAPS_PLANE_RELOCATE_MEM; | ||
684 | if (plane > 0) | ||
685 | caps->ctrl |= OMAPFB_CAPS_PLANE_SCALE; | ||
686 | caps->plane_color |= (1 << OMAPFB_COLOR_RGB565) | | ||
687 | (1 << OMAPFB_COLOR_YUV422) | | ||
688 | (1 << OMAPFB_COLOR_YUY422); | ||
689 | if (plane == 0) | ||
690 | caps->plane_color |= (1 << OMAPFB_COLOR_CLUT_8BPP) | | ||
691 | (1 << OMAPFB_COLOR_CLUT_4BPP) | | ||
692 | (1 << OMAPFB_COLOR_CLUT_2BPP) | | ||
693 | (1 << OMAPFB_COLOR_CLUT_1BPP) | | ||
694 | (1 << OMAPFB_COLOR_RGB444); | ||
695 | } | ||
696 | |||
697 | static enum omapfb_update_mode omap_dispc_get_update_mode(void) | ||
698 | { | ||
699 | return dispc.update_mode; | ||
700 | } | ||
701 | |||
702 | static void setup_color_conv_coef(void) | ||
703 | { | ||
704 | u32 mask = FLD_MASK(16, 11) | FLD_MASK(0, 11); | ||
705 | int cf1_reg = DISPC_VID1_BASE + DISPC_VID_CONV_COEF0; | ||
706 | int cf2_reg = DISPC_VID2_BASE + DISPC_VID_CONV_COEF0; | ||
707 | int at1_reg = DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES; | ||
708 | int at2_reg = DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES; | ||
709 | const struct color_conv_coef { | ||
710 | int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb; | ||
711 | int full_range; | ||
712 | } ctbl_bt601_5 = { | ||
713 | 298, 409, 0, 298, -208, -100, 298, 0, 517, 0, | ||
714 | }; | ||
715 | const struct color_conv_coef *ct; | ||
716 | #define CVAL(x, y) (((x & 2047) << 16) | (y & 2047)) | ||
717 | |||
718 | ct = &ctbl_bt601_5; | ||
719 | |||
720 | MOD_REG_FLD(cf1_reg, mask, CVAL(ct->rcr, ct->ry)); | ||
721 | MOD_REG_FLD(cf1_reg + 4, mask, CVAL(ct->gy, ct->rcb)); | ||
722 | MOD_REG_FLD(cf1_reg + 8, mask, CVAL(ct->gcb, ct->gcr)); | ||
723 | MOD_REG_FLD(cf1_reg + 12, mask, CVAL(ct->bcr, ct->by)); | ||
724 | MOD_REG_FLD(cf1_reg + 16, mask, CVAL(0, ct->bcb)); | ||
725 | |||
726 | MOD_REG_FLD(cf2_reg, mask, CVAL(ct->rcr, ct->ry)); | ||
727 | MOD_REG_FLD(cf2_reg + 4, mask, CVAL(ct->gy, ct->rcb)); | ||
728 | MOD_REG_FLD(cf2_reg + 8, mask, CVAL(ct->gcb, ct->gcr)); | ||
729 | MOD_REG_FLD(cf2_reg + 12, mask, CVAL(ct->bcr, ct->by)); | ||
730 | MOD_REG_FLD(cf2_reg + 16, mask, CVAL(0, ct->bcb)); | ||
731 | #undef CVAL | ||
732 | |||
733 | MOD_REG_FLD(at1_reg, (1 << 11), ct->full_range); | ||
734 | MOD_REG_FLD(at2_reg, (1 << 11), ct->full_range); | ||
735 | } | ||
736 | |||
737 | static void calc_ck_div(int is_tft, int pck, int *lck_div, int *pck_div) | ||
738 | { | ||
739 | unsigned long fck, lck; | ||
740 | |||
741 | *lck_div = 1; | ||
742 | pck = max(1, pck); | ||
743 | fck = clk_get_rate(dispc.dss1_fck); | ||
744 | lck = fck; | ||
745 | *pck_div = (lck + pck - 1) / pck; | ||
746 | if (is_tft) | ||
747 | *pck_div = max(2, *pck_div); | ||
748 | else | ||
749 | *pck_div = max(3, *pck_div); | ||
750 | if (*pck_div > 255) { | ||
751 | *pck_div = 255; | ||
752 | lck = pck * *pck_div; | ||
753 | *lck_div = fck / lck; | ||
754 | BUG_ON(*lck_div < 1); | ||
755 | if (*lck_div > 255) { | ||
756 | *lck_div = 255; | ||
757 | dev_warn(dispc.fbdev->dev, "pixclock %d kHz too low.\n", | ||
758 | pck / 1000); | ||
759 | } | ||
760 | } | ||
761 | } | ||
762 | |||
763 | static void set_lcd_tft_mode(int enable) | ||
764 | { | ||
765 | u32 mask; | ||
766 | |||
767 | mask = 1 << 3; | ||
768 | MOD_REG_FLD(DISPC_CONTROL, mask, enable ? mask : 0); | ||
769 | } | ||
770 | |||
771 | static void set_lcd_timings(void) | ||
772 | { | ||
773 | u32 l; | ||
774 | int lck_div, pck_div; | ||
775 | struct lcd_panel *panel = dispc.fbdev->panel; | ||
776 | int is_tft = panel->config & OMAP_LCDC_PANEL_TFT; | ||
777 | unsigned long fck; | ||
778 | |||
779 | l = dispc_read_reg(DISPC_TIMING_H); | ||
780 | l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8)); | ||
781 | l |= ( max(1, (min(64, panel->hsw))) - 1 ) << 0; | ||
782 | l |= ( max(1, (min(256, panel->hfp))) - 1 ) << 8; | ||
783 | l |= ( max(1, (min(256, panel->hbp))) - 1 ) << 20; | ||
784 | dispc_write_reg(DISPC_TIMING_H, l); | ||
785 | |||
786 | l = dispc_read_reg(DISPC_TIMING_V); | ||
787 | l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8)); | ||
788 | l |= ( max(1, (min(64, panel->vsw))) - 1 ) << 0; | ||
789 | l |= ( max(0, (min(255, panel->vfp))) - 0 ) << 8; | ||
790 | l |= ( max(0, (min(255, panel->vbp))) - 0 ) << 20; | ||
791 | dispc_write_reg(DISPC_TIMING_V, l); | ||
792 | |||
793 | l = dispc_read_reg(DISPC_POL_FREQ); | ||
794 | l &= ~FLD_MASK(12, 6); | ||
795 | l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 12; | ||
796 | l |= panel->acb & 0xff; | ||
797 | dispc_write_reg(DISPC_POL_FREQ, l); | ||
798 | |||
799 | calc_ck_div(is_tft, panel->pixel_clock * 1000, &lck_div, &pck_div); | ||
800 | |||
801 | l = dispc_read_reg(DISPC_DIVISOR); | ||
802 | l &= ~(FLD_MASK(16, 8) | FLD_MASK(0, 8)); | ||
803 | l |= (lck_div << 16) | (pck_div << 0); | ||
804 | dispc_write_reg(DISPC_DIVISOR, l); | ||
805 | |||
806 | /* update panel info with the exact clock */ | ||
807 | fck = clk_get_rate(dispc.dss1_fck); | ||
808 | panel->pixel_clock = fck / lck_div / pck_div / 1000; | ||
809 | } | ||
810 | |||
811 | int omap_dispc_request_irq(void (*callback)(void *data), void *data) | ||
812 | { | ||
813 | int r = 0; | ||
814 | |||
815 | BUG_ON(callback == NULL); | ||
816 | |||
817 | if (dispc.irq_callback) | ||
818 | r = -EBUSY; | ||
819 | else { | ||
820 | dispc.irq_callback = callback; | ||
821 | dispc.irq_callback_data = data; | ||
822 | } | ||
823 | |||
824 | return r; | ||
825 | } | ||
826 | EXPORT_SYMBOL(omap_dispc_request_irq); | ||
827 | |||
828 | void omap_dispc_enable_irqs(int irq_mask) | ||
829 | { | ||
830 | enable_lcd_clocks(1); | ||
831 | dispc.enabled_irqs = irq_mask; | ||
832 | irq_mask |= DISPC_IRQ_MASK_ERROR; | ||
833 | MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask); | ||
834 | enable_lcd_clocks(0); | ||
835 | } | ||
836 | EXPORT_SYMBOL(omap_dispc_enable_irqs); | ||
837 | |||
838 | void omap_dispc_disable_irqs(int irq_mask) | ||
839 | { | ||
840 | enable_lcd_clocks(1); | ||
841 | dispc.enabled_irqs &= ~irq_mask; | ||
842 | irq_mask &= ~DISPC_IRQ_MASK_ERROR; | ||
843 | MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask); | ||
844 | enable_lcd_clocks(0); | ||
845 | } | ||
846 | EXPORT_SYMBOL(omap_dispc_disable_irqs); | ||
847 | |||
848 | void omap_dispc_free_irq(void) | ||
849 | { | ||
850 | enable_lcd_clocks(1); | ||
851 | omap_dispc_disable_irqs(DISPC_IRQ_MASK_ALL); | ||
852 | dispc.irq_callback = NULL; | ||
853 | dispc.irq_callback_data = NULL; | ||
854 | enable_lcd_clocks(0); | ||
855 | } | ||
856 | EXPORT_SYMBOL(omap_dispc_free_irq); | ||
857 | |||
858 | static irqreturn_t omap_dispc_irq_handler(int irq, void *dev) | ||
859 | { | ||
860 | u32 stat = dispc_read_reg(DISPC_IRQSTATUS); | ||
861 | |||
862 | if (stat & DISPC_IRQ_FRAMEMASK) | ||
863 | complete(&dispc.frame_done); | ||
864 | |||
865 | if (stat & DISPC_IRQ_MASK_ERROR) { | ||
866 | if (printk_ratelimit()) { | ||
867 | dev_err(dispc.fbdev->dev, "irq error status %04x\n", | ||
868 | stat & 0x7fff); | ||
869 | } | ||
870 | } | ||
871 | |||
872 | if ((stat & dispc.enabled_irqs) && dispc.irq_callback) | ||
873 | dispc.irq_callback(dispc.irq_callback_data); | ||
874 | |||
875 | dispc_write_reg(DISPC_IRQSTATUS, stat); | ||
876 | |||
877 | return IRQ_HANDLED; | ||
878 | } | ||
879 | |||
880 | static int get_dss_clocks(void) | ||
881 | { | ||
882 | if (IS_ERR((dispc.dss_ick = clk_get(dispc.fbdev->dev, "dss_ick")))) { | ||
883 | dev_err(dispc.fbdev->dev, "can't get dss_ick"); | ||
884 | return PTR_ERR(dispc.dss_ick); | ||
885 | } | ||
886 | |||
887 | if (IS_ERR((dispc.dss1_fck = clk_get(dispc.fbdev->dev, "dss1_fck")))) { | ||
888 | dev_err(dispc.fbdev->dev, "can't get dss1_fck"); | ||
889 | clk_put(dispc.dss_ick); | ||
890 | return PTR_ERR(dispc.dss1_fck); | ||
891 | } | ||
892 | |||
893 | if (IS_ERR((dispc.dss_54m_fck = | ||
894 | clk_get(dispc.fbdev->dev, "dss_54m_fck")))) { | ||
895 | dev_err(dispc.fbdev->dev, "can't get dss_54m_fck"); | ||
896 | clk_put(dispc.dss_ick); | ||
897 | clk_put(dispc.dss1_fck); | ||
898 | return PTR_ERR(dispc.dss_54m_fck); | ||
899 | } | ||
900 | |||
901 | return 0; | ||
902 | } | ||
903 | |||
904 | static void put_dss_clocks(void) | ||
905 | { | ||
906 | clk_put(dispc.dss_54m_fck); | ||
907 | clk_put(dispc.dss1_fck); | ||
908 | clk_put(dispc.dss_ick); | ||
909 | } | ||
910 | |||
911 | static void enable_lcd_clocks(int enable) | ||
912 | { | ||
913 | if (enable) | ||
914 | clk_enable(dispc.dss1_fck); | ||
915 | else | ||
916 | clk_disable(dispc.dss1_fck); | ||
917 | } | ||
918 | |||
919 | static void enable_interface_clocks(int enable) | ||
920 | { | ||
921 | if (enable) | ||
922 | clk_enable(dispc.dss_ick); | ||
923 | else | ||
924 | clk_disable(dispc.dss_ick); | ||
925 | } | ||
926 | |||
927 | static void enable_digit_clocks(int enable) | ||
928 | { | ||
929 | if (enable) | ||
930 | clk_enable(dispc.dss_54m_fck); | ||
931 | else | ||
932 | clk_disable(dispc.dss_54m_fck); | ||
933 | } | ||
934 | |||
935 | static void omap_dispc_suspend(void) | ||
936 | { | ||
937 | if (dispc.update_mode == OMAPFB_AUTO_UPDATE) { | ||
938 | init_completion(&dispc.frame_done); | ||
939 | omap_dispc_enable_lcd_out(0); | ||
940 | if (!wait_for_completion_timeout(&dispc.frame_done, | ||
941 | msecs_to_jiffies(500))) { | ||
942 | dev_err(dispc.fbdev->dev, | ||
943 | "timeout waiting for FRAME DONE\n"); | ||
944 | } | ||
945 | enable_lcd_clocks(0); | ||
946 | } | ||
947 | } | ||
948 | |||
949 | static void omap_dispc_resume(void) | ||
950 | { | ||
951 | if (dispc.update_mode == OMAPFB_AUTO_UPDATE) { | ||
952 | enable_lcd_clocks(1); | ||
953 | if (!dispc.ext_mode) { | ||
954 | set_lcd_timings(); | ||
955 | load_palette(); | ||
956 | } | ||
957 | omap_dispc_enable_lcd_out(1); | ||
958 | } | ||
959 | } | ||
960 | |||
961 | |||
962 | static int omap_dispc_update_window(struct fb_info *fbi, | ||
963 | struct omapfb_update_window *win, | ||
964 | void (*complete_callback)(void *arg), | ||
965 | void *complete_callback_data) | ||
966 | { | ||
967 | return dispc.update_mode == OMAPFB_UPDATE_DISABLED ? -ENODEV : 0; | ||
968 | } | ||
969 | |||
970 | static int mmap_kern(struct omapfb_mem_region *region) | ||
971 | { | ||
972 | struct vm_struct *kvma; | ||
973 | struct vm_area_struct vma; | ||
974 | pgprot_t pgprot; | ||
975 | unsigned long vaddr; | ||
976 | |||
977 | kvma = get_vm_area(region->size, VM_IOREMAP); | ||
978 | if (kvma == NULL) { | ||
979 | dev_err(dispc.fbdev->dev, "can't get kernel vm area\n"); | ||
980 | return -ENOMEM; | ||
981 | } | ||
982 | vma.vm_mm = &init_mm; | ||
983 | |||
984 | vaddr = (unsigned long)kvma->addr; | ||
985 | |||
986 | pgprot = pgprot_writecombine(pgprot_kernel); | ||
987 | vma.vm_start = vaddr; | ||
988 | vma.vm_end = vaddr + region->size; | ||
989 | if (io_remap_pfn_range(&vma, vaddr, region->paddr >> PAGE_SHIFT, | ||
990 | region->size, pgprot) < 0) { | ||
991 | dev_err(dispc.fbdev->dev, "kernel mmap for FBMEM failed\n"); | ||
992 | return -EAGAIN; | ||
993 | } | ||
994 | region->vaddr = (void *)vaddr; | ||
995 | |||
996 | return 0; | ||
997 | } | ||
998 | |||
999 | static void mmap_user_open(struct vm_area_struct *vma) | ||
1000 | { | ||
1001 | int plane = (int)vma->vm_private_data; | ||
1002 | |||
1003 | atomic_inc(&dispc.map_count[plane]); | ||
1004 | } | ||
1005 | |||
1006 | static void mmap_user_close(struct vm_area_struct *vma) | ||
1007 | { | ||
1008 | int plane = (int)vma->vm_private_data; | ||
1009 | |||
1010 | atomic_dec(&dispc.map_count[plane]); | ||
1011 | } | ||
1012 | |||
1013 | static struct vm_operations_struct mmap_user_ops = { | ||
1014 | .open = mmap_user_open, | ||
1015 | .close = mmap_user_close, | ||
1016 | }; | ||
1017 | |||
1018 | static int omap_dispc_mmap_user(struct fb_info *info, | ||
1019 | struct vm_area_struct *vma) | ||
1020 | { | ||
1021 | struct omapfb_plane_struct *plane = info->par; | ||
1022 | unsigned long off; | ||
1023 | unsigned long start; | ||
1024 | u32 len; | ||
1025 | |||
1026 | if (vma->vm_end - vma->vm_start == 0) | ||
1027 | return 0; | ||
1028 | if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) | ||
1029 | return -EINVAL; | ||
1030 | off = vma->vm_pgoff << PAGE_SHIFT; | ||
1031 | |||
1032 | start = info->fix.smem_start; | ||
1033 | len = info->fix.smem_len; | ||
1034 | if (off >= len) | ||
1035 | return -EINVAL; | ||
1036 | if ((vma->vm_end - vma->vm_start + off) > len) | ||
1037 | return -EINVAL; | ||
1038 | off += start; | ||
1039 | vma->vm_pgoff = off >> PAGE_SHIFT; | ||
1040 | vma->vm_flags |= VM_IO | VM_RESERVED; | ||
1041 | vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); | ||
1042 | vma->vm_ops = &mmap_user_ops; | ||
1043 | vma->vm_private_data = (void *)plane->idx; | ||
1044 | if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, | ||
1045 | vma->vm_end - vma->vm_start, vma->vm_page_prot)) | ||
1046 | return -EAGAIN; | ||
1047 | /* vm_ops.open won't be called for mmap itself. */ | ||
1048 | atomic_inc(&dispc.map_count[plane->idx]); | ||
1049 | return 0; | ||
1050 | } | ||
1051 | |||
1052 | static void unmap_kern(struct omapfb_mem_region *region) | ||
1053 | { | ||
1054 | vunmap(region->vaddr); | ||
1055 | } | ||
1056 | |||
1057 | static int alloc_palette_ram(void) | ||
1058 | { | ||
1059 | dispc.palette_vaddr = dma_alloc_writecombine(dispc.fbdev->dev, | ||
1060 | MAX_PALETTE_SIZE, &dispc.palette_paddr, GFP_KERNEL); | ||
1061 | if (dispc.palette_vaddr == NULL) { | ||
1062 | dev_err(dispc.fbdev->dev, "failed to alloc palette memory\n"); | ||
1063 | return -ENOMEM; | ||
1064 | } | ||
1065 | |||
1066 | return 0; | ||
1067 | } | ||
1068 | |||
1069 | static void free_palette_ram(void) | ||
1070 | { | ||
1071 | dma_free_writecombine(dispc.fbdev->dev, MAX_PALETTE_SIZE, | ||
1072 | dispc.palette_vaddr, dispc.palette_paddr); | ||
1073 | } | ||
1074 | |||
1075 | static int alloc_fbmem(struct omapfb_mem_region *region) | ||
1076 | { | ||
1077 | region->vaddr = dma_alloc_writecombine(dispc.fbdev->dev, | ||
1078 | region->size, ®ion->paddr, GFP_KERNEL); | ||
1079 | |||
1080 | if (region->vaddr == NULL) { | ||
1081 | dev_err(dispc.fbdev->dev, "unable to allocate FB DMA memory\n"); | ||
1082 | return -ENOMEM; | ||
1083 | } | ||
1084 | |||
1085 | return 0; | ||
1086 | } | ||
1087 | |||
1088 | static void free_fbmem(struct omapfb_mem_region *region) | ||
1089 | { | ||
1090 | dma_free_writecombine(dispc.fbdev->dev, region->size, | ||
1091 | region->vaddr, region->paddr); | ||
1092 | } | ||
1093 | |||
1094 | static struct resmap *init_resmap(unsigned long start, size_t size) | ||
1095 | { | ||
1096 | unsigned page_cnt; | ||
1097 | struct resmap *res_map; | ||
1098 | |||
1099 | page_cnt = PAGE_ALIGN(size) / PAGE_SIZE; | ||
1100 | res_map = | ||
1101 | kzalloc(sizeof(struct resmap) + RESMAP_SIZE(page_cnt), GFP_KERNEL); | ||
1102 | if (res_map == NULL) | ||
1103 | return NULL; | ||
1104 | res_map->start = start; | ||
1105 | res_map->page_cnt = page_cnt; | ||
1106 | res_map->map = (unsigned long *)(res_map + 1); | ||
1107 | return res_map; | ||
1108 | } | ||
1109 | |||
1110 | static void cleanup_resmap(struct resmap *res_map) | ||
1111 | { | ||
1112 | kfree(res_map); | ||
1113 | } | ||
1114 | |||
1115 | static inline int resmap_mem_type(unsigned long start) | ||
1116 | { | ||
1117 | if (start >= OMAP2_SRAM_START && | ||
1118 | start < OMAP2_SRAM_START + OMAP2_SRAM_SIZE) | ||
1119 | return OMAPFB_MEMTYPE_SRAM; | ||
1120 | else | ||
1121 | return OMAPFB_MEMTYPE_SDRAM; | ||
1122 | } | ||
1123 | |||
1124 | static inline int resmap_page_reserved(struct resmap *res_map, unsigned page_nr) | ||
1125 | { | ||
1126 | return *RESMAP_PTR(res_map, page_nr) & RESMAP_MASK(page_nr) ? 1 : 0; | ||
1127 | } | ||
1128 | |||
1129 | static inline void resmap_reserve_page(struct resmap *res_map, unsigned page_nr) | ||
1130 | { | ||
1131 | BUG_ON(resmap_page_reserved(res_map, page_nr)); | ||
1132 | *RESMAP_PTR(res_map, page_nr) |= RESMAP_MASK(page_nr); | ||
1133 | } | ||
1134 | |||
1135 | static inline void resmap_free_page(struct resmap *res_map, unsigned page_nr) | ||
1136 | { | ||
1137 | BUG_ON(!resmap_page_reserved(res_map, page_nr)); | ||
1138 | *RESMAP_PTR(res_map, page_nr) &= ~RESMAP_MASK(page_nr); | ||
1139 | } | ||
1140 | |||
1141 | static void resmap_reserve_region(unsigned long start, size_t size) | ||
1142 | { | ||
1143 | |||
1144 | struct resmap *res_map; | ||
1145 | unsigned start_page; | ||
1146 | unsigned end_page; | ||
1147 | int mtype; | ||
1148 | unsigned i; | ||
1149 | |||
1150 | mtype = resmap_mem_type(start); | ||
1151 | res_map = dispc.res_map[mtype]; | ||
1152 | dev_dbg(dispc.fbdev->dev, "reserve mem type %d start %08lx size %d\n", | ||
1153 | mtype, start, size); | ||
1154 | start_page = (start - res_map->start) / PAGE_SIZE; | ||
1155 | end_page = start_page + PAGE_ALIGN(size) / PAGE_SIZE; | ||
1156 | for (i = start_page; i < end_page; i++) | ||
1157 | resmap_reserve_page(res_map, i); | ||
1158 | } | ||
1159 | |||
1160 | static void resmap_free_region(unsigned long start, size_t size) | ||
1161 | { | ||
1162 | struct resmap *res_map; | ||
1163 | unsigned start_page; | ||
1164 | unsigned end_page; | ||
1165 | unsigned i; | ||
1166 | int mtype; | ||
1167 | |||
1168 | mtype = resmap_mem_type(start); | ||
1169 | res_map = dispc.res_map[mtype]; | ||
1170 | dev_dbg(dispc.fbdev->dev, "free mem type %d start %08lx size %d\n", | ||
1171 | mtype, start, size); | ||
1172 | start_page = (start - res_map->start) / PAGE_SIZE; | ||
1173 | end_page = start_page + PAGE_ALIGN(size) / PAGE_SIZE; | ||
1174 | for (i = start_page; i < end_page; i++) | ||
1175 | resmap_free_page(res_map, i); | ||
1176 | } | ||
1177 | |||
1178 | static unsigned long resmap_alloc_region(int mtype, size_t size) | ||
1179 | { | ||
1180 | unsigned i; | ||
1181 | unsigned total; | ||
1182 | unsigned start_page; | ||
1183 | unsigned long start; | ||
1184 | struct resmap *res_map = dispc.res_map[mtype]; | ||
1185 | |||
1186 | BUG_ON(mtype >= DISPC_MEMTYPE_NUM || res_map == NULL || !size); | ||
1187 | |||
1188 | size = PAGE_ALIGN(size) / PAGE_SIZE; | ||
1189 | start_page = 0; | ||
1190 | total = 0; | ||
1191 | for (i = 0; i < res_map->page_cnt; i++) { | ||
1192 | if (resmap_page_reserved(res_map, i)) { | ||
1193 | start_page = i + 1; | ||
1194 | total = 0; | ||
1195 | } else if (++total == size) | ||
1196 | break; | ||
1197 | } | ||
1198 | if (total < size) | ||
1199 | return 0; | ||
1200 | |||
1201 | start = res_map->start + start_page * PAGE_SIZE; | ||
1202 | resmap_reserve_region(start, size * PAGE_SIZE); | ||
1203 | |||
1204 | return start; | ||
1205 | } | ||
1206 | |||
1207 | /* Note that this will only work for user mappings, we don't deal with | ||
1208 | * kernel mappings here, so fbcon will keep using the old region. | ||
1209 | */ | ||
1210 | static int omap_dispc_setup_mem(int plane, size_t size, int mem_type, | ||
1211 | unsigned long *paddr) | ||
1212 | { | ||
1213 | struct omapfb_mem_region *rg; | ||
1214 | unsigned long new_addr = 0; | ||
1215 | |||
1216 | if ((unsigned)plane > dispc.mem_desc.region_cnt) | ||
1217 | return -EINVAL; | ||
1218 | if (mem_type >= DISPC_MEMTYPE_NUM) | ||
1219 | return -EINVAL; | ||
1220 | if (dispc.res_map[mem_type] == NULL) | ||
1221 | return -ENOMEM; | ||
1222 | rg = &dispc.mem_desc.region[plane]; | ||
1223 | if (size == rg->size && mem_type == rg->type) | ||
1224 | return 0; | ||
1225 | if (atomic_read(&dispc.map_count[plane])) | ||
1226 | return -EBUSY; | ||
1227 | if (rg->size != 0) | ||
1228 | resmap_free_region(rg->paddr, rg->size); | ||
1229 | if (size != 0) { | ||
1230 | new_addr = resmap_alloc_region(mem_type, size); | ||
1231 | if (!new_addr) { | ||
1232 | /* Reallocate old region. */ | ||
1233 | resmap_reserve_region(rg->paddr, rg->size); | ||
1234 | return -ENOMEM; | ||
1235 | } | ||
1236 | } | ||
1237 | rg->paddr = new_addr; | ||
1238 | rg->size = size; | ||
1239 | rg->type = mem_type; | ||
1240 | |||
1241 | *paddr = new_addr; | ||
1242 | |||
1243 | return 0; | ||
1244 | } | ||
1245 | |||
1246 | static int setup_fbmem(struct omapfb_mem_desc *req_md) | ||
1247 | { | ||
1248 | struct omapfb_mem_region *rg; | ||
1249 | int i; | ||
1250 | int r; | ||
1251 | unsigned long mem_start[DISPC_MEMTYPE_NUM]; | ||
1252 | unsigned long mem_end[DISPC_MEMTYPE_NUM]; | ||
1253 | |||
1254 | if (!req_md->region_cnt) { | ||
1255 | dev_err(dispc.fbdev->dev, "no memory regions defined\n"); | ||
1256 | return -ENOENT; | ||
1257 | } | ||
1258 | |||
1259 | rg = &req_md->region[0]; | ||
1260 | memset(mem_start, 0xff, sizeof(mem_start)); | ||
1261 | memset(mem_end, 0, sizeof(mem_end)); | ||
1262 | |||
1263 | for (i = 0; i < req_md->region_cnt; i++, rg++) { | ||
1264 | int mtype; | ||
1265 | if (rg->paddr) { | ||
1266 | rg->alloc = 0; | ||
1267 | if (rg->vaddr == NULL) { | ||
1268 | rg->map = 1; | ||
1269 | if ((r = mmap_kern(rg)) < 0) | ||
1270 | return r; | ||
1271 | } | ||
1272 | } else { | ||
1273 | if (rg->type != OMAPFB_MEMTYPE_SDRAM) { | ||
1274 | dev_err(dispc.fbdev->dev, | ||
1275 | "unsupported memory type\n"); | ||
1276 | return -EINVAL; | ||
1277 | } | ||
1278 | rg->alloc = rg->map = 1; | ||
1279 | if ((r = alloc_fbmem(rg)) < 0) | ||
1280 | return r; | ||
1281 | } | ||
1282 | mtype = rg->type; | ||
1283 | |||
1284 | if (rg->paddr < mem_start[mtype]) | ||
1285 | mem_start[mtype] = rg->paddr; | ||
1286 | if (rg->paddr + rg->size > mem_end[mtype]) | ||
1287 | mem_end[mtype] = rg->paddr + rg->size; | ||
1288 | } | ||
1289 | |||
1290 | for (i = 0; i < DISPC_MEMTYPE_NUM; i++) { | ||
1291 | unsigned long start; | ||
1292 | size_t size; | ||
1293 | if (mem_end[i] == 0) | ||
1294 | continue; | ||
1295 | start = mem_start[i]; | ||
1296 | size = mem_end[i] - start; | ||
1297 | dispc.res_map[i] = init_resmap(start, size); | ||
1298 | r = -ENOMEM; | ||
1299 | if (dispc.res_map[i] == NULL) | ||
1300 | goto fail; | ||
1301 | /* Initial state is that everything is reserved. This | ||
1302 | * includes possible holes as well, which will never be | ||
1303 | * freed. | ||
1304 | */ | ||
1305 | resmap_reserve_region(start, size); | ||
1306 | } | ||
1307 | |||
1308 | dispc.mem_desc = *req_md; | ||
1309 | |||
1310 | return 0; | ||
1311 | fail: | ||
1312 | for (i = 0; i < DISPC_MEMTYPE_NUM; i++) { | ||
1313 | if (dispc.res_map[i] != NULL) | ||
1314 | cleanup_resmap(dispc.res_map[i]); | ||
1315 | } | ||
1316 | return r; | ||
1317 | } | ||
1318 | |||
1319 | static void cleanup_fbmem(void) | ||
1320 | { | ||
1321 | struct omapfb_mem_region *rg; | ||
1322 | int i; | ||
1323 | |||
1324 | for (i = 0; i < DISPC_MEMTYPE_NUM; i++) { | ||
1325 | if (dispc.res_map[i] != NULL) | ||
1326 | cleanup_resmap(dispc.res_map[i]); | ||
1327 | } | ||
1328 | rg = &dispc.mem_desc.region[0]; | ||
1329 | for (i = 0; i < dispc.mem_desc.region_cnt; i++, rg++) { | ||
1330 | if (rg->alloc) | ||
1331 | free_fbmem(rg); | ||
1332 | else { | ||
1333 | if (rg->map) | ||
1334 | unmap_kern(rg); | ||
1335 | } | ||
1336 | } | ||
1337 | } | ||
1338 | |||
1339 | static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode, | ||
1340 | struct omapfb_mem_desc *req_vram) | ||
1341 | { | ||
1342 | int r; | ||
1343 | u32 l; | ||
1344 | struct lcd_panel *panel = fbdev->panel; | ||
1345 | int tmo = 10000; | ||
1346 | int skip_init = 0; | ||
1347 | int i; | ||
1348 | |||
1349 | memset(&dispc, 0, sizeof(dispc)); | ||
1350 | |||
1351 | dispc.base = io_p2v(DISPC_BASE); | ||
1352 | dispc.fbdev = fbdev; | ||
1353 | dispc.ext_mode = ext_mode; | ||
1354 | |||
1355 | init_completion(&dispc.frame_done); | ||
1356 | |||
1357 | if ((r = get_dss_clocks()) < 0) | ||
1358 | return r; | ||
1359 | |||
1360 | enable_interface_clocks(1); | ||
1361 | enable_lcd_clocks(1); | ||
1362 | |||
1363 | #ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT | ||
1364 | l = dispc_read_reg(DISPC_CONTROL); | ||
1365 | /* LCD enabled ? */ | ||
1366 | if (l & 1) { | ||
1367 | pr_info("omapfb: skipping hardware initialization\n"); | ||
1368 | skip_init = 1; | ||
1369 | } | ||
1370 | #endif | ||
1371 | |||
1372 | if (!skip_init) { | ||
1373 | /* Reset monitoring works only w/ the 54M clk */ | ||
1374 | enable_digit_clocks(1); | ||
1375 | |||
1376 | /* Soft reset */ | ||
1377 | MOD_REG_FLD(DISPC_SYSCONFIG, 1 << 1, 1 << 1); | ||
1378 | |||
1379 | while (!(dispc_read_reg(DISPC_SYSSTATUS) & 1)) { | ||
1380 | if (!--tmo) { | ||
1381 | dev_err(dispc.fbdev->dev, "soft reset failed\n"); | ||
1382 | r = -ENODEV; | ||
1383 | enable_digit_clocks(0); | ||
1384 | goto fail1; | ||
1385 | } | ||
1386 | } | ||
1387 | |||
1388 | enable_digit_clocks(0); | ||
1389 | } | ||
1390 | |||
1391 | /* Enable smart idle and autoidle */ | ||
1392 | l = dispc_read_reg(DISPC_CONTROL); | ||
1393 | l &= ~((3 << 12) | (3 << 3)); | ||
1394 | l |= (2 << 12) | (2 << 3) | (1 << 0); | ||
1395 | dispc_write_reg(DISPC_SYSCONFIG, l); | ||
1396 | omap_writel(1 << 0, DSS_BASE + DSS_SYSCONFIG); | ||
1397 | |||
1398 | /* Set functional clock autogating */ | ||
1399 | l = dispc_read_reg(DISPC_CONFIG); | ||
1400 | l |= 1 << 9; | ||
1401 | dispc_write_reg(DISPC_CONFIG, l); | ||
1402 | |||
1403 | l = dispc_read_reg(DISPC_IRQSTATUS); | ||
1404 | dispc_write_reg(l, DISPC_IRQSTATUS); | ||
1405 | |||
1406 | /* Enable those that we handle always */ | ||
1407 | omap_dispc_enable_irqs(DISPC_IRQ_FRAMEMASK); | ||
1408 | |||
1409 | if ((r = request_irq(INT_24XX_DSS_IRQ, omap_dispc_irq_handler, | ||
1410 | 0, MODULE_NAME, fbdev)) < 0) { | ||
1411 | dev_err(dispc.fbdev->dev, "can't get DSS IRQ\n"); | ||
1412 | goto fail1; | ||
1413 | } | ||
1414 | |||
1415 | /* L3 firewall setting: enable access to OCM RAM */ | ||
1416 | __raw_writel(0x402000b0, io_p2v(0x680050a0)); | ||
1417 | |||
1418 | if ((r = alloc_palette_ram()) < 0) | ||
1419 | goto fail2; | ||
1420 | |||
1421 | if ((r = setup_fbmem(req_vram)) < 0) | ||
1422 | goto fail3; | ||
1423 | |||
1424 | if (!skip_init) { | ||
1425 | for (i = 0; i < dispc.mem_desc.region_cnt; i++) { | ||
1426 | memset(dispc.mem_desc.region[i].vaddr, 0, | ||
1427 | dispc.mem_desc.region[i].size); | ||
1428 | } | ||
1429 | |||
1430 | /* Set logic clock to fck, pixel clock to fck/2 for now */ | ||
1431 | MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(16, 8), 1 << 16); | ||
1432 | MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(0, 8), 2 << 0); | ||
1433 | |||
1434 | setup_plane_fifo(0, ext_mode); | ||
1435 | setup_plane_fifo(1, ext_mode); | ||
1436 | setup_plane_fifo(2, ext_mode); | ||
1437 | |||
1438 | setup_color_conv_coef(); | ||
1439 | |||
1440 | set_lcd_tft_mode(panel->config & OMAP_LCDC_PANEL_TFT); | ||
1441 | set_load_mode(DISPC_LOAD_FRAME_ONLY); | ||
1442 | |||
1443 | if (!ext_mode) { | ||
1444 | set_lcd_data_lines(panel->data_lines); | ||
1445 | omap_dispc_set_lcd_size(panel->x_res, panel->y_res); | ||
1446 | set_lcd_timings(); | ||
1447 | } else | ||
1448 | set_lcd_data_lines(panel->bpp); | ||
1449 | enable_rfbi_mode(ext_mode); | ||
1450 | } | ||
1451 | |||
1452 | l = dispc_read_reg(DISPC_REVISION); | ||
1453 | pr_info("omapfb: DISPC version %d.%d initialized\n", | ||
1454 | l >> 4 & 0x0f, l & 0x0f); | ||
1455 | enable_lcd_clocks(0); | ||
1456 | |||
1457 | return 0; | ||
1458 | fail3: | ||
1459 | free_palette_ram(); | ||
1460 | fail2: | ||
1461 | free_irq(INT_24XX_DSS_IRQ, fbdev); | ||
1462 | fail1: | ||
1463 | enable_lcd_clocks(0); | ||
1464 | enable_interface_clocks(0); | ||
1465 | put_dss_clocks(); | ||
1466 | |||
1467 | return r; | ||
1468 | } | ||
1469 | |||
1470 | static void omap_dispc_cleanup(void) | ||
1471 | { | ||
1472 | int i; | ||
1473 | |||
1474 | omap_dispc_set_update_mode(OMAPFB_UPDATE_DISABLED); | ||
1475 | /* This will also disable clocks that are on */ | ||
1476 | for (i = 0; i < dispc.mem_desc.region_cnt; i++) | ||
1477 | omap_dispc_enable_plane(i, 0); | ||
1478 | cleanup_fbmem(); | ||
1479 | free_palette_ram(); | ||
1480 | free_irq(INT_24XX_DSS_IRQ, dispc.fbdev); | ||
1481 | enable_interface_clocks(0); | ||
1482 | put_dss_clocks(); | ||
1483 | } | ||
1484 | |||
1485 | const struct lcd_ctrl omap2_int_ctrl = { | ||
1486 | .name = "internal", | ||
1487 | .init = omap_dispc_init, | ||
1488 | .cleanup = omap_dispc_cleanup, | ||
1489 | .get_caps = omap_dispc_get_caps, | ||
1490 | .set_update_mode = omap_dispc_set_update_mode, | ||
1491 | .get_update_mode = omap_dispc_get_update_mode, | ||
1492 | .update_window = omap_dispc_update_window, | ||
1493 | .suspend = omap_dispc_suspend, | ||
1494 | .resume = omap_dispc_resume, | ||
1495 | .setup_plane = omap_dispc_setup_plane, | ||
1496 | .setup_mem = omap_dispc_setup_mem, | ||
1497 | .set_scale = omap_dispc_set_scale, | ||
1498 | .enable_plane = omap_dispc_enable_plane, | ||
1499 | .set_color_key = omap_dispc_set_color_key, | ||
1500 | .get_color_key = omap_dispc_get_color_key, | ||
1501 | .mmap = omap_dispc_mmap_user, | ||
1502 | }; | ||
diff --git a/drivers/video/omap/dispc.h b/drivers/video/omap/dispc.h new file mode 100644 index 000000000000..eb1512b56ce8 --- /dev/null +++ b/drivers/video/omap/dispc.h | |||
@@ -0,0 +1,43 @@ | |||
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(void (*callback)(void *data), void *data); | ||
41 | extern void omap_dispc_free_irq(void); | ||
42 | |||
43 | #endif | ||
diff --git a/drivers/video/omap/hwa742.c b/drivers/video/omap/hwa742.c new file mode 100644 index 000000000000..dc48e02f215c --- /dev/null +++ b/drivers/video/omap/hwa742.c | |||
@@ -0,0 +1,1077 @@ | |||
1 | /* | ||
2 | * Epson HWA742 LCD controller driver | ||
3 | * | ||
4 | * Copyright (C) 2004-2005 Nokia Corporation | ||
5 | * Authors: Juha Yrjölä <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 <asm/arch/dma.h> | ||
30 | #include <asm/arch/omapfb.h> | ||
31 | #include <asm/arch/hwa742.h> | ||
32 | |||
33 | #define HWA742_REV_CODE_REG 0x0 | ||
34 | #define HWA742_CONFIG_REG 0x2 | ||
35 | #define HWA742_PLL_DIV_REG 0x4 | ||
36 | #define HWA742_PLL_0_REG 0x6 | ||
37 | #define HWA742_PLL_1_REG 0x8 | ||
38 | #define HWA742_PLL_2_REG 0xa | ||
39 | #define HWA742_PLL_3_REG 0xc | ||
40 | #define HWA742_PLL_4_REG 0xe | ||
41 | #define HWA742_CLK_SRC_REG 0x12 | ||
42 | #define HWA742_PANEL_TYPE_REG 0x14 | ||
43 | #define HWA742_H_DISP_REG 0x16 | ||
44 | #define HWA742_H_NDP_REG 0x18 | ||
45 | #define HWA742_V_DISP_1_REG 0x1a | ||
46 | #define HWA742_V_DISP_2_REG 0x1c | ||
47 | #define HWA742_V_NDP_REG 0x1e | ||
48 | #define HWA742_HS_W_REG 0x20 | ||
49 | #define HWA742_HP_S_REG 0x22 | ||
50 | #define HWA742_VS_W_REG 0x24 | ||
51 | #define HWA742_VP_S_REG 0x26 | ||
52 | #define HWA742_PCLK_POL_REG 0x28 | ||
53 | #define HWA742_INPUT_MODE_REG 0x2a | ||
54 | #define HWA742_TRANSL_MODE_REG1 0x2e | ||
55 | #define HWA742_DISP_MODE_REG 0x34 | ||
56 | #define HWA742_WINDOW_TYPE 0x36 | ||
57 | #define HWA742_WINDOW_X_START_0 0x38 | ||
58 | #define HWA742_WINDOW_X_START_1 0x3a | ||
59 | #define HWA742_WINDOW_Y_START_0 0x3c | ||
60 | #define HWA742_WINDOW_Y_START_1 0x3e | ||
61 | #define HWA742_WINDOW_X_END_0 0x40 | ||
62 | #define HWA742_WINDOW_X_END_1 0x42 | ||
63 | #define HWA742_WINDOW_Y_END_0 0x44 | ||
64 | #define HWA742_WINDOW_Y_END_1 0x46 | ||
65 | #define HWA742_MEMORY_WRITE_LSB 0x48 | ||
66 | #define HWA742_MEMORY_WRITE_MSB 0x49 | ||
67 | #define HWA742_MEMORY_READ_0 0x4a | ||
68 | #define HWA742_MEMORY_READ_1 0x4c | ||
69 | #define HWA742_MEMORY_READ_2 0x4e | ||
70 | #define HWA742_POWER_SAVE 0x56 | ||
71 | #define HWA742_NDP_CTRL 0x58 | ||
72 | |||
73 | #define HWA742_AUTO_UPDATE_TIME (HZ / 20) | ||
74 | |||
75 | /* Reserve 4 request slots for requests in irq context */ | ||
76 | #define REQ_POOL_SIZE 24 | ||
77 | #define IRQ_REQ_POOL_SIZE 4 | ||
78 | |||
79 | #define REQ_FROM_IRQ_POOL 0x01 | ||
80 | |||
81 | #define REQ_COMPLETE 0 | ||
82 | #define REQ_PENDING 1 | ||
83 | |||
84 | struct update_param { | ||
85 | int x, y, width, height; | ||
86 | int color_mode; | ||
87 | int flags; | ||
88 | }; | ||
89 | |||
90 | struct hwa742_request { | ||
91 | struct list_head entry; | ||
92 | unsigned int flags; | ||
93 | |||
94 | int (*handler)(struct hwa742_request *req); | ||
95 | void (*complete)(void *data); | ||
96 | void *complete_data; | ||
97 | |||
98 | union { | ||
99 | struct update_param update; | ||
100 | struct completion *sync; | ||
101 | } par; | ||
102 | }; | ||
103 | |||
104 | struct { | ||
105 | enum omapfb_update_mode update_mode; | ||
106 | enum omapfb_update_mode update_mode_before_suspend; | ||
107 | |||
108 | struct timer_list auto_update_timer; | ||
109 | int stop_auto_update; | ||
110 | struct omapfb_update_window auto_update_window; | ||
111 | unsigned te_connected:1; | ||
112 | unsigned vsync_only:1; | ||
113 | |||
114 | struct hwa742_request req_pool[REQ_POOL_SIZE]; | ||
115 | struct list_head pending_req_list; | ||
116 | struct list_head free_req_list; | ||
117 | struct semaphore req_sema; | ||
118 | spinlock_t req_lock; | ||
119 | |||
120 | struct extif_timings reg_timings, lut_timings; | ||
121 | |||
122 | int prev_color_mode; | ||
123 | int prev_flags; | ||
124 | int window_type; | ||
125 | |||
126 | u32 max_transmit_size; | ||
127 | u32 extif_clk_period; | ||
128 | unsigned long pix_tx_time; | ||
129 | unsigned long line_upd_time; | ||
130 | |||
131 | |||
132 | struct omapfb_device *fbdev; | ||
133 | struct lcd_ctrl_extif *extif; | ||
134 | struct lcd_ctrl *int_ctrl; | ||
135 | |||
136 | void (*power_up)(struct device *dev); | ||
137 | void (*power_down)(struct device *dev); | ||
138 | } hwa742; | ||
139 | |||
140 | struct lcd_ctrl hwa742_ctrl; | ||
141 | |||
142 | static u8 hwa742_read_reg(u8 reg) | ||
143 | { | ||
144 | u8 data; | ||
145 | |||
146 | hwa742.extif->set_bits_per_cycle(8); | ||
147 | hwa742.extif->write_command(®, 1); | ||
148 | hwa742.extif->read_data(&data, 1); | ||
149 | |||
150 | return data; | ||
151 | } | ||
152 | |||
153 | static void hwa742_write_reg(u8 reg, u8 data) | ||
154 | { | ||
155 | hwa742.extif->set_bits_per_cycle(8); | ||
156 | hwa742.extif->write_command(®, 1); | ||
157 | hwa742.extif->write_data(&data, 1); | ||
158 | } | ||
159 | |||
160 | static void set_window_regs(int x_start, int y_start, int x_end, int y_end) | ||
161 | { | ||
162 | u8 tmp[8]; | ||
163 | u8 cmd; | ||
164 | |||
165 | x_end--; | ||
166 | y_end--; | ||
167 | tmp[0] = x_start; | ||
168 | tmp[1] = x_start >> 8; | ||
169 | tmp[2] = y_start; | ||
170 | tmp[3] = y_start >> 8; | ||
171 | tmp[4] = x_end; | ||
172 | tmp[5] = x_end >> 8; | ||
173 | tmp[6] = y_end; | ||
174 | tmp[7] = y_end >> 8; | ||
175 | |||
176 | hwa742.extif->set_bits_per_cycle(8); | ||
177 | cmd = HWA742_WINDOW_X_START_0; | ||
178 | |||
179 | hwa742.extif->write_command(&cmd, 1); | ||
180 | |||
181 | hwa742.extif->write_data(tmp, 8); | ||
182 | } | ||
183 | |||
184 | static void set_format_regs(int conv, int transl, int flags) | ||
185 | { | ||
186 | if (flags & OMAPFB_FORMAT_FLAG_DOUBLE) { | ||
187 | hwa742.window_type = ((hwa742.window_type & 0xfc) | 0x01); | ||
188 | #ifdef VERBOSE | ||
189 | dev_dbg(hwa742.fbdev->dev, "hwa742: enabled pixel doubling\n"); | ||
190 | #endif | ||
191 | } else { | ||
192 | hwa742.window_type = (hwa742.window_type & 0xfc); | ||
193 | #ifdef VERBOSE | ||
194 | dev_dbg(hwa742.fbdev->dev, "hwa742: disabled pixel doubling\n"); | ||
195 | #endif | ||
196 | } | ||
197 | |||
198 | hwa742_write_reg(HWA742_INPUT_MODE_REG, conv); | ||
199 | hwa742_write_reg(HWA742_TRANSL_MODE_REG1, transl); | ||
200 | hwa742_write_reg(HWA742_WINDOW_TYPE, hwa742.window_type); | ||
201 | } | ||
202 | |||
203 | static void enable_tearsync(int y, int width, int height, int screen_height, | ||
204 | int force_vsync) | ||
205 | { | ||
206 | u8 b; | ||
207 | |||
208 | b = hwa742_read_reg(HWA742_NDP_CTRL); | ||
209 | b |= 1 << 2; | ||
210 | hwa742_write_reg(HWA742_NDP_CTRL, b); | ||
211 | |||
212 | if (likely(hwa742.vsync_only || force_vsync)) { | ||
213 | hwa742.extif->enable_tearsync(1, 0); | ||
214 | return; | ||
215 | } | ||
216 | |||
217 | if (width * hwa742.pix_tx_time < hwa742.line_upd_time) { | ||
218 | hwa742.extif->enable_tearsync(1, 0); | ||
219 | return; | ||
220 | } | ||
221 | |||
222 | if ((width * hwa742.pix_tx_time / 1000) * height < | ||
223 | (y + height) * (hwa742.line_upd_time / 1000)) { | ||
224 | hwa742.extif->enable_tearsync(1, 0); | ||
225 | return; | ||
226 | } | ||
227 | |||
228 | hwa742.extif->enable_tearsync(1, y + 1); | ||
229 | } | ||
230 | |||
231 | static void disable_tearsync(void) | ||
232 | { | ||
233 | u8 b; | ||
234 | |||
235 | hwa742.extif->enable_tearsync(0, 0); | ||
236 | |||
237 | b = hwa742_read_reg(HWA742_NDP_CTRL); | ||
238 | b &= ~(1 << 2); | ||
239 | hwa742_write_reg(HWA742_NDP_CTRL, b); | ||
240 | } | ||
241 | |||
242 | static inline struct hwa742_request *alloc_req(void) | ||
243 | { | ||
244 | unsigned long flags; | ||
245 | struct hwa742_request *req; | ||
246 | int req_flags = 0; | ||
247 | |||
248 | if (!in_interrupt()) | ||
249 | down(&hwa742.req_sema); | ||
250 | else | ||
251 | req_flags = REQ_FROM_IRQ_POOL; | ||
252 | |||
253 | spin_lock_irqsave(&hwa742.req_lock, flags); | ||
254 | BUG_ON(list_empty(&hwa742.free_req_list)); | ||
255 | req = list_entry(hwa742.free_req_list.next, | ||
256 | struct hwa742_request, entry); | ||
257 | list_del(&req->entry); | ||
258 | spin_unlock_irqrestore(&hwa742.req_lock, flags); | ||
259 | |||
260 | INIT_LIST_HEAD(&req->entry); | ||
261 | req->flags = req_flags; | ||
262 | |||
263 | return req; | ||
264 | } | ||
265 | |||
266 | static inline void free_req(struct hwa742_request *req) | ||
267 | { | ||
268 | unsigned long flags; | ||
269 | |||
270 | spin_lock_irqsave(&hwa742.req_lock, flags); | ||
271 | |||
272 | list_del(&req->entry); | ||
273 | list_add(&req->entry, &hwa742.free_req_list); | ||
274 | if (!(req->flags & REQ_FROM_IRQ_POOL)) | ||
275 | up(&hwa742.req_sema); | ||
276 | |||
277 | spin_unlock_irqrestore(&hwa742.req_lock, flags); | ||
278 | } | ||
279 | |||
280 | static void process_pending_requests(void) | ||
281 | { | ||
282 | unsigned long flags; | ||
283 | |||
284 | spin_lock_irqsave(&hwa742.req_lock, flags); | ||
285 | |||
286 | while (!list_empty(&hwa742.pending_req_list)) { | ||
287 | struct hwa742_request *req; | ||
288 | void (*complete)(void *); | ||
289 | void *complete_data; | ||
290 | |||
291 | req = list_entry(hwa742.pending_req_list.next, | ||
292 | struct hwa742_request, entry); | ||
293 | spin_unlock_irqrestore(&hwa742.req_lock, flags); | ||
294 | |||
295 | if (req->handler(req) == REQ_PENDING) | ||
296 | return; | ||
297 | |||
298 | complete = req->complete; | ||
299 | complete_data = req->complete_data; | ||
300 | free_req(req); | ||
301 | |||
302 | if (complete) | ||
303 | complete(complete_data); | ||
304 | |||
305 | spin_lock_irqsave(&hwa742.req_lock, flags); | ||
306 | } | ||
307 | |||
308 | spin_unlock_irqrestore(&hwa742.req_lock, flags); | ||
309 | } | ||
310 | |||
311 | static void submit_req_list(struct list_head *head) | ||
312 | { | ||
313 | unsigned long flags; | ||
314 | int process = 1; | ||
315 | |||
316 | spin_lock_irqsave(&hwa742.req_lock, flags); | ||
317 | if (likely(!list_empty(&hwa742.pending_req_list))) | ||
318 | process = 0; | ||
319 | list_splice_init(head, hwa742.pending_req_list.prev); | ||
320 | spin_unlock_irqrestore(&hwa742.req_lock, flags); | ||
321 | |||
322 | if (process) | ||
323 | process_pending_requests(); | ||
324 | } | ||
325 | |||
326 | static void request_complete(void *data) | ||
327 | { | ||
328 | struct hwa742_request *req = (struct hwa742_request *)data; | ||
329 | void (*complete)(void *); | ||
330 | void *complete_data; | ||
331 | |||
332 | complete = req->complete; | ||
333 | complete_data = req->complete_data; | ||
334 | |||
335 | free_req(req); | ||
336 | |||
337 | if (complete) | ||
338 | complete(complete_data); | ||
339 | |||
340 | process_pending_requests(); | ||
341 | } | ||
342 | |||
343 | static int send_frame_handler(struct hwa742_request *req) | ||
344 | { | ||
345 | struct update_param *par = &req->par.update; | ||
346 | int x = par->x; | ||
347 | int y = par->y; | ||
348 | int w = par->width; | ||
349 | int h = par->height; | ||
350 | int bpp; | ||
351 | int conv, transl; | ||
352 | unsigned long offset; | ||
353 | int color_mode = par->color_mode; | ||
354 | int flags = par->flags; | ||
355 | int scr_width = hwa742.fbdev->panel->x_res; | ||
356 | int scr_height = hwa742.fbdev->panel->y_res; | ||
357 | |||
358 | #ifdef VERBOSE | ||
359 | dev_dbg(hwa742.fbdev->dev, "x %d y %d w %d h %d scr_width %d " | ||
360 | "color_mode %d flags %d\n", | ||
361 | x, y, w, h, scr_width, color_mode, flags); | ||
362 | #endif | ||
363 | |||
364 | switch (color_mode) { | ||
365 | case OMAPFB_COLOR_YUV422: | ||
366 | bpp = 16; | ||
367 | conv = 0x08; | ||
368 | transl = 0x25; | ||
369 | break; | ||
370 | case OMAPFB_COLOR_YUV420: | ||
371 | bpp = 12; | ||
372 | conv = 0x09; | ||
373 | transl = 0x25; | ||
374 | break; | ||
375 | case OMAPFB_COLOR_RGB565: | ||
376 | bpp = 16; | ||
377 | conv = 0x01; | ||
378 | transl = 0x05; | ||
379 | break; | ||
380 | default: | ||
381 | return -EINVAL; | ||
382 | } | ||
383 | |||
384 | if (hwa742.prev_flags != flags || | ||
385 | hwa742.prev_color_mode != color_mode) { | ||
386 | set_format_regs(conv, transl, flags); | ||
387 | hwa742.prev_color_mode = color_mode; | ||
388 | hwa742.prev_flags = flags; | ||
389 | } | ||
390 | flags = req->par.update.flags; | ||
391 | if (flags & OMAPFB_FORMAT_FLAG_TEARSYNC) | ||
392 | enable_tearsync(y, scr_width, h, scr_height, | ||
393 | flags & OMAPFB_FORMAT_FLAG_FORCE_VSYNC); | ||
394 | else | ||
395 | disable_tearsync(); | ||
396 | |||
397 | set_window_regs(x, y, x + w, y + h); | ||
398 | |||
399 | offset = (scr_width * y + x) * bpp / 8; | ||
400 | |||
401 | hwa742.int_ctrl->setup_plane(OMAPFB_PLANE_GFX, | ||
402 | OMAPFB_CHANNEL_OUT_LCD, offset, scr_width, 0, 0, w, h, | ||
403 | color_mode); | ||
404 | |||
405 | hwa742.extif->set_bits_per_cycle(16); | ||
406 | |||
407 | hwa742.int_ctrl->enable_plane(OMAPFB_PLANE_GFX, 1); | ||
408 | hwa742.extif->transfer_area(w, h, request_complete, req); | ||
409 | |||
410 | return REQ_PENDING; | ||
411 | } | ||
412 | |||
413 | static void send_frame_complete(void *data) | ||
414 | { | ||
415 | hwa742.int_ctrl->enable_plane(OMAPFB_PLANE_GFX, 0); | ||
416 | } | ||
417 | |||
418 | #define ADD_PREQ(_x, _y, _w, _h) do { \ | ||
419 | req = alloc_req(); \ | ||
420 | req->handler = send_frame_handler; \ | ||
421 | req->complete = send_frame_complete; \ | ||
422 | req->par.update.x = _x; \ | ||
423 | req->par.update.y = _y; \ | ||
424 | req->par.update.width = _w; \ | ||
425 | req->par.update.height = _h; \ | ||
426 | req->par.update.color_mode = color_mode;\ | ||
427 | req->par.update.flags = flags; \ | ||
428 | list_add_tail(&req->entry, req_head); \ | ||
429 | } while(0) | ||
430 | |||
431 | static void create_req_list(struct omapfb_update_window *win, | ||
432 | struct list_head *req_head) | ||
433 | { | ||
434 | struct hwa742_request *req; | ||
435 | int x = win->x; | ||
436 | int y = win->y; | ||
437 | int width = win->width; | ||
438 | int height = win->height; | ||
439 | int color_mode; | ||
440 | int flags; | ||
441 | |||
442 | flags = win->format & ~OMAPFB_FORMAT_MASK; | ||
443 | color_mode = win->format & OMAPFB_FORMAT_MASK; | ||
444 | |||
445 | if (x & 1) { | ||
446 | ADD_PREQ(x, y, 1, height); | ||
447 | width--; | ||
448 | x++; | ||
449 | flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC; | ||
450 | } | ||
451 | if (width & ~1) { | ||
452 | unsigned int xspan = width & ~1; | ||
453 | unsigned int ystart = y; | ||
454 | unsigned int yspan = height; | ||
455 | |||
456 | if (xspan * height * 2 > hwa742.max_transmit_size) { | ||
457 | yspan = hwa742.max_transmit_size / (xspan * 2); | ||
458 | ADD_PREQ(x, ystart, xspan, yspan); | ||
459 | ystart += yspan; | ||
460 | yspan = height - yspan; | ||
461 | flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC; | ||
462 | } | ||
463 | |||
464 | ADD_PREQ(x, ystart, xspan, yspan); | ||
465 | x += xspan; | ||
466 | width -= xspan; | ||
467 | flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC; | ||
468 | } | ||
469 | if (width) | ||
470 | ADD_PREQ(x, y, 1, height); | ||
471 | } | ||
472 | |||
473 | static void auto_update_complete(void *data) | ||
474 | { | ||
475 | if (!hwa742.stop_auto_update) | ||
476 | mod_timer(&hwa742.auto_update_timer, | ||
477 | jiffies + HWA742_AUTO_UPDATE_TIME); | ||
478 | } | ||
479 | |||
480 | static void hwa742_update_window_auto(unsigned long arg) | ||
481 | { | ||
482 | LIST_HEAD(req_list); | ||
483 | struct hwa742_request *last; | ||
484 | |||
485 | create_req_list(&hwa742.auto_update_window, &req_list); | ||
486 | last = list_entry(req_list.prev, struct hwa742_request, entry); | ||
487 | |||
488 | last->complete = auto_update_complete; | ||
489 | last->complete_data = NULL; | ||
490 | |||
491 | submit_req_list(&req_list); | ||
492 | } | ||
493 | |||
494 | int hwa742_update_window_async(struct fb_info *fbi, | ||
495 | struct omapfb_update_window *win, | ||
496 | void (*complete_callback)(void *arg), | ||
497 | void *complete_callback_data) | ||
498 | { | ||
499 | LIST_HEAD(req_list); | ||
500 | struct hwa742_request *last; | ||
501 | int r = 0; | ||
502 | |||
503 | if (hwa742.update_mode != OMAPFB_MANUAL_UPDATE) { | ||
504 | dev_dbg(hwa742.fbdev->dev, "invalid update mode\n"); | ||
505 | r = -EINVAL; | ||
506 | goto out; | ||
507 | } | ||
508 | if (unlikely(win->format & | ||
509 | ~(0x03 | OMAPFB_FORMAT_FLAG_DOUBLE | | ||
510 | OMAPFB_FORMAT_FLAG_TEARSYNC | OMAPFB_FORMAT_FLAG_FORCE_VSYNC))) { | ||
511 | dev_dbg(hwa742.fbdev->dev, "invalid window flag"); | ||
512 | r = -EINVAL; | ||
513 | goto out; | ||
514 | } | ||
515 | |||
516 | create_req_list(win, &req_list); | ||
517 | last = list_entry(req_list.prev, struct hwa742_request, entry); | ||
518 | |||
519 | last->complete = complete_callback; | ||
520 | last->complete_data = (void *)complete_callback_data; | ||
521 | |||
522 | submit_req_list(&req_list); | ||
523 | |||
524 | out: | ||
525 | return r; | ||
526 | } | ||
527 | EXPORT_SYMBOL(hwa742_update_window_async); | ||
528 | |||
529 | static int hwa742_setup_plane(int plane, int channel_out, | ||
530 | unsigned long offset, int screen_width, | ||
531 | int pos_x, int pos_y, int width, int height, | ||
532 | int color_mode) | ||
533 | { | ||
534 | if (plane != OMAPFB_PLANE_GFX || | ||
535 | channel_out != OMAPFB_CHANNEL_OUT_LCD) | ||
536 | return -EINVAL; | ||
537 | |||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | static int hwa742_enable_plane(int plane, int enable) | ||
542 | { | ||
543 | if (plane != 0) | ||
544 | return -EINVAL; | ||
545 | |||
546 | hwa742.int_ctrl->enable_plane(plane, enable); | ||
547 | |||
548 | return 0; | ||
549 | } | ||
550 | |||
551 | static int sync_handler(struct hwa742_request *req) | ||
552 | { | ||
553 | complete(req->par.sync); | ||
554 | return REQ_COMPLETE; | ||
555 | } | ||
556 | |||
557 | static void hwa742_sync(void) | ||
558 | { | ||
559 | LIST_HEAD(req_list); | ||
560 | struct hwa742_request *req; | ||
561 | struct completion comp; | ||
562 | |||
563 | req = alloc_req(); | ||
564 | |||
565 | req->handler = sync_handler; | ||
566 | req->complete = NULL; | ||
567 | init_completion(&comp); | ||
568 | req->par.sync = ∁ | ||
569 | |||
570 | list_add(&req->entry, &req_list); | ||
571 | submit_req_list(&req_list); | ||
572 | |||
573 | wait_for_completion(&comp); | ||
574 | } | ||
575 | |||
576 | static void hwa742_bind_client(struct omapfb_notifier_block *nb) | ||
577 | { | ||
578 | dev_dbg(hwa742.fbdev->dev, "update_mode %d\n", hwa742.update_mode); | ||
579 | if (hwa742.update_mode == OMAPFB_MANUAL_UPDATE) { | ||
580 | omapfb_notify_clients(hwa742.fbdev, OMAPFB_EVENT_READY); | ||
581 | } | ||
582 | } | ||
583 | |||
584 | static int hwa742_set_update_mode(enum omapfb_update_mode mode) | ||
585 | { | ||
586 | if (mode != OMAPFB_MANUAL_UPDATE && mode != OMAPFB_AUTO_UPDATE && | ||
587 | mode != OMAPFB_UPDATE_DISABLED) | ||
588 | return -EINVAL; | ||
589 | |||
590 | if (mode == hwa742.update_mode) | ||
591 | return 0; | ||
592 | |||
593 | dev_info(hwa742.fbdev->dev, "HWA742: setting update mode to %s\n", | ||
594 | mode == OMAPFB_UPDATE_DISABLED ? "disabled" : | ||
595 | (mode == OMAPFB_AUTO_UPDATE ? "auto" : "manual")); | ||
596 | |||
597 | switch (hwa742.update_mode) { | ||
598 | case OMAPFB_MANUAL_UPDATE: | ||
599 | omapfb_notify_clients(hwa742.fbdev, OMAPFB_EVENT_DISABLED); | ||
600 | break; | ||
601 | case OMAPFB_AUTO_UPDATE: | ||
602 | hwa742.stop_auto_update = 1; | ||
603 | del_timer_sync(&hwa742.auto_update_timer); | ||
604 | break; | ||
605 | case OMAPFB_UPDATE_DISABLED: | ||
606 | break; | ||
607 | } | ||
608 | |||
609 | hwa742.update_mode = mode; | ||
610 | hwa742_sync(); | ||
611 | hwa742.stop_auto_update = 0; | ||
612 | |||
613 | switch (mode) { | ||
614 | case OMAPFB_MANUAL_UPDATE: | ||
615 | omapfb_notify_clients(hwa742.fbdev, OMAPFB_EVENT_READY); | ||
616 | break; | ||
617 | case OMAPFB_AUTO_UPDATE: | ||
618 | hwa742_update_window_auto(0); | ||
619 | break; | ||
620 | case OMAPFB_UPDATE_DISABLED: | ||
621 | break; | ||
622 | } | ||
623 | |||
624 | return 0; | ||
625 | } | ||
626 | |||
627 | static enum omapfb_update_mode hwa742_get_update_mode(void) | ||
628 | { | ||
629 | return hwa742.update_mode; | ||
630 | } | ||
631 | |||
632 | static unsigned long round_to_extif_ticks(unsigned long ps, int div) | ||
633 | { | ||
634 | int bus_tick = hwa742.extif_clk_period * div; | ||
635 | return (ps + bus_tick - 1) / bus_tick * bus_tick; | ||
636 | } | ||
637 | |||
638 | static int calc_reg_timing(unsigned long sysclk, int div) | ||
639 | { | ||
640 | struct extif_timings *t; | ||
641 | unsigned long systim; | ||
642 | |||
643 | /* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns, | ||
644 | * AccessTime 2 ns + 12.2 ns (regs), | ||
645 | * WEOffTime = WEOnTime + 1 ns, | ||
646 | * REOffTime = REOnTime + 16 ns (regs), | ||
647 | * CSOffTime = REOffTime + 1 ns | ||
648 | * ReadCycle = 2ns + 2*SYSCLK (regs), | ||
649 | * WriteCycle = 2*SYSCLK + 2 ns, | ||
650 | * CSPulseWidth = 10 ns */ | ||
651 | systim = 1000000000 / (sysclk / 1000); | ||
652 | dev_dbg(hwa742.fbdev->dev, "HWA742 systim %lu ps extif_clk_period %u ps" | ||
653 | "extif_clk_div %d\n", systim, hwa742.extif_clk_period, div); | ||
654 | |||
655 | t = &hwa742.reg_timings; | ||
656 | memset(t, 0, sizeof(*t)); | ||
657 | t->clk_div = div; | ||
658 | t->cs_on_time = 0; | ||
659 | t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
660 | t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
661 | t->access_time = round_to_extif_ticks(t->re_on_time + 12200, div); | ||
662 | t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div); | ||
663 | t->re_off_time = round_to_extif_ticks(t->re_on_time + 16000, div); | ||
664 | t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div); | ||
665 | t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div); | ||
666 | if (t->we_cycle_time < t->we_off_time) | ||
667 | t->we_cycle_time = t->we_off_time; | ||
668 | t->re_cycle_time = round_to_extif_ticks(2 * systim + 2000, div); | ||
669 | if (t->re_cycle_time < t->re_off_time) | ||
670 | t->re_cycle_time = t->re_off_time; | ||
671 | t->cs_pulse_width = 0; | ||
672 | |||
673 | dev_dbg(hwa742.fbdev->dev, "[reg]cson %d csoff %d reon %d reoff %d\n", | ||
674 | t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time); | ||
675 | dev_dbg(hwa742.fbdev->dev, "[reg]weon %d weoff %d recyc %d wecyc %d\n", | ||
676 | t->we_on_time, t->we_off_time, t->re_cycle_time, | ||
677 | t->we_cycle_time); | ||
678 | dev_dbg(hwa742.fbdev->dev, "[reg]rdaccess %d cspulse %d\n", | ||
679 | t->access_time, t->cs_pulse_width); | ||
680 | |||
681 | return hwa742.extif->convert_timings(t); | ||
682 | } | ||
683 | |||
684 | static int calc_lut_timing(unsigned long sysclk, int div) | ||
685 | { | ||
686 | struct extif_timings *t; | ||
687 | unsigned long systim; | ||
688 | |||
689 | /* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns, | ||
690 | * AccessTime 2 ns + 4 * SYSCLK + 26 (lut), | ||
691 | * WEOffTime = WEOnTime + 1 ns, | ||
692 | * REOffTime = REOnTime + 4*SYSCLK + 26 ns (lut), | ||
693 | * CSOffTime = REOffTime + 1 ns | ||
694 | * ReadCycle = 2ns + 4*SYSCLK + 26 ns (lut), | ||
695 | * WriteCycle = 2*SYSCLK + 2 ns, | ||
696 | * CSPulseWidth = 10 ns | ||
697 | */ | ||
698 | systim = 1000000000 / (sysclk / 1000); | ||
699 | dev_dbg(hwa742.fbdev->dev, "HWA742 systim %lu ps extif_clk_period %u ps" | ||
700 | "extif_clk_div %d\n", systim, hwa742.extif_clk_period, div); | ||
701 | |||
702 | t = &hwa742.lut_timings; | ||
703 | memset(t, 0, sizeof(*t)); | ||
704 | |||
705 | t->clk_div = div; | ||
706 | |||
707 | t->cs_on_time = 0; | ||
708 | t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
709 | t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div); | ||
710 | t->access_time = round_to_extif_ticks(t->re_on_time + 4 * systim + | ||
711 | 26000, div); | ||
712 | t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div); | ||
713 | t->re_off_time = round_to_extif_ticks(t->re_on_time + 4 * systim + | ||
714 | 26000, div); | ||
715 | t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div); | ||
716 | t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div); | ||
717 | if (t->we_cycle_time < t->we_off_time) | ||
718 | t->we_cycle_time = t->we_off_time; | ||
719 | t->re_cycle_time = round_to_extif_ticks(2000 + 4 * systim + 26000, div); | ||
720 | if (t->re_cycle_time < t->re_off_time) | ||
721 | t->re_cycle_time = t->re_off_time; | ||
722 | t->cs_pulse_width = 0; | ||
723 | |||
724 | dev_dbg(hwa742.fbdev->dev, "[lut]cson %d csoff %d reon %d reoff %d\n", | ||
725 | t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time); | ||
726 | dev_dbg(hwa742.fbdev->dev, "[lut]weon %d weoff %d recyc %d wecyc %d\n", | ||
727 | t->we_on_time, t->we_off_time, t->re_cycle_time, | ||
728 | t->we_cycle_time); | ||
729 | dev_dbg(hwa742.fbdev->dev, "[lut]rdaccess %d cspulse %d\n", | ||
730 | t->access_time, t->cs_pulse_width); | ||
731 | |||
732 | return hwa742.extif->convert_timings(t); | ||
733 | } | ||
734 | |||
735 | static int calc_extif_timings(unsigned long sysclk, int *extif_mem_div) | ||
736 | { | ||
737 | int max_clk_div; | ||
738 | int div; | ||
739 | |||
740 | hwa742.extif->get_clk_info(&hwa742.extif_clk_period, &max_clk_div); | ||
741 | for (div = 1; div < max_clk_div; div++) { | ||
742 | if (calc_reg_timing(sysclk, div) == 0) | ||
743 | break; | ||
744 | } | ||
745 | if (div > max_clk_div) | ||
746 | goto err; | ||
747 | |||
748 | *extif_mem_div = div; | ||
749 | |||
750 | for (div = 1; div < max_clk_div; div++) { | ||
751 | if (calc_lut_timing(sysclk, div) == 0) | ||
752 | break; | ||
753 | } | ||
754 | |||
755 | if (div > max_clk_div) | ||
756 | goto err; | ||
757 | |||
758 | return 0; | ||
759 | |||
760 | err: | ||
761 | dev_err(hwa742.fbdev->dev, "can't setup timings\n"); | ||
762 | return -1; | ||
763 | } | ||
764 | |||
765 | static void calc_hwa742_clk_rates(unsigned long ext_clk, | ||
766 | unsigned long *sys_clk, unsigned long *pix_clk) | ||
767 | { | ||
768 | int pix_clk_src; | ||
769 | int sys_div = 0, sys_mul = 0; | ||
770 | int pix_div; | ||
771 | |||
772 | pix_clk_src = hwa742_read_reg(HWA742_CLK_SRC_REG); | ||
773 | pix_div = ((pix_clk_src >> 3) & 0x1f) + 1; | ||
774 | if ((pix_clk_src & (0x3 << 1)) == 0) { | ||
775 | /* Source is the PLL */ | ||
776 | sys_div = (hwa742_read_reg(HWA742_PLL_DIV_REG) & 0x3f) + 1; | ||
777 | sys_mul = (hwa742_read_reg(HWA742_PLL_4_REG) & 0x7f) + 1; | ||
778 | *sys_clk = ext_clk * sys_mul / sys_div; | ||
779 | } else /* else source is ext clk, or oscillator */ | ||
780 | *sys_clk = ext_clk; | ||
781 | |||
782 | *pix_clk = *sys_clk / pix_div; /* HZ */ | ||
783 | dev_dbg(hwa742.fbdev->dev, | ||
784 | "ext_clk %ld pix_src %d pix_div %d sys_div %d sys_mul %d\n", | ||
785 | ext_clk, pix_clk_src & (0x3 << 1), pix_div, sys_div, sys_mul); | ||
786 | dev_dbg(hwa742.fbdev->dev, "sys_clk %ld pix_clk %ld\n", | ||
787 | *sys_clk, *pix_clk); | ||
788 | } | ||
789 | |||
790 | |||
791 | static int setup_tearsync(unsigned long pix_clk, int extif_div) | ||
792 | { | ||
793 | int hdisp, vdisp; | ||
794 | int hndp, vndp; | ||
795 | int hsw, vsw; | ||
796 | int hs, vs; | ||
797 | int hs_pol_inv, vs_pol_inv; | ||
798 | int use_hsvs, use_ndp; | ||
799 | u8 b; | ||
800 | |||
801 | hsw = hwa742_read_reg(HWA742_HS_W_REG); | ||
802 | vsw = hwa742_read_reg(HWA742_VS_W_REG); | ||
803 | hs_pol_inv = !(hsw & 0x80); | ||
804 | vs_pol_inv = !(vsw & 0x80); | ||
805 | hsw = hsw & 0x7f; | ||
806 | vsw = vsw & 0x3f; | ||
807 | |||
808 | hdisp = (hwa742_read_reg(HWA742_H_DISP_REG) & 0x7f) * 8; | ||
809 | vdisp = hwa742_read_reg(HWA742_V_DISP_1_REG) + | ||
810 | ((hwa742_read_reg(HWA742_V_DISP_2_REG) & 0x3) << 8); | ||
811 | |||
812 | hndp = hwa742_read_reg(HWA742_H_NDP_REG) & 0x7f; | ||
813 | vndp = hwa742_read_reg(HWA742_V_NDP_REG); | ||
814 | |||
815 | /* time to transfer one pixel (16bpp) in ps */ | ||
816 | hwa742.pix_tx_time = hwa742.reg_timings.we_cycle_time; | ||
817 | if (hwa742.extif->get_max_tx_rate != NULL) { | ||
818 | /* | ||
819 | * The external interface might have a rate limitation, | ||
820 | * if so, we have to maximize our transfer rate. | ||
821 | */ | ||
822 | unsigned long min_tx_time; | ||
823 | unsigned long max_tx_rate = hwa742.extif->get_max_tx_rate(); | ||
824 | |||
825 | dev_dbg(hwa742.fbdev->dev, "max_tx_rate %ld HZ\n", | ||
826 | max_tx_rate); | ||
827 | min_tx_time = 1000000000 / (max_tx_rate / 1000); /* ps */ | ||
828 | if (hwa742.pix_tx_time < min_tx_time) | ||
829 | hwa742.pix_tx_time = min_tx_time; | ||
830 | } | ||
831 | |||
832 | /* time to update one line in ps */ | ||
833 | hwa742.line_upd_time = (hdisp + hndp) * 1000000 / (pix_clk / 1000); | ||
834 | hwa742.line_upd_time *= 1000; | ||
835 | if (hdisp * hwa742.pix_tx_time > hwa742.line_upd_time) | ||
836 | /* | ||
837 | * transfer speed too low, we might have to use both | ||
838 | * HS and VS | ||
839 | */ | ||
840 | use_hsvs = 1; | ||
841 | else | ||
842 | /* decent transfer speed, we'll always use only VS */ | ||
843 | use_hsvs = 0; | ||
844 | |||
845 | if (use_hsvs && (hs_pol_inv || vs_pol_inv)) { | ||
846 | /* | ||
847 | * HS or'ed with VS doesn't work, use the active high | ||
848 | * TE signal based on HNDP / VNDP | ||
849 | */ | ||
850 | use_ndp = 1; | ||
851 | hs_pol_inv = 0; | ||
852 | vs_pol_inv = 0; | ||
853 | hs = hndp; | ||
854 | vs = vndp; | ||
855 | } else { | ||
856 | /* | ||
857 | * Use HS or'ed with VS as a TE signal if both are needed | ||
858 | * or VNDP if only vsync is needed. | ||
859 | */ | ||
860 | use_ndp = 0; | ||
861 | hs = hsw; | ||
862 | vs = vsw; | ||
863 | if (!use_hsvs) { | ||
864 | hs_pol_inv = 0; | ||
865 | vs_pol_inv = 0; | ||
866 | } | ||
867 | } | ||
868 | |||
869 | hs = hs * 1000000 / (pix_clk / 1000); /* ps */ | ||
870 | hs *= 1000; | ||
871 | |||
872 | vs = vs * (hdisp + hndp) * 1000000 / (pix_clk / 1000); /* ps */ | ||
873 | vs *= 1000; | ||
874 | |||
875 | if (vs <= hs) | ||
876 | return -EDOM; | ||
877 | /* set VS to 120% of HS to minimize VS detection time */ | ||
878 | vs = hs * 12 / 10; | ||
879 | /* minimize HS too */ | ||
880 | hs = 10000; | ||
881 | |||
882 | b = hwa742_read_reg(HWA742_NDP_CTRL); | ||
883 | b &= ~0x3; | ||
884 | b |= use_hsvs ? 1 : 0; | ||
885 | b |= (use_ndp && use_hsvs) ? 0 : 2; | ||
886 | hwa742_write_reg(HWA742_NDP_CTRL, b); | ||
887 | |||
888 | hwa742.vsync_only = !use_hsvs; | ||
889 | |||
890 | dev_dbg(hwa742.fbdev->dev, | ||
891 | "pix_clk %ld HZ pix_tx_time %ld ps line_upd_time %ld ps\n", | ||
892 | pix_clk, hwa742.pix_tx_time, hwa742.line_upd_time); | ||
893 | dev_dbg(hwa742.fbdev->dev, | ||
894 | "hs %d ps vs %d ps mode %d vsync_only %d\n", | ||
895 | hs, vs, (b & 0x3), !use_hsvs); | ||
896 | |||
897 | return hwa742.extif->setup_tearsync(1, hs, vs, | ||
898 | hs_pol_inv, vs_pol_inv, extif_div); | ||
899 | } | ||
900 | |||
901 | static void hwa742_get_caps(int plane, struct omapfb_caps *caps) | ||
902 | { | ||
903 | hwa742.int_ctrl->get_caps(plane, caps); | ||
904 | caps->ctrl |= OMAPFB_CAPS_MANUAL_UPDATE | | ||
905 | OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE; | ||
906 | if (hwa742.te_connected) | ||
907 | caps->ctrl |= OMAPFB_CAPS_TEARSYNC; | ||
908 | caps->wnd_color |= (1 << OMAPFB_COLOR_RGB565) | | ||
909 | (1 << OMAPFB_COLOR_YUV420); | ||
910 | } | ||
911 | |||
912 | static void hwa742_suspend(void) | ||
913 | { | ||
914 | hwa742.update_mode_before_suspend = hwa742.update_mode; | ||
915 | hwa742_set_update_mode(OMAPFB_UPDATE_DISABLED); | ||
916 | /* Enable sleep mode */ | ||
917 | hwa742_write_reg(HWA742_POWER_SAVE, 1 << 1); | ||
918 | if (hwa742.power_down != NULL) | ||
919 | hwa742.power_down(hwa742.fbdev->dev); | ||
920 | } | ||
921 | |||
922 | static void hwa742_resume(void) | ||
923 | { | ||
924 | if (hwa742.power_up != NULL) | ||
925 | hwa742.power_up(hwa742.fbdev->dev); | ||
926 | /* Disable sleep mode */ | ||
927 | hwa742_write_reg(HWA742_POWER_SAVE, 0); | ||
928 | while (1) { | ||
929 | /* Loop until PLL output is stabilized */ | ||
930 | if (hwa742_read_reg(HWA742_PLL_DIV_REG) & (1 << 7)) | ||
931 | break; | ||
932 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
933 | schedule_timeout(msecs_to_jiffies(5)); | ||
934 | } | ||
935 | hwa742_set_update_mode(hwa742.update_mode_before_suspend); | ||
936 | } | ||
937 | |||
938 | static int hwa742_init(struct omapfb_device *fbdev, int ext_mode, | ||
939 | struct omapfb_mem_desc *req_vram) | ||
940 | { | ||
941 | int r = 0, i; | ||
942 | u8 rev, conf; | ||
943 | unsigned long ext_clk; | ||
944 | unsigned long sys_clk, pix_clk; | ||
945 | int extif_mem_div; | ||
946 | struct omapfb_platform_data *omapfb_conf; | ||
947 | struct hwa742_platform_data *ctrl_conf; | ||
948 | |||
949 | BUG_ON(!fbdev->ext_if || !fbdev->int_ctrl); | ||
950 | |||
951 | hwa742.fbdev = fbdev; | ||
952 | hwa742.extif = fbdev->ext_if; | ||
953 | hwa742.int_ctrl = fbdev->int_ctrl; | ||
954 | |||
955 | omapfb_conf = fbdev->dev->platform_data; | ||
956 | ctrl_conf = omapfb_conf->ctrl_platform_data; | ||
957 | |||
958 | if (ctrl_conf == NULL || ctrl_conf->get_clock_rate == NULL) { | ||
959 | dev_err(fbdev->dev, "HWA742: missing platform data\n"); | ||
960 | r = -ENOENT; | ||
961 | goto err1; | ||
962 | } | ||
963 | |||
964 | hwa742.power_down = ctrl_conf->power_down; | ||
965 | hwa742.power_up = ctrl_conf->power_up; | ||
966 | |||
967 | spin_lock_init(&hwa742.req_lock); | ||
968 | |||
969 | if ((r = hwa742.int_ctrl->init(fbdev, 1, req_vram)) < 0) | ||
970 | goto err1; | ||
971 | |||
972 | if ((r = hwa742.extif->init(fbdev)) < 0) | ||
973 | goto err2; | ||
974 | |||
975 | ext_clk = ctrl_conf->get_clock_rate(fbdev->dev); | ||
976 | if ((r = calc_extif_timings(ext_clk, &extif_mem_div)) < 0) | ||
977 | goto err3; | ||
978 | hwa742.extif->set_timings(&hwa742.reg_timings); | ||
979 | if (hwa742.power_up != NULL) | ||
980 | hwa742.power_up(fbdev->dev); | ||
981 | |||
982 | calc_hwa742_clk_rates(ext_clk, &sys_clk, &pix_clk); | ||
983 | if ((r = calc_extif_timings(sys_clk, &extif_mem_div)) < 0) | ||
984 | goto err4; | ||
985 | hwa742.extif->set_timings(&hwa742.reg_timings); | ||
986 | |||
987 | rev = hwa742_read_reg(HWA742_REV_CODE_REG); | ||
988 | if ((rev & 0xfc) != 0x80) { | ||
989 | dev_err(fbdev->dev, "HWA742: invalid revision %02x\n", rev); | ||
990 | r = -ENODEV; | ||
991 | goto err4; | ||
992 | } | ||
993 | |||
994 | |||
995 | if (!(hwa742_read_reg(HWA742_PLL_DIV_REG) & 0x80)) { | ||
996 | dev_err(fbdev->dev, | ||
997 | "HWA742: controller not initialized by the bootloader\n"); | ||
998 | r = -ENODEV; | ||
999 | goto err4; | ||
1000 | } | ||
1001 | |||
1002 | if (ctrl_conf->te_connected) { | ||
1003 | if ((r = setup_tearsync(pix_clk, extif_mem_div)) < 0) { | ||
1004 | dev_err(hwa742.fbdev->dev, | ||
1005 | "HWA742: can't setup tearing synchronization\n"); | ||
1006 | goto err4; | ||
1007 | } | ||
1008 | hwa742.te_connected = 1; | ||
1009 | } | ||
1010 | |||
1011 | hwa742.max_transmit_size = hwa742.extif->max_transmit_size; | ||
1012 | |||
1013 | hwa742.update_mode = OMAPFB_UPDATE_DISABLED; | ||
1014 | |||
1015 | hwa742.auto_update_window.x = 0; | ||
1016 | hwa742.auto_update_window.y = 0; | ||
1017 | hwa742.auto_update_window.width = fbdev->panel->x_res; | ||
1018 | hwa742.auto_update_window.height = fbdev->panel->y_res; | ||
1019 | hwa742.auto_update_window.format = 0; | ||
1020 | |||
1021 | init_timer(&hwa742.auto_update_timer); | ||
1022 | hwa742.auto_update_timer.function = hwa742_update_window_auto; | ||
1023 | hwa742.auto_update_timer.data = 0; | ||
1024 | |||
1025 | hwa742.prev_color_mode = -1; | ||
1026 | hwa742.prev_flags = 0; | ||
1027 | |||
1028 | hwa742.fbdev = fbdev; | ||
1029 | |||
1030 | INIT_LIST_HEAD(&hwa742.free_req_list); | ||
1031 | INIT_LIST_HEAD(&hwa742.pending_req_list); | ||
1032 | for (i = 0; i < ARRAY_SIZE(hwa742.req_pool); i++) | ||
1033 | list_add(&hwa742.req_pool[i].entry, &hwa742.free_req_list); | ||
1034 | BUG_ON(i <= IRQ_REQ_POOL_SIZE); | ||
1035 | sema_init(&hwa742.req_sema, i - IRQ_REQ_POOL_SIZE); | ||
1036 | |||
1037 | conf = hwa742_read_reg(HWA742_CONFIG_REG); | ||
1038 | dev_info(fbdev->dev, ": Epson HWA742 LCD controller rev %d " | ||
1039 | "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07); | ||
1040 | |||
1041 | return 0; | ||
1042 | err4: | ||
1043 | if (hwa742.power_down != NULL) | ||
1044 | hwa742.power_down(fbdev->dev); | ||
1045 | err3: | ||
1046 | hwa742.extif->cleanup(); | ||
1047 | err2: | ||
1048 | hwa742.int_ctrl->cleanup(); | ||
1049 | err1: | ||
1050 | return r; | ||
1051 | } | ||
1052 | |||
1053 | static void hwa742_cleanup(void) | ||
1054 | { | ||
1055 | hwa742_set_update_mode(OMAPFB_UPDATE_DISABLED); | ||
1056 | hwa742.extif->cleanup(); | ||
1057 | hwa742.int_ctrl->cleanup(); | ||
1058 | if (hwa742.power_down != NULL) | ||
1059 | hwa742.power_down(hwa742.fbdev->dev); | ||
1060 | } | ||
1061 | |||
1062 | struct lcd_ctrl hwa742_ctrl = { | ||
1063 | .name = "hwa742", | ||
1064 | .init = hwa742_init, | ||
1065 | .cleanup = hwa742_cleanup, | ||
1066 | .bind_client = hwa742_bind_client, | ||
1067 | .get_caps = hwa742_get_caps, | ||
1068 | .set_update_mode = hwa742_set_update_mode, | ||
1069 | .get_update_mode = hwa742_get_update_mode, | ||
1070 | .setup_plane = hwa742_setup_plane, | ||
1071 | .enable_plane = hwa742_enable_plane, | ||
1072 | .update_window = hwa742_update_window_async, | ||
1073 | .sync = hwa742_sync, | ||
1074 | .suspend = hwa742_suspend, | ||
1075 | .resume = hwa742_resume, | ||
1076 | }; | ||
1077 | |||
diff --git a/drivers/video/omap/lcd_h3.c b/drivers/video/omap/lcd_h3.c new file mode 100644 index 000000000000..51807b4e26d1 --- /dev/null +++ b/drivers/video/omap/lcd_h3.c | |||
@@ -0,0 +1,141 @@ | |||
1 | /* | ||
2 | * LCD panel support for the TI OMAP H3 board | ||
3 | * | ||
4 | * Copyright (C) 2004 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 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | |||
25 | #include <asm/arch/gpio.h> | ||
26 | #include <asm/arch/tps65010.h> | ||
27 | #include <asm/arch/omapfb.h> | ||
28 | |||
29 | #define MODULE_NAME "omapfb-lcd_h3" | ||
30 | |||
31 | #define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args) | ||
32 | |||
33 | static int h3_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev) | ||
34 | { | ||
35 | return 0; | ||
36 | } | ||
37 | |||
38 | static void h3_panel_cleanup(struct lcd_panel *panel) | ||
39 | { | ||
40 | } | ||
41 | |||
42 | static int h3_panel_enable(struct lcd_panel *panel) | ||
43 | { | ||
44 | int r = 0; | ||
45 | |||
46 | /* GPIO1 and GPIO2 of TPS65010 send LCD_ENBKL and LCD_ENVDD signals */ | ||
47 | r = tps65010_set_gpio_out_value(GPIO1, HIGH); | ||
48 | if (!r) | ||
49 | r = tps65010_set_gpio_out_value(GPIO2, HIGH); | ||
50 | if (r) | ||
51 | pr_err("Unable to turn on LCD panel\n"); | ||
52 | |||
53 | return r; | ||
54 | } | ||
55 | |||
56 | static void h3_panel_disable(struct lcd_panel *panel) | ||
57 | { | ||
58 | int r = 0; | ||
59 | |||
60 | /* GPIO1 and GPIO2 of TPS65010 send LCD_ENBKL and LCD_ENVDD signals */ | ||
61 | r = tps65010_set_gpio_out_value(GPIO1, LOW); | ||
62 | if (!r) | ||
63 | tps65010_set_gpio_out_value(GPIO2, LOW); | ||
64 | if (r) | ||
65 | pr_err("Unable to turn off LCD panel\n"); | ||
66 | } | ||
67 | |||
68 | static unsigned long h3_panel_get_caps(struct lcd_panel *panel) | ||
69 | { | ||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | struct lcd_panel h3_panel = { | ||
74 | .name = "h3", | ||
75 | .config = OMAP_LCDC_PANEL_TFT, | ||
76 | |||
77 | .data_lines = 16, | ||
78 | .bpp = 16, | ||
79 | .x_res = 240, | ||
80 | .y_res = 320, | ||
81 | .pixel_clock = 12000, | ||
82 | .hsw = 12, | ||
83 | .hfp = 14, | ||
84 | .hbp = 72 - 12, | ||
85 | .vsw = 1, | ||
86 | .vfp = 1, | ||
87 | .vbp = 0, | ||
88 | .pcd = 0, | ||
89 | |||
90 | .init = h3_panel_init, | ||
91 | .cleanup = h3_panel_cleanup, | ||
92 | .enable = h3_panel_enable, | ||
93 | .disable = h3_panel_disable, | ||
94 | .get_caps = h3_panel_get_caps, | ||
95 | }; | ||
96 | |||
97 | static int h3_panel_probe(struct platform_device *pdev) | ||
98 | { | ||
99 | omapfb_register_panel(&h3_panel); | ||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static int h3_panel_remove(struct platform_device *pdev) | ||
104 | { | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static int h3_panel_suspend(struct platform_device *pdev, pm_message_t mesg) | ||
109 | { | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static int h3_panel_resume(struct platform_device *pdev) | ||
114 | { | ||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | struct platform_driver h3_panel_driver = { | ||
119 | .probe = h3_panel_probe, | ||
120 | .remove = h3_panel_remove, | ||
121 | .suspend = h3_panel_suspend, | ||
122 | .resume = h3_panel_resume, | ||
123 | .driver = { | ||
124 | .name = "lcd_h3", | ||
125 | .owner = THIS_MODULE, | ||
126 | }, | ||
127 | }; | ||
128 | |||
129 | static int h3_panel_drv_init(void) | ||
130 | { | ||
131 | return platform_driver_register(&h3_panel_driver); | ||
132 | } | ||
133 | |||
134 | static void h3_panel_drv_cleanup(void) | ||
135 | { | ||
136 | platform_driver_unregister(&h3_panel_driver); | ||
137 | } | ||
138 | |||
139 | module_init(h3_panel_drv_init); | ||
140 | module_exit(h3_panel_drv_cleanup); | ||
141 | |||
diff --git a/drivers/video/omap/lcd_h4.c b/drivers/video/omap/lcd_h4.c new file mode 100644 index 000000000000..fd6f0eb16de1 --- /dev/null +++ b/drivers/video/omap/lcd_h4.c | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * LCD panel support for the TI OMAP H4 board | ||
3 | * | ||
4 | * Copyright (C) 2004 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 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | |||
25 | #include <asm/arch/omapfb.h> | ||
26 | |||
27 | static int h4_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev) | ||
28 | { | ||
29 | return 0; | ||
30 | } | ||
31 | |||
32 | static void h4_panel_cleanup(struct lcd_panel *panel) | ||
33 | { | ||
34 | } | ||
35 | |||
36 | static int h4_panel_enable(struct lcd_panel *panel) | ||
37 | { | ||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | static void h4_panel_disable(struct lcd_panel *panel) | ||
42 | { | ||
43 | } | ||
44 | |||
45 | static unsigned long h4_panel_get_caps(struct lcd_panel *panel) | ||
46 | { | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | struct lcd_panel h4_panel = { | ||
51 | .name = "h4", | ||
52 | .config = OMAP_LCDC_PANEL_TFT, | ||
53 | |||
54 | .bpp = 16, | ||
55 | .data_lines = 16, | ||
56 | .x_res = 240, | ||
57 | .y_res = 320, | ||
58 | .pixel_clock = 6250, | ||
59 | .hsw = 15, | ||
60 | .hfp = 15, | ||
61 | .hbp = 60, | ||
62 | .vsw = 1, | ||
63 | .vfp = 1, | ||
64 | .vbp = 1, | ||
65 | |||
66 | .init = h4_panel_init, | ||
67 | .cleanup = h4_panel_cleanup, | ||
68 | .enable = h4_panel_enable, | ||
69 | .disable = h4_panel_disable, | ||
70 | .get_caps = h4_panel_get_caps, | ||
71 | }; | ||
72 | |||
73 | static int h4_panel_probe(struct platform_device *pdev) | ||
74 | { | ||
75 | omapfb_register_panel(&h4_panel); | ||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | static int h4_panel_remove(struct platform_device *pdev) | ||
80 | { | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int h4_panel_suspend(struct platform_device *pdev, pm_message_t mesg) | ||
85 | { | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static int h4_panel_resume(struct platform_device *pdev) | ||
90 | { | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | struct platform_driver h4_panel_driver = { | ||
95 | .probe = h4_panel_probe, | ||
96 | .remove = h4_panel_remove, | ||
97 | .suspend = h4_panel_suspend, | ||
98 | .resume = h4_panel_resume, | ||
99 | .driver = { | ||
100 | .name = "lcd_h4", | ||
101 | .owner = THIS_MODULE, | ||
102 | }, | ||
103 | }; | ||
104 | |||
105 | static int h4_panel_drv_init(void) | ||
106 | { | ||
107 | return platform_driver_register(&h4_panel_driver); | ||
108 | } | ||
109 | |||
110 | static void h4_panel_drv_cleanup(void) | ||
111 | { | ||
112 | platform_driver_unregister(&h4_panel_driver); | ||
113 | } | ||
114 | |||
115 | module_init(h4_panel_drv_init); | ||
116 | module_exit(h4_panel_drv_cleanup); | ||
117 | |||
diff --git a/drivers/video/omap/lcd_inn1510.c b/drivers/video/omap/lcd_inn1510.c new file mode 100644 index 000000000000..551f385861d1 --- /dev/null +++ b/drivers/video/omap/lcd_inn1510.c | |||
@@ -0,0 +1,124 @@ | |||
1 | /* | ||
2 | * LCD panel support for the TI OMAP1510 Innovator board | ||
3 | * | ||
4 | * Copyright (C) 2004 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 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/io.h> | ||
25 | |||
26 | #include <asm/arch/fpga.h> | ||
27 | #include <asm/arch/omapfb.h> | ||
28 | |||
29 | static int innovator1510_panel_init(struct lcd_panel *panel, | ||
30 | struct omapfb_device *fbdev) | ||
31 | { | ||
32 | return 0; | ||
33 | } | ||
34 | |||
35 | static void innovator1510_panel_cleanup(struct lcd_panel *panel) | ||
36 | { | ||
37 | } | ||
38 | |||
39 | static int innovator1510_panel_enable(struct lcd_panel *panel) | ||
40 | { | ||
41 | fpga_write(0x7, OMAP1510_FPGA_LCD_PANEL_CONTROL); | ||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | static void innovator1510_panel_disable(struct lcd_panel *panel) | ||
46 | { | ||
47 | fpga_write(0x0, OMAP1510_FPGA_LCD_PANEL_CONTROL); | ||
48 | } | ||
49 | |||
50 | static unsigned long innovator1510_panel_get_caps(struct lcd_panel *panel) | ||
51 | { | ||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | struct lcd_panel innovator1510_panel = { | ||
56 | .name = "inn1510", | ||
57 | .config = OMAP_LCDC_PANEL_TFT, | ||
58 | |||
59 | .bpp = 16, | ||
60 | .data_lines = 16, | ||
61 | .x_res = 240, | ||
62 | .y_res = 320, | ||
63 | .pixel_clock = 12500, | ||
64 | .hsw = 40, | ||
65 | .hfp = 40, | ||
66 | .hbp = 72, | ||
67 | .vsw = 1, | ||
68 | .vfp = 1, | ||
69 | .vbp = 0, | ||
70 | .pcd = 12, | ||
71 | |||
72 | .init = innovator1510_panel_init, | ||
73 | .cleanup = innovator1510_panel_cleanup, | ||
74 | .enable = innovator1510_panel_enable, | ||
75 | .disable = innovator1510_panel_disable, | ||
76 | .get_caps = innovator1510_panel_get_caps, | ||
77 | }; | ||
78 | |||
79 | static int innovator1510_panel_probe(struct platform_device *pdev) | ||
80 | { | ||
81 | omapfb_register_panel(&innovator1510_panel); | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static int innovator1510_panel_remove(struct platform_device *pdev) | ||
86 | { | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static int innovator1510_panel_suspend(struct platform_device *pdev, | ||
91 | pm_message_t mesg) | ||
92 | { | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int innovator1510_panel_resume(struct platform_device *pdev) | ||
97 | { | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | struct platform_driver innovator1510_panel_driver = { | ||
102 | .probe = innovator1510_panel_probe, | ||
103 | .remove = innovator1510_panel_remove, | ||
104 | .suspend = innovator1510_panel_suspend, | ||
105 | .resume = innovator1510_panel_resume, | ||
106 | .driver = { | ||
107 | .name = "lcd_inn1510", | ||
108 | .owner = THIS_MODULE, | ||
109 | }, | ||
110 | }; | ||
111 | |||
112 | static int innovator1510_panel_drv_init(void) | ||
113 | { | ||
114 | return platform_driver_register(&innovator1510_panel_driver); | ||
115 | } | ||
116 | |||
117 | static void innovator1510_panel_drv_cleanup(void) | ||
118 | { | ||
119 | platform_driver_unregister(&innovator1510_panel_driver); | ||
120 | } | ||
121 | |||
122 | module_init(innovator1510_panel_drv_init); | ||
123 | module_exit(innovator1510_panel_drv_cleanup); | ||
124 | |||
diff --git a/drivers/video/omap/lcd_inn1610.c b/drivers/video/omap/lcd_inn1610.c new file mode 100644 index 000000000000..95604ca43301 --- /dev/null +++ b/drivers/video/omap/lcd_inn1610.c | |||
@@ -0,0 +1,150 @@ | |||
1 | /* | ||
2 | * LCD panel support for the TI OMAP1610 Innovator board | ||
3 | * | ||
4 | * Copyright (C) 2004 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 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | |||
25 | #include <asm/arch/gpio.h> | ||
26 | #include <asm/arch/omapfb.h> | ||
27 | |||
28 | #define MODULE_NAME "omapfb-lcd_h3" | ||
29 | |||
30 | #define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args) | ||
31 | |||
32 | static int innovator1610_panel_init(struct lcd_panel *panel, | ||
33 | struct omapfb_device *fbdev) | ||
34 | { | ||
35 | int r = 0; | ||
36 | |||
37 | if (omap_request_gpio(14)) { | ||
38 | pr_err("can't request GPIO 14\n"); | ||
39 | r = -1; | ||
40 | goto exit; | ||
41 | } | ||
42 | if (omap_request_gpio(15)) { | ||
43 | pr_err("can't request GPIO 15\n"); | ||
44 | omap_free_gpio(14); | ||
45 | r = -1; | ||
46 | goto exit; | ||
47 | } | ||
48 | /* configure GPIO(14, 15) as outputs */ | ||
49 | omap_set_gpio_direction(14, 0); | ||
50 | omap_set_gpio_direction(15, 0); | ||
51 | exit: | ||
52 | return r; | ||
53 | } | ||
54 | |||
55 | static void innovator1610_panel_cleanup(struct lcd_panel *panel) | ||
56 | { | ||
57 | omap_free_gpio(15); | ||
58 | omap_free_gpio(14); | ||
59 | } | ||
60 | |||
61 | static int innovator1610_panel_enable(struct lcd_panel *panel) | ||
62 | { | ||
63 | /* set GPIO14 and GPIO15 high */ | ||
64 | omap_set_gpio_dataout(14, 1); | ||
65 | omap_set_gpio_dataout(15, 1); | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static void innovator1610_panel_disable(struct lcd_panel *panel) | ||
70 | { | ||
71 | /* set GPIO13, GPIO14 and GPIO15 low */ | ||
72 | omap_set_gpio_dataout(14, 0); | ||
73 | omap_set_gpio_dataout(15, 0); | ||
74 | } | ||
75 | |||
76 | static unsigned long innovator1610_panel_get_caps(struct lcd_panel *panel) | ||
77 | { | ||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | struct lcd_panel innovator1610_panel = { | ||
82 | .name = "inn1610", | ||
83 | .config = OMAP_LCDC_PANEL_TFT, | ||
84 | |||
85 | .bpp = 16, | ||
86 | .data_lines = 16, | ||
87 | .x_res = 320, | ||
88 | .y_res = 240, | ||
89 | .pixel_clock = 12500, | ||
90 | .hsw = 40, | ||
91 | .hfp = 40, | ||
92 | .hbp = 72, | ||
93 | .vsw = 1, | ||
94 | .vfp = 1, | ||
95 | .vbp = 0, | ||
96 | .pcd = 12, | ||
97 | |||
98 | .init = innovator1610_panel_init, | ||
99 | .cleanup = innovator1610_panel_cleanup, | ||
100 | .enable = innovator1610_panel_enable, | ||
101 | .disable = innovator1610_panel_disable, | ||
102 | .get_caps = innovator1610_panel_get_caps, | ||
103 | }; | ||
104 | |||
105 | static int innovator1610_panel_probe(struct platform_device *pdev) | ||
106 | { | ||
107 | omapfb_register_panel(&innovator1610_panel); | ||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static int innovator1610_panel_remove(struct platform_device *pdev) | ||
112 | { | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static int innovator1610_panel_suspend(struct platform_device *pdev, | ||
117 | pm_message_t mesg) | ||
118 | { | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | static int innovator1610_panel_resume(struct platform_device *pdev) | ||
123 | { | ||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | struct platform_driver innovator1610_panel_driver = { | ||
128 | .probe = innovator1610_panel_probe, | ||
129 | .remove = innovator1610_panel_remove, | ||
130 | .suspend = innovator1610_panel_suspend, | ||
131 | .resume = innovator1610_panel_resume, | ||
132 | .driver = { | ||
133 | .name = "lcd_inn1610", | ||
134 | .owner = THIS_MODULE, | ||
135 | }, | ||
136 | }; | ||
137 | |||
138 | static int innovator1610_panel_drv_init(void) | ||
139 | { | ||
140 | return platform_driver_register(&innovator1610_panel_driver); | ||
141 | } | ||
142 | |||
143 | static void innovator1610_panel_drv_cleanup(void) | ||
144 | { | ||
145 | platform_driver_unregister(&innovator1610_panel_driver); | ||
146 | } | ||
147 | |||
148 | module_init(innovator1610_panel_drv_init); | ||
149 | module_exit(innovator1610_panel_drv_cleanup); | ||
150 | |||
diff --git a/drivers/video/omap/lcd_osk.c b/drivers/video/omap/lcd_osk.c new file mode 100644 index 000000000000..a38038840fd6 --- /dev/null +++ b/drivers/video/omap/lcd_osk.c | |||
@@ -0,0 +1,144 @@ | |||
1 | /* | ||
2 | * LCD panel support for the TI OMAP OSK board | ||
3 | * | ||
4 | * Copyright (C) 2004 Nokia Corporation | ||
5 | * Author: Imre Deak <imre.deak@nokia.com> | ||
6 | * Adapted for OSK by <dirk.behme@de.bosch.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 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | |||
26 | #include <asm/arch/gpio.h> | ||
27 | #include <asm/arch/mux.h> | ||
28 | #include <asm/arch/omapfb.h> | ||
29 | |||
30 | static int osk_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev) | ||
31 | { | ||
32 | return 0; | ||
33 | } | ||
34 | |||
35 | static void osk_panel_cleanup(struct lcd_panel *panel) | ||
36 | { | ||
37 | } | ||
38 | |||
39 | static int osk_panel_enable(struct lcd_panel *panel) | ||
40 | { | ||
41 | /* configure PWL pin */ | ||
42 | omap_cfg_reg(PWL); | ||
43 | |||
44 | /* Enable PWL unit */ | ||
45 | omap_writeb(0x01, OMAP_PWL_CLK_ENABLE); | ||
46 | |||
47 | /* Set PWL level */ | ||
48 | omap_writeb(0xFF, OMAP_PWL_ENABLE); | ||
49 | |||
50 | /* configure GPIO2 as output */ | ||
51 | omap_set_gpio_direction(2, 0); | ||
52 | |||
53 | /* set GPIO2 high */ | ||
54 | omap_set_gpio_dataout(2, 1); | ||
55 | |||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | static void osk_panel_disable(struct lcd_panel *panel) | ||
60 | { | ||
61 | /* Set PWL level to zero */ | ||
62 | omap_writeb(0x00, OMAP_PWL_ENABLE); | ||
63 | |||
64 | /* Disable PWL unit */ | ||
65 | omap_writeb(0x00, OMAP_PWL_CLK_ENABLE); | ||
66 | |||
67 | /* set GPIO2 low */ | ||
68 | omap_set_gpio_dataout(2, 0); | ||
69 | } | ||
70 | |||
71 | static unsigned long osk_panel_get_caps(struct lcd_panel *panel) | ||
72 | { | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | struct lcd_panel osk_panel = { | ||
77 | .name = "osk", | ||
78 | .config = OMAP_LCDC_PANEL_TFT, | ||
79 | |||
80 | .bpp = 16, | ||
81 | .data_lines = 16, | ||
82 | .x_res = 240, | ||
83 | .y_res = 320, | ||
84 | .pixel_clock = 12500, | ||
85 | .hsw = 40, | ||
86 | .hfp = 40, | ||
87 | .hbp = 72, | ||
88 | .vsw = 1, | ||
89 | .vfp = 1, | ||
90 | .vbp = 0, | ||
91 | .pcd = 12, | ||
92 | |||
93 | .init = osk_panel_init, | ||
94 | .cleanup = osk_panel_cleanup, | ||
95 | .enable = osk_panel_enable, | ||
96 | .disable = osk_panel_disable, | ||
97 | .get_caps = osk_panel_get_caps, | ||
98 | }; | ||
99 | |||
100 | static int osk_panel_probe(struct platform_device *pdev) | ||
101 | { | ||
102 | omapfb_register_panel(&osk_panel); | ||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static int osk_panel_remove(struct platform_device *pdev) | ||
107 | { | ||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static int osk_panel_suspend(struct platform_device *pdev, pm_message_t mesg) | ||
112 | { | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static int osk_panel_resume(struct platform_device *pdev) | ||
117 | { | ||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | struct platform_driver osk_panel_driver = { | ||
122 | .probe = osk_panel_probe, | ||
123 | .remove = osk_panel_remove, | ||
124 | .suspend = osk_panel_suspend, | ||
125 | .resume = osk_panel_resume, | ||
126 | .driver = { | ||
127 | .name = "lcd_osk", | ||
128 | .owner = THIS_MODULE, | ||
129 | }, | ||
130 | }; | ||
131 | |||
132 | static int osk_panel_drv_init(void) | ||
133 | { | ||
134 | return platform_driver_register(&osk_panel_driver); | ||
135 | } | ||
136 | |||
137 | static void osk_panel_drv_cleanup(void) | ||
138 | { | ||
139 | platform_driver_unregister(&osk_panel_driver); | ||
140 | } | ||
141 | |||
142 | module_init(osk_panel_drv_init); | ||
143 | module_exit(osk_panel_drv_cleanup); | ||
144 | |||
diff --git a/drivers/video/omap/lcd_palmte.c b/drivers/video/omap/lcd_palmte.c new file mode 100644 index 000000000000..52bdfdac42c9 --- /dev/null +++ b/drivers/video/omap/lcd_palmte.c | |||
@@ -0,0 +1,123 @@ | |||
1 | /* | ||
2 | * LCD panel support for the Palm Tungsten E | ||
3 | * | ||
4 | * Original version : Romain Goyet <r.goyet@gmail.com> | ||
5 | * Current version : Laurent Gonzalez <palmte.linux@free.fr> | ||
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 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/io.h> | ||
25 | |||
26 | #include <asm/arch/fpga.h> | ||
27 | #include <asm/arch/omapfb.h> | ||
28 | |||
29 | static int palmte_panel_init(struct lcd_panel *panel, | ||
30 | struct omapfb_device *fbdev) | ||
31 | { | ||
32 | return 0; | ||
33 | } | ||
34 | |||
35 | static void palmte_panel_cleanup(struct lcd_panel *panel) | ||
36 | { | ||
37 | } | ||
38 | |||
39 | static int palmte_panel_enable(struct lcd_panel *panel) | ||
40 | { | ||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | static void palmte_panel_disable(struct lcd_panel *panel) | ||
45 | { | ||
46 | } | ||
47 | |||
48 | static unsigned long palmte_panel_get_caps(struct lcd_panel *panel) | ||
49 | { | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | struct lcd_panel palmte_panel = { | ||
54 | .name = "palmte", | ||
55 | .config = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC | | ||
56 | OMAP_LCDC_INV_HSYNC | OMAP_LCDC_HSVS_RISING_EDGE | | ||
57 | OMAP_LCDC_HSVS_OPPOSITE, | ||
58 | |||
59 | .data_lines = 16, | ||
60 | .bpp = 8, | ||
61 | .pixel_clock = 12000, | ||
62 | .x_res = 320, | ||
63 | .y_res = 320, | ||
64 | .hsw = 4, | ||
65 | .hfp = 8, | ||
66 | .hbp = 28, | ||
67 | .vsw = 1, | ||
68 | .vfp = 8, | ||
69 | .vbp = 7, | ||
70 | .pcd = 0, | ||
71 | |||
72 | .init = palmte_panel_init, | ||
73 | .cleanup = palmte_panel_cleanup, | ||
74 | .enable = palmte_panel_enable, | ||
75 | .disable = palmte_panel_disable, | ||
76 | .get_caps = palmte_panel_get_caps, | ||
77 | }; | ||
78 | |||
79 | static int palmte_panel_probe(struct platform_device *pdev) | ||
80 | { | ||
81 | omapfb_register_panel(&palmte_panel); | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static int palmte_panel_remove(struct platform_device *pdev) | ||
86 | { | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static int palmte_panel_suspend(struct platform_device *pdev, pm_message_t mesg) | ||
91 | { | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static int palmte_panel_resume(struct platform_device *pdev) | ||
96 | { | ||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | struct platform_driver palmte_panel_driver = { | ||
101 | .probe = palmte_panel_probe, | ||
102 | .remove = palmte_panel_remove, | ||
103 | .suspend = palmte_panel_suspend, | ||
104 | .resume = palmte_panel_resume, | ||
105 | .driver = { | ||
106 | .name = "lcd_palmte", | ||
107 | .owner = THIS_MODULE, | ||
108 | }, | ||
109 | }; | ||
110 | |||
111 | static int palmte_panel_drv_init(void) | ||
112 | { | ||
113 | return platform_driver_register(&palmte_panel_driver); | ||
114 | } | ||
115 | |||
116 | static void palmte_panel_drv_cleanup(void) | ||
117 | { | ||
118 | platform_driver_unregister(&palmte_panel_driver); | ||
119 | } | ||
120 | |||
121 | module_init(palmte_panel_drv_init); | ||
122 | module_exit(palmte_panel_drv_cleanup); | ||
123 | |||
diff --git a/drivers/video/omap/lcd_palmtt.c b/drivers/video/omap/lcd_palmtt.c new file mode 100644 index 000000000000..4bb349f54356 --- /dev/null +++ b/drivers/video/omap/lcd_palmtt.c | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | * LCD panel support for Palm Tungsten|T | ||
3 | * Current version : Marek Vasut <marek.vasut@gmail.com> | ||
4 | * | ||
5 | * Modified from lcd_inn1510.c | ||
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 | |||
22 | /* | ||
23 | GPIO11 - backlight | ||
24 | GPIO12 - screen blanking | ||
25 | GPIO13 - screen blanking | ||
26 | */ | ||
27 | |||
28 | #include <linux/platform_device.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/io.h> | ||
31 | |||
32 | #include <asm/arch/gpio.h> | ||
33 | #include <asm/arch/omapfb.h> | ||
34 | |||
35 | static int palmtt_panel_init(struct lcd_panel *panel, | ||
36 | struct omapfb_device *fbdev) | ||
37 | { | ||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | static void palmtt_panel_cleanup(struct lcd_panel *panel) | ||
42 | { | ||
43 | } | ||
44 | |||
45 | static int palmtt_panel_enable(struct lcd_panel *panel) | ||
46 | { | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | static void palmtt_panel_disable(struct lcd_panel *panel) | ||
51 | { | ||
52 | } | ||
53 | |||
54 | static unsigned long palmtt_panel_get_caps(struct lcd_panel *panel) | ||
55 | { | ||
56 | return OMAPFB_CAPS_SET_BACKLIGHT; | ||
57 | } | ||
58 | |||
59 | struct lcd_panel palmtt_panel = { | ||
60 | .name = "palmtt", | ||
61 | .config = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC | | ||
62 | OMAP_LCDC_INV_HSYNC | OMAP_LCDC_HSVS_RISING_EDGE | | ||
63 | OMAP_LCDC_HSVS_OPPOSITE, | ||
64 | .bpp = 16, | ||
65 | .data_lines = 16, | ||
66 | .x_res = 320, | ||
67 | .y_res = 320, | ||
68 | .pixel_clock = 10000, | ||
69 | .hsw = 4, | ||
70 | .hfp = 8, | ||
71 | .hbp = 28, | ||
72 | .vsw = 1, | ||
73 | .vfp = 8, | ||
74 | .vbp = 7, | ||
75 | .pcd = 0, | ||
76 | |||
77 | .init = palmtt_panel_init, | ||
78 | .cleanup = palmtt_panel_cleanup, | ||
79 | .enable = palmtt_panel_enable, | ||
80 | .disable = palmtt_panel_disable, | ||
81 | .get_caps = palmtt_panel_get_caps, | ||
82 | }; | ||
83 | |||
84 | static int palmtt_panel_probe(struct platform_device *pdev) | ||
85 | { | ||
86 | omapfb_register_panel(&palmtt_panel); | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static int palmtt_panel_remove(struct platform_device *pdev) | ||
91 | { | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static int palmtt_panel_suspend(struct platform_device *pdev, pm_message_t mesg) | ||
96 | { | ||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | static int palmtt_panel_resume(struct platform_device *pdev) | ||
101 | { | ||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | struct platform_driver palmtt_panel_driver = { | ||
106 | .probe = palmtt_panel_probe, | ||
107 | .remove = palmtt_panel_remove, | ||
108 | .suspend = palmtt_panel_suspend, | ||
109 | .resume = palmtt_panel_resume, | ||
110 | .driver = { | ||
111 | .name = "lcd_palmtt", | ||
112 | .owner = THIS_MODULE, | ||
113 | }, | ||
114 | }; | ||
115 | |||
116 | static int palmtt_panel_drv_init(void) | ||
117 | { | ||
118 | return platform_driver_register(&palmtt_panel_driver); | ||
119 | } | ||
120 | |||
121 | static void palmtt_panel_drv_cleanup(void) | ||
122 | { | ||
123 | platform_driver_unregister(&palmtt_panel_driver); | ||
124 | } | ||
125 | |||
126 | module_init(palmtt_panel_drv_init); | ||
127 | module_exit(palmtt_panel_drv_cleanup); | ||
diff --git a/drivers/video/omap/lcd_palmz71.c b/drivers/video/omap/lcd_palmz71.c new file mode 100644 index 000000000000..ea6170ddff35 --- /dev/null +++ b/drivers/video/omap/lcd_palmz71.c | |||
@@ -0,0 +1,123 @@ | |||
1 | /* | ||
2 | * LCD panel support for the Palm Zire71 | ||
3 | * | ||
4 | * Original version : Romain Goyet | ||
5 | * Current version : Laurent Gonzalez | ||
6 | * Modified for zire71 : Marek Vasut | ||
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 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/io.h> | ||
26 | |||
27 | #include <asm/arch/omapfb.h> | ||
28 | |||
29 | static int palmz71_panel_init(struct lcd_panel *panel, | ||
30 | struct omapfb_device *fbdev) | ||
31 | { | ||
32 | return 0; | ||
33 | } | ||
34 | |||
35 | static void palmz71_panel_cleanup(struct lcd_panel *panel) | ||
36 | { | ||
37 | |||
38 | } | ||
39 | |||
40 | static int palmz71_panel_enable(struct lcd_panel *panel) | ||
41 | { | ||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | static void palmz71_panel_disable(struct lcd_panel *panel) | ||
46 | { | ||
47 | } | ||
48 | |||
49 | static unsigned long palmz71_panel_get_caps(struct lcd_panel *panel) | ||
50 | { | ||
51 | return OMAPFB_CAPS_SET_BACKLIGHT; | ||
52 | } | ||
53 | |||
54 | struct lcd_panel palmz71_panel = { | ||
55 | .name = "palmz71", | ||
56 | .config = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC | | ||
57 | OMAP_LCDC_INV_HSYNC | OMAP_LCDC_HSVS_RISING_EDGE | | ||
58 | OMAP_LCDC_HSVS_OPPOSITE, | ||
59 | .data_lines = 16, | ||
60 | .bpp = 16, | ||
61 | .pixel_clock = 24000, | ||
62 | .x_res = 320, | ||
63 | .y_res = 320, | ||
64 | .hsw = 4, | ||
65 | .hfp = 8, | ||
66 | .hbp = 28, | ||
67 | .vsw = 1, | ||
68 | .vfp = 8, | ||
69 | .vbp = 7, | ||
70 | .pcd = 0, | ||
71 | |||
72 | .init = palmz71_panel_init, | ||
73 | .cleanup = palmz71_panel_cleanup, | ||
74 | .enable = palmz71_panel_enable, | ||
75 | .disable = palmz71_panel_disable, | ||
76 | .get_caps = palmz71_panel_get_caps, | ||
77 | }; | ||
78 | |||
79 | static int palmz71_panel_probe(struct platform_device *pdev) | ||
80 | { | ||
81 | omapfb_register_panel(&palmz71_panel); | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static int palmz71_panel_remove(struct platform_device *pdev) | ||
86 | { | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static int palmz71_panel_suspend(struct platform_device *pdev, | ||
91 | pm_message_t mesg) | ||
92 | { | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int palmz71_panel_resume(struct platform_device *pdev) | ||
97 | { | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | struct platform_driver palmz71_panel_driver = { | ||
102 | .probe = palmz71_panel_probe, | ||
103 | .remove = palmz71_panel_remove, | ||
104 | .suspend = palmz71_panel_suspend, | ||
105 | .resume = palmz71_panel_resume, | ||
106 | .driver = { | ||
107 | .name = "lcd_palmz71", | ||
108 | .owner = THIS_MODULE, | ||
109 | }, | ||
110 | }; | ||
111 | |||
112 | static int palmz71_panel_drv_init(void) | ||
113 | { | ||
114 | return platform_driver_register(&palmz71_panel_driver); | ||
115 | } | ||
116 | |||
117 | static void palmz71_panel_drv_cleanup(void) | ||
118 | { | ||
119 | platform_driver_unregister(&palmz71_panel_driver); | ||
120 | } | ||
121 | |||
122 | module_init(palmz71_panel_drv_init); | ||
123 | module_exit(palmz71_panel_drv_cleanup); | ||
diff --git a/drivers/video/omap/lcd_sx1.c b/drivers/video/omap/lcd_sx1.c new file mode 100644 index 000000000000..c4f306a4e5c9 --- /dev/null +++ b/drivers/video/omap/lcd_sx1.c | |||
@@ -0,0 +1,334 @@ | |||
1 | /* | ||
2 | * LCD panel support for the Siemens SX1 mobile phone | ||
3 | * | ||
4 | * Current version : Vovan888@gmail.com, great help from FCA00000 | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/io.h> | ||
25 | |||
26 | #include <asm/arch/gpio.h> | ||
27 | #include <asm/arch/omapfb.h> | ||
28 | #include <asm/arch/mcbsp.h> | ||
29 | #include <asm/arch/mux.h> | ||
30 | |||
31 | /* | ||
32 | * OMAP310 GPIO registers | ||
33 | */ | ||
34 | #define GPIO_DATA_INPUT 0xfffce000 | ||
35 | #define GPIO_DATA_OUTPUT 0xfffce004 | ||
36 | #define GPIO_DIR_CONTROL 0xfffce008 | ||
37 | #define GPIO_INT_CONTROL 0xfffce00c | ||
38 | #define GPIO_INT_MASK 0xfffce010 | ||
39 | #define GPIO_INT_STATUS 0xfffce014 | ||
40 | #define GPIO_PIN_CONTROL 0xfffce018 | ||
41 | |||
42 | |||
43 | #define A_LCD_SSC_RD 3 | ||
44 | #define A_LCD_SSC_SD 7 | ||
45 | #define _A_LCD_RESET 9 | ||
46 | #define _A_LCD_SSC_CS 12 | ||
47 | #define _A_LCD_SSC_A0 13 | ||
48 | |||
49 | #define DSP_REG 0xE1017024 | ||
50 | |||
51 | const unsigned char INIT_1[12] = { | ||
52 | 0x1C, 0x02, 0x88, 0x00, 0x1E, 0xE0, 0x00, 0xDC, 0x00, 0x02, 0x00 | ||
53 | }; | ||
54 | |||
55 | const unsigned char INIT_2[127] = { | ||
56 | 0x15, 0x00, 0x29, 0x00, 0x3E, 0x00, 0x51, 0x00, | ||
57 | 0x65, 0x00, 0x7A, 0x00, 0x8D, 0x00, 0xA1, 0x00, | ||
58 | 0xB6, 0x00, 0xC7, 0x00, 0xD8, 0x00, 0xEB, 0x00, | ||
59 | 0xFB, 0x00, 0x0B, 0x01, 0x1B, 0x01, 0x27, 0x01, | ||
60 | 0x34, 0x01, 0x41, 0x01, 0x4C, 0x01, 0x55, 0x01, | ||
61 | 0x5F, 0x01, 0x68, 0x01, 0x70, 0x01, 0x78, 0x01, | ||
62 | 0x7E, 0x01, 0x86, 0x01, 0x8C, 0x01, 0x94, 0x01, | ||
63 | 0x9B, 0x01, 0xA1, 0x01, 0xA4, 0x01, 0xA9, 0x01, | ||
64 | 0xAD, 0x01, 0xB2, 0x01, 0xB7, 0x01, 0xBC, 0x01, | ||
65 | 0xC0, 0x01, 0xC4, 0x01, 0xC8, 0x01, 0xCB, 0x01, | ||
66 | 0xCF, 0x01, 0xD2, 0x01, 0xD5, 0x01, 0xD8, 0x01, | ||
67 | 0xDB, 0x01, 0xE0, 0x01, 0xE3, 0x01, 0xE6, 0x01, | ||
68 | 0xE8, 0x01, 0xEB, 0x01, 0xEE, 0x01, 0xF1, 0x01, | ||
69 | 0xF3, 0x01, 0xF8, 0x01, 0xF9, 0x01, 0xFC, 0x01, | ||
70 | 0x00, 0x02, 0x03, 0x02, 0x07, 0x02, 0x09, 0x02, | ||
71 | 0x0E, 0x02, 0x13, 0x02, 0x1C, 0x02, 0x00 | ||
72 | }; | ||
73 | |||
74 | const unsigned char INIT_3[15] = { | ||
75 | 0x14, 0x26, 0x33, 0x3D, 0x45, 0x4D, 0x53, 0x59, | ||
76 | 0x5E, 0x63, 0x67, 0x6D, 0x71, 0x78, 0xFF | ||
77 | }; | ||
78 | |||
79 | static void epson_sendbyte(int flag, unsigned char byte) | ||
80 | { | ||
81 | int i, shifter = 0x80; | ||
82 | |||
83 | if (!flag) | ||
84 | omap_set_gpio_dataout(_A_LCD_SSC_A0, 0); | ||
85 | mdelay(2); | ||
86 | omap_set_gpio_dataout(A_LCD_SSC_RD, 1); | ||
87 | |||
88 | omap_set_gpio_dataout(A_LCD_SSC_SD, flag); | ||
89 | |||
90 | OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2200); | ||
91 | OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2202); | ||
92 | for (i = 0; i < 8; i++) { | ||
93 | OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2200); | ||
94 | omap_set_gpio_dataout(A_LCD_SSC_SD, shifter & byte); | ||
95 | OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2202); | ||
96 | shifter >>= 1; | ||
97 | } | ||
98 | omap_set_gpio_dataout(_A_LCD_SSC_A0, 1); | ||
99 | } | ||
100 | |||
101 | static void init_system(void) | ||
102 | { | ||
103 | omap_mcbsp_request(OMAP_MCBSP3); | ||
104 | omap_mcbsp_stop(OMAP_MCBSP3); | ||
105 | } | ||
106 | |||
107 | static void setup_GPIO(void) | ||
108 | { | ||
109 | /* new wave */ | ||
110 | omap_request_gpio(A_LCD_SSC_RD); | ||
111 | omap_request_gpio(A_LCD_SSC_SD); | ||
112 | omap_request_gpio(_A_LCD_RESET); | ||
113 | omap_request_gpio(_A_LCD_SSC_CS); | ||
114 | omap_request_gpio(_A_LCD_SSC_A0); | ||
115 | |||
116 | /* set all GPIOs to output */ | ||
117 | omap_set_gpio_direction(A_LCD_SSC_RD, 0); | ||
118 | omap_set_gpio_direction(A_LCD_SSC_SD, 0); | ||
119 | omap_set_gpio_direction(_A_LCD_RESET, 0); | ||
120 | omap_set_gpio_direction(_A_LCD_SSC_CS, 0); | ||
121 | omap_set_gpio_direction(_A_LCD_SSC_A0, 0); | ||
122 | |||
123 | /* set GPIO data */ | ||
124 | omap_set_gpio_dataout(A_LCD_SSC_RD, 1); | ||
125 | omap_set_gpio_dataout(A_LCD_SSC_SD, 0); | ||
126 | omap_set_gpio_dataout(_A_LCD_RESET, 0); | ||
127 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
128 | omap_set_gpio_dataout(_A_LCD_SSC_A0, 1); | ||
129 | } | ||
130 | |||
131 | static void display_init(void) | ||
132 | { | ||
133 | int i; | ||
134 | |||
135 | omap_cfg_reg(MCBSP3_CLKX); | ||
136 | |||
137 | mdelay(2); | ||
138 | setup_GPIO(); | ||
139 | mdelay(2); | ||
140 | |||
141 | /* reset LCD */ | ||
142 | omap_set_gpio_dataout(A_LCD_SSC_SD, 1); | ||
143 | epson_sendbyte(0, 0x25); | ||
144 | |||
145 | omap_set_gpio_dataout(_A_LCD_RESET, 0); | ||
146 | mdelay(10); | ||
147 | omap_set_gpio_dataout(_A_LCD_RESET, 1); | ||
148 | |||
149 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
150 | mdelay(2); | ||
151 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); | ||
152 | |||
153 | /* init LCD, phase 1 */ | ||
154 | epson_sendbyte(0, 0xCA); | ||
155 | for (i = 0; i < 10; i++) | ||
156 | epson_sendbyte(1, INIT_1[i]); | ||
157 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
158 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); | ||
159 | |||
160 | /* init LCD phase 2 */ | ||
161 | epson_sendbyte(0, 0xCB); | ||
162 | for (i = 0; i < 125; i++) | ||
163 | epson_sendbyte(1, INIT_2[i]); | ||
164 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
165 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); | ||
166 | |||
167 | /* init LCD phase 2a */ | ||
168 | epson_sendbyte(0, 0xCC); | ||
169 | for (i = 0; i < 14; i++) | ||
170 | epson_sendbyte(1, INIT_3[i]); | ||
171 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
172 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); | ||
173 | |||
174 | /* init LCD phase 3 */ | ||
175 | epson_sendbyte(0, 0xBC); | ||
176 | epson_sendbyte(1, 0x08); | ||
177 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
178 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); | ||
179 | |||
180 | /* init LCD phase 4 */ | ||
181 | epson_sendbyte(0, 0x07); | ||
182 | epson_sendbyte(1, 0x05); | ||
183 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
184 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); | ||
185 | |||
186 | /* init LCD phase 5 */ | ||
187 | epson_sendbyte(0, 0x94); | ||
188 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
189 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); | ||
190 | |||
191 | /* init LCD phase 6 */ | ||
192 | epson_sendbyte(0, 0xC6); | ||
193 | epson_sendbyte(1, 0x80); | ||
194 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
195 | mdelay(100); /* used to be 1000 */ | ||
196 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); | ||
197 | |||
198 | /* init LCD phase 7 */ | ||
199 | epson_sendbyte(0, 0x16); | ||
200 | epson_sendbyte(1, 0x02); | ||
201 | epson_sendbyte(1, 0x00); | ||
202 | epson_sendbyte(1, 0xB1); | ||
203 | epson_sendbyte(1, 0x00); | ||
204 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
205 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); | ||
206 | |||
207 | /* init LCD phase 8 */ | ||
208 | epson_sendbyte(0, 0x76); | ||
209 | epson_sendbyte(1, 0x00); | ||
210 | epson_sendbyte(1, 0x00); | ||
211 | epson_sendbyte(1, 0xDB); | ||
212 | epson_sendbyte(1, 0x00); | ||
213 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
214 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); | ||
215 | |||
216 | /* init LCD phase 9 */ | ||
217 | epson_sendbyte(0, 0xAF); | ||
218 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
219 | } | ||
220 | |||
221 | static int sx1_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev) | ||
222 | { | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static void sx1_panel_cleanup(struct lcd_panel *panel) | ||
227 | { | ||
228 | } | ||
229 | |||
230 | static void sx1_panel_disable(struct lcd_panel *panel) | ||
231 | { | ||
232 | printk(KERN_INFO "SX1: LCD panel disable\n"); | ||
233 | sx1_setmmipower(0); | ||
234 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
235 | |||
236 | epson_sendbyte(0, 0x25); | ||
237 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); | ||
238 | |||
239 | epson_sendbyte(0, 0xAE); | ||
240 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
241 | mdelay(100); | ||
242 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); | ||
243 | |||
244 | epson_sendbyte(0, 0x95); | ||
245 | omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); | ||
246 | } | ||
247 | |||
248 | static int sx1_panel_enable(struct lcd_panel *panel) | ||
249 | { | ||
250 | printk(KERN_INFO "lcd_sx1: LCD panel enable\n"); | ||
251 | init_system(); | ||
252 | display_init(); | ||
253 | |||
254 | sx1_setmmipower(1); | ||
255 | sx1_setbacklight(0x18); | ||
256 | sx1_setkeylight (0x06); | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | |||
261 | static unsigned long sx1_panel_get_caps(struct lcd_panel *panel) | ||
262 | { | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | struct lcd_panel sx1_panel = { | ||
267 | .name = "sx1", | ||
268 | .config = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC | | ||
269 | OMAP_LCDC_INV_HSYNC | OMAP_LCDC_INV_PIX_CLOCK | | ||
270 | OMAP_LCDC_INV_OUTPUT_EN, | ||
271 | |||
272 | .x_res = 176, | ||
273 | .y_res = 220, | ||
274 | .data_lines = 16, | ||
275 | .bpp = 16, | ||
276 | .hsw = 5, | ||
277 | .hfp = 5, | ||
278 | .hbp = 5, | ||
279 | .vsw = 2, | ||
280 | .vfp = 1, | ||
281 | .vbp = 1, | ||
282 | .pixel_clock = 1500, | ||
283 | |||
284 | .init = sx1_panel_init, | ||
285 | .cleanup = sx1_panel_cleanup, | ||
286 | .enable = sx1_panel_enable, | ||
287 | .disable = sx1_panel_disable, | ||
288 | .get_caps = sx1_panel_get_caps, | ||
289 | }; | ||
290 | |||
291 | static int sx1_panel_probe(struct platform_device *pdev) | ||
292 | { | ||
293 | omapfb_register_panel(&sx1_panel); | ||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | static int sx1_panel_remove(struct platform_device *pdev) | ||
298 | { | ||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | static int sx1_panel_suspend(struct platform_device *pdev, pm_message_t mesg) | ||
303 | { | ||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | static int sx1_panel_resume(struct platform_device *pdev) | ||
308 | { | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | struct platform_driver sx1_panel_driver = { | ||
313 | .probe = sx1_panel_probe, | ||
314 | .remove = sx1_panel_remove, | ||
315 | .suspend = sx1_panel_suspend, | ||
316 | .resume = sx1_panel_resume, | ||
317 | .driver = { | ||
318 | .name = "lcd_sx1", | ||
319 | .owner = THIS_MODULE, | ||
320 | }, | ||
321 | }; | ||
322 | |||
323 | static int sx1_panel_drv_init(void) | ||
324 | { | ||
325 | return platform_driver_register(&sx1_panel_driver); | ||
326 | } | ||
327 | |||
328 | static void sx1_panel_drv_cleanup(void) | ||
329 | { | ||
330 | platform_driver_unregister(&sx1_panel_driver); | ||
331 | } | ||
332 | |||
333 | module_init(sx1_panel_drv_init); | ||
334 | module_exit(sx1_panel_drv_cleanup); | ||
diff --git a/drivers/video/omap/lcdc.c b/drivers/video/omap/lcdc.c new file mode 100644 index 000000000000..9085188d815e --- /dev/null +++ b/drivers/video/omap/lcdc.c | |||
@@ -0,0 +1,893 @@ | |||
1 | /* | ||
2 | * OMAP1 internal LCD controller | ||
3 | * | ||
4 | * Copyright (C) 2004 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/module.h> | ||
22 | #include <linux/device.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/spinlock.h> | ||
25 | #include <linux/err.h> | ||
26 | #include <linux/mm.h> | ||
27 | #include <linux/fb.h> | ||
28 | #include <linux/dma-mapping.h> | ||
29 | #include <linux/vmalloc.h> | ||
30 | #include <linux/clk.h> | ||
31 | |||
32 | #include <asm/arch/dma.h> | ||
33 | #include <asm/arch/omapfb.h> | ||
34 | |||
35 | #include <asm/mach-types.h> | ||
36 | |||
37 | #define MODULE_NAME "lcdc" | ||
38 | |||
39 | #define OMAP_LCDC_BASE 0xfffec000 | ||
40 | #define OMAP_LCDC_SIZE 256 | ||
41 | #define OMAP_LCDC_IRQ INT_LCD_CTRL | ||
42 | |||
43 | #define OMAP_LCDC_CONTROL (OMAP_LCDC_BASE + 0x00) | ||
44 | #define OMAP_LCDC_TIMING0 (OMAP_LCDC_BASE + 0x04) | ||
45 | #define OMAP_LCDC_TIMING1 (OMAP_LCDC_BASE + 0x08) | ||
46 | #define OMAP_LCDC_TIMING2 (OMAP_LCDC_BASE + 0x0c) | ||
47 | #define OMAP_LCDC_STATUS (OMAP_LCDC_BASE + 0x10) | ||
48 | #define OMAP_LCDC_SUBPANEL (OMAP_LCDC_BASE + 0x14) | ||
49 | #define OMAP_LCDC_LINE_INT (OMAP_LCDC_BASE + 0x18) | ||
50 | #define OMAP_LCDC_DISPLAY_STATUS (OMAP_LCDC_BASE + 0x1c) | ||
51 | |||
52 | #define OMAP_LCDC_STAT_DONE (1 << 0) | ||
53 | #define OMAP_LCDC_STAT_VSYNC (1 << 1) | ||
54 | #define OMAP_LCDC_STAT_SYNC_LOST (1 << 2) | ||
55 | #define OMAP_LCDC_STAT_ABC (1 << 3) | ||
56 | #define OMAP_LCDC_STAT_LINE_INT (1 << 4) | ||
57 | #define OMAP_LCDC_STAT_FUF (1 << 5) | ||
58 | #define OMAP_LCDC_STAT_LOADED_PALETTE (1 << 6) | ||
59 | |||
60 | #define OMAP_LCDC_CTRL_LCD_EN (1 << 0) | ||
61 | #define OMAP_LCDC_CTRL_LCD_TFT (1 << 7) | ||
62 | #define OMAP_LCDC_CTRL_LINE_IRQ_CLR_SEL (1 << 10) | ||
63 | |||
64 | #define OMAP_LCDC_IRQ_VSYNC (1 << 2) | ||
65 | #define OMAP_LCDC_IRQ_DONE (1 << 3) | ||
66 | #define OMAP_LCDC_IRQ_LOADED_PALETTE (1 << 4) | ||
67 | #define OMAP_LCDC_IRQ_LINE_NIRQ (1 << 5) | ||
68 | #define OMAP_LCDC_IRQ_LINE (1 << 6) | ||
69 | #define OMAP_LCDC_IRQ_MASK (((1 << 5) - 1) << 2) | ||
70 | |||
71 | #define MAX_PALETTE_SIZE PAGE_SIZE | ||
72 | |||
73 | enum lcdc_load_mode { | ||
74 | OMAP_LCDC_LOAD_PALETTE, | ||
75 | OMAP_LCDC_LOAD_FRAME, | ||
76 | OMAP_LCDC_LOAD_PALETTE_AND_FRAME | ||
77 | }; | ||
78 | |||
79 | static struct omap_lcd_controller { | ||
80 | enum omapfb_update_mode update_mode; | ||
81 | int ext_mode; | ||
82 | |||
83 | unsigned long frame_offset; | ||
84 | int screen_width; | ||
85 | int xres; | ||
86 | int yres; | ||
87 | |||
88 | enum omapfb_color_format color_mode; | ||
89 | int bpp; | ||
90 | void *palette_virt; | ||
91 | dma_addr_t palette_phys; | ||
92 | int palette_code; | ||
93 | int palette_size; | ||
94 | |||
95 | unsigned int irq_mask; | ||
96 | struct completion last_frame_complete; | ||
97 | struct completion palette_load_complete; | ||
98 | struct clk *lcd_ck; | ||
99 | struct omapfb_device *fbdev; | ||
100 | |||
101 | void (*dma_callback)(void *data); | ||
102 | void *dma_callback_data; | ||
103 | |||
104 | int fbmem_allocated; | ||
105 | dma_addr_t vram_phys; | ||
106 | void *vram_virt; | ||
107 | unsigned long vram_size; | ||
108 | } lcdc; | ||
109 | |||
110 | static void inline enable_irqs(int mask) | ||
111 | { | ||
112 | lcdc.irq_mask |= mask; | ||
113 | } | ||
114 | |||
115 | static void inline disable_irqs(int mask) | ||
116 | { | ||
117 | lcdc.irq_mask &= ~mask; | ||
118 | } | ||
119 | |||
120 | static void set_load_mode(enum lcdc_load_mode mode) | ||
121 | { | ||
122 | u32 l; | ||
123 | |||
124 | l = omap_readl(OMAP_LCDC_CONTROL); | ||
125 | l &= ~(3 << 20); | ||
126 | switch (mode) { | ||
127 | case OMAP_LCDC_LOAD_PALETTE: | ||
128 | l |= 1 << 20; | ||
129 | break; | ||
130 | case OMAP_LCDC_LOAD_FRAME: | ||
131 | l |= 2 << 20; | ||
132 | break; | ||
133 | case OMAP_LCDC_LOAD_PALETTE_AND_FRAME: | ||
134 | break; | ||
135 | default: | ||
136 | BUG(); | ||
137 | } | ||
138 | omap_writel(l, OMAP_LCDC_CONTROL); | ||
139 | } | ||
140 | |||
141 | static void enable_controller(void) | ||
142 | { | ||
143 | u32 l; | ||
144 | |||
145 | l = omap_readl(OMAP_LCDC_CONTROL); | ||
146 | l |= OMAP_LCDC_CTRL_LCD_EN; | ||
147 | l &= ~OMAP_LCDC_IRQ_MASK; | ||
148 | l |= lcdc.irq_mask | OMAP_LCDC_IRQ_DONE; /* enabled IRQs */ | ||
149 | omap_writel(l, OMAP_LCDC_CONTROL); | ||
150 | } | ||
151 | |||
152 | static void disable_controller_async(void) | ||
153 | { | ||
154 | u32 l; | ||
155 | u32 mask; | ||
156 | |||
157 | l = omap_readl(OMAP_LCDC_CONTROL); | ||
158 | mask = OMAP_LCDC_CTRL_LCD_EN | OMAP_LCDC_IRQ_MASK; | ||
159 | /* | ||
160 | * Preserve the DONE mask, since we still want to get the | ||
161 | * final DONE irq. It will be disabled in the IRQ handler. | ||
162 | */ | ||
163 | mask &= ~OMAP_LCDC_IRQ_DONE; | ||
164 | l &= ~mask; | ||
165 | omap_writel(l, OMAP_LCDC_CONTROL); | ||
166 | } | ||
167 | |||
168 | static void disable_controller(void) | ||
169 | { | ||
170 | init_completion(&lcdc.last_frame_complete); | ||
171 | disable_controller_async(); | ||
172 | if (!wait_for_completion_timeout(&lcdc.last_frame_complete, | ||
173 | msecs_to_jiffies(500))) | ||
174 | dev_err(lcdc.fbdev->dev, "timeout waiting for FRAME DONE\n"); | ||
175 | } | ||
176 | |||
177 | static void reset_controller(u32 status) | ||
178 | { | ||
179 | static unsigned long reset_count; | ||
180 | static unsigned long last_jiffies; | ||
181 | |||
182 | disable_controller_async(); | ||
183 | reset_count++; | ||
184 | if (reset_count == 1 || time_after(jiffies, last_jiffies + HZ)) { | ||
185 | dev_err(lcdc.fbdev->dev, | ||
186 | "resetting (status %#010x,reset count %lu)\n", | ||
187 | status, reset_count); | ||
188 | last_jiffies = jiffies; | ||
189 | } | ||
190 | if (reset_count < 100) { | ||
191 | enable_controller(); | ||
192 | } else { | ||
193 | reset_count = 0; | ||
194 | dev_err(lcdc.fbdev->dev, | ||
195 | "too many reset attempts, giving up.\n"); | ||
196 | } | ||
197 | } | ||
198 | |||
199 | /* | ||
200 | * Configure the LCD DMA according to the current mode specified by parameters | ||
201 | * in lcdc.fbdev and fbdev->var. | ||
202 | */ | ||
203 | static void setup_lcd_dma(void) | ||
204 | { | ||
205 | static const int dma_elem_type[] = { | ||
206 | 0, | ||
207 | OMAP_DMA_DATA_TYPE_S8, | ||
208 | OMAP_DMA_DATA_TYPE_S16, | ||
209 | 0, | ||
210 | OMAP_DMA_DATA_TYPE_S32, | ||
211 | }; | ||
212 | struct omapfb_plane_struct *plane = lcdc.fbdev->fb_info[0]->par; | ||
213 | struct fb_var_screeninfo *var = &lcdc.fbdev->fb_info[0]->var; | ||
214 | unsigned long src; | ||
215 | int esize, xelem, yelem; | ||
216 | |||
217 | src = lcdc.vram_phys + lcdc.frame_offset; | ||
218 | |||
219 | switch (var->rotate) { | ||
220 | case 0: | ||
221 | if (plane->info.mirror || (src & 3) || | ||
222 | lcdc.color_mode == OMAPFB_COLOR_YUV420 || | ||
223 | (lcdc.xres & 1)) | ||
224 | esize = 2; | ||
225 | else | ||
226 | esize = 4; | ||
227 | xelem = lcdc.xres * lcdc.bpp / 8 / esize; | ||
228 | yelem = lcdc.yres; | ||
229 | break; | ||
230 | case 90: | ||
231 | case 180: | ||
232 | case 270: | ||
233 | if (cpu_is_omap15xx()) { | ||
234 | BUG(); | ||
235 | } | ||
236 | esize = 2; | ||
237 | xelem = lcdc.yres * lcdc.bpp / 16; | ||
238 | yelem = lcdc.xres; | ||
239 | break; | ||
240 | default: | ||
241 | BUG(); | ||
242 | return; | ||
243 | } | ||
244 | #ifdef VERBOSE | ||
245 | dev_dbg(lcdc.fbdev->dev, | ||
246 | "setup_dma: src %#010lx esize %d xelem %d yelem %d\n", | ||
247 | src, esize, xelem, yelem); | ||
248 | #endif | ||
249 | omap_set_lcd_dma_b1(src, xelem, yelem, dma_elem_type[esize]); | ||
250 | if (!cpu_is_omap15xx()) { | ||
251 | int bpp = lcdc.bpp; | ||
252 | |||
253 | /* | ||
254 | * YUV support is only for external mode when we have the | ||
255 | * YUV window embedded in a 16bpp frame buffer. | ||
256 | */ | ||
257 | if (lcdc.color_mode == OMAPFB_COLOR_YUV420) | ||
258 | bpp = 16; | ||
259 | /* Set virtual xres elem size */ | ||
260 | omap_set_lcd_dma_b1_vxres( | ||
261 | lcdc.screen_width * bpp / 8 / esize); | ||
262 | /* Setup transformations */ | ||
263 | omap_set_lcd_dma_b1_rotation(var->rotate); | ||
264 | omap_set_lcd_dma_b1_mirror(plane->info.mirror); | ||
265 | } | ||
266 | omap_setup_lcd_dma(); | ||
267 | } | ||
268 | |||
269 | static irqreturn_t lcdc_irq_handler(int irq, void *dev_id) | ||
270 | { | ||
271 | u32 status; | ||
272 | |||
273 | status = omap_readl(OMAP_LCDC_STATUS); | ||
274 | |||
275 | if (status & (OMAP_LCDC_STAT_FUF | OMAP_LCDC_STAT_SYNC_LOST)) | ||
276 | reset_controller(status); | ||
277 | else { | ||
278 | if (status & OMAP_LCDC_STAT_DONE) { | ||
279 | u32 l; | ||
280 | |||
281 | /* | ||
282 | * Disable IRQ_DONE. The status bit will be cleared | ||
283 | * only when the controller is reenabled and we don't | ||
284 | * want to get more interrupts. | ||
285 | */ | ||
286 | l = omap_readl(OMAP_LCDC_CONTROL); | ||
287 | l &= ~OMAP_LCDC_IRQ_DONE; | ||
288 | omap_writel(l, OMAP_LCDC_CONTROL); | ||
289 | complete(&lcdc.last_frame_complete); | ||
290 | } | ||
291 | if (status & OMAP_LCDC_STAT_LOADED_PALETTE) { | ||
292 | disable_controller_async(); | ||
293 | complete(&lcdc.palette_load_complete); | ||
294 | } | ||
295 | } | ||
296 | |||
297 | /* | ||
298 | * Clear these interrupt status bits. | ||
299 | * Sync_lost, FUF bits were cleared by disabling the LCD controller | ||
300 | * LOADED_PALETTE can be cleared this way only in palette only | ||
301 | * load mode. In other load modes it's cleared by disabling the | ||
302 | * controller. | ||
303 | */ | ||
304 | status &= ~(OMAP_LCDC_STAT_VSYNC | | ||
305 | OMAP_LCDC_STAT_LOADED_PALETTE | | ||
306 | OMAP_LCDC_STAT_ABC | | ||
307 | OMAP_LCDC_STAT_LINE_INT); | ||
308 | omap_writel(status, OMAP_LCDC_STATUS); | ||
309 | return IRQ_HANDLED; | ||
310 | } | ||
311 | |||
312 | /* | ||
313 | * Change to a new video mode. We defer this to a later time to avoid any | ||
314 | * flicker and not to mess up the current LCD DMA context. For this we disable | ||
315 | * the LCD controler, which will generate a DONE irq after the last frame has | ||
316 | * been transferred. Then it'll be safe to reconfigure both the LCD controller | ||
317 | * as well as the LCD DMA. | ||
318 | */ | ||
319 | static int omap_lcdc_setup_plane(int plane, int channel_out, | ||
320 | unsigned long offset, int screen_width, | ||
321 | int pos_x, int pos_y, int width, int height, | ||
322 | int color_mode) | ||
323 | { | ||
324 | struct fb_var_screeninfo *var = &lcdc.fbdev->fb_info[0]->var; | ||
325 | struct lcd_panel *panel = lcdc.fbdev->panel; | ||
326 | int rot_x, rot_y; | ||
327 | |||
328 | if (var->rotate == 0) { | ||
329 | rot_x = panel->x_res; | ||
330 | rot_y = panel->y_res; | ||
331 | } else { | ||
332 | rot_x = panel->y_res; | ||
333 | rot_y = panel->x_res; | ||
334 | } | ||
335 | if (plane != 0 || channel_out != 0 || pos_x != 0 || pos_y != 0 || | ||
336 | width > rot_x || height > rot_y) { | ||
337 | #ifdef VERBOSE | ||
338 | dev_dbg(lcdc.fbdev->dev, | ||
339 | "invalid plane params plane %d pos_x %d pos_y %d " | ||
340 | "w %d h %d\n", plane, pos_x, pos_y, width, height); | ||
341 | #endif | ||
342 | return -EINVAL; | ||
343 | } | ||
344 | |||
345 | lcdc.frame_offset = offset; | ||
346 | lcdc.xres = width; | ||
347 | lcdc.yres = height; | ||
348 | lcdc.screen_width = screen_width; | ||
349 | lcdc.color_mode = color_mode; | ||
350 | |||
351 | switch (color_mode) { | ||
352 | case OMAPFB_COLOR_CLUT_8BPP: | ||
353 | lcdc.bpp = 8; | ||
354 | lcdc.palette_code = 0x3000; | ||
355 | lcdc.palette_size = 512; | ||
356 | break; | ||
357 | case OMAPFB_COLOR_RGB565: | ||
358 | lcdc.bpp = 16; | ||
359 | lcdc.palette_code = 0x4000; | ||
360 | lcdc.palette_size = 32; | ||
361 | break; | ||
362 | case OMAPFB_COLOR_RGB444: | ||
363 | lcdc.bpp = 16; | ||
364 | lcdc.palette_code = 0x4000; | ||
365 | lcdc.palette_size = 32; | ||
366 | break; | ||
367 | case OMAPFB_COLOR_YUV420: | ||
368 | if (lcdc.ext_mode) { | ||
369 | lcdc.bpp = 12; | ||
370 | break; | ||
371 | } | ||
372 | /* fallthrough */ | ||
373 | case OMAPFB_COLOR_YUV422: | ||
374 | if (lcdc.ext_mode) { | ||
375 | lcdc.bpp = 16; | ||
376 | break; | ||
377 | } | ||
378 | /* fallthrough */ | ||
379 | default: | ||
380 | /* FIXME: other BPPs. | ||
381 | * bpp1: code 0, size 256 | ||
382 | * bpp2: code 0x1000 size 256 | ||
383 | * bpp4: code 0x2000 size 256 | ||
384 | * bpp12: code 0x4000 size 32 | ||
385 | */ | ||
386 | dev_dbg(lcdc.fbdev->dev, "invalid color mode %d\n", color_mode); | ||
387 | BUG(); | ||
388 | return -1; | ||
389 | } | ||
390 | |||
391 | if (lcdc.ext_mode) { | ||
392 | setup_lcd_dma(); | ||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) { | ||
397 | disable_controller(); | ||
398 | omap_stop_lcd_dma(); | ||
399 | setup_lcd_dma(); | ||
400 | enable_controller(); | ||
401 | } | ||
402 | |||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | static int omap_lcdc_enable_plane(int plane, int enable) | ||
407 | { | ||
408 | dev_dbg(lcdc.fbdev->dev, | ||
409 | "plane %d enable %d update_mode %d ext_mode %d\n", | ||
410 | plane, enable, lcdc.update_mode, lcdc.ext_mode); | ||
411 | if (plane != OMAPFB_PLANE_GFX) | ||
412 | return -EINVAL; | ||
413 | |||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | /* | ||
418 | * Configure the LCD DMA for a palette load operation and do the palette | ||
419 | * downloading synchronously. We don't use the frame+palette load mode of | ||
420 | * the controller, since the palette can always be downloaded seperately. | ||
421 | */ | ||
422 | static void load_palette(void) | ||
423 | { | ||
424 | u16 *palette; | ||
425 | |||
426 | palette = (u16 *)lcdc.palette_virt; | ||
427 | |||
428 | *(u16 *)palette &= 0x0fff; | ||
429 | *(u16 *)palette |= lcdc.palette_code; | ||
430 | |||
431 | omap_set_lcd_dma_b1(lcdc.palette_phys, | ||
432 | lcdc.palette_size / 4 + 1, 1, OMAP_DMA_DATA_TYPE_S32); | ||
433 | |||
434 | omap_set_lcd_dma_single_transfer(1); | ||
435 | omap_setup_lcd_dma(); | ||
436 | |||
437 | init_completion(&lcdc.palette_load_complete); | ||
438 | enable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE); | ||
439 | set_load_mode(OMAP_LCDC_LOAD_PALETTE); | ||
440 | enable_controller(); | ||
441 | if (!wait_for_completion_timeout(&lcdc.palette_load_complete, | ||
442 | msecs_to_jiffies(500))) | ||
443 | dev_err(lcdc.fbdev->dev, "timeout waiting for FRAME DONE\n"); | ||
444 | /* The controller gets disabled in the irq handler */ | ||
445 | disable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE); | ||
446 | omap_stop_lcd_dma(); | ||
447 | |||
448 | omap_set_lcd_dma_single_transfer(lcdc.ext_mode); | ||
449 | } | ||
450 | |||
451 | /* Used only in internal controller mode */ | ||
452 | static int omap_lcdc_setcolreg(u_int regno, u16 red, u16 green, u16 blue, | ||
453 | u16 transp, int update_hw_pal) | ||
454 | { | ||
455 | u16 *palette; | ||
456 | |||
457 | if (lcdc.color_mode != OMAPFB_COLOR_CLUT_8BPP || regno > 255) | ||
458 | return -EINVAL; | ||
459 | |||
460 | palette = (u16 *)lcdc.palette_virt; | ||
461 | |||
462 | palette[regno] &= ~0x0fff; | ||
463 | palette[regno] |= ((red >> 12) << 8) | ((green >> 12) << 4 ) | | ||
464 | (blue >> 12); | ||
465 | |||
466 | if (update_hw_pal) { | ||
467 | disable_controller(); | ||
468 | omap_stop_lcd_dma(); | ||
469 | load_palette(); | ||
470 | setup_lcd_dma(); | ||
471 | set_load_mode(OMAP_LCDC_LOAD_FRAME); | ||
472 | enable_controller(); | ||
473 | } | ||
474 | |||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | static void calc_ck_div(int is_tft, int pck, int *pck_div) | ||
479 | { | ||
480 | unsigned long lck; | ||
481 | |||
482 | pck = max(1, pck); | ||
483 | lck = clk_get_rate(lcdc.lcd_ck); | ||
484 | *pck_div = (lck + pck - 1) / pck; | ||
485 | if (is_tft) | ||
486 | *pck_div = max(2, *pck_div); | ||
487 | else | ||
488 | *pck_div = max(3, *pck_div); | ||
489 | if (*pck_div > 255) { | ||
490 | /* FIXME: try to adjust logic clock divider as well */ | ||
491 | *pck_div = 255; | ||
492 | dev_warn(lcdc.fbdev->dev, "pixclock %d kHz too low.\n", | ||
493 | pck / 1000); | ||
494 | } | ||
495 | } | ||
496 | |||
497 | static void inline setup_regs(void) | ||
498 | { | ||
499 | u32 l; | ||
500 | struct lcd_panel *panel = lcdc.fbdev->panel; | ||
501 | int is_tft = panel->config & OMAP_LCDC_PANEL_TFT; | ||
502 | unsigned long lck; | ||
503 | int pcd; | ||
504 | |||
505 | l = omap_readl(OMAP_LCDC_CONTROL); | ||
506 | l &= ~OMAP_LCDC_CTRL_LCD_TFT; | ||
507 | l |= is_tft ? OMAP_LCDC_CTRL_LCD_TFT : 0; | ||
508 | #ifdef CONFIG_MACH_OMAP_PALMTE | ||
509 | /* FIXME:if (machine_is_omap_palmte()) { */ | ||
510 | /* PalmTE uses alternate TFT setting in 8BPP mode */ | ||
511 | l |= (is_tft && panel->bpp == 8) ? 0x810000 : 0; | ||
512 | /* } */ | ||
513 | #endif | ||
514 | omap_writel(l, OMAP_LCDC_CONTROL); | ||
515 | |||
516 | l = omap_readl(OMAP_LCDC_TIMING2); | ||
517 | l &= ~(((1 << 6) - 1) << 20); | ||
518 | l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 20; | ||
519 | omap_writel(l, OMAP_LCDC_TIMING2); | ||
520 | |||
521 | l = panel->x_res - 1; | ||
522 | l |= (panel->hsw - 1) << 10; | ||
523 | l |= (panel->hfp - 1) << 16; | ||
524 | l |= (panel->hbp - 1) << 24; | ||
525 | omap_writel(l, OMAP_LCDC_TIMING0); | ||
526 | |||
527 | l = panel->y_res - 1; | ||
528 | l |= (panel->vsw - 1) << 10; | ||
529 | l |= panel->vfp << 16; | ||
530 | l |= panel->vbp << 24; | ||
531 | omap_writel(l, OMAP_LCDC_TIMING1); | ||
532 | |||
533 | l = omap_readl(OMAP_LCDC_TIMING2); | ||
534 | l &= ~0xff; | ||
535 | |||
536 | lck = clk_get_rate(lcdc.lcd_ck); | ||
537 | |||
538 | if (!panel->pcd) | ||
539 | calc_ck_div(is_tft, panel->pixel_clock * 1000, &pcd); | ||
540 | else { | ||
541 | dev_warn(lcdc.fbdev->dev, | ||
542 | "Pixel clock divider value is obsolete.\n" | ||
543 | "Try to set pixel_clock to %lu and pcd to 0 " | ||
544 | "in drivers/video/omap/lcd_%s.c and submit a patch.\n", | ||
545 | lck / panel->pcd / 1000, panel->name); | ||
546 | |||
547 | pcd = panel->pcd; | ||
548 | } | ||
549 | l |= pcd & 0xff; | ||
550 | l |= panel->acb << 8; | ||
551 | omap_writel(l, OMAP_LCDC_TIMING2); | ||
552 | |||
553 | /* update panel info with the exact clock */ | ||
554 | panel->pixel_clock = lck / pcd / 1000; | ||
555 | } | ||
556 | |||
557 | /* | ||
558 | * Configure the LCD controller, download the color palette and start a looped | ||
559 | * DMA transfer of the frame image data. Called only in internal | ||
560 | * controller mode. | ||
561 | */ | ||
562 | static int omap_lcdc_set_update_mode(enum omapfb_update_mode mode) | ||
563 | { | ||
564 | int r = 0; | ||
565 | |||
566 | if (mode != lcdc.update_mode) { | ||
567 | switch (mode) { | ||
568 | case OMAPFB_AUTO_UPDATE: | ||
569 | setup_regs(); | ||
570 | load_palette(); | ||
571 | |||
572 | /* Setup and start LCD DMA */ | ||
573 | setup_lcd_dma(); | ||
574 | |||
575 | set_load_mode(OMAP_LCDC_LOAD_FRAME); | ||
576 | enable_irqs(OMAP_LCDC_IRQ_DONE); | ||
577 | /* This will start the actual DMA transfer */ | ||
578 | enable_controller(); | ||
579 | lcdc.update_mode = mode; | ||
580 | break; | ||
581 | case OMAPFB_UPDATE_DISABLED: | ||
582 | disable_controller(); | ||
583 | omap_stop_lcd_dma(); | ||
584 | lcdc.update_mode = mode; | ||
585 | break; | ||
586 | default: | ||
587 | r = -EINVAL; | ||
588 | } | ||
589 | } | ||
590 | |||
591 | return r; | ||
592 | } | ||
593 | |||
594 | static enum omapfb_update_mode omap_lcdc_get_update_mode(void) | ||
595 | { | ||
596 | return lcdc.update_mode; | ||
597 | } | ||
598 | |||
599 | /* PM code called only in internal controller mode */ | ||
600 | static void omap_lcdc_suspend(void) | ||
601 | { | ||
602 | if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) { | ||
603 | disable_controller(); | ||
604 | omap_stop_lcd_dma(); | ||
605 | } | ||
606 | } | ||
607 | |||
608 | static void omap_lcdc_resume(void) | ||
609 | { | ||
610 | if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) { | ||
611 | setup_regs(); | ||
612 | load_palette(); | ||
613 | setup_lcd_dma(); | ||
614 | set_load_mode(OMAP_LCDC_LOAD_FRAME); | ||
615 | enable_irqs(OMAP_LCDC_IRQ_DONE); | ||
616 | enable_controller(); | ||
617 | } | ||
618 | } | ||
619 | |||
620 | static void omap_lcdc_get_caps(int plane, struct omapfb_caps *caps) | ||
621 | { | ||
622 | return; | ||
623 | } | ||
624 | |||
625 | int omap_lcdc_set_dma_callback(void (*callback)(void *data), void *data) | ||
626 | { | ||
627 | BUG_ON(callback == NULL); | ||
628 | |||
629 | if (lcdc.dma_callback) | ||
630 | return -EBUSY; | ||
631 | else { | ||
632 | lcdc.dma_callback = callback; | ||
633 | lcdc.dma_callback_data = data; | ||
634 | } | ||
635 | return 0; | ||
636 | } | ||
637 | EXPORT_SYMBOL(omap_lcdc_set_dma_callback); | ||
638 | |||
639 | void omap_lcdc_free_dma_callback(void) | ||
640 | { | ||
641 | lcdc.dma_callback = NULL; | ||
642 | } | ||
643 | EXPORT_SYMBOL(omap_lcdc_free_dma_callback); | ||
644 | |||
645 | static void lcdc_dma_handler(u16 status, void *data) | ||
646 | { | ||
647 | if (lcdc.dma_callback) | ||
648 | lcdc.dma_callback(lcdc.dma_callback_data); | ||
649 | } | ||
650 | |||
651 | static int mmap_kern(void) | ||
652 | { | ||
653 | struct vm_struct *kvma; | ||
654 | struct vm_area_struct vma; | ||
655 | pgprot_t pgprot; | ||
656 | unsigned long vaddr; | ||
657 | |||
658 | kvma = get_vm_area(lcdc.vram_size, VM_IOREMAP); | ||
659 | if (kvma == NULL) { | ||
660 | dev_err(lcdc.fbdev->dev, "can't get kernel vm area\n"); | ||
661 | return -ENOMEM; | ||
662 | } | ||
663 | vma.vm_mm = &init_mm; | ||
664 | |||
665 | vaddr = (unsigned long)kvma->addr; | ||
666 | vma.vm_start = vaddr; | ||
667 | vma.vm_end = vaddr + lcdc.vram_size; | ||
668 | |||
669 | pgprot = pgprot_writecombine(pgprot_kernel); | ||
670 | if (io_remap_pfn_range(&vma, vaddr, | ||
671 | lcdc.vram_phys >> PAGE_SHIFT, | ||
672 | lcdc.vram_size, pgprot) < 0) { | ||
673 | dev_err(lcdc.fbdev->dev, "kernel mmap for FB memory failed\n"); | ||
674 | return -EAGAIN; | ||
675 | } | ||
676 | |||
677 | lcdc.vram_virt = (void *)vaddr; | ||
678 | |||
679 | return 0; | ||
680 | } | ||
681 | |||
682 | static void unmap_kern(void) | ||
683 | { | ||
684 | vunmap(lcdc.vram_virt); | ||
685 | } | ||
686 | |||
687 | static int alloc_palette_ram(void) | ||
688 | { | ||
689 | lcdc.palette_virt = dma_alloc_writecombine(lcdc.fbdev->dev, | ||
690 | MAX_PALETTE_SIZE, &lcdc.palette_phys, GFP_KERNEL); | ||
691 | if (lcdc.palette_virt == NULL) { | ||
692 | dev_err(lcdc.fbdev->dev, "failed to alloc palette memory\n"); | ||
693 | return -ENOMEM; | ||
694 | } | ||
695 | memset(lcdc.palette_virt, 0, MAX_PALETTE_SIZE); | ||
696 | |||
697 | return 0; | ||
698 | } | ||
699 | |||
700 | static void free_palette_ram(void) | ||
701 | { | ||
702 | dma_free_writecombine(lcdc.fbdev->dev, MAX_PALETTE_SIZE, | ||
703 | lcdc.palette_virt, lcdc.palette_phys); | ||
704 | } | ||
705 | |||
706 | static int alloc_fbmem(struct omapfb_mem_region *region) | ||
707 | { | ||
708 | int bpp; | ||
709 | int frame_size; | ||
710 | struct lcd_panel *panel = lcdc.fbdev->panel; | ||
711 | |||
712 | bpp = panel->bpp; | ||
713 | if (bpp == 12) | ||
714 | bpp = 16; | ||
715 | frame_size = PAGE_ALIGN(panel->x_res * bpp / 8 * panel->y_res); | ||
716 | if (region->size > frame_size) | ||
717 | frame_size = region->size; | ||
718 | lcdc.vram_size = frame_size; | ||
719 | lcdc.vram_virt = dma_alloc_writecombine(lcdc.fbdev->dev, | ||
720 | lcdc.vram_size, &lcdc.vram_phys, GFP_KERNEL); | ||
721 | if (lcdc.vram_virt == NULL) { | ||
722 | dev_err(lcdc.fbdev->dev, "unable to allocate FB DMA memory\n"); | ||
723 | return -ENOMEM; | ||
724 | } | ||
725 | region->size = frame_size; | ||
726 | region->paddr = lcdc.vram_phys; | ||
727 | region->vaddr = lcdc.vram_virt; | ||
728 | region->alloc = 1; | ||
729 | |||
730 | memset(lcdc.vram_virt, 0, lcdc.vram_size); | ||
731 | |||
732 | return 0; | ||
733 | } | ||
734 | |||
735 | static void free_fbmem(void) | ||
736 | { | ||
737 | dma_free_writecombine(lcdc.fbdev->dev, lcdc.vram_size, | ||
738 | lcdc.vram_virt, lcdc.vram_phys); | ||
739 | } | ||
740 | |||
741 | static int setup_fbmem(struct omapfb_mem_desc *req_md) | ||
742 | { | ||
743 | int r; | ||
744 | |||
745 | if (!req_md->region_cnt) { | ||
746 | dev_err(lcdc.fbdev->dev, "no memory regions defined\n"); | ||
747 | return -EINVAL; | ||
748 | } | ||
749 | |||
750 | if (req_md->region_cnt > 1) { | ||
751 | dev_err(lcdc.fbdev->dev, "only one plane is supported\n"); | ||
752 | req_md->region_cnt = 1; | ||
753 | } | ||
754 | |||
755 | if (req_md->region[0].paddr == 0) { | ||
756 | lcdc.fbmem_allocated = 1; | ||
757 | if ((r = alloc_fbmem(&req_md->region[0])) < 0) | ||
758 | return r; | ||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | lcdc.vram_phys = req_md->region[0].paddr; | ||
763 | lcdc.vram_size = req_md->region[0].size; | ||
764 | |||
765 | if ((r = mmap_kern()) < 0) | ||
766 | return r; | ||
767 | |||
768 | dev_dbg(lcdc.fbdev->dev, "vram at %08x size %08lx mapped to 0x%p\n", | ||
769 | lcdc.vram_phys, lcdc.vram_size, lcdc.vram_virt); | ||
770 | |||
771 | return 0; | ||
772 | } | ||
773 | |||
774 | static void cleanup_fbmem(void) | ||
775 | { | ||
776 | if (lcdc.fbmem_allocated) | ||
777 | free_fbmem(); | ||
778 | else | ||
779 | unmap_kern(); | ||
780 | } | ||
781 | |||
782 | static int omap_lcdc_init(struct omapfb_device *fbdev, int ext_mode, | ||
783 | struct omapfb_mem_desc *req_vram) | ||
784 | { | ||
785 | int r; | ||
786 | u32 l; | ||
787 | int rate; | ||
788 | struct clk *tc_ck; | ||
789 | |||
790 | lcdc.irq_mask = 0; | ||
791 | |||
792 | lcdc.fbdev = fbdev; | ||
793 | lcdc.ext_mode = ext_mode; | ||
794 | |||
795 | l = 0; | ||
796 | omap_writel(l, OMAP_LCDC_CONTROL); | ||
797 | |||
798 | /* FIXME: | ||
799 | * According to errata some platforms have a clock rate limitiation | ||
800 | */ | ||
801 | lcdc.lcd_ck = clk_get(NULL, "lcd_ck"); | ||
802 | if (IS_ERR(lcdc.lcd_ck)) { | ||
803 | dev_err(fbdev->dev, "unable to access LCD clock\n"); | ||
804 | r = PTR_ERR(lcdc.lcd_ck); | ||
805 | goto fail0; | ||
806 | } | ||
807 | |||
808 | tc_ck = clk_get(NULL, "tc_ck"); | ||
809 | if (IS_ERR(tc_ck)) { | ||
810 | dev_err(fbdev->dev, "unable to access TC clock\n"); | ||
811 | r = PTR_ERR(tc_ck); | ||
812 | goto fail1; | ||
813 | } | ||
814 | |||
815 | rate = clk_get_rate(tc_ck); | ||
816 | clk_put(tc_ck); | ||
817 | |||
818 | if (machine_is_ams_delta()) | ||
819 | rate /= 4; | ||
820 | if (machine_is_omap_h3()) | ||
821 | rate /= 3; | ||
822 | r = clk_set_rate(lcdc.lcd_ck, rate); | ||
823 | if (r) { | ||
824 | dev_err(fbdev->dev, "failed to adjust LCD rate\n"); | ||
825 | goto fail1; | ||
826 | } | ||
827 | clk_enable(lcdc.lcd_ck); | ||
828 | |||
829 | r = request_irq(OMAP_LCDC_IRQ, lcdc_irq_handler, 0, MODULE_NAME, fbdev); | ||
830 | if (r) { | ||
831 | dev_err(fbdev->dev, "unable to get IRQ\n"); | ||
832 | goto fail2; | ||
833 | } | ||
834 | |||
835 | r = omap_request_lcd_dma(lcdc_dma_handler, NULL); | ||
836 | if (r) { | ||
837 | dev_err(fbdev->dev, "unable to get LCD DMA\n"); | ||
838 | goto fail3; | ||
839 | } | ||
840 | |||
841 | omap_set_lcd_dma_single_transfer(ext_mode); | ||
842 | omap_set_lcd_dma_ext_controller(ext_mode); | ||
843 | |||
844 | if (!ext_mode) | ||
845 | if ((r = alloc_palette_ram()) < 0) | ||
846 | goto fail4; | ||
847 | |||
848 | if ((r = setup_fbmem(req_vram)) < 0) | ||
849 | goto fail5; | ||
850 | |||
851 | pr_info("omapfb: LCDC initialized\n"); | ||
852 | |||
853 | return 0; | ||
854 | fail5: | ||
855 | if (!ext_mode) | ||
856 | free_palette_ram(); | ||
857 | fail4: | ||
858 | omap_free_lcd_dma(); | ||
859 | fail3: | ||
860 | free_irq(OMAP_LCDC_IRQ, lcdc.fbdev); | ||
861 | fail2: | ||
862 | clk_disable(lcdc.lcd_ck); | ||
863 | fail1: | ||
864 | clk_put(lcdc.lcd_ck); | ||
865 | fail0: | ||
866 | return r; | ||
867 | } | ||
868 | |||
869 | static void omap_lcdc_cleanup(void) | ||
870 | { | ||
871 | if (!lcdc.ext_mode) | ||
872 | free_palette_ram(); | ||
873 | cleanup_fbmem(); | ||
874 | omap_free_lcd_dma(); | ||
875 | free_irq(OMAP_LCDC_IRQ, lcdc.fbdev); | ||
876 | clk_disable(lcdc.lcd_ck); | ||
877 | clk_put(lcdc.lcd_ck); | ||
878 | } | ||
879 | |||
880 | const struct lcd_ctrl omap1_int_ctrl = { | ||
881 | .name = "internal", | ||
882 | .init = omap_lcdc_init, | ||
883 | .cleanup = omap_lcdc_cleanup, | ||
884 | .get_caps = omap_lcdc_get_caps, | ||
885 | .set_update_mode = omap_lcdc_set_update_mode, | ||
886 | .get_update_mode = omap_lcdc_get_update_mode, | ||
887 | .update_window = NULL, | ||
888 | .suspend = omap_lcdc_suspend, | ||
889 | .resume = omap_lcdc_resume, | ||
890 | .setup_plane = omap_lcdc_setup_plane, | ||
891 | .enable_plane = omap_lcdc_enable_plane, | ||
892 | .setcolreg = omap_lcdc_setcolreg, | ||
893 | }; | ||
diff --git a/drivers/video/omap/lcdc.h b/drivers/video/omap/lcdc.h new file mode 100644 index 000000000000..adb731e5314a --- /dev/null +++ b/drivers/video/omap/lcdc.h | |||
@@ -0,0 +1,7 @@ | |||
1 | #ifndef LCDC_H | ||
2 | #define LCDC_H | ||
3 | |||
4 | int omap_lcdc_set_dma_callback(void (*callback)(void *data), void *data); | ||
5 | void omap_lcdc_free_dma_callback(void); | ||
6 | |||
7 | #endif | ||
diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c new file mode 100644 index 000000000000..14d0f7a11145 --- /dev/null +++ b/drivers/video/omap/omapfb_main.c | |||
@@ -0,0 +1,1941 @@ | |||
1 | /* | ||
2 | * Framebuffer driver for TI OMAP boards | ||
3 | * | ||
4 | * Copyright (C) 2004 Nokia Corporation | ||
5 | * Author: Imre Deak <imre.deak@nokia.com> | ||
6 | * | ||
7 | * Acknowledgements: | ||
8 | * Alex McMains <aam@ridgerun.com> - Original driver | ||
9 | * Juha Yrjola <juha.yrjola@nokia.com> - Original driver and improvements | ||
10 | * Dirk Behme <dirk.behme@de.bosch.com> - changes for 2.6 kernel API | ||
11 | * Texas Instruments - H3 support | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, but | ||
19 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
21 | * General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License along | ||
24 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
25 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
26 | */ | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/uaccess.h> | ||
29 | |||
30 | #include <asm/mach-types.h> | ||
31 | #include <asm/arch/dma.h> | ||
32 | #include <asm/arch/omapfb.h> | ||
33 | |||
34 | #define MODULE_NAME "omapfb" | ||
35 | |||
36 | static unsigned int def_accel; | ||
37 | static unsigned long def_vram[OMAPFB_PLANE_NUM]; | ||
38 | static int def_vram_cnt; | ||
39 | static unsigned long def_vxres; | ||
40 | static unsigned long def_vyres; | ||
41 | static unsigned int def_rotate; | ||
42 | static unsigned int def_mirror; | ||
43 | |||
44 | #ifdef CONFIG_FB_OMAP_MANUAL_UPDATE | ||
45 | static int manual_update = 1; | ||
46 | #else | ||
47 | static int manual_update; | ||
48 | #endif | ||
49 | |||
50 | static struct platform_device *fbdev_pdev; | ||
51 | static struct lcd_panel *fbdev_panel; | ||
52 | static struct omapfb_device *omapfb_dev; | ||
53 | |||
54 | struct caps_table_struct { | ||
55 | unsigned long flag; | ||
56 | const char *name; | ||
57 | }; | ||
58 | |||
59 | static struct caps_table_struct ctrl_caps[] = { | ||
60 | { OMAPFB_CAPS_MANUAL_UPDATE, "manual update" }, | ||
61 | { OMAPFB_CAPS_TEARSYNC, "tearing synchronization" }, | ||
62 | { OMAPFB_CAPS_PLANE_RELOCATE_MEM, "relocate plane memory" }, | ||
63 | { OMAPFB_CAPS_PLANE_SCALE, "scale plane" }, | ||
64 | { OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE, "pixel double window" }, | ||
65 | { OMAPFB_CAPS_WINDOW_SCALE, "scale window" }, | ||
66 | { OMAPFB_CAPS_WINDOW_OVERLAY, "overlay window" }, | ||
67 | { OMAPFB_CAPS_SET_BACKLIGHT, "backlight setting" }, | ||
68 | }; | ||
69 | |||
70 | static struct caps_table_struct color_caps[] = { | ||
71 | { 1 << OMAPFB_COLOR_RGB565, "RGB565", }, | ||
72 | { 1 << OMAPFB_COLOR_YUV422, "YUV422", }, | ||
73 | { 1 << OMAPFB_COLOR_YUV420, "YUV420", }, | ||
74 | { 1 << OMAPFB_COLOR_CLUT_8BPP, "CLUT8", }, | ||
75 | { 1 << OMAPFB_COLOR_CLUT_4BPP, "CLUT4", }, | ||
76 | { 1 << OMAPFB_COLOR_CLUT_2BPP, "CLUT2", }, | ||
77 | { 1 << OMAPFB_COLOR_CLUT_1BPP, "CLUT1", }, | ||
78 | { 1 << OMAPFB_COLOR_RGB444, "RGB444", }, | ||
79 | { 1 << OMAPFB_COLOR_YUY422, "YUY422", }, | ||
80 | }; | ||
81 | |||
82 | /* | ||
83 | * --------------------------------------------------------------------------- | ||
84 | * LCD panel | ||
85 | * --------------------------------------------------------------------------- | ||
86 | */ | ||
87 | extern struct lcd_ctrl omap1_int_ctrl; | ||
88 | extern struct lcd_ctrl omap2_int_ctrl; | ||
89 | extern struct lcd_ctrl hwa742_ctrl; | ||
90 | extern struct lcd_ctrl blizzard_ctrl; | ||
91 | |||
92 | static struct lcd_ctrl *ctrls[] = { | ||
93 | #ifdef CONFIG_ARCH_OMAP1 | ||
94 | &omap1_int_ctrl, | ||
95 | #else | ||
96 | &omap2_int_ctrl, | ||
97 | #endif | ||
98 | |||
99 | #ifdef CONFIG_FB_OMAP_LCDC_HWA742 | ||
100 | &hwa742_ctrl, | ||
101 | #endif | ||
102 | #ifdef CONFIG_FB_OMAP_LCDC_BLIZZARD | ||
103 | &blizzard_ctrl, | ||
104 | #endif | ||
105 | }; | ||
106 | |||
107 | #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL | ||
108 | #ifdef CONFIG_ARCH_OMAP1 | ||
109 | extern struct lcd_ctrl_extif omap1_ext_if; | ||
110 | #else | ||
111 | extern struct lcd_ctrl_extif omap2_ext_if; | ||
112 | #endif | ||
113 | #endif | ||
114 | |||
115 | static void omapfb_rqueue_lock(struct omapfb_device *fbdev) | ||
116 | { | ||
117 | mutex_lock(&fbdev->rqueue_mutex); | ||
118 | } | ||
119 | |||
120 | static void omapfb_rqueue_unlock(struct omapfb_device *fbdev) | ||
121 | { | ||
122 | mutex_unlock(&fbdev->rqueue_mutex); | ||
123 | } | ||
124 | |||
125 | /* | ||
126 | * --------------------------------------------------------------------------- | ||
127 | * LCD controller and LCD DMA | ||
128 | * --------------------------------------------------------------------------- | ||
129 | */ | ||
130 | /* Lookup table to map elem size to elem type. */ | ||
131 | static const int dma_elem_type[] = { | ||
132 | 0, | ||
133 | OMAP_DMA_DATA_TYPE_S8, | ||
134 | OMAP_DMA_DATA_TYPE_S16, | ||
135 | 0, | ||
136 | OMAP_DMA_DATA_TYPE_S32, | ||
137 | }; | ||
138 | |||
139 | /* | ||
140 | * Allocate resources needed for LCD controller and LCD DMA operations. Video | ||
141 | * memory is allocated from system memory according to the virtual display | ||
142 | * size, except if a bigger memory size is specified explicitly as a kernel | ||
143 | * parameter. | ||
144 | */ | ||
145 | static int ctrl_init(struct omapfb_device *fbdev) | ||
146 | { | ||
147 | int r; | ||
148 | int i; | ||
149 | |||
150 | /* kernel/module vram parameters override boot tags/board config */ | ||
151 | if (def_vram_cnt) { | ||
152 | for (i = 0; i < def_vram_cnt; i++) | ||
153 | fbdev->mem_desc.region[i].size = | ||
154 | PAGE_ALIGN(def_vram[i]); | ||
155 | fbdev->mem_desc.region_cnt = i; | ||
156 | } else { | ||
157 | struct omapfb_platform_data *conf; | ||
158 | |||
159 | conf = fbdev->dev->platform_data; | ||
160 | fbdev->mem_desc = conf->mem_desc; | ||
161 | } | ||
162 | |||
163 | if (!fbdev->mem_desc.region_cnt) { | ||
164 | struct lcd_panel *panel = fbdev->panel; | ||
165 | int def_size; | ||
166 | int bpp = panel->bpp; | ||
167 | |||
168 | /* 12 bpp is packed in 16 bits */ | ||
169 | if (bpp == 12) | ||
170 | bpp = 16; | ||
171 | def_size = def_vxres * def_vyres * bpp / 8; | ||
172 | fbdev->mem_desc.region_cnt = 1; | ||
173 | fbdev->mem_desc.region[0].size = PAGE_ALIGN(def_size); | ||
174 | } | ||
175 | r = fbdev->ctrl->init(fbdev, 0, &fbdev->mem_desc); | ||
176 | if (r < 0) { | ||
177 | dev_err(fbdev->dev, "controller initialization failed (%d)\n", | ||
178 | r); | ||
179 | return r; | ||
180 | } | ||
181 | |||
182 | #ifdef DEBUG | ||
183 | for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { | ||
184 | dev_dbg(fbdev->dev, "region%d phys %08x virt %p size=%lu\n", | ||
185 | i, | ||
186 | fbdev->mem_desc.region[i].paddr, | ||
187 | fbdev->mem_desc.region[i].vaddr, | ||
188 | fbdev->mem_desc.region[i].size); | ||
189 | } | ||
190 | #endif | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static void ctrl_cleanup(struct omapfb_device *fbdev) | ||
195 | { | ||
196 | fbdev->ctrl->cleanup(); | ||
197 | } | ||
198 | |||
199 | /* Must be called with fbdev->rqueue_mutex held. */ | ||
200 | static int ctrl_change_mode(struct fb_info *fbi) | ||
201 | { | ||
202 | int r; | ||
203 | unsigned long offset; | ||
204 | struct omapfb_plane_struct *plane = fbi->par; | ||
205 | struct omapfb_device *fbdev = plane->fbdev; | ||
206 | struct fb_var_screeninfo *var = &fbi->var; | ||
207 | |||
208 | offset = var->yoffset * fbi->fix.line_length + | ||
209 | var->xoffset * var->bits_per_pixel / 8; | ||
210 | |||
211 | if (fbdev->ctrl->sync) | ||
212 | fbdev->ctrl->sync(); | ||
213 | r = fbdev->ctrl->setup_plane(plane->idx, plane->info.channel_out, | ||
214 | offset, var->xres_virtual, | ||
215 | plane->info.pos_x, plane->info.pos_y, | ||
216 | var->xres, var->yres, plane->color_mode); | ||
217 | if (fbdev->ctrl->set_scale != NULL) | ||
218 | r = fbdev->ctrl->set_scale(plane->idx, | ||
219 | var->xres, var->yres, | ||
220 | plane->info.out_width, | ||
221 | plane->info.out_height); | ||
222 | |||
223 | return r; | ||
224 | } | ||
225 | |||
226 | /* | ||
227 | * --------------------------------------------------------------------------- | ||
228 | * fbdev framework callbacks and the ioctl interface | ||
229 | * --------------------------------------------------------------------------- | ||
230 | */ | ||
231 | /* Called each time the omapfb device is opened */ | ||
232 | static int omapfb_open(struct fb_info *info, int user) | ||
233 | { | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static void omapfb_sync(struct fb_info *info); | ||
238 | |||
239 | /* Called when the omapfb device is closed. We make sure that any pending | ||
240 | * gfx DMA operations are ended, before we return. */ | ||
241 | static int omapfb_release(struct fb_info *info, int user) | ||
242 | { | ||
243 | omapfb_sync(info); | ||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | /* Store a single color palette entry into a pseudo palette or the hardware | ||
248 | * palette if one is available. For now we support only 16bpp and thus store | ||
249 | * the entry only to the pseudo palette. | ||
250 | */ | ||
251 | static int _setcolreg(struct fb_info *info, u_int regno, u_int red, u_int green, | ||
252 | u_int blue, u_int transp, int update_hw_pal) | ||
253 | { | ||
254 | struct omapfb_plane_struct *plane = info->par; | ||
255 | struct omapfb_device *fbdev = plane->fbdev; | ||
256 | struct fb_var_screeninfo *var = &info->var; | ||
257 | int r = 0; | ||
258 | |||
259 | switch (plane->color_mode) { | ||
260 | case OMAPFB_COLOR_YUV422: | ||
261 | case OMAPFB_COLOR_YUV420: | ||
262 | case OMAPFB_COLOR_YUY422: | ||
263 | r = -EINVAL; | ||
264 | break; | ||
265 | case OMAPFB_COLOR_CLUT_8BPP: | ||
266 | case OMAPFB_COLOR_CLUT_4BPP: | ||
267 | case OMAPFB_COLOR_CLUT_2BPP: | ||
268 | case OMAPFB_COLOR_CLUT_1BPP: | ||
269 | if (fbdev->ctrl->setcolreg) | ||
270 | r = fbdev->ctrl->setcolreg(regno, red, green, blue, | ||
271 | transp, update_hw_pal); | ||
272 | /* Fallthrough */ | ||
273 | case OMAPFB_COLOR_RGB565: | ||
274 | case OMAPFB_COLOR_RGB444: | ||
275 | if (r != 0) | ||
276 | break; | ||
277 | |||
278 | if (regno < 0) { | ||
279 | r = -EINVAL; | ||
280 | break; | ||
281 | } | ||
282 | |||
283 | if (regno < 16) { | ||
284 | u16 pal; | ||
285 | pal = ((red >> (16 - var->red.length)) << | ||
286 | var->red.offset) | | ||
287 | ((green >> (16 - var->green.length)) << | ||
288 | var->green.offset) | | ||
289 | (blue >> (16 - var->blue.length)); | ||
290 | ((u32 *)(info->pseudo_palette))[regno] = pal; | ||
291 | } | ||
292 | break; | ||
293 | default: | ||
294 | BUG(); | ||
295 | } | ||
296 | return r; | ||
297 | } | ||
298 | |||
299 | static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, | ||
300 | u_int transp, struct fb_info *info) | ||
301 | { | ||
302 | return _setcolreg(info, regno, red, green, blue, transp, 1); | ||
303 | } | ||
304 | |||
305 | static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info) | ||
306 | { | ||
307 | int count, index, r; | ||
308 | u16 *red, *green, *blue, *transp; | ||
309 | u16 trans = 0xffff; | ||
310 | |||
311 | red = cmap->red; | ||
312 | green = cmap->green; | ||
313 | blue = cmap->blue; | ||
314 | transp = cmap->transp; | ||
315 | index = cmap->start; | ||
316 | |||
317 | for (count = 0; count < cmap->len; count++) { | ||
318 | if (transp) | ||
319 | trans = *transp++; | ||
320 | r = _setcolreg(info, index++, *red++, *green++, *blue++, trans, | ||
321 | count == cmap->len - 1); | ||
322 | if (r != 0) | ||
323 | return r; | ||
324 | } | ||
325 | |||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static int omapfb_update_full_screen(struct fb_info *fbi); | ||
330 | |||
331 | static int omapfb_blank(int blank, struct fb_info *fbi) | ||
332 | { | ||
333 | struct omapfb_plane_struct *plane = fbi->par; | ||
334 | struct omapfb_device *fbdev = plane->fbdev; | ||
335 | int do_update = 0; | ||
336 | int r = 0; | ||
337 | |||
338 | omapfb_rqueue_lock(fbdev); | ||
339 | switch (blank) { | ||
340 | case VESA_NO_BLANKING: | ||
341 | if (fbdev->state == OMAPFB_SUSPENDED) { | ||
342 | if (fbdev->ctrl->resume) | ||
343 | fbdev->ctrl->resume(); | ||
344 | fbdev->panel->enable(fbdev->panel); | ||
345 | fbdev->state = OMAPFB_ACTIVE; | ||
346 | if (fbdev->ctrl->get_update_mode() == | ||
347 | OMAPFB_MANUAL_UPDATE) | ||
348 | do_update = 1; | ||
349 | } | ||
350 | break; | ||
351 | case VESA_POWERDOWN: | ||
352 | if (fbdev->state == OMAPFB_ACTIVE) { | ||
353 | fbdev->panel->disable(fbdev->panel); | ||
354 | if (fbdev->ctrl->suspend) | ||
355 | fbdev->ctrl->suspend(); | ||
356 | fbdev->state = OMAPFB_SUSPENDED; | ||
357 | } | ||
358 | break; | ||
359 | default: | ||
360 | r = -EINVAL; | ||
361 | } | ||
362 | omapfb_rqueue_unlock(fbdev); | ||
363 | |||
364 | if (r == 0 && do_update) | ||
365 | r = omapfb_update_full_screen(fbi); | ||
366 | |||
367 | return r; | ||
368 | } | ||
369 | |||
370 | static void omapfb_sync(struct fb_info *fbi) | ||
371 | { | ||
372 | struct omapfb_plane_struct *plane = fbi->par; | ||
373 | struct omapfb_device *fbdev = plane->fbdev; | ||
374 | |||
375 | omapfb_rqueue_lock(fbdev); | ||
376 | if (fbdev->ctrl->sync) | ||
377 | fbdev->ctrl->sync(); | ||
378 | omapfb_rqueue_unlock(fbdev); | ||
379 | } | ||
380 | |||
381 | /* | ||
382 | * Set fb_info.fix fields and also updates fbdev. | ||
383 | * When calling this fb_info.var must be set up already. | ||
384 | */ | ||
385 | static void set_fb_fix(struct fb_info *fbi) | ||
386 | { | ||
387 | struct fb_fix_screeninfo *fix = &fbi->fix; | ||
388 | struct fb_var_screeninfo *var = &fbi->var; | ||
389 | struct omapfb_plane_struct *plane = fbi->par; | ||
390 | struct omapfb_mem_region *rg; | ||
391 | int bpp; | ||
392 | |||
393 | rg = &plane->fbdev->mem_desc.region[plane->idx]; | ||
394 | fbi->screen_base = (char __iomem *)rg->vaddr; | ||
395 | fix->smem_start = rg->paddr; | ||
396 | fix->smem_len = rg->size; | ||
397 | |||
398 | fix->type = FB_TYPE_PACKED_PIXELS; | ||
399 | bpp = var->bits_per_pixel; | ||
400 | if (var->nonstd) | ||
401 | fix->visual = FB_VISUAL_PSEUDOCOLOR; | ||
402 | else switch (var->bits_per_pixel) { | ||
403 | case 16: | ||
404 | case 12: | ||
405 | fix->visual = FB_VISUAL_TRUECOLOR; | ||
406 | /* 12bpp is stored in 16 bits */ | ||
407 | bpp = 16; | ||
408 | break; | ||
409 | case 1: | ||
410 | case 2: | ||
411 | case 4: | ||
412 | case 8: | ||
413 | fix->visual = FB_VISUAL_PSEUDOCOLOR; | ||
414 | break; | ||
415 | } | ||
416 | fix->accel = FB_ACCEL_OMAP1610; | ||
417 | fix->line_length = var->xres_virtual * bpp / 8; | ||
418 | } | ||
419 | |||
420 | static int set_color_mode(struct omapfb_plane_struct *plane, | ||
421 | struct fb_var_screeninfo *var) | ||
422 | { | ||
423 | switch (var->nonstd) { | ||
424 | case 0: | ||
425 | break; | ||
426 | case OMAPFB_COLOR_YUV422: | ||
427 | var->bits_per_pixel = 16; | ||
428 | plane->color_mode = var->nonstd; | ||
429 | return 0; | ||
430 | case OMAPFB_COLOR_YUV420: | ||
431 | var->bits_per_pixel = 12; | ||
432 | plane->color_mode = var->nonstd; | ||
433 | return 0; | ||
434 | case OMAPFB_COLOR_YUY422: | ||
435 | var->bits_per_pixel = 16; | ||
436 | plane->color_mode = var->nonstd; | ||
437 | return 0; | ||
438 | default: | ||
439 | return -EINVAL; | ||
440 | } | ||
441 | |||
442 | switch (var->bits_per_pixel) { | ||
443 | case 1: | ||
444 | plane->color_mode = OMAPFB_COLOR_CLUT_1BPP; | ||
445 | return 0; | ||
446 | case 2: | ||
447 | plane->color_mode = OMAPFB_COLOR_CLUT_2BPP; | ||
448 | return 0; | ||
449 | case 4: | ||
450 | plane->color_mode = OMAPFB_COLOR_CLUT_4BPP; | ||
451 | return 0; | ||
452 | case 8: | ||
453 | plane->color_mode = OMAPFB_COLOR_CLUT_8BPP; | ||
454 | return 0; | ||
455 | case 12: | ||
456 | var->bits_per_pixel = 16; | ||
457 | plane->color_mode = OMAPFB_COLOR_RGB444; | ||
458 | return 0; | ||
459 | case 16: | ||
460 | plane->color_mode = OMAPFB_COLOR_RGB565; | ||
461 | return 0; | ||
462 | default: | ||
463 | return -EINVAL; | ||
464 | } | ||
465 | } | ||
466 | |||
467 | /* | ||
468 | * Check the values in var against our capabilities and in case of out of | ||
469 | * bound values try to adjust them. | ||
470 | */ | ||
471 | static int set_fb_var(struct fb_info *fbi, | ||
472 | struct fb_var_screeninfo *var) | ||
473 | { | ||
474 | int bpp; | ||
475 | unsigned long max_frame_size; | ||
476 | unsigned long line_size; | ||
477 | int xres_min, xres_max; | ||
478 | int yres_min, yres_max; | ||
479 | struct omapfb_plane_struct *plane = fbi->par; | ||
480 | struct omapfb_device *fbdev = plane->fbdev; | ||
481 | struct lcd_panel *panel = fbdev->panel; | ||
482 | |||
483 | if (set_color_mode(plane, var) < 0) | ||
484 | return -EINVAL; | ||
485 | |||
486 | bpp = var->bits_per_pixel; | ||
487 | if (plane->color_mode == OMAPFB_COLOR_RGB444) | ||
488 | bpp = 16; | ||
489 | |||
490 | switch (var->rotate) { | ||
491 | case 0: | ||
492 | case 180: | ||
493 | xres_min = OMAPFB_PLANE_XRES_MIN; | ||
494 | xres_max = panel->x_res; | ||
495 | yres_min = OMAPFB_PLANE_YRES_MIN; | ||
496 | yres_max = panel->y_res; | ||
497 | if (cpu_is_omap15xx()) { | ||
498 | var->xres = panel->x_res; | ||
499 | var->yres = panel->y_res; | ||
500 | } | ||
501 | break; | ||
502 | case 90: | ||
503 | case 270: | ||
504 | xres_min = OMAPFB_PLANE_YRES_MIN; | ||
505 | xres_max = panel->y_res; | ||
506 | yres_min = OMAPFB_PLANE_XRES_MIN; | ||
507 | yres_max = panel->x_res; | ||
508 | if (cpu_is_omap15xx()) { | ||
509 | var->xres = panel->y_res; | ||
510 | var->yres = panel->x_res; | ||
511 | } | ||
512 | break; | ||
513 | default: | ||
514 | return -EINVAL; | ||
515 | } | ||
516 | |||
517 | if (var->xres < xres_min) | ||
518 | var->xres = xres_min; | ||
519 | if (var->yres < yres_min) | ||
520 | var->yres = yres_min; | ||
521 | if (var->xres > xres_max) | ||
522 | var->xres = xres_max; | ||
523 | if (var->yres > yres_max) | ||
524 | var->yres = yres_max; | ||
525 | |||
526 | if (var->xres_virtual < var->xres) | ||
527 | var->xres_virtual = var->xres; | ||
528 | if (var->yres_virtual < var->yres) | ||
529 | var->yres_virtual = var->yres; | ||
530 | max_frame_size = fbdev->mem_desc.region[plane->idx].size; | ||
531 | line_size = var->xres_virtual * bpp / 8; | ||
532 | if (line_size * var->yres_virtual > max_frame_size) { | ||
533 | /* Try to keep yres_virtual first */ | ||
534 | line_size = max_frame_size / var->yres_virtual; | ||
535 | var->xres_virtual = line_size * 8 / bpp; | ||
536 | if (var->xres_virtual < var->xres) { | ||
537 | /* Still doesn't fit. Shrink yres_virtual too */ | ||
538 | var->xres_virtual = var->xres; | ||
539 | line_size = var->xres * bpp / 8; | ||
540 | var->yres_virtual = max_frame_size / line_size; | ||
541 | } | ||
542 | /* Recheck this, as the virtual size changed. */ | ||
543 | if (var->xres_virtual < var->xres) | ||
544 | var->xres = var->xres_virtual; | ||
545 | if (var->yres_virtual < var->yres) | ||
546 | var->yres = var->yres_virtual; | ||
547 | if (var->xres < xres_min || var->yres < yres_min) | ||
548 | return -EINVAL; | ||
549 | } | ||
550 | if (var->xres + var->xoffset > var->xres_virtual) | ||
551 | var->xoffset = var->xres_virtual - var->xres; | ||
552 | if (var->yres + var->yoffset > var->yres_virtual) | ||
553 | var->yoffset = var->yres_virtual - var->yres; | ||
554 | line_size = var->xres * bpp / 8; | ||
555 | |||
556 | if (plane->color_mode == OMAPFB_COLOR_RGB444) { | ||
557 | var->red.offset = 8; var->red.length = 4; | ||
558 | var->red.msb_right = 0; | ||
559 | var->green.offset = 4; var->green.length = 4; | ||
560 | var->green.msb_right = 0; | ||
561 | var->blue.offset = 0; var->blue.length = 4; | ||
562 | var->blue.msb_right = 0; | ||
563 | } else { | ||
564 | var->red.offset = 11; var->red.length = 5; | ||
565 | var->red.msb_right = 0; | ||
566 | var->green.offset = 5; var->green.length = 6; | ||
567 | var->green.msb_right = 0; | ||
568 | var->blue.offset = 0; var->blue.length = 5; | ||
569 | var->blue.msb_right = 0; | ||
570 | } | ||
571 | |||
572 | var->height = -1; | ||
573 | var->width = -1; | ||
574 | var->grayscale = 0; | ||
575 | |||
576 | /* pixclock in ps, the rest in pixclock */ | ||
577 | var->pixclock = 10000000 / (panel->pixel_clock / 100); | ||
578 | var->left_margin = panel->hfp; | ||
579 | var->right_margin = panel->hbp; | ||
580 | var->upper_margin = panel->vfp; | ||
581 | var->lower_margin = panel->vbp; | ||
582 | var->hsync_len = panel->hsw; | ||
583 | var->vsync_len = panel->vsw; | ||
584 | |||
585 | /* TODO: get these from panel->config */ | ||
586 | var->vmode = FB_VMODE_NONINTERLACED; | ||
587 | var->sync = 0; | ||
588 | |||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | |||
593 | /* Set rotation (0, 90, 180, 270 degree), and switch to the new mode. */ | ||
594 | static void omapfb_rotate(struct fb_info *fbi, int rotate) | ||
595 | { | ||
596 | struct omapfb_plane_struct *plane = fbi->par; | ||
597 | struct omapfb_device *fbdev = plane->fbdev; | ||
598 | |||
599 | omapfb_rqueue_lock(fbdev); | ||
600 | if (cpu_is_omap15xx() && rotate != fbi->var.rotate) { | ||
601 | struct fb_var_screeninfo *new_var = &fbdev->new_var; | ||
602 | |||
603 | memcpy(new_var, &fbi->var, sizeof(*new_var)); | ||
604 | new_var->rotate = rotate; | ||
605 | if (set_fb_var(fbi, new_var) == 0 && | ||
606 | memcmp(new_var, &fbi->var, sizeof(*new_var))) { | ||
607 | memcpy(&fbi->var, new_var, sizeof(*new_var)); | ||
608 | ctrl_change_mode(fbi); | ||
609 | } | ||
610 | } | ||
611 | omapfb_rqueue_unlock(fbdev); | ||
612 | } | ||
613 | |||
614 | /* | ||
615 | * Set new x,y offsets in the virtual display for the visible area and switch | ||
616 | * to the new mode. | ||
617 | */ | ||
618 | static int omapfb_pan_display(struct fb_var_screeninfo *var, | ||
619 | struct fb_info *fbi) | ||
620 | { | ||
621 | struct omapfb_plane_struct *plane = fbi->par; | ||
622 | struct omapfb_device *fbdev = plane->fbdev; | ||
623 | int r = 0; | ||
624 | |||
625 | omapfb_rqueue_lock(fbdev); | ||
626 | if (var->xoffset != fbi->var.xoffset || | ||
627 | var->yoffset != fbi->var.yoffset) { | ||
628 | struct fb_var_screeninfo *new_var = &fbdev->new_var; | ||
629 | |||
630 | memcpy(new_var, &fbi->var, sizeof(*new_var)); | ||
631 | new_var->xoffset = var->xoffset; | ||
632 | new_var->yoffset = var->yoffset; | ||
633 | if (set_fb_var(fbi, new_var)) | ||
634 | r = -EINVAL; | ||
635 | else { | ||
636 | memcpy(&fbi->var, new_var, sizeof(*new_var)); | ||
637 | ctrl_change_mode(fbi); | ||
638 | } | ||
639 | } | ||
640 | omapfb_rqueue_unlock(fbdev); | ||
641 | |||
642 | return r; | ||
643 | } | ||
644 | |||
645 | /* Set mirror to vertical axis and switch to the new mode. */ | ||
646 | static int omapfb_mirror(struct fb_info *fbi, int mirror) | ||
647 | { | ||
648 | struct omapfb_plane_struct *plane = fbi->par; | ||
649 | struct omapfb_device *fbdev = plane->fbdev; | ||
650 | int r = 0; | ||
651 | |||
652 | omapfb_rqueue_lock(fbdev); | ||
653 | mirror = mirror ? 1 : 0; | ||
654 | if (cpu_is_omap15xx()) | ||
655 | r = -EINVAL; | ||
656 | else if (mirror != plane->info.mirror) { | ||
657 | plane->info.mirror = mirror; | ||
658 | r = ctrl_change_mode(fbi); | ||
659 | } | ||
660 | omapfb_rqueue_unlock(fbdev); | ||
661 | |||
662 | return r; | ||
663 | } | ||
664 | |||
665 | /* | ||
666 | * Check values in var, try to adjust them in case of out of bound values if | ||
667 | * possible, or return error. | ||
668 | */ | ||
669 | static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi) | ||
670 | { | ||
671 | struct omapfb_plane_struct *plane = fbi->par; | ||
672 | struct omapfb_device *fbdev = plane->fbdev; | ||
673 | int r; | ||
674 | |||
675 | omapfb_rqueue_lock(fbdev); | ||
676 | if (fbdev->ctrl->sync != NULL) | ||
677 | fbdev->ctrl->sync(); | ||
678 | r = set_fb_var(fbi, var); | ||
679 | omapfb_rqueue_unlock(fbdev); | ||
680 | |||
681 | return r; | ||
682 | } | ||
683 | |||
684 | /* | ||
685 | * Switch to a new mode. The parameters for it has been check already by | ||
686 | * omapfb_check_var. | ||
687 | */ | ||
688 | static int omapfb_set_par(struct fb_info *fbi) | ||
689 | { | ||
690 | struct omapfb_plane_struct *plane = fbi->par; | ||
691 | struct omapfb_device *fbdev = plane->fbdev; | ||
692 | int r = 0; | ||
693 | |||
694 | omapfb_rqueue_lock(fbdev); | ||
695 | set_fb_fix(fbi); | ||
696 | r = ctrl_change_mode(fbi); | ||
697 | omapfb_rqueue_unlock(fbdev); | ||
698 | |||
699 | return r; | ||
700 | } | ||
701 | |||
702 | int omapfb_update_window_async(struct fb_info *fbi, | ||
703 | struct omapfb_update_window *win, | ||
704 | void (*callback)(void *), | ||
705 | void *callback_data) | ||
706 | { | ||
707 | struct omapfb_plane_struct *plane = fbi->par; | ||
708 | struct omapfb_device *fbdev = plane->fbdev; | ||
709 | struct fb_var_screeninfo *var; | ||
710 | |||
711 | var = &fbi->var; | ||
712 | if (win->x >= var->xres || win->y >= var->yres || | ||
713 | win->out_x > var->xres || win->out_y >= var->yres) | ||
714 | return -EINVAL; | ||
715 | |||
716 | if (!fbdev->ctrl->update_window || | ||
717 | fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE) | ||
718 | return -ENODEV; | ||
719 | |||
720 | if (win->x + win->width >= var->xres) | ||
721 | win->width = var->xres - win->x; | ||
722 | if (win->y + win->height >= var->yres) | ||
723 | win->height = var->yres - win->y; | ||
724 | /* The out sizes should be cropped to the LCD size */ | ||
725 | if (win->out_x + win->out_width > fbdev->panel->x_res) | ||
726 | win->out_width = fbdev->panel->x_res - win->out_x; | ||
727 | if (win->out_y + win->out_height > fbdev->panel->y_res) | ||
728 | win->out_height = fbdev->panel->y_res - win->out_y; | ||
729 | if (!win->width || !win->height || !win->out_width || !win->out_height) | ||
730 | return 0; | ||
731 | |||
732 | return fbdev->ctrl->update_window(fbi, win, callback, callback_data); | ||
733 | } | ||
734 | EXPORT_SYMBOL(omapfb_update_window_async); | ||
735 | |||
736 | static int omapfb_update_win(struct fb_info *fbi, | ||
737 | struct omapfb_update_window *win) | ||
738 | { | ||
739 | struct omapfb_plane_struct *plane = fbi->par; | ||
740 | int ret; | ||
741 | |||
742 | omapfb_rqueue_lock(plane->fbdev); | ||
743 | ret = omapfb_update_window_async(fbi, win, NULL, 0); | ||
744 | omapfb_rqueue_unlock(plane->fbdev); | ||
745 | |||
746 | return ret; | ||
747 | } | ||
748 | |||
749 | static int omapfb_update_full_screen(struct fb_info *fbi) | ||
750 | { | ||
751 | struct omapfb_plane_struct *plane = fbi->par; | ||
752 | struct omapfb_device *fbdev = plane->fbdev; | ||
753 | struct omapfb_update_window win; | ||
754 | int r; | ||
755 | |||
756 | if (!fbdev->ctrl->update_window || | ||
757 | fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE) | ||
758 | return -ENODEV; | ||
759 | |||
760 | win.x = 0; | ||
761 | win.y = 0; | ||
762 | win.width = fbi->var.xres; | ||
763 | win.height = fbi->var.yres; | ||
764 | win.out_x = 0; | ||
765 | win.out_y = 0; | ||
766 | win.out_width = fbi->var.xres; | ||
767 | win.out_height = fbi->var.yres; | ||
768 | win.format = 0; | ||
769 | |||
770 | omapfb_rqueue_lock(fbdev); | ||
771 | r = fbdev->ctrl->update_window(fbi, &win, NULL, 0); | ||
772 | omapfb_rqueue_unlock(fbdev); | ||
773 | |||
774 | return r; | ||
775 | } | ||
776 | |||
777 | static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) | ||
778 | { | ||
779 | struct omapfb_plane_struct *plane = fbi->par; | ||
780 | struct omapfb_device *fbdev = plane->fbdev; | ||
781 | struct lcd_panel *panel = fbdev->panel; | ||
782 | struct omapfb_plane_info old_info; | ||
783 | int r = 0; | ||
784 | |||
785 | if (pi->pos_x + pi->out_width > panel->x_res || | ||
786 | pi->pos_y + pi->out_height > panel->y_res) | ||
787 | return -EINVAL; | ||
788 | |||
789 | omapfb_rqueue_lock(fbdev); | ||
790 | if (pi->enabled && !fbdev->mem_desc.region[plane->idx].size) { | ||
791 | /* | ||
792 | * This plane's memory was freed, can't enable it | ||
793 | * until it's reallocated. | ||
794 | */ | ||
795 | r = -EINVAL; | ||
796 | goto out; | ||
797 | } | ||
798 | old_info = plane->info; | ||
799 | plane->info = *pi; | ||
800 | if (pi->enabled) { | ||
801 | r = ctrl_change_mode(fbi); | ||
802 | if (r < 0) { | ||
803 | plane->info = old_info; | ||
804 | goto out; | ||
805 | } | ||
806 | } | ||
807 | r = fbdev->ctrl->enable_plane(plane->idx, pi->enabled); | ||
808 | if (r < 0) { | ||
809 | plane->info = old_info; | ||
810 | goto out; | ||
811 | } | ||
812 | out: | ||
813 | omapfb_rqueue_unlock(fbdev); | ||
814 | return r; | ||
815 | } | ||
816 | |||
817 | static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) | ||
818 | { | ||
819 | struct omapfb_plane_struct *plane = fbi->par; | ||
820 | |||
821 | *pi = plane->info; | ||
822 | return 0; | ||
823 | } | ||
824 | |||
825 | static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | ||
826 | { | ||
827 | struct omapfb_plane_struct *plane = fbi->par; | ||
828 | struct omapfb_device *fbdev = plane->fbdev; | ||
829 | struct omapfb_mem_region *rg = &fbdev->mem_desc.region[plane->idx]; | ||
830 | size_t size; | ||
831 | int r = 0; | ||
832 | |||
833 | if (fbdev->ctrl->setup_mem == NULL) | ||
834 | return -ENODEV; | ||
835 | if (mi->type > OMAPFB_MEMTYPE_MAX) | ||
836 | return -EINVAL; | ||
837 | |||
838 | size = PAGE_ALIGN(mi->size); | ||
839 | omapfb_rqueue_lock(fbdev); | ||
840 | if (plane->info.enabled) { | ||
841 | r = -EBUSY; | ||
842 | goto out; | ||
843 | } | ||
844 | if (rg->size != size || rg->type != mi->type) { | ||
845 | struct fb_var_screeninfo *new_var = &fbdev->new_var; | ||
846 | unsigned long old_size = rg->size; | ||
847 | u8 old_type = rg->type; | ||
848 | unsigned long paddr; | ||
849 | |||
850 | rg->size = size; | ||
851 | rg->type = mi->type; | ||
852 | /* | ||
853 | * size == 0 is a special case, for which we | ||
854 | * don't check / adjust the screen parameters. | ||
855 | * This isn't a problem since the plane can't | ||
856 | * be reenabled unless its size is > 0. | ||
857 | */ | ||
858 | if (old_size != size && size) { | ||
859 | if (size) { | ||
860 | memcpy(new_var, &fbi->var, sizeof(*new_var)); | ||
861 | r = set_fb_var(fbi, new_var); | ||
862 | if (r < 0) | ||
863 | goto out; | ||
864 | } | ||
865 | } | ||
866 | |||
867 | if (fbdev->ctrl->sync) | ||
868 | fbdev->ctrl->sync(); | ||
869 | r = fbdev->ctrl->setup_mem(plane->idx, size, mi->type, &paddr); | ||
870 | if (r < 0) { | ||
871 | /* Revert changes. */ | ||
872 | rg->size = old_size; | ||
873 | rg->type = old_type; | ||
874 | goto out; | ||
875 | } | ||
876 | rg->paddr = paddr; | ||
877 | |||
878 | if (old_size != size) { | ||
879 | if (size) { | ||
880 | memcpy(&fbi->var, new_var, sizeof(fbi->var)); | ||
881 | set_fb_fix(fbi); | ||
882 | } else { | ||
883 | /* | ||
884 | * Set these explicitly to indicate that the | ||
885 | * plane memory is dealloce'd, the other | ||
886 | * screen parameters in var / fix are invalid. | ||
887 | */ | ||
888 | fbi->fix.smem_start = 0; | ||
889 | fbi->fix.smem_len = 0; | ||
890 | } | ||
891 | } | ||
892 | } | ||
893 | out: | ||
894 | omapfb_rqueue_unlock(fbdev); | ||
895 | |||
896 | return r; | ||
897 | } | ||
898 | |||
899 | static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | ||
900 | { | ||
901 | struct omapfb_plane_struct *plane = fbi->par; | ||
902 | struct omapfb_device *fbdev = plane->fbdev; | ||
903 | struct omapfb_mem_region *rg; | ||
904 | |||
905 | rg = &fbdev->mem_desc.region[plane->idx]; | ||
906 | memset(mi, 0, sizeof(*mi)); | ||
907 | mi->size = rg->size; | ||
908 | mi->type = rg->type; | ||
909 | |||
910 | return 0; | ||
911 | } | ||
912 | |||
913 | static int omapfb_set_color_key(struct omapfb_device *fbdev, | ||
914 | struct omapfb_color_key *ck) | ||
915 | { | ||
916 | int r; | ||
917 | |||
918 | if (!fbdev->ctrl->set_color_key) | ||
919 | return -ENODEV; | ||
920 | |||
921 | omapfb_rqueue_lock(fbdev); | ||
922 | r = fbdev->ctrl->set_color_key(ck); | ||
923 | omapfb_rqueue_unlock(fbdev); | ||
924 | |||
925 | return r; | ||
926 | } | ||
927 | |||
928 | static int omapfb_get_color_key(struct omapfb_device *fbdev, | ||
929 | struct omapfb_color_key *ck) | ||
930 | { | ||
931 | int r; | ||
932 | |||
933 | if (!fbdev->ctrl->get_color_key) | ||
934 | return -ENODEV; | ||
935 | |||
936 | omapfb_rqueue_lock(fbdev); | ||
937 | r = fbdev->ctrl->get_color_key(ck); | ||
938 | omapfb_rqueue_unlock(fbdev); | ||
939 | |||
940 | return r; | ||
941 | } | ||
942 | |||
943 | static struct blocking_notifier_head omapfb_client_list[OMAPFB_PLANE_NUM]; | ||
944 | static int notifier_inited; | ||
945 | |||
946 | static void omapfb_init_notifier(void) | ||
947 | { | ||
948 | int i; | ||
949 | |||
950 | for (i = 0; i < OMAPFB_PLANE_NUM; i++) | ||
951 | BLOCKING_INIT_NOTIFIER_HEAD(&omapfb_client_list[i]); | ||
952 | } | ||
953 | |||
954 | int omapfb_register_client(struct omapfb_notifier_block *omapfb_nb, | ||
955 | omapfb_notifier_callback_t callback, | ||
956 | void *callback_data) | ||
957 | { | ||
958 | int r; | ||
959 | |||
960 | if ((unsigned)omapfb_nb->plane_idx > OMAPFB_PLANE_NUM) | ||
961 | return -EINVAL; | ||
962 | |||
963 | if (!notifier_inited) { | ||
964 | omapfb_init_notifier(); | ||
965 | notifier_inited = 1; | ||
966 | } | ||
967 | |||
968 | omapfb_nb->nb.notifier_call = (int (*)(struct notifier_block *, | ||
969 | unsigned long, void *))callback; | ||
970 | omapfb_nb->data = callback_data; | ||
971 | r = blocking_notifier_chain_register( | ||
972 | &omapfb_client_list[omapfb_nb->plane_idx], | ||
973 | &omapfb_nb->nb); | ||
974 | if (r) | ||
975 | return r; | ||
976 | if (omapfb_dev != NULL && | ||
977 | omapfb_dev->ctrl && omapfb_dev->ctrl->bind_client) { | ||
978 | omapfb_dev->ctrl->bind_client(omapfb_nb); | ||
979 | } | ||
980 | |||
981 | return 0; | ||
982 | } | ||
983 | EXPORT_SYMBOL(omapfb_register_client); | ||
984 | |||
985 | int omapfb_unregister_client(struct omapfb_notifier_block *omapfb_nb) | ||
986 | { | ||
987 | return blocking_notifier_chain_unregister( | ||
988 | &omapfb_client_list[omapfb_nb->plane_idx], &omapfb_nb->nb); | ||
989 | } | ||
990 | EXPORT_SYMBOL(omapfb_unregister_client); | ||
991 | |||
992 | void omapfb_notify_clients(struct omapfb_device *fbdev, unsigned long event) | ||
993 | { | ||
994 | int i; | ||
995 | |||
996 | if (!notifier_inited) | ||
997 | /* no client registered yet */ | ||
998 | return; | ||
999 | |||
1000 | for (i = 0; i < OMAPFB_PLANE_NUM; i++) | ||
1001 | blocking_notifier_call_chain(&omapfb_client_list[i], event, | ||
1002 | fbdev->fb_info[i]); | ||
1003 | } | ||
1004 | EXPORT_SYMBOL(omapfb_notify_clients); | ||
1005 | |||
1006 | static int omapfb_set_update_mode(struct omapfb_device *fbdev, | ||
1007 | enum omapfb_update_mode mode) | ||
1008 | { | ||
1009 | int r; | ||
1010 | |||
1011 | omapfb_rqueue_lock(fbdev); | ||
1012 | r = fbdev->ctrl->set_update_mode(mode); | ||
1013 | omapfb_rqueue_unlock(fbdev); | ||
1014 | |||
1015 | return r; | ||
1016 | } | ||
1017 | |||
1018 | static enum omapfb_update_mode omapfb_get_update_mode(struct omapfb_device *fbdev) | ||
1019 | { | ||
1020 | int r; | ||
1021 | |||
1022 | omapfb_rqueue_lock(fbdev); | ||
1023 | r = fbdev->ctrl->get_update_mode(); | ||
1024 | omapfb_rqueue_unlock(fbdev); | ||
1025 | |||
1026 | return r; | ||
1027 | } | ||
1028 | |||
1029 | static void omapfb_get_caps(struct omapfb_device *fbdev, int plane, | ||
1030 | struct omapfb_caps *caps) | ||
1031 | { | ||
1032 | memset(caps, 0, sizeof(*caps)); | ||
1033 | fbdev->ctrl->get_caps(plane, caps); | ||
1034 | caps->ctrl |= fbdev->panel->get_caps(fbdev->panel); | ||
1035 | } | ||
1036 | |||
1037 | /* For lcd testing */ | ||
1038 | void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval) | ||
1039 | { | ||
1040 | omapfb_rqueue_lock(fbdev); | ||
1041 | *(u16 *)fbdev->mem_desc.region[0].vaddr = pixval; | ||
1042 | if (fbdev->ctrl->get_update_mode() == OMAPFB_MANUAL_UPDATE) { | ||
1043 | struct omapfb_update_window win; | ||
1044 | |||
1045 | memset(&win, 0, sizeof(win)); | ||
1046 | win.width = 2; | ||
1047 | win.height = 2; | ||
1048 | win.out_width = 2; | ||
1049 | win.out_height = 2; | ||
1050 | fbdev->ctrl->update_window(fbdev->fb_info[0], &win, NULL, 0); | ||
1051 | } | ||
1052 | omapfb_rqueue_unlock(fbdev); | ||
1053 | } | ||
1054 | EXPORT_SYMBOL(omapfb_write_first_pixel); | ||
1055 | |||
1056 | /* | ||
1057 | * Ioctl interface. Part of the kernel mode frame buffer API is duplicated | ||
1058 | * here to be accessible by user mode code. | ||
1059 | */ | ||
1060 | static int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, | ||
1061 | unsigned long arg) | ||
1062 | { | ||
1063 | struct omapfb_plane_struct *plane = fbi->par; | ||
1064 | struct omapfb_device *fbdev = plane->fbdev; | ||
1065 | struct fb_ops *ops = fbi->fbops; | ||
1066 | union { | ||
1067 | struct omapfb_update_window update_window; | ||
1068 | struct omapfb_plane_info plane_info; | ||
1069 | struct omapfb_mem_info mem_info; | ||
1070 | struct omapfb_color_key color_key; | ||
1071 | enum omapfb_update_mode update_mode; | ||
1072 | struct omapfb_caps caps; | ||
1073 | unsigned int mirror; | ||
1074 | int plane_out; | ||
1075 | int enable_plane; | ||
1076 | } p; | ||
1077 | int r = 0; | ||
1078 | |||
1079 | BUG_ON(!ops); | ||
1080 | switch (cmd) { | ||
1081 | case OMAPFB_MIRROR: | ||
1082 | if (get_user(p.mirror, (int __user *)arg)) | ||
1083 | r = -EFAULT; | ||
1084 | else | ||
1085 | omapfb_mirror(fbi, p.mirror); | ||
1086 | break; | ||
1087 | case OMAPFB_SYNC_GFX: | ||
1088 | omapfb_sync(fbi); | ||
1089 | break; | ||
1090 | case OMAPFB_VSYNC: | ||
1091 | break; | ||
1092 | case OMAPFB_SET_UPDATE_MODE: | ||
1093 | if (get_user(p.update_mode, (int __user *)arg)) | ||
1094 | r = -EFAULT; | ||
1095 | else | ||
1096 | r = omapfb_set_update_mode(fbdev, p.update_mode); | ||
1097 | break; | ||
1098 | case OMAPFB_GET_UPDATE_MODE: | ||
1099 | p.update_mode = omapfb_get_update_mode(fbdev); | ||
1100 | if (put_user(p.update_mode, | ||
1101 | (enum omapfb_update_mode __user *)arg)) | ||
1102 | r = -EFAULT; | ||
1103 | break; | ||
1104 | case OMAPFB_UPDATE_WINDOW_OLD: | ||
1105 | if (copy_from_user(&p.update_window, (void __user *)arg, | ||
1106 | sizeof(struct omapfb_update_window_old))) | ||
1107 | r = -EFAULT; | ||
1108 | else { | ||
1109 | struct omapfb_update_window *u = &p.update_window; | ||
1110 | u->out_x = u->x; | ||
1111 | u->out_y = u->y; | ||
1112 | u->out_width = u->width; | ||
1113 | u->out_height = u->height; | ||
1114 | memset(u->reserved, 0, sizeof(u->reserved)); | ||
1115 | r = omapfb_update_win(fbi, u); | ||
1116 | } | ||
1117 | break; | ||
1118 | case OMAPFB_UPDATE_WINDOW: | ||
1119 | if (copy_from_user(&p.update_window, (void __user *)arg, | ||
1120 | sizeof(p.update_window))) | ||
1121 | r = -EFAULT; | ||
1122 | else | ||
1123 | r = omapfb_update_win(fbi, &p.update_window); | ||
1124 | break; | ||
1125 | case OMAPFB_SETUP_PLANE: | ||
1126 | if (copy_from_user(&p.plane_info, (void __user *)arg, | ||
1127 | sizeof(p.plane_info))) | ||
1128 | r = -EFAULT; | ||
1129 | else | ||
1130 | r = omapfb_setup_plane(fbi, &p.plane_info); | ||
1131 | break; | ||
1132 | case OMAPFB_QUERY_PLANE: | ||
1133 | if ((r = omapfb_query_plane(fbi, &p.plane_info)) < 0) | ||
1134 | break; | ||
1135 | if (copy_to_user((void __user *)arg, &p.plane_info, | ||
1136 | sizeof(p.plane_info))) | ||
1137 | r = -EFAULT; | ||
1138 | break; | ||
1139 | case OMAPFB_SETUP_MEM: | ||
1140 | if (copy_from_user(&p.mem_info, (void __user *)arg, | ||
1141 | sizeof(p.mem_info))) | ||
1142 | r = -EFAULT; | ||
1143 | else | ||
1144 | r = omapfb_setup_mem(fbi, &p.mem_info); | ||
1145 | break; | ||
1146 | case OMAPFB_QUERY_MEM: | ||
1147 | if ((r = omapfb_query_mem(fbi, &p.mem_info)) < 0) | ||
1148 | break; | ||
1149 | if (copy_to_user((void __user *)arg, &p.mem_info, | ||
1150 | sizeof(p.mem_info))) | ||
1151 | r = -EFAULT; | ||
1152 | break; | ||
1153 | case OMAPFB_SET_COLOR_KEY: | ||
1154 | if (copy_from_user(&p.color_key, (void __user *)arg, | ||
1155 | sizeof(p.color_key))) | ||
1156 | r = -EFAULT; | ||
1157 | else | ||
1158 | r = omapfb_set_color_key(fbdev, &p.color_key); | ||
1159 | break; | ||
1160 | case OMAPFB_GET_COLOR_KEY: | ||
1161 | if ((r = omapfb_get_color_key(fbdev, &p.color_key)) < 0) | ||
1162 | break; | ||
1163 | if (copy_to_user((void __user *)arg, &p.color_key, | ||
1164 | sizeof(p.color_key))) | ||
1165 | r = -EFAULT; | ||
1166 | break; | ||
1167 | case OMAPFB_GET_CAPS: | ||
1168 | omapfb_get_caps(fbdev, plane->idx, &p.caps); | ||
1169 | if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps))) | ||
1170 | r = -EFAULT; | ||
1171 | break; | ||
1172 | case OMAPFB_LCD_TEST: | ||
1173 | { | ||
1174 | int test_num; | ||
1175 | |||
1176 | if (get_user(test_num, (int __user *)arg)) { | ||
1177 | r = -EFAULT; | ||
1178 | break; | ||
1179 | } | ||
1180 | if (!fbdev->panel->run_test) { | ||
1181 | r = -EINVAL; | ||
1182 | break; | ||
1183 | } | ||
1184 | r = fbdev->panel->run_test(fbdev->panel, test_num); | ||
1185 | break; | ||
1186 | } | ||
1187 | case OMAPFB_CTRL_TEST: | ||
1188 | { | ||
1189 | int test_num; | ||
1190 | |||
1191 | if (get_user(test_num, (int __user *)arg)) { | ||
1192 | r = -EFAULT; | ||
1193 | break; | ||
1194 | } | ||
1195 | if (!fbdev->ctrl->run_test) { | ||
1196 | r = -EINVAL; | ||
1197 | break; | ||
1198 | } | ||
1199 | r = fbdev->ctrl->run_test(test_num); | ||
1200 | break; | ||
1201 | } | ||
1202 | default: | ||
1203 | r = -EINVAL; | ||
1204 | } | ||
1205 | |||
1206 | return r; | ||
1207 | } | ||
1208 | |||
1209 | static int omapfb_mmap(struct fb_info *info, struct vm_area_struct *vma) | ||
1210 | { | ||
1211 | struct omapfb_plane_struct *plane = info->par; | ||
1212 | struct omapfb_device *fbdev = plane->fbdev; | ||
1213 | int r; | ||
1214 | |||
1215 | omapfb_rqueue_lock(fbdev); | ||
1216 | r = fbdev->ctrl->mmap(info, vma); | ||
1217 | omapfb_rqueue_unlock(fbdev); | ||
1218 | |||
1219 | return r; | ||
1220 | } | ||
1221 | |||
1222 | /* | ||
1223 | * Callback table for the frame buffer framework. Some of these pointers | ||
1224 | * will be changed according to the current setting of fb_info->accel_flags. | ||
1225 | */ | ||
1226 | static struct fb_ops omapfb_ops = { | ||
1227 | .owner = THIS_MODULE, | ||
1228 | .fb_open = omapfb_open, | ||
1229 | .fb_release = omapfb_release, | ||
1230 | .fb_setcolreg = omapfb_setcolreg, | ||
1231 | .fb_setcmap = omapfb_setcmap, | ||
1232 | .fb_fillrect = cfb_fillrect, | ||
1233 | .fb_copyarea = cfb_copyarea, | ||
1234 | .fb_imageblit = cfb_imageblit, | ||
1235 | .fb_blank = omapfb_blank, | ||
1236 | .fb_ioctl = omapfb_ioctl, | ||
1237 | .fb_check_var = omapfb_check_var, | ||
1238 | .fb_set_par = omapfb_set_par, | ||
1239 | .fb_rotate = omapfb_rotate, | ||
1240 | .fb_pan_display = omapfb_pan_display, | ||
1241 | }; | ||
1242 | |||
1243 | /* | ||
1244 | * --------------------------------------------------------------------------- | ||
1245 | * Sysfs interface | ||
1246 | * --------------------------------------------------------------------------- | ||
1247 | */ | ||
1248 | /* omapfbX sysfs entries */ | ||
1249 | static ssize_t omapfb_show_caps_num(struct device *dev, | ||
1250 | struct device_attribute *attr, char *buf) | ||
1251 | { | ||
1252 | struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; | ||
1253 | int plane; | ||
1254 | size_t size; | ||
1255 | struct omapfb_caps caps; | ||
1256 | |||
1257 | plane = 0; | ||
1258 | size = 0; | ||
1259 | while (size < PAGE_SIZE && plane < OMAPFB_PLANE_NUM) { | ||
1260 | omapfb_get_caps(fbdev, plane, &caps); | ||
1261 | size += snprintf(&buf[size], PAGE_SIZE - size, | ||
1262 | "plane#%d %#010x %#010x %#010x\n", | ||
1263 | plane, caps.ctrl, caps.plane_color, caps.wnd_color); | ||
1264 | plane++; | ||
1265 | } | ||
1266 | return size; | ||
1267 | } | ||
1268 | |||
1269 | static ssize_t omapfb_show_caps_text(struct device *dev, | ||
1270 | struct device_attribute *attr, char *buf) | ||
1271 | { | ||
1272 | struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; | ||
1273 | int i; | ||
1274 | struct omapfb_caps caps; | ||
1275 | int plane; | ||
1276 | size_t size; | ||
1277 | |||
1278 | plane = 0; | ||
1279 | size = 0; | ||
1280 | while (size < PAGE_SIZE && plane < OMAPFB_PLANE_NUM) { | ||
1281 | omapfb_get_caps(fbdev, plane, &caps); | ||
1282 | size += snprintf(&buf[size], PAGE_SIZE - size, | ||
1283 | "plane#%d:\n", plane); | ||
1284 | for (i = 0; i < ARRAY_SIZE(ctrl_caps) && | ||
1285 | size < PAGE_SIZE; i++) { | ||
1286 | if (ctrl_caps[i].flag & caps.ctrl) | ||
1287 | size += snprintf(&buf[size], PAGE_SIZE - size, | ||
1288 | " %s\n", ctrl_caps[i].name); | ||
1289 | } | ||
1290 | size += snprintf(&buf[size], PAGE_SIZE - size, | ||
1291 | " plane colors:\n"); | ||
1292 | for (i = 0; i < ARRAY_SIZE(color_caps) && | ||
1293 | size < PAGE_SIZE; i++) { | ||
1294 | if (color_caps[i].flag & caps.plane_color) | ||
1295 | size += snprintf(&buf[size], PAGE_SIZE - size, | ||
1296 | " %s\n", color_caps[i].name); | ||
1297 | } | ||
1298 | size += snprintf(&buf[size], PAGE_SIZE - size, | ||
1299 | " window colors:\n"); | ||
1300 | for (i = 0; i < ARRAY_SIZE(color_caps) && | ||
1301 | size < PAGE_SIZE; i++) { | ||
1302 | if (color_caps[i].flag & caps.wnd_color) | ||
1303 | size += snprintf(&buf[size], PAGE_SIZE - size, | ||
1304 | " %s\n", color_caps[i].name); | ||
1305 | } | ||
1306 | |||
1307 | plane++; | ||
1308 | } | ||
1309 | return size; | ||
1310 | } | ||
1311 | |||
1312 | static DEVICE_ATTR(caps_num, 0444, omapfb_show_caps_num, NULL); | ||
1313 | static DEVICE_ATTR(caps_text, 0444, omapfb_show_caps_text, NULL); | ||
1314 | |||
1315 | /* panel sysfs entries */ | ||
1316 | static ssize_t omapfb_show_panel_name(struct device *dev, | ||
1317 | struct device_attribute *attr, char *buf) | ||
1318 | { | ||
1319 | struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; | ||
1320 | |||
1321 | return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->panel->name); | ||
1322 | } | ||
1323 | |||
1324 | static ssize_t omapfb_show_bklight_level(struct device *dev, | ||
1325 | struct device_attribute *attr, | ||
1326 | char *buf) | ||
1327 | { | ||
1328 | struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; | ||
1329 | int r; | ||
1330 | |||
1331 | if (fbdev->panel->get_bklight_level) { | ||
1332 | r = snprintf(buf, PAGE_SIZE, "%d\n", | ||
1333 | fbdev->panel->get_bklight_level(fbdev->panel)); | ||
1334 | } else | ||
1335 | r = -ENODEV; | ||
1336 | return r; | ||
1337 | } | ||
1338 | |||
1339 | static ssize_t omapfb_store_bklight_level(struct device *dev, | ||
1340 | struct device_attribute *attr, | ||
1341 | const char *buf, size_t size) | ||
1342 | { | ||
1343 | struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; | ||
1344 | int r; | ||
1345 | |||
1346 | if (fbdev->panel->set_bklight_level) { | ||
1347 | unsigned int level; | ||
1348 | |||
1349 | if (sscanf(buf, "%10d", &level) == 1) { | ||
1350 | r = fbdev->panel->set_bklight_level(fbdev->panel, | ||
1351 | level); | ||
1352 | } else | ||
1353 | r = -EINVAL; | ||
1354 | } else | ||
1355 | r = -ENODEV; | ||
1356 | return r ? r : size; | ||
1357 | } | ||
1358 | |||
1359 | static ssize_t omapfb_show_bklight_max(struct device *dev, | ||
1360 | struct device_attribute *attr, char *buf) | ||
1361 | { | ||
1362 | struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; | ||
1363 | int r; | ||
1364 | |||
1365 | if (fbdev->panel->get_bklight_level) { | ||
1366 | r = snprintf(buf, PAGE_SIZE, "%d\n", | ||
1367 | fbdev->panel->get_bklight_max(fbdev->panel)); | ||
1368 | } else | ||
1369 | r = -ENODEV; | ||
1370 | return r; | ||
1371 | } | ||
1372 | |||
1373 | static struct device_attribute dev_attr_panel_name = | ||
1374 | __ATTR(name, 0444, omapfb_show_panel_name, NULL); | ||
1375 | static DEVICE_ATTR(backlight_level, 0664, | ||
1376 | omapfb_show_bklight_level, omapfb_store_bklight_level); | ||
1377 | static DEVICE_ATTR(backlight_max, 0444, omapfb_show_bklight_max, NULL); | ||
1378 | |||
1379 | static struct attribute *panel_attrs[] = { | ||
1380 | &dev_attr_panel_name.attr, | ||
1381 | &dev_attr_backlight_level.attr, | ||
1382 | &dev_attr_backlight_max.attr, | ||
1383 | NULL, | ||
1384 | }; | ||
1385 | |||
1386 | static struct attribute_group panel_attr_grp = { | ||
1387 | .name = "panel", | ||
1388 | .attrs = panel_attrs, | ||
1389 | }; | ||
1390 | |||
1391 | /* ctrl sysfs entries */ | ||
1392 | static ssize_t omapfb_show_ctrl_name(struct device *dev, | ||
1393 | struct device_attribute *attr, char *buf) | ||
1394 | { | ||
1395 | struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; | ||
1396 | |||
1397 | return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->ctrl->name); | ||
1398 | } | ||
1399 | |||
1400 | static struct device_attribute dev_attr_ctrl_name = | ||
1401 | __ATTR(name, 0444, omapfb_show_ctrl_name, NULL); | ||
1402 | |||
1403 | static struct attribute *ctrl_attrs[] = { | ||
1404 | &dev_attr_ctrl_name.attr, | ||
1405 | NULL, | ||
1406 | }; | ||
1407 | |||
1408 | static struct attribute_group ctrl_attr_grp = { | ||
1409 | .name = "ctrl", | ||
1410 | .attrs = ctrl_attrs, | ||
1411 | }; | ||
1412 | |||
1413 | static int omapfb_register_sysfs(struct omapfb_device *fbdev) | ||
1414 | { | ||
1415 | int r; | ||
1416 | |||
1417 | if ((r = device_create_file(fbdev->dev, &dev_attr_caps_num))) | ||
1418 | goto fail0; | ||
1419 | |||
1420 | if ((r = device_create_file(fbdev->dev, &dev_attr_caps_text))) | ||
1421 | goto fail1; | ||
1422 | |||
1423 | if ((r = sysfs_create_group(&fbdev->dev->kobj, &panel_attr_grp))) | ||
1424 | goto fail2; | ||
1425 | |||
1426 | if ((r = sysfs_create_group(&fbdev->dev->kobj, &ctrl_attr_grp))) | ||
1427 | goto fail3; | ||
1428 | |||
1429 | return 0; | ||
1430 | fail3: | ||
1431 | sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp); | ||
1432 | fail2: | ||
1433 | device_remove_file(fbdev->dev, &dev_attr_caps_text); | ||
1434 | fail1: | ||
1435 | device_remove_file(fbdev->dev, &dev_attr_caps_num); | ||
1436 | fail0: | ||
1437 | dev_err(fbdev->dev, "unable to register sysfs interface\n"); | ||
1438 | return r; | ||
1439 | } | ||
1440 | |||
1441 | static void omapfb_unregister_sysfs(struct omapfb_device *fbdev) | ||
1442 | { | ||
1443 | sysfs_remove_group(&fbdev->dev->kobj, &ctrl_attr_grp); | ||
1444 | sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp); | ||
1445 | device_remove_file(fbdev->dev, &dev_attr_caps_num); | ||
1446 | device_remove_file(fbdev->dev, &dev_attr_caps_text); | ||
1447 | } | ||
1448 | |||
1449 | /* | ||
1450 | * --------------------------------------------------------------------------- | ||
1451 | * LDM callbacks | ||
1452 | * --------------------------------------------------------------------------- | ||
1453 | */ | ||
1454 | /* Initialize system fb_info object and set the default video mode. | ||
1455 | * The frame buffer memory already allocated by lcddma_init | ||
1456 | */ | ||
1457 | static int fbinfo_init(struct omapfb_device *fbdev, struct fb_info *info) | ||
1458 | { | ||
1459 | struct fb_var_screeninfo *var = &info->var; | ||
1460 | struct fb_fix_screeninfo *fix = &info->fix; | ||
1461 | int r = 0; | ||
1462 | |||
1463 | info->fbops = &omapfb_ops; | ||
1464 | info->flags = FBINFO_FLAG_DEFAULT; | ||
1465 | |||
1466 | strncpy(fix->id, MODULE_NAME, sizeof(fix->id)); | ||
1467 | |||
1468 | info->pseudo_palette = fbdev->pseudo_palette; | ||
1469 | |||
1470 | var->accel_flags = def_accel ? FB_ACCELF_TEXT : 0; | ||
1471 | var->xres = def_vxres; | ||
1472 | var->yres = def_vyres; | ||
1473 | var->xres_virtual = def_vxres; | ||
1474 | var->yres_virtual = def_vyres; | ||
1475 | var->rotate = def_rotate; | ||
1476 | var->bits_per_pixel = fbdev->panel->bpp; | ||
1477 | |||
1478 | set_fb_var(info, var); | ||
1479 | set_fb_fix(info); | ||
1480 | |||
1481 | r = fb_alloc_cmap(&info->cmap, 16, 0); | ||
1482 | if (r != 0) | ||
1483 | dev_err(fbdev->dev, "unable to allocate color map memory\n"); | ||
1484 | |||
1485 | return r; | ||
1486 | } | ||
1487 | |||
1488 | /* Release the fb_info object */ | ||
1489 | static void fbinfo_cleanup(struct omapfb_device *fbdev, struct fb_info *fbi) | ||
1490 | { | ||
1491 | fb_dealloc_cmap(&fbi->cmap); | ||
1492 | } | ||
1493 | |||
1494 | static void planes_cleanup(struct omapfb_device *fbdev) | ||
1495 | { | ||
1496 | int i; | ||
1497 | |||
1498 | for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { | ||
1499 | if (fbdev->fb_info[i] == NULL) | ||
1500 | break; | ||
1501 | fbinfo_cleanup(fbdev, fbdev->fb_info[i]); | ||
1502 | framebuffer_release(fbdev->fb_info[i]); | ||
1503 | } | ||
1504 | } | ||
1505 | |||
1506 | static int planes_init(struct omapfb_device *fbdev) | ||
1507 | { | ||
1508 | struct fb_info *fbi; | ||
1509 | int i; | ||
1510 | int r; | ||
1511 | |||
1512 | for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { | ||
1513 | struct omapfb_plane_struct *plane; | ||
1514 | fbi = framebuffer_alloc(sizeof(struct omapfb_plane_struct), | ||
1515 | fbdev->dev); | ||
1516 | if (fbi == NULL) { | ||
1517 | dev_err(fbdev->dev, | ||
1518 | "unable to allocate memory for plane info\n"); | ||
1519 | planes_cleanup(fbdev); | ||
1520 | return -ENOMEM; | ||
1521 | } | ||
1522 | plane = fbi->par; | ||
1523 | plane->idx = i; | ||
1524 | plane->fbdev = fbdev; | ||
1525 | plane->info.mirror = def_mirror; | ||
1526 | fbdev->fb_info[i] = fbi; | ||
1527 | |||
1528 | if ((r = fbinfo_init(fbdev, fbi)) < 0) { | ||
1529 | framebuffer_release(fbi); | ||
1530 | planes_cleanup(fbdev); | ||
1531 | return r; | ||
1532 | } | ||
1533 | plane->info.out_width = fbi->var.xres; | ||
1534 | plane->info.out_height = fbi->var.yres; | ||
1535 | } | ||
1536 | return 0; | ||
1537 | } | ||
1538 | |||
1539 | /* | ||
1540 | * Free driver resources. Can be called to rollback an aborted initialization | ||
1541 | * sequence. | ||
1542 | */ | ||
1543 | static void omapfb_free_resources(struct omapfb_device *fbdev, int state) | ||
1544 | { | ||
1545 | int i; | ||
1546 | |||
1547 | switch (state) { | ||
1548 | case OMAPFB_ACTIVE: | ||
1549 | for (i = 0; i < fbdev->mem_desc.region_cnt; i++) | ||
1550 | unregister_framebuffer(fbdev->fb_info[i]); | ||
1551 | case 7: | ||
1552 | omapfb_unregister_sysfs(fbdev); | ||
1553 | case 6: | ||
1554 | fbdev->panel->disable(fbdev->panel); | ||
1555 | case 5: | ||
1556 | omapfb_set_update_mode(fbdev, OMAPFB_UPDATE_DISABLED); | ||
1557 | case 4: | ||
1558 | planes_cleanup(fbdev); | ||
1559 | case 3: | ||
1560 | ctrl_cleanup(fbdev); | ||
1561 | case 2: | ||
1562 | fbdev->panel->cleanup(fbdev->panel); | ||
1563 | case 1: | ||
1564 | dev_set_drvdata(fbdev->dev, NULL); | ||
1565 | kfree(fbdev); | ||
1566 | case 0: | ||
1567 | /* nothing to free */ | ||
1568 | break; | ||
1569 | default: | ||
1570 | BUG(); | ||
1571 | } | ||
1572 | } | ||
1573 | |||
1574 | static int omapfb_find_ctrl(struct omapfb_device *fbdev) | ||
1575 | { | ||
1576 | struct omapfb_platform_data *conf; | ||
1577 | char name[17]; | ||
1578 | int i; | ||
1579 | |||
1580 | conf = fbdev->dev->platform_data; | ||
1581 | |||
1582 | fbdev->ctrl = NULL; | ||
1583 | |||
1584 | strncpy(name, conf->lcd.ctrl_name, sizeof(name) - 1); | ||
1585 | name[sizeof(name) - 1] = '\0'; | ||
1586 | |||
1587 | if (strcmp(name, "internal") == 0) { | ||
1588 | fbdev->ctrl = fbdev->int_ctrl; | ||
1589 | return 0; | ||
1590 | } | ||
1591 | |||
1592 | for (i = 0; i < ARRAY_SIZE(ctrls); i++) { | ||
1593 | dev_dbg(fbdev->dev, "ctrl %s\n", ctrls[i]->name); | ||
1594 | if (strcmp(ctrls[i]->name, name) == 0) { | ||
1595 | fbdev->ctrl = ctrls[i]; | ||
1596 | break; | ||
1597 | } | ||
1598 | } | ||
1599 | |||
1600 | if (fbdev->ctrl == NULL) { | ||
1601 | dev_dbg(fbdev->dev, "ctrl %s not supported\n", name); | ||
1602 | return -1; | ||
1603 | } | ||
1604 | |||
1605 | return 0; | ||
1606 | } | ||
1607 | |||
1608 | static void check_required_callbacks(struct omapfb_device *fbdev) | ||
1609 | { | ||
1610 | #define _C(x) (fbdev->ctrl->x != NULL) | ||
1611 | #define _P(x) (fbdev->panel->x != NULL) | ||
1612 | BUG_ON(fbdev->ctrl == NULL || fbdev->panel == NULL); | ||
1613 | BUG_ON(!(_C(init) && _C(cleanup) && _C(get_caps) && | ||
1614 | _C(set_update_mode) && _C(setup_plane) && _C(enable_plane) && | ||
1615 | _P(init) && _P(cleanup) && _P(enable) && _P(disable) && | ||
1616 | _P(get_caps))); | ||
1617 | #undef _P | ||
1618 | #undef _C | ||
1619 | } | ||
1620 | |||
1621 | /* | ||
1622 | * Called by LDM binding to probe and attach a new device. | ||
1623 | * Initialization sequence: | ||
1624 | * 1. allocate system omapfb_device structure | ||
1625 | * 2. select controller type according to platform configuration | ||
1626 | * init LCD panel | ||
1627 | * 3. init LCD controller and LCD DMA | ||
1628 | * 4. init system fb_info structure for all planes | ||
1629 | * 5. setup video mode for first plane and enable it | ||
1630 | * 6. enable LCD panel | ||
1631 | * 7. register sysfs attributes | ||
1632 | * OMAPFB_ACTIVE: register system fb_info structure for all planes | ||
1633 | */ | ||
1634 | static int omapfb_do_probe(struct platform_device *pdev, | ||
1635 | struct lcd_panel *panel) | ||
1636 | { | ||
1637 | struct omapfb_device *fbdev = NULL; | ||
1638 | int init_state; | ||
1639 | unsigned long phz, hhz, vhz; | ||
1640 | unsigned long vram; | ||
1641 | int i; | ||
1642 | int r = 0; | ||
1643 | |||
1644 | init_state = 0; | ||
1645 | |||
1646 | if (pdev->num_resources != 0) { | ||
1647 | dev_err(&pdev->dev, "probed for an unknown device\n"); | ||
1648 | r = -ENODEV; | ||
1649 | goto cleanup; | ||
1650 | } | ||
1651 | |||
1652 | if (pdev->dev.platform_data == NULL) { | ||
1653 | dev_err(&pdev->dev, "missing platform data\n"); | ||
1654 | r = -ENOENT; | ||
1655 | goto cleanup; | ||
1656 | } | ||
1657 | |||
1658 | fbdev = kzalloc(sizeof(struct omapfb_device), GFP_KERNEL); | ||
1659 | if (fbdev == NULL) { | ||
1660 | dev_err(&pdev->dev, | ||
1661 | "unable to allocate memory for device info\n"); | ||
1662 | r = -ENOMEM; | ||
1663 | goto cleanup; | ||
1664 | } | ||
1665 | init_state++; | ||
1666 | |||
1667 | fbdev->dev = &pdev->dev; | ||
1668 | fbdev->panel = panel; | ||
1669 | platform_set_drvdata(pdev, fbdev); | ||
1670 | |||
1671 | mutex_init(&fbdev->rqueue_mutex); | ||
1672 | |||
1673 | #ifdef CONFIG_ARCH_OMAP1 | ||
1674 | fbdev->int_ctrl = &omap1_int_ctrl; | ||
1675 | #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL | ||
1676 | fbdev->ext_if = &omap1_ext_if; | ||
1677 | #endif | ||
1678 | #else /* OMAP2 */ | ||
1679 | fbdev->int_ctrl = &omap2_int_ctrl; | ||
1680 | #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL | ||
1681 | fbdev->ext_if = &omap2_ext_if; | ||
1682 | #endif | ||
1683 | #endif | ||
1684 | if (omapfb_find_ctrl(fbdev) < 0) { | ||
1685 | dev_err(fbdev->dev, | ||
1686 | "LCD controller not found, board not supported\n"); | ||
1687 | r = -ENODEV; | ||
1688 | goto cleanup; | ||
1689 | } | ||
1690 | |||
1691 | r = fbdev->panel->init(fbdev->panel, fbdev); | ||
1692 | if (r) | ||
1693 | goto cleanup; | ||
1694 | |||
1695 | pr_info("omapfb: configured for panel %s\n", fbdev->panel->name); | ||
1696 | |||
1697 | def_vxres = def_vxres ? : fbdev->panel->x_res; | ||
1698 | def_vyres = def_vyres ? : fbdev->panel->y_res; | ||
1699 | |||
1700 | init_state++; | ||
1701 | |||
1702 | r = ctrl_init(fbdev); | ||
1703 | if (r) | ||
1704 | goto cleanup; | ||
1705 | if (fbdev->ctrl->mmap != NULL) | ||
1706 | omapfb_ops.fb_mmap = omapfb_mmap; | ||
1707 | init_state++; | ||
1708 | |||
1709 | check_required_callbacks(fbdev); | ||
1710 | |||
1711 | r = planes_init(fbdev); | ||
1712 | if (r) | ||
1713 | goto cleanup; | ||
1714 | init_state++; | ||
1715 | |||
1716 | #ifdef CONFIG_FB_OMAP_DMA_TUNE | ||
1717 | /* Set DMA priority for EMIFF access to highest */ | ||
1718 | if (cpu_class_is_omap1()) | ||
1719 | omap_set_dma_priority(0, OMAP_DMA_PORT_EMIFF, 15); | ||
1720 | #endif | ||
1721 | |||
1722 | r = ctrl_change_mode(fbdev->fb_info[0]); | ||
1723 | if (r) { | ||
1724 | dev_err(fbdev->dev, "mode setting failed\n"); | ||
1725 | goto cleanup; | ||
1726 | } | ||
1727 | |||
1728 | /* GFX plane is enabled by default */ | ||
1729 | r = fbdev->ctrl->enable_plane(OMAPFB_PLANE_GFX, 1); | ||
1730 | if (r) | ||
1731 | goto cleanup; | ||
1732 | |||
1733 | omapfb_set_update_mode(fbdev, manual_update ? | ||
1734 | OMAPFB_MANUAL_UPDATE : OMAPFB_AUTO_UPDATE); | ||
1735 | init_state++; | ||
1736 | |||
1737 | r = fbdev->panel->enable(fbdev->panel); | ||
1738 | if (r) | ||
1739 | goto cleanup; | ||
1740 | init_state++; | ||
1741 | |||
1742 | r = omapfb_register_sysfs(fbdev); | ||
1743 | if (r) | ||
1744 | goto cleanup; | ||
1745 | init_state++; | ||
1746 | |||
1747 | vram = 0; | ||
1748 | for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { | ||
1749 | r = register_framebuffer(fbdev->fb_info[i]); | ||
1750 | if (r != 0) { | ||
1751 | dev_err(fbdev->dev, | ||
1752 | "registering framebuffer %d failed\n", i); | ||
1753 | goto cleanup; | ||
1754 | } | ||
1755 | vram += fbdev->mem_desc.region[i].size; | ||
1756 | } | ||
1757 | |||
1758 | fbdev->state = OMAPFB_ACTIVE; | ||
1759 | |||
1760 | panel = fbdev->panel; | ||
1761 | phz = panel->pixel_clock * 1000; | ||
1762 | hhz = phz * 10 / (panel->hfp + panel->x_res + panel->hbp + panel->hsw); | ||
1763 | vhz = hhz / (panel->vfp + panel->y_res + panel->vbp + panel->vsw); | ||
1764 | |||
1765 | omapfb_dev = fbdev; | ||
1766 | |||
1767 | pr_info("omapfb: Framebuffer initialized. Total vram %lu planes %d\n", | ||
1768 | vram, fbdev->mem_desc.region_cnt); | ||
1769 | pr_info("omapfb: Pixclock %lu kHz hfreq %lu.%lu kHz " | ||
1770 | "vfreq %lu.%lu Hz\n", | ||
1771 | phz / 1000, hhz / 10000, hhz % 10, vhz / 10, vhz % 10); | ||
1772 | |||
1773 | return 0; | ||
1774 | |||
1775 | cleanup: | ||
1776 | omapfb_free_resources(fbdev, init_state); | ||
1777 | |||
1778 | return r; | ||
1779 | } | ||
1780 | |||
1781 | static int omapfb_probe(struct platform_device *pdev) | ||
1782 | { | ||
1783 | BUG_ON(fbdev_pdev != NULL); | ||
1784 | |||
1785 | /* Delay actual initialization until the LCD is registered */ | ||
1786 | fbdev_pdev = pdev; | ||
1787 | if (fbdev_panel != NULL) | ||
1788 | omapfb_do_probe(fbdev_pdev, fbdev_panel); | ||
1789 | return 0; | ||
1790 | } | ||
1791 | |||
1792 | void omapfb_register_panel(struct lcd_panel *panel) | ||
1793 | { | ||
1794 | BUG_ON(fbdev_panel != NULL); | ||
1795 | |||
1796 | fbdev_panel = panel; | ||
1797 | if (fbdev_pdev != NULL) | ||
1798 | omapfb_do_probe(fbdev_pdev, fbdev_panel); | ||
1799 | } | ||
1800 | |||
1801 | /* Called when the device is being detached from the driver */ | ||
1802 | static int omapfb_remove(struct platform_device *pdev) | ||
1803 | { | ||
1804 | struct omapfb_device *fbdev = platform_get_drvdata(pdev); | ||
1805 | enum omapfb_state saved_state = fbdev->state; | ||
1806 | |||
1807 | /* FIXME: wait till completion of pending events */ | ||
1808 | |||
1809 | fbdev->state = OMAPFB_DISABLED; | ||
1810 | omapfb_free_resources(fbdev, saved_state); | ||
1811 | |||
1812 | return 0; | ||
1813 | } | ||
1814 | |||
1815 | /* PM suspend */ | ||
1816 | static int omapfb_suspend(struct platform_device *pdev, pm_message_t mesg) | ||
1817 | { | ||
1818 | struct omapfb_device *fbdev = platform_get_drvdata(pdev); | ||
1819 | |||
1820 | omapfb_blank(VESA_POWERDOWN, fbdev->fb_info[0]); | ||
1821 | |||
1822 | return 0; | ||
1823 | } | ||
1824 | |||
1825 | /* PM resume */ | ||
1826 | static int omapfb_resume(struct platform_device *pdev) | ||
1827 | { | ||
1828 | struct omapfb_device *fbdev = platform_get_drvdata(pdev); | ||
1829 | |||
1830 | omapfb_blank(VESA_NO_BLANKING, fbdev->fb_info[0]); | ||
1831 | return 0; | ||
1832 | } | ||
1833 | |||
1834 | static struct platform_driver omapfb_driver = { | ||
1835 | .probe = omapfb_probe, | ||
1836 | .remove = omapfb_remove, | ||
1837 | .suspend = omapfb_suspend, | ||
1838 | .resume = omapfb_resume, | ||
1839 | .driver = { | ||
1840 | .name = MODULE_NAME, | ||
1841 | .owner = THIS_MODULE, | ||
1842 | }, | ||
1843 | }; | ||
1844 | |||
1845 | #ifndef MODULE | ||
1846 | |||
1847 | /* Process kernel command line parameters */ | ||
1848 | static int __init omapfb_setup(char *options) | ||
1849 | { | ||
1850 | char *this_opt = NULL; | ||
1851 | int r = 0; | ||
1852 | |||
1853 | pr_debug("omapfb: options %s\n", options); | ||
1854 | |||
1855 | if (!options || !*options) | ||
1856 | return 0; | ||
1857 | |||
1858 | while (!r && (this_opt = strsep(&options, ",")) != NULL) { | ||
1859 | if (!strncmp(this_opt, "accel", 5)) | ||
1860 | def_accel = 1; | ||
1861 | else if (!strncmp(this_opt, "vram:", 5)) { | ||
1862 | char *suffix; | ||
1863 | unsigned long vram; | ||
1864 | vram = (simple_strtoul(this_opt + 5, &suffix, 0)); | ||
1865 | switch (suffix[0]) { | ||
1866 | case '\0': | ||
1867 | break; | ||
1868 | case 'm': | ||
1869 | case 'M': | ||
1870 | vram *= 1024; | ||
1871 | /* Fall through */ | ||
1872 | case 'k': | ||
1873 | case 'K': | ||
1874 | vram *= 1024; | ||
1875 | break; | ||
1876 | default: | ||
1877 | pr_debug("omapfb: invalid vram suffix %c\n", | ||
1878 | suffix[0]); | ||
1879 | r = -1; | ||
1880 | } | ||
1881 | def_vram[def_vram_cnt++] = vram; | ||
1882 | } | ||
1883 | else if (!strncmp(this_opt, "vxres:", 6)) | ||
1884 | def_vxres = simple_strtoul(this_opt + 6, NULL, 0); | ||
1885 | else if (!strncmp(this_opt, "vyres:", 6)) | ||
1886 | def_vyres = simple_strtoul(this_opt + 6, NULL, 0); | ||
1887 | else if (!strncmp(this_opt, "rotate:", 7)) | ||
1888 | def_rotate = (simple_strtoul(this_opt + 7, NULL, 0)); | ||
1889 | else if (!strncmp(this_opt, "mirror:", 7)) | ||
1890 | def_mirror = (simple_strtoul(this_opt + 7, NULL, 0)); | ||
1891 | else if (!strncmp(this_opt, "manual_update", 13)) | ||
1892 | manual_update = 1; | ||
1893 | else { | ||
1894 | pr_debug("omapfb: invalid option\n"); | ||
1895 | r = -1; | ||
1896 | } | ||
1897 | } | ||
1898 | |||
1899 | return r; | ||
1900 | } | ||
1901 | |||
1902 | #endif | ||
1903 | |||
1904 | /* Register both the driver and the device */ | ||
1905 | static int __init omapfb_init(void) | ||
1906 | { | ||
1907 | #ifndef MODULE | ||
1908 | char *option; | ||
1909 | |||
1910 | if (fb_get_options("omapfb", &option)) | ||
1911 | return -ENODEV; | ||
1912 | omapfb_setup(option); | ||
1913 | #endif | ||
1914 | /* Register the driver with LDM */ | ||
1915 | if (platform_driver_register(&omapfb_driver)) { | ||
1916 | pr_debug("failed to register omapfb driver\n"); | ||
1917 | return -ENODEV; | ||
1918 | } | ||
1919 | |||
1920 | return 0; | ||
1921 | } | ||
1922 | |||
1923 | static void __exit omapfb_cleanup(void) | ||
1924 | { | ||
1925 | platform_driver_unregister(&omapfb_driver); | ||
1926 | } | ||
1927 | |||
1928 | module_param_named(accel, def_accel, uint, 0664); | ||
1929 | module_param_array_named(vram, def_vram, ulong, &def_vram_cnt, 0664); | ||
1930 | module_param_named(vxres, def_vxres, long, 0664); | ||
1931 | module_param_named(vyres, def_vyres, long, 0664); | ||
1932 | module_param_named(rotate, def_rotate, uint, 0664); | ||
1933 | module_param_named(mirror, def_mirror, uint, 0664); | ||
1934 | module_param_named(manual_update, manual_update, bool, 0664); | ||
1935 | |||
1936 | module_init(omapfb_init); | ||
1937 | module_exit(omapfb_cleanup); | ||
1938 | |||
1939 | MODULE_DESCRIPTION("TI OMAP framebuffer driver"); | ||
1940 | MODULE_AUTHOR("Imre Deak <imre.deak@nokia.com>"); | ||
1941 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap/rfbi.c b/drivers/video/omap/rfbi.c new file mode 100644 index 000000000000..2b4269813b22 --- /dev/null +++ b/drivers/video/omap/rfbi.c | |||
@@ -0,0 +1,588 @@ | |||
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 | |||
30 | #include <asm/arch/omapfb.h> | ||
31 | |||
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 | |||
61 | static struct { | ||
62 | u32 base; | ||
63 | void (*lcdc_callback)(void *data); | ||
64 | void *lcdc_callback_data; | ||
65 | unsigned long l4_khz; | ||
66 | int bits_per_cycle; | ||
67 | struct omapfb_device *fbdev; | ||
68 | struct clk *dss_ick; | ||
69 | struct clk *dss1_fck; | ||
70 | unsigned tearsync_pin_cnt; | ||
71 | unsigned tearsync_mode; | ||
72 | } rfbi; | ||
73 | |||
74 | static inline void rfbi_write_reg(int idx, u32 val) | ||
75 | { | ||
76 | __raw_writel(val, rfbi.base + idx); | ||
77 | } | ||
78 | |||
79 | static inline u32 rfbi_read_reg(int idx) | ||
80 | { | ||
81 | return __raw_readl(rfbi.base + idx); | ||
82 | } | ||
83 | |||
84 | static int rfbi_get_clocks(void) | ||
85 | { | ||
86 | if (IS_ERR((rfbi.dss_ick = clk_get(rfbi.fbdev->dev, "dss_ick")))) { | ||
87 | dev_err(rfbi.fbdev->dev, "can't get dss_ick"); | ||
88 | return PTR_ERR(rfbi.dss_ick); | ||
89 | } | ||
90 | |||
91 | if (IS_ERR((rfbi.dss1_fck = clk_get(rfbi.fbdev->dev, "dss1_fck")))) { | ||
92 | dev_err(rfbi.fbdev->dev, "can't get dss1_fck"); | ||
93 | clk_put(rfbi.dss_ick); | ||
94 | return PTR_ERR(rfbi.dss1_fck); | ||
95 | } | ||
96 | |||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | static void rfbi_put_clocks(void) | ||
101 | { | ||
102 | clk_put(rfbi.dss1_fck); | ||
103 | clk_put(rfbi.dss_ick); | ||
104 | } | ||
105 | |||
106 | static void rfbi_enable_clocks(int enable) | ||
107 | { | ||
108 | if (enable) { | ||
109 | clk_enable(rfbi.dss_ick); | ||
110 | clk_enable(rfbi.dss1_fck); | ||
111 | } else { | ||
112 | clk_disable(rfbi.dss1_fck); | ||
113 | clk_disable(rfbi.dss_ick); | ||
114 | } | ||
115 | } | ||
116 | |||
117 | |||
118 | #ifdef VERBOSE | ||
119 | static void rfbi_print_timings(void) | ||
120 | { | ||
121 | u32 l; | ||
122 | u32 time; | ||
123 | |||
124 | l = rfbi_read_reg(RFBI_CONFIG0); | ||
125 | time = 1000000000 / rfbi.l4_khz; | ||
126 | if (l & (1 << 4)) | ||
127 | time *= 2; | ||
128 | |||
129 | dev_dbg(rfbi.fbdev->dev, "Tick time %u ps\n", time); | ||
130 | l = rfbi_read_reg(RFBI_ONOFF_TIME0); | ||
131 | dev_dbg(rfbi.fbdev->dev, | ||
132 | "CSONTIME %d, CSOFFTIME %d, WEONTIME %d, WEOFFTIME %d, " | ||
133 | "REONTIME %d, REOFFTIME %d\n", | ||
134 | l & 0x0f, (l >> 4) & 0x3f, (l >> 10) & 0x0f, (l >> 14) & 0x3f, | ||
135 | (l >> 20) & 0x0f, (l >> 24) & 0x3f); | ||
136 | |||
137 | l = rfbi_read_reg(RFBI_CYCLE_TIME0); | ||
138 | dev_dbg(rfbi.fbdev->dev, | ||
139 | "WECYCLETIME %d, RECYCLETIME %d, CSPULSEWIDTH %d, " | ||
140 | "ACCESSTIME %d\n", | ||
141 | (l & 0x3f), (l >> 6) & 0x3f, (l >> 12) & 0x3f, | ||
142 | (l >> 22) & 0x3f); | ||
143 | } | ||
144 | #else | ||
145 | static void rfbi_print_timings(void) {} | ||
146 | #endif | ||
147 | |||
148 | static void rfbi_set_timings(const struct extif_timings *t) | ||
149 | { | ||
150 | u32 l; | ||
151 | |||
152 | BUG_ON(!t->converted); | ||
153 | |||
154 | rfbi_enable_clocks(1); | ||
155 | rfbi_write_reg(RFBI_ONOFF_TIME0, t->tim[0]); | ||
156 | rfbi_write_reg(RFBI_CYCLE_TIME0, t->tim[1]); | ||
157 | |||
158 | l = rfbi_read_reg(RFBI_CONFIG0); | ||
159 | l &= ~(1 << 4); | ||
160 | l |= (t->tim[2] ? 1 : 0) << 4; | ||
161 | rfbi_write_reg(RFBI_CONFIG0, l); | ||
162 | |||
163 | rfbi_print_timings(); | ||
164 | rfbi_enable_clocks(0); | ||
165 | } | ||
166 | |||
167 | static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div) | ||
168 | { | ||
169 | *clk_period = 1000000000 / rfbi.l4_khz; | ||
170 | *max_clk_div = 2; | ||
171 | } | ||
172 | |||
173 | static int ps_to_rfbi_ticks(int time, int div) | ||
174 | { | ||
175 | unsigned long tick_ps; | ||
176 | int ret; | ||
177 | |||
178 | /* Calculate in picosecs to yield more exact results */ | ||
179 | tick_ps = 1000000000 / (rfbi.l4_khz) * div; | ||
180 | |||
181 | ret = (time + tick_ps - 1) / tick_ps; | ||
182 | |||
183 | return ret; | ||
184 | } | ||
185 | |||
186 | #ifdef OMAP_RFBI_RATE_LIMIT | ||
187 | static unsigned long rfbi_get_max_tx_rate(void) | ||
188 | { | ||
189 | unsigned long l4_rate, dss1_rate; | ||
190 | int min_l4_ticks = 0; | ||
191 | int i; | ||
192 | |||
193 | /* According to TI this can't be calculated so make the | ||
194 | * adjustments for a couple of known frequencies and warn for | ||
195 | * others. | ||
196 | */ | ||
197 | static const struct { | ||
198 | unsigned long l4_clk; /* HZ */ | ||
199 | unsigned long dss1_clk; /* HZ */ | ||
200 | unsigned long min_l4_ticks; | ||
201 | } ftab[] = { | ||
202 | { 55, 132, 7, }, /* 7.86 MPix/s */ | ||
203 | { 110, 110, 12, }, /* 9.16 MPix/s */ | ||
204 | { 110, 132, 10, }, /* 11 Mpix/s */ | ||
205 | { 120, 120, 10, }, /* 12 Mpix/s */ | ||
206 | { 133, 133, 10, }, /* 13.3 Mpix/s */ | ||
207 | }; | ||
208 | |||
209 | l4_rate = rfbi.l4_khz / 1000; | ||
210 | dss1_rate = clk_get_rate(rfbi.dss1_fck) / 1000000; | ||
211 | |||
212 | for (i = 0; i < ARRAY_SIZE(ftab); i++) { | ||
213 | /* Use a window instead of an exact match, to account | ||
214 | * for different DPLL multiplier / divider pairs. | ||
215 | */ | ||
216 | if (abs(ftab[i].l4_clk - l4_rate) < 3 && | ||
217 | abs(ftab[i].dss1_clk - dss1_rate) < 3) { | ||
218 | min_l4_ticks = ftab[i].min_l4_ticks; | ||
219 | break; | ||
220 | } | ||
221 | } | ||
222 | if (i == ARRAY_SIZE(ftab)) { | ||
223 | /* Can't be sure, return anyway the maximum not | ||
224 | * rate-limited. This might cause a problem only for the | ||
225 | * tearing synchronisation. | ||
226 | */ | ||
227 | dev_err(rfbi.fbdev->dev, | ||
228 | "can't determine maximum RFBI transfer rate\n"); | ||
229 | return rfbi.l4_khz * 1000; | ||
230 | } | ||
231 | return rfbi.l4_khz * 1000 / min_l4_ticks; | ||
232 | } | ||
233 | #else | ||
234 | static int rfbi_get_max_tx_rate(void) | ||
235 | { | ||
236 | return rfbi.l4_khz * 1000; | ||
237 | } | ||
238 | #endif | ||
239 | |||
240 | |||
241 | static int rfbi_convert_timings(struct extif_timings *t) | ||
242 | { | ||
243 | u32 l; | ||
244 | int reon, reoff, weon, weoff, cson, csoff, cs_pulse; | ||
245 | int actim, recyc, wecyc; | ||
246 | int div = t->clk_div; | ||
247 | |||
248 | if (div <= 0 || div > 2) | ||
249 | return -1; | ||
250 | |||
251 | /* Make sure that after conversion it still holds that: | ||
252 | * weoff > weon, reoff > reon, recyc >= reoff, wecyc >= weoff, | ||
253 | * csoff > cson, csoff >= max(weoff, reoff), actim > reon | ||
254 | */ | ||
255 | weon = ps_to_rfbi_ticks(t->we_on_time, div); | ||
256 | weoff = ps_to_rfbi_ticks(t->we_off_time, div); | ||
257 | if (weoff <= weon) | ||
258 | weoff = weon + 1; | ||
259 | if (weon > 0x0f) | ||
260 | return -1; | ||
261 | if (weoff > 0x3f) | ||
262 | return -1; | ||
263 | |||
264 | reon = ps_to_rfbi_ticks(t->re_on_time, div); | ||
265 | reoff = ps_to_rfbi_ticks(t->re_off_time, div); | ||
266 | if (reoff <= reon) | ||
267 | reoff = reon + 1; | ||
268 | if (reon > 0x0f) | ||
269 | return -1; | ||
270 | if (reoff > 0x3f) | ||
271 | return -1; | ||
272 | |||
273 | cson = ps_to_rfbi_ticks(t->cs_on_time, div); | ||
274 | csoff = ps_to_rfbi_ticks(t->cs_off_time, div); | ||
275 | if (csoff <= cson) | ||
276 | csoff = cson + 1; | ||
277 | if (csoff < max(weoff, reoff)) | ||
278 | csoff = max(weoff, reoff); | ||
279 | if (cson > 0x0f) | ||
280 | return -1; | ||
281 | if (csoff > 0x3f) | ||
282 | return -1; | ||
283 | |||
284 | l = cson; | ||
285 | l |= csoff << 4; | ||
286 | l |= weon << 10; | ||
287 | l |= weoff << 14; | ||
288 | l |= reon << 20; | ||
289 | l |= reoff << 24; | ||
290 | |||
291 | t->tim[0] = l; | ||
292 | |||
293 | actim = ps_to_rfbi_ticks(t->access_time, div); | ||
294 | if (actim <= reon) | ||
295 | actim = reon + 1; | ||
296 | if (actim > 0x3f) | ||
297 | return -1; | ||
298 | |||
299 | wecyc = ps_to_rfbi_ticks(t->we_cycle_time, div); | ||
300 | if (wecyc < weoff) | ||
301 | wecyc = weoff; | ||
302 | if (wecyc > 0x3f) | ||
303 | return -1; | ||
304 | |||
305 | recyc = ps_to_rfbi_ticks(t->re_cycle_time, div); | ||
306 | if (recyc < reoff) | ||
307 | recyc = reoff; | ||
308 | if (recyc > 0x3f) | ||
309 | return -1; | ||
310 | |||
311 | cs_pulse = ps_to_rfbi_ticks(t->cs_pulse_width, div); | ||
312 | if (cs_pulse > 0x3f) | ||
313 | return -1; | ||
314 | |||
315 | l = wecyc; | ||
316 | l |= recyc << 6; | ||
317 | l |= cs_pulse << 12; | ||
318 | l |= actim << 22; | ||
319 | |||
320 | t->tim[1] = l; | ||
321 | |||
322 | t->tim[2] = div - 1; | ||
323 | |||
324 | t->converted = 1; | ||
325 | |||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static int rfbi_setup_tearsync(unsigned pin_cnt, | ||
330 | unsigned hs_pulse_time, unsigned vs_pulse_time, | ||
331 | int hs_pol_inv, int vs_pol_inv, int extif_div) | ||
332 | { | ||
333 | int hs, vs; | ||
334 | int min; | ||
335 | u32 l; | ||
336 | |||
337 | if (pin_cnt != 1 && pin_cnt != 2) | ||
338 | return -EINVAL; | ||
339 | |||
340 | hs = ps_to_rfbi_ticks(hs_pulse_time, 1); | ||
341 | vs = ps_to_rfbi_ticks(vs_pulse_time, 1); | ||
342 | if (hs < 2) | ||
343 | return -EDOM; | ||
344 | if (pin_cnt == 2) | ||
345 | min = 2; | ||
346 | else | ||
347 | min = 4; | ||
348 | if (vs < min) | ||
349 | return -EDOM; | ||
350 | if (vs == hs) | ||
351 | return -EINVAL; | ||
352 | rfbi.tearsync_pin_cnt = pin_cnt; | ||
353 | dev_dbg(rfbi.fbdev->dev, | ||
354 | "setup_tearsync: pins %d hs %d vs %d hs_inv %d vs_inv %d\n", | ||
355 | pin_cnt, hs, vs, hs_pol_inv, vs_pol_inv); | ||
356 | |||
357 | rfbi_enable_clocks(1); | ||
358 | rfbi_write_reg(RFBI_HSYNC_WIDTH, hs); | ||
359 | rfbi_write_reg(RFBI_VSYNC_WIDTH, vs); | ||
360 | |||
361 | l = rfbi_read_reg(RFBI_CONFIG0); | ||
362 | if (hs_pol_inv) | ||
363 | l &= ~(1 << 21); | ||
364 | else | ||
365 | l |= 1 << 21; | ||
366 | if (vs_pol_inv) | ||
367 | l &= ~(1 << 20); | ||
368 | else | ||
369 | l |= 1 << 20; | ||
370 | rfbi_enable_clocks(0); | ||
371 | |||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | static int rfbi_enable_tearsync(int enable, unsigned line) | ||
376 | { | ||
377 | u32 l; | ||
378 | |||
379 | dev_dbg(rfbi.fbdev->dev, "tearsync %d line %d mode %d\n", | ||
380 | enable, line, rfbi.tearsync_mode); | ||
381 | if (line > (1 << 11) - 1) | ||
382 | return -EINVAL; | ||
383 | |||
384 | rfbi_enable_clocks(1); | ||
385 | l = rfbi_read_reg(RFBI_CONFIG0); | ||
386 | l &= ~(0x3 << 2); | ||
387 | if (enable) { | ||
388 | rfbi.tearsync_mode = rfbi.tearsync_pin_cnt; | ||
389 | l |= rfbi.tearsync_mode << 2; | ||
390 | } else | ||
391 | rfbi.tearsync_mode = 0; | ||
392 | rfbi_write_reg(RFBI_CONFIG0, l); | ||
393 | rfbi_write_reg(RFBI_LINE_NUMBER, line); | ||
394 | rfbi_enable_clocks(0); | ||
395 | |||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | static void rfbi_write_command(const void *buf, unsigned int len) | ||
400 | { | ||
401 | rfbi_enable_clocks(1); | ||
402 | if (rfbi.bits_per_cycle == 16) { | ||
403 | const u16 *w = buf; | ||
404 | BUG_ON(len & 1); | ||
405 | for (; len; len -= 2) | ||
406 | rfbi_write_reg(RFBI_CMD, *w++); | ||
407 | } else { | ||
408 | const u8 *b = buf; | ||
409 | BUG_ON(rfbi.bits_per_cycle != 8); | ||
410 | for (; len; len--) | ||
411 | rfbi_write_reg(RFBI_CMD, *b++); | ||
412 | } | ||
413 | rfbi_enable_clocks(0); | ||
414 | } | ||
415 | |||
416 | static void rfbi_read_data(void *buf, unsigned int len) | ||
417 | { | ||
418 | rfbi_enable_clocks(1); | ||
419 | if (rfbi.bits_per_cycle == 16) { | ||
420 | u16 *w = buf; | ||
421 | BUG_ON(len & ~1); | ||
422 | for (; len; len -= 2) { | ||
423 | rfbi_write_reg(RFBI_READ, 0); | ||
424 | *w++ = rfbi_read_reg(RFBI_READ); | ||
425 | } | ||
426 | } else { | ||
427 | u8 *b = buf; | ||
428 | BUG_ON(rfbi.bits_per_cycle != 8); | ||
429 | for (; len; len--) { | ||
430 | rfbi_write_reg(RFBI_READ, 0); | ||
431 | *b++ = rfbi_read_reg(RFBI_READ); | ||
432 | } | ||
433 | } | ||
434 | rfbi_enable_clocks(0); | ||
435 | } | ||
436 | |||
437 | static void rfbi_write_data(const void *buf, unsigned int len) | ||
438 | { | ||
439 | rfbi_enable_clocks(1); | ||
440 | if (rfbi.bits_per_cycle == 16) { | ||
441 | const u16 *w = buf; | ||
442 | BUG_ON(len & 1); | ||
443 | for (; len; len -= 2) | ||
444 | rfbi_write_reg(RFBI_PARAM, *w++); | ||
445 | } else { | ||
446 | const u8 *b = buf; | ||
447 | BUG_ON(rfbi.bits_per_cycle != 8); | ||
448 | for (; len; len--) | ||
449 | rfbi_write_reg(RFBI_PARAM, *b++); | ||
450 | } | ||
451 | rfbi_enable_clocks(0); | ||
452 | } | ||
453 | |||
454 | static void rfbi_transfer_area(int width, int height, | ||
455 | void (callback)(void * data), void *data) | ||
456 | { | ||
457 | u32 w; | ||
458 | |||
459 | BUG_ON(callback == NULL); | ||
460 | |||
461 | rfbi_enable_clocks(1); | ||
462 | omap_dispc_set_lcd_size(width, height); | ||
463 | |||
464 | rfbi.lcdc_callback = callback; | ||
465 | rfbi.lcdc_callback_data = data; | ||
466 | |||
467 | rfbi_write_reg(RFBI_PIXEL_CNT, width * height); | ||
468 | |||
469 | w = rfbi_read_reg(RFBI_CONTROL); | ||
470 | w |= 1; /* enable */ | ||
471 | if (!rfbi.tearsync_mode) | ||
472 | w |= 1 << 4; /* internal trigger, reset by HW */ | ||
473 | rfbi_write_reg(RFBI_CONTROL, w); | ||
474 | |||
475 | omap_dispc_enable_lcd_out(1); | ||
476 | } | ||
477 | |||
478 | static inline void _stop_transfer(void) | ||
479 | { | ||
480 | u32 w; | ||
481 | |||
482 | w = rfbi_read_reg(RFBI_CONTROL); | ||
483 | rfbi_write_reg(RFBI_CONTROL, w & ~(1 << 0)); | ||
484 | rfbi_enable_clocks(0); | ||
485 | } | ||
486 | |||
487 | static void rfbi_dma_callback(void *data) | ||
488 | { | ||
489 | _stop_transfer(); | ||
490 | rfbi.lcdc_callback(rfbi.lcdc_callback_data); | ||
491 | } | ||
492 | |||
493 | static void rfbi_set_bits_per_cycle(int bpc) | ||
494 | { | ||
495 | u32 l; | ||
496 | |||
497 | rfbi_enable_clocks(1); | ||
498 | l = rfbi_read_reg(RFBI_CONFIG0); | ||
499 | l &= ~(0x03 << 0); | ||
500 | |||
501 | switch (bpc) { | ||
502 | case 8: | ||
503 | break; | ||
504 | case 16: | ||
505 | l |= 3; | ||
506 | break; | ||
507 | default: | ||
508 | BUG(); | ||
509 | } | ||
510 | rfbi_write_reg(RFBI_CONFIG0, l); | ||
511 | rfbi.bits_per_cycle = bpc; | ||
512 | rfbi_enable_clocks(0); | ||
513 | } | ||
514 | |||
515 | static int rfbi_init(struct omapfb_device *fbdev) | ||
516 | { | ||
517 | u32 l; | ||
518 | int r; | ||
519 | |||
520 | rfbi.fbdev = fbdev; | ||
521 | rfbi.base = io_p2v(RFBI_BASE); | ||
522 | |||
523 | if ((r = rfbi_get_clocks()) < 0) | ||
524 | return r; | ||
525 | rfbi_enable_clocks(1); | ||
526 | |||
527 | rfbi.l4_khz = clk_get_rate(rfbi.dss_ick) / 1000; | ||
528 | |||
529 | /* Reset */ | ||
530 | rfbi_write_reg(RFBI_SYSCONFIG, 1 << 1); | ||
531 | while (!(rfbi_read_reg(RFBI_SYSSTATUS) & (1 << 0))); | ||
532 | |||
533 | l = rfbi_read_reg(RFBI_SYSCONFIG); | ||
534 | /* Enable autoidle and smart-idle */ | ||
535 | l |= (1 << 0) | (2 << 3); | ||
536 | rfbi_write_reg(RFBI_SYSCONFIG, l); | ||
537 | |||
538 | /* 16-bit interface, ITE trigger mode, 16-bit data */ | ||
539 | l = (0x03 << 0) | (0x00 << 2) | (0x01 << 5) | (0x02 << 7); | ||
540 | l |= (0 << 9) | (1 << 20) | (1 << 21); | ||
541 | rfbi_write_reg(RFBI_CONFIG0, l); | ||
542 | |||
543 | rfbi_write_reg(RFBI_DATA_CYCLE1_0, 0x00000010); | ||
544 | |||
545 | l = rfbi_read_reg(RFBI_CONTROL); | ||
546 | /* Select CS0, clear bypass mode */ | ||
547 | l = (0x01 << 2); | ||
548 | rfbi_write_reg(RFBI_CONTROL, l); | ||
549 | |||
550 | if ((r = omap_dispc_request_irq(rfbi_dma_callback, NULL)) < 0) { | ||
551 | dev_err(fbdev->dev, "can't get DISPC irq\n"); | ||
552 | rfbi_enable_clocks(0); | ||
553 | return r; | ||
554 | } | ||
555 | |||
556 | l = rfbi_read_reg(RFBI_REVISION); | ||
557 | pr_info("omapfb: RFBI version %d.%d initialized\n", | ||
558 | (l >> 4) & 0x0f, l & 0x0f); | ||
559 | |||
560 | rfbi_enable_clocks(0); | ||
561 | |||
562 | return 0; | ||
563 | } | ||
564 | |||
565 | static void rfbi_cleanup(void) | ||
566 | { | ||
567 | omap_dispc_free_irq(); | ||
568 | rfbi_put_clocks(); | ||
569 | } | ||
570 | |||
571 | const struct lcd_ctrl_extif omap2_ext_if = { | ||
572 | .init = rfbi_init, | ||
573 | .cleanup = rfbi_cleanup, | ||
574 | .get_clk_info = rfbi_get_clk_info, | ||
575 | .get_max_tx_rate = rfbi_get_max_tx_rate, | ||
576 | .set_bits_per_cycle = rfbi_set_bits_per_cycle, | ||
577 | .convert_timings = rfbi_convert_timings, | ||
578 | .set_timings = rfbi_set_timings, | ||
579 | .write_command = rfbi_write_command, | ||
580 | .read_data = rfbi_read_data, | ||
581 | .write_data = rfbi_write_data, | ||
582 | .transfer_area = rfbi_transfer_area, | ||
583 | .setup_tearsync = rfbi_setup_tearsync, | ||
584 | .enable_tearsync = rfbi_enable_tearsync, | ||
585 | |||
586 | .max_transmit_size = (u32) ~0, | ||
587 | }; | ||
588 | |||
diff --git a/drivers/video/omap/sossi.c b/drivers/video/omap/sossi.c new file mode 100644 index 000000000000..81dbcf53cf0e --- /dev/null +++ b/drivers/video/omap/sossi.c | |||
@@ -0,0 +1,686 @@ | |||
1 | /* | ||
2 | * OMAP1 Special OptimiSed Screen Interface support | ||
3 | * | ||
4 | * Copyright (C) 2004-2005 Nokia Corporation | ||
5 | * Author: Juha Yrjölä <juha.yrjola@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/module.h> | ||
22 | #include <linux/mm.h> | ||
23 | #include <linux/clk.h> | ||
24 | #include <linux/irq.h> | ||
25 | #include <linux/io.h> | ||
26 | |||
27 | #include <asm/arch/dma.h> | ||
28 | #include <asm/arch/omapfb.h> | ||
29 | |||
30 | #include "lcdc.h" | ||
31 | |||
32 | #define MODULE_NAME "omapfb-sossi" | ||
33 | |||
34 | #define OMAP_SOSSI_BASE 0xfffbac00 | ||
35 | #define SOSSI_ID_REG 0x00 | ||
36 | #define SOSSI_INIT1_REG 0x04 | ||
37 | #define SOSSI_INIT2_REG 0x08 | ||
38 | #define SOSSI_INIT3_REG 0x0c | ||
39 | #define SOSSI_FIFO_REG 0x10 | ||
40 | #define SOSSI_REOTABLE_REG 0x14 | ||
41 | #define SOSSI_TEARING_REG 0x18 | ||
42 | #define SOSSI_INIT1B_REG 0x1c | ||
43 | #define SOSSI_FIFOB_REG 0x20 | ||
44 | |||
45 | #define DMA_GSCR 0xfffedc04 | ||
46 | #define DMA_LCD_CCR 0xfffee3c2 | ||
47 | #define DMA_LCD_CTRL 0xfffee3c4 | ||
48 | #define DMA_LCD_LCH_CTRL 0xfffee3ea | ||
49 | |||
50 | #define CONF_SOSSI_RESET_R (1 << 23) | ||
51 | |||
52 | #define RD_ACCESS 0 | ||
53 | #define WR_ACCESS 1 | ||
54 | |||
55 | #define SOSSI_MAX_XMIT_BYTES (512 * 1024) | ||
56 | |||
57 | static struct { | ||
58 | void __iomem *base; | ||
59 | struct clk *fck; | ||
60 | unsigned long fck_hz; | ||
61 | spinlock_t lock; | ||
62 | int bus_pick_count; | ||
63 | int bus_pick_width; | ||
64 | int tearsync_mode; | ||
65 | int tearsync_line; | ||
66 | void (*lcdc_callback)(void *data); | ||
67 | void *lcdc_callback_data; | ||
68 | int vsync_dma_pending; | ||
69 | /* timing for read and write access */ | ||
70 | int clk_div; | ||
71 | u8 clk_tw0[2]; | ||
72 | u8 clk_tw1[2]; | ||
73 | /* | ||
74 | * if last_access is the same as current we don't have to change | ||
75 | * the timings | ||
76 | */ | ||
77 | int last_access; | ||
78 | |||
79 | struct omapfb_device *fbdev; | ||
80 | } sossi; | ||
81 | |||
82 | static inline u32 sossi_read_reg(int reg) | ||
83 | { | ||
84 | return readl(sossi.base + reg); | ||
85 | } | ||
86 | |||
87 | static inline u16 sossi_read_reg16(int reg) | ||
88 | { | ||
89 | return readw(sossi.base + reg); | ||
90 | } | ||
91 | |||
92 | static inline u8 sossi_read_reg8(int reg) | ||
93 | { | ||
94 | return readb(sossi.base + reg); | ||
95 | } | ||
96 | |||
97 | static inline void sossi_write_reg(int reg, u32 value) | ||
98 | { | ||
99 | writel(value, sossi.base + reg); | ||
100 | } | ||
101 | |||
102 | static inline void sossi_write_reg16(int reg, u16 value) | ||
103 | { | ||
104 | writew(value, sossi.base + reg); | ||
105 | } | ||
106 | |||
107 | static inline void sossi_write_reg8(int reg, u8 value) | ||
108 | { | ||
109 | writeb(value, sossi.base + reg); | ||
110 | } | ||
111 | |||
112 | static void sossi_set_bits(int reg, u32 bits) | ||
113 | { | ||
114 | sossi_write_reg(reg, sossi_read_reg(reg) | bits); | ||
115 | } | ||
116 | |||
117 | static void sossi_clear_bits(int reg, u32 bits) | ||
118 | { | ||
119 | sossi_write_reg(reg, sossi_read_reg(reg) & ~bits); | ||
120 | } | ||
121 | |||
122 | #define HZ_TO_PS(x) (1000000000 / (x / 1000)) | ||
123 | |||
124 | static u32 ps_to_sossi_ticks(u32 ps, int div) | ||
125 | { | ||
126 | u32 clk_period = HZ_TO_PS(sossi.fck_hz) * div; | ||
127 | return (clk_period + ps - 1) / clk_period; | ||
128 | } | ||
129 | |||
130 | static int calc_rd_timings(struct extif_timings *t) | ||
131 | { | ||
132 | u32 tw0, tw1; | ||
133 | int reon, reoff, recyc, actim; | ||
134 | int div = t->clk_div; | ||
135 | |||
136 | /* | ||
137 | * Make sure that after conversion it still holds that: | ||
138 | * reoff > reon, recyc >= reoff, actim > reon | ||
139 | */ | ||
140 | reon = ps_to_sossi_ticks(t->re_on_time, div); | ||
141 | /* reon will be exactly one sossi tick */ | ||
142 | if (reon > 1) | ||
143 | return -1; | ||
144 | |||
145 | reoff = ps_to_sossi_ticks(t->re_off_time, div); | ||
146 | |||
147 | if (reoff <= reon) | ||
148 | reoff = reon + 1; | ||
149 | |||
150 | tw0 = reoff - reon; | ||
151 | if (tw0 > 0x10) | ||
152 | return -1; | ||
153 | |||
154 | recyc = ps_to_sossi_ticks(t->re_cycle_time, div); | ||
155 | if (recyc <= reoff) | ||
156 | recyc = reoff + 1; | ||
157 | |||
158 | tw1 = recyc - tw0; | ||
159 | /* values less then 3 result in the SOSSI block resetting itself */ | ||
160 | if (tw1 < 3) | ||
161 | tw1 = 3; | ||
162 | if (tw1 > 0x40) | ||
163 | return -1; | ||
164 | |||
165 | actim = ps_to_sossi_ticks(t->access_time, div); | ||
166 | if (actim < reoff) | ||
167 | actim++; | ||
168 | /* | ||
169 | * access time (data hold time) will be exactly one sossi | ||
170 | * tick | ||
171 | */ | ||
172 | if (actim - reoff > 1) | ||
173 | return -1; | ||
174 | |||
175 | t->tim[0] = tw0 - 1; | ||
176 | t->tim[1] = tw1 - 1; | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | static int calc_wr_timings(struct extif_timings *t) | ||
182 | { | ||
183 | u32 tw0, tw1; | ||
184 | int weon, weoff, wecyc; | ||
185 | int div = t->clk_div; | ||
186 | |||
187 | /* | ||
188 | * Make sure that after conversion it still holds that: | ||
189 | * weoff > weon, wecyc >= weoff | ||
190 | */ | ||
191 | weon = ps_to_sossi_ticks(t->we_on_time, div); | ||
192 | /* weon will be exactly one sossi tick */ | ||
193 | if (weon > 1) | ||
194 | return -1; | ||
195 | |||
196 | weoff = ps_to_sossi_ticks(t->we_off_time, div); | ||
197 | if (weoff <= weon) | ||
198 | weoff = weon + 1; | ||
199 | tw0 = weoff - weon; | ||
200 | if (tw0 > 0x10) | ||
201 | return -1; | ||
202 | |||
203 | wecyc = ps_to_sossi_ticks(t->we_cycle_time, div); | ||
204 | if (wecyc <= weoff) | ||
205 | wecyc = weoff + 1; | ||
206 | |||
207 | tw1 = wecyc - tw0; | ||
208 | /* values less then 3 result in the SOSSI block resetting itself */ | ||
209 | if (tw1 < 3) | ||
210 | tw1 = 3; | ||
211 | if (tw1 > 0x40) | ||
212 | return -1; | ||
213 | |||
214 | t->tim[2] = tw0 - 1; | ||
215 | t->tim[3] = tw1 - 1; | ||
216 | |||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | static void _set_timing(int div, int tw0, int tw1) | ||
221 | { | ||
222 | u32 l; | ||
223 | |||
224 | #ifdef VERBOSE | ||
225 | dev_dbg(sossi.fbdev->dev, "Using TW0 = %d, TW1 = %d, div = %d\n", | ||
226 | tw0 + 1, tw1 + 1, div); | ||
227 | #endif | ||
228 | |||
229 | clk_set_rate(sossi.fck, sossi.fck_hz / div); | ||
230 | clk_enable(sossi.fck); | ||
231 | l = sossi_read_reg(SOSSI_INIT1_REG); | ||
232 | l &= ~((0x0f << 20) | (0x3f << 24)); | ||
233 | l |= (tw0 << 20) | (tw1 << 24); | ||
234 | sossi_write_reg(SOSSI_INIT1_REG, l); | ||
235 | clk_disable(sossi.fck); | ||
236 | } | ||
237 | |||
238 | static void _set_bits_per_cycle(int bus_pick_count, int bus_pick_width) | ||
239 | { | ||
240 | u32 l; | ||
241 | |||
242 | l = sossi_read_reg(SOSSI_INIT3_REG); | ||
243 | l &= ~0x3ff; | ||
244 | l |= ((bus_pick_count - 1) << 5) | ((bus_pick_width - 1) & 0x1f); | ||
245 | sossi_write_reg(SOSSI_INIT3_REG, l); | ||
246 | } | ||
247 | |||
248 | static void _set_tearsync_mode(int mode, unsigned line) | ||
249 | { | ||
250 | u32 l; | ||
251 | |||
252 | l = sossi_read_reg(SOSSI_TEARING_REG); | ||
253 | l &= ~(((1 << 11) - 1) << 15); | ||
254 | l |= line << 15; | ||
255 | l &= ~(0x3 << 26); | ||
256 | l |= mode << 26; | ||
257 | sossi_write_reg(SOSSI_TEARING_REG, l); | ||
258 | if (mode) | ||
259 | sossi_set_bits(SOSSI_INIT2_REG, 1 << 6); /* TE logic */ | ||
260 | else | ||
261 | sossi_clear_bits(SOSSI_INIT2_REG, 1 << 6); | ||
262 | } | ||
263 | |||
264 | static inline void set_timing(int access) | ||
265 | { | ||
266 | if (access != sossi.last_access) { | ||
267 | sossi.last_access = access; | ||
268 | _set_timing(sossi.clk_div, | ||
269 | sossi.clk_tw0[access], sossi.clk_tw1[access]); | ||
270 | } | ||
271 | } | ||
272 | |||
273 | static void sossi_start_transfer(void) | ||
274 | { | ||
275 | /* WE */ | ||
276 | sossi_clear_bits(SOSSI_INIT2_REG, 1 << 4); | ||
277 | /* CS active low */ | ||
278 | sossi_clear_bits(SOSSI_INIT1_REG, 1 << 30); | ||
279 | } | ||
280 | |||
281 | static void sossi_stop_transfer(void) | ||
282 | { | ||
283 | /* WE */ | ||
284 | sossi_set_bits(SOSSI_INIT2_REG, 1 << 4); | ||
285 | /* CS active low */ | ||
286 | sossi_set_bits(SOSSI_INIT1_REG, 1 << 30); | ||
287 | } | ||
288 | |||
289 | static void wait_end_of_write(void) | ||
290 | { | ||
291 | /* Before reading we must check if some writings are going on */ | ||
292 | while (!(sossi_read_reg(SOSSI_INIT2_REG) & (1 << 3))); | ||
293 | } | ||
294 | |||
295 | static void send_data(const void *data, unsigned int len) | ||
296 | { | ||
297 | while (len >= 4) { | ||
298 | sossi_write_reg(SOSSI_FIFO_REG, *(const u32 *) data); | ||
299 | len -= 4; | ||
300 | data += 4; | ||
301 | } | ||
302 | while (len >= 2) { | ||
303 | sossi_write_reg16(SOSSI_FIFO_REG, *(const u16 *) data); | ||
304 | len -= 2; | ||
305 | data += 2; | ||
306 | } | ||
307 | while (len) { | ||
308 | sossi_write_reg8(SOSSI_FIFO_REG, *(const u8 *) data); | ||
309 | len--; | ||
310 | data++; | ||
311 | } | ||
312 | } | ||
313 | |||
314 | static void set_cycles(unsigned int len) | ||
315 | { | ||
316 | unsigned long nr_cycles = len / (sossi.bus_pick_width / 8); | ||
317 | |||
318 | BUG_ON((nr_cycles - 1) & ~0x3ffff); | ||
319 | |||
320 | sossi_clear_bits(SOSSI_INIT1_REG, 0x3ffff); | ||
321 | sossi_set_bits(SOSSI_INIT1_REG, (nr_cycles - 1) & 0x3ffff); | ||
322 | } | ||
323 | |||
324 | static int sossi_convert_timings(struct extif_timings *t) | ||
325 | { | ||
326 | int r = 0; | ||
327 | int div = t->clk_div; | ||
328 | |||
329 | t->converted = 0; | ||
330 | |||
331 | if (div <= 0 || div > 8) | ||
332 | return -1; | ||
333 | |||
334 | /* no CS on SOSSI, so ignore cson, csoff, cs_pulsewidth */ | ||
335 | if ((r = calc_rd_timings(t)) < 0) | ||
336 | return r; | ||
337 | |||
338 | if ((r = calc_wr_timings(t)) < 0) | ||
339 | return r; | ||
340 | |||
341 | t->tim[4] = div; | ||
342 | |||
343 | t->converted = 1; | ||
344 | |||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static void sossi_set_timings(const struct extif_timings *t) | ||
349 | { | ||
350 | BUG_ON(!t->converted); | ||
351 | |||
352 | sossi.clk_tw0[RD_ACCESS] = t->tim[0]; | ||
353 | sossi.clk_tw1[RD_ACCESS] = t->tim[1]; | ||
354 | |||
355 | sossi.clk_tw0[WR_ACCESS] = t->tim[2]; | ||
356 | sossi.clk_tw1[WR_ACCESS] = t->tim[3]; | ||
357 | |||
358 | sossi.clk_div = t->tim[4]; | ||
359 | } | ||
360 | |||
361 | static void sossi_get_clk_info(u32 *clk_period, u32 *max_clk_div) | ||
362 | { | ||
363 | *clk_period = HZ_TO_PS(sossi.fck_hz); | ||
364 | *max_clk_div = 8; | ||
365 | } | ||
366 | |||
367 | static void sossi_set_bits_per_cycle(int bpc) | ||
368 | { | ||
369 | int bus_pick_count, bus_pick_width; | ||
370 | |||
371 | /* | ||
372 | * We set explicitly the the bus_pick_count as well, although | ||
373 | * with remapping/reordering disabled it will be calculated by HW | ||
374 | * as (32 / bus_pick_width). | ||
375 | */ | ||
376 | switch (bpc) { | ||
377 | case 8: | ||
378 | bus_pick_count = 4; | ||
379 | bus_pick_width = 8; | ||
380 | break; | ||
381 | case 16: | ||
382 | bus_pick_count = 2; | ||
383 | bus_pick_width = 16; | ||
384 | break; | ||
385 | default: | ||
386 | BUG(); | ||
387 | return; | ||
388 | } | ||
389 | sossi.bus_pick_width = bus_pick_width; | ||
390 | sossi.bus_pick_count = bus_pick_count; | ||
391 | } | ||
392 | |||
393 | static int sossi_setup_tearsync(unsigned pin_cnt, | ||
394 | unsigned hs_pulse_time, unsigned vs_pulse_time, | ||
395 | int hs_pol_inv, int vs_pol_inv, int div) | ||
396 | { | ||
397 | int hs, vs; | ||
398 | u32 l; | ||
399 | |||
400 | if (pin_cnt != 1 || div < 1 || div > 8) | ||
401 | return -EINVAL; | ||
402 | |||
403 | hs = ps_to_sossi_ticks(hs_pulse_time, div); | ||
404 | vs = ps_to_sossi_ticks(vs_pulse_time, div); | ||
405 | if (vs < 8 || vs <= hs || vs >= (1 << 12)) | ||
406 | return -EDOM; | ||
407 | vs /= 8; | ||
408 | vs--; | ||
409 | if (hs > 8) | ||
410 | hs = 8; | ||
411 | if (hs) | ||
412 | hs--; | ||
413 | |||
414 | dev_dbg(sossi.fbdev->dev, | ||
415 | "setup_tearsync: hs %d vs %d hs_inv %d vs_inv %d\n", | ||
416 | hs, vs, hs_pol_inv, vs_pol_inv); | ||
417 | |||
418 | clk_enable(sossi.fck); | ||
419 | l = sossi_read_reg(SOSSI_TEARING_REG); | ||
420 | l &= ~((1 << 15) - 1); | ||
421 | l |= vs << 3; | ||
422 | l |= hs; | ||
423 | if (hs_pol_inv) | ||
424 | l |= 1 << 29; | ||
425 | else | ||
426 | l &= ~(1 << 29); | ||
427 | if (vs_pol_inv) | ||
428 | l |= 1 << 28; | ||
429 | else | ||
430 | l &= ~(1 << 28); | ||
431 | sossi_write_reg(SOSSI_TEARING_REG, l); | ||
432 | clk_disable(sossi.fck); | ||
433 | |||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | static int sossi_enable_tearsync(int enable, unsigned line) | ||
438 | { | ||
439 | int mode; | ||
440 | |||
441 | dev_dbg(sossi.fbdev->dev, "tearsync %d line %d\n", enable, line); | ||
442 | if (line >= 1 << 11) | ||
443 | return -EINVAL; | ||
444 | if (enable) { | ||
445 | if (line) | ||
446 | mode = 2; /* HS or VS */ | ||
447 | else | ||
448 | mode = 3; /* VS only */ | ||
449 | } else | ||
450 | mode = 0; | ||
451 | sossi.tearsync_line = line; | ||
452 | sossi.tearsync_mode = mode; | ||
453 | |||
454 | return 0; | ||
455 | } | ||
456 | |||
457 | static void sossi_write_command(const void *data, unsigned int len) | ||
458 | { | ||
459 | clk_enable(sossi.fck); | ||
460 | set_timing(WR_ACCESS); | ||
461 | _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width); | ||
462 | /* CMD#/DATA */ | ||
463 | sossi_clear_bits(SOSSI_INIT1_REG, 1 << 18); | ||
464 | set_cycles(len); | ||
465 | sossi_start_transfer(); | ||
466 | send_data(data, len); | ||
467 | sossi_stop_transfer(); | ||
468 | wait_end_of_write(); | ||
469 | clk_disable(sossi.fck); | ||
470 | } | ||
471 | |||
472 | static void sossi_write_data(const void *data, unsigned int len) | ||
473 | { | ||
474 | clk_enable(sossi.fck); | ||
475 | set_timing(WR_ACCESS); | ||
476 | _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width); | ||
477 | /* CMD#/DATA */ | ||
478 | sossi_set_bits(SOSSI_INIT1_REG, 1 << 18); | ||
479 | set_cycles(len); | ||
480 | sossi_start_transfer(); | ||
481 | send_data(data, len); | ||
482 | sossi_stop_transfer(); | ||
483 | wait_end_of_write(); | ||
484 | clk_disable(sossi.fck); | ||
485 | } | ||
486 | |||
487 | static void sossi_transfer_area(int width, int height, | ||
488 | void (callback)(void *data), void *data) | ||
489 | { | ||
490 | BUG_ON(callback == NULL); | ||
491 | |||
492 | sossi.lcdc_callback = callback; | ||
493 | sossi.lcdc_callback_data = data; | ||
494 | |||
495 | clk_enable(sossi.fck); | ||
496 | set_timing(WR_ACCESS); | ||
497 | _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width); | ||
498 | _set_tearsync_mode(sossi.tearsync_mode, sossi.tearsync_line); | ||
499 | /* CMD#/DATA */ | ||
500 | sossi_set_bits(SOSSI_INIT1_REG, 1 << 18); | ||
501 | set_cycles(width * height * sossi.bus_pick_width / 8); | ||
502 | |||
503 | sossi_start_transfer(); | ||
504 | if (sossi.tearsync_mode) { | ||
505 | /* | ||
506 | * Wait for the sync signal and start the transfer only | ||
507 | * then. We can't seem to be able to use HW sync DMA for | ||
508 | * this since LCD DMA shows huge latencies, as if it | ||
509 | * would ignore some of the DMA requests from SoSSI. | ||
510 | */ | ||
511 | unsigned long flags; | ||
512 | |||
513 | spin_lock_irqsave(&sossi.lock, flags); | ||
514 | sossi.vsync_dma_pending++; | ||
515 | spin_unlock_irqrestore(&sossi.lock, flags); | ||
516 | } else | ||
517 | /* Just start the transfer right away. */ | ||
518 | omap_enable_lcd_dma(); | ||
519 | } | ||
520 | |||
521 | static void sossi_dma_callback(void *data) | ||
522 | { | ||
523 | omap_stop_lcd_dma(); | ||
524 | sossi_stop_transfer(); | ||
525 | clk_disable(sossi.fck); | ||
526 | sossi.lcdc_callback(sossi.lcdc_callback_data); | ||
527 | } | ||
528 | |||
529 | static void sossi_read_data(void *data, unsigned int len) | ||
530 | { | ||
531 | clk_enable(sossi.fck); | ||
532 | set_timing(RD_ACCESS); | ||
533 | _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width); | ||
534 | /* CMD#/DATA */ | ||
535 | sossi_set_bits(SOSSI_INIT1_REG, 1 << 18); | ||
536 | set_cycles(len); | ||
537 | sossi_start_transfer(); | ||
538 | while (len >= 4) { | ||
539 | *(u32 *) data = sossi_read_reg(SOSSI_FIFO_REG); | ||
540 | len -= 4; | ||
541 | data += 4; | ||
542 | } | ||
543 | while (len >= 2) { | ||
544 | *(u16 *) data = sossi_read_reg16(SOSSI_FIFO_REG); | ||
545 | len -= 2; | ||
546 | data += 2; | ||
547 | } | ||
548 | while (len) { | ||
549 | *(u8 *) data = sossi_read_reg8(SOSSI_FIFO_REG); | ||
550 | len--; | ||
551 | data++; | ||
552 | } | ||
553 | sossi_stop_transfer(); | ||
554 | clk_disable(sossi.fck); | ||
555 | } | ||
556 | |||
557 | static irqreturn_t sossi_match_irq(int irq, void *data) | ||
558 | { | ||
559 | unsigned long flags; | ||
560 | |||
561 | spin_lock_irqsave(&sossi.lock, flags); | ||
562 | if (sossi.vsync_dma_pending) { | ||
563 | sossi.vsync_dma_pending--; | ||
564 | omap_enable_lcd_dma(); | ||
565 | } | ||
566 | spin_unlock_irqrestore(&sossi.lock, flags); | ||
567 | return IRQ_HANDLED; | ||
568 | } | ||
569 | |||
570 | static int sossi_init(struct omapfb_device *fbdev) | ||
571 | { | ||
572 | u32 l, k; | ||
573 | struct clk *fck; | ||
574 | struct clk *dpll1out_ck; | ||
575 | int r; | ||
576 | |||
577 | sossi.base = (void __iomem *)IO_ADDRESS(OMAP_SOSSI_BASE); | ||
578 | sossi.fbdev = fbdev; | ||
579 | spin_lock_init(&sossi.lock); | ||
580 | |||
581 | dpll1out_ck = clk_get(fbdev->dev, "ck_dpll1out"); | ||
582 | if (IS_ERR(dpll1out_ck)) { | ||
583 | dev_err(fbdev->dev, "can't get DPLL1OUT clock\n"); | ||
584 | return PTR_ERR(dpll1out_ck); | ||
585 | } | ||
586 | /* | ||
587 | * We need the parent clock rate, which we might divide further | ||
588 | * depending on the timing requirements of the controller. See | ||
589 | * _set_timings. | ||
590 | */ | ||
591 | sossi.fck_hz = clk_get_rate(dpll1out_ck); | ||
592 | clk_put(dpll1out_ck); | ||
593 | |||
594 | fck = clk_get(fbdev->dev, "ck_sossi"); | ||
595 | if (IS_ERR(fck)) { | ||
596 | dev_err(fbdev->dev, "can't get SoSSI functional clock\n"); | ||
597 | return PTR_ERR(fck); | ||
598 | } | ||
599 | sossi.fck = fck; | ||
600 | |||
601 | /* Reset and enable the SoSSI module */ | ||
602 | l = omap_readl(MOD_CONF_CTRL_1); | ||
603 | l |= CONF_SOSSI_RESET_R; | ||
604 | omap_writel(l, MOD_CONF_CTRL_1); | ||
605 | l &= ~CONF_SOSSI_RESET_R; | ||
606 | omap_writel(l, MOD_CONF_CTRL_1); | ||
607 | |||
608 | clk_enable(sossi.fck); | ||
609 | l = omap_readl(ARM_IDLECT2); | ||
610 | l &= ~(1 << 8); /* DMACK_REQ */ | ||
611 | omap_writel(l, ARM_IDLECT2); | ||
612 | |||
613 | l = sossi_read_reg(SOSSI_INIT2_REG); | ||
614 | /* Enable and reset the SoSSI block */ | ||
615 | l |= (1 << 0) | (1 << 1); | ||
616 | sossi_write_reg(SOSSI_INIT2_REG, l); | ||
617 | /* Take SoSSI out of reset */ | ||
618 | l &= ~(1 << 1); | ||
619 | sossi_write_reg(SOSSI_INIT2_REG, l); | ||
620 | |||
621 | sossi_write_reg(SOSSI_ID_REG, 0); | ||
622 | l = sossi_read_reg(SOSSI_ID_REG); | ||
623 | k = sossi_read_reg(SOSSI_ID_REG); | ||
624 | |||
625 | if (l != 0x55555555 || k != 0xaaaaaaaa) { | ||
626 | dev_err(fbdev->dev, | ||
627 | "invalid SoSSI sync pattern: %08x, %08x\n", l, k); | ||
628 | r = -ENODEV; | ||
629 | goto err; | ||
630 | } | ||
631 | |||
632 | if ((r = omap_lcdc_set_dma_callback(sossi_dma_callback, NULL)) < 0) { | ||
633 | dev_err(fbdev->dev, "can't get LCDC IRQ\n"); | ||
634 | r = -ENODEV; | ||
635 | goto err; | ||
636 | } | ||
637 | |||
638 | l = sossi_read_reg(SOSSI_ID_REG); /* Component code */ | ||
639 | l = sossi_read_reg(SOSSI_ID_REG); | ||
640 | dev_info(fbdev->dev, "SoSSI version %d.%d initialized\n", | ||
641 | l >> 16, l & 0xffff); | ||
642 | |||
643 | l = sossi_read_reg(SOSSI_INIT1_REG); | ||
644 | l |= (1 << 19); /* DMA_MODE */ | ||
645 | l &= ~(1 << 31); /* REORDERING */ | ||
646 | sossi_write_reg(SOSSI_INIT1_REG, l); | ||
647 | |||
648 | if ((r = request_irq(INT_1610_SoSSI_MATCH, sossi_match_irq, | ||
649 | IRQT_FALLING, | ||
650 | "sossi_match", sossi.fbdev->dev)) < 0) { | ||
651 | dev_err(sossi.fbdev->dev, "can't get SoSSI match IRQ\n"); | ||
652 | goto err; | ||
653 | } | ||
654 | |||
655 | clk_disable(sossi.fck); | ||
656 | return 0; | ||
657 | |||
658 | err: | ||
659 | clk_disable(sossi.fck); | ||
660 | clk_put(sossi.fck); | ||
661 | return r; | ||
662 | } | ||
663 | |||
664 | static void sossi_cleanup(void) | ||
665 | { | ||
666 | omap_lcdc_free_dma_callback(); | ||
667 | clk_put(sossi.fck); | ||
668 | } | ||
669 | |||
670 | struct lcd_ctrl_extif omap1_ext_if = { | ||
671 | .init = sossi_init, | ||
672 | .cleanup = sossi_cleanup, | ||
673 | .get_clk_info = sossi_get_clk_info, | ||
674 | .convert_timings = sossi_convert_timings, | ||
675 | .set_timings = sossi_set_timings, | ||
676 | .set_bits_per_cycle = sossi_set_bits_per_cycle, | ||
677 | .setup_tearsync = sossi_setup_tearsync, | ||
678 | .enable_tearsync = sossi_enable_tearsync, | ||
679 | .write_command = sossi_write_command, | ||
680 | .read_data = sossi_read_data, | ||
681 | .write_data = sossi_write_data, | ||
682 | .transfer_area = sossi_transfer_area, | ||
683 | |||
684 | .max_transmit_size = SOSSI_MAX_XMIT_BYTES, | ||
685 | }; | ||
686 | |||
diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c index e64f8b5d0056..8503e733a172 100644 --- a/drivers/video/platinumfb.c +++ b/drivers/video/platinumfb.c | |||
@@ -52,7 +52,7 @@ struct fb_info_platinum { | |||
52 | struct { | 52 | struct { |
53 | __u8 red, green, blue; | 53 | __u8 red, green, blue; |
54 | } palette[256]; | 54 | } palette[256]; |
55 | u32 pseudo_palette[17]; | 55 | u32 pseudo_palette[16]; |
56 | 56 | ||
57 | volatile struct cmap_regs __iomem *cmap_regs; | 57 | volatile struct cmap_regs __iomem *cmap_regs; |
58 | unsigned long cmap_regs_phys; | 58 | unsigned long cmap_regs_phys; |
diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c index 1ac5264bb2c1..10c0cc6e93fc 100644 --- a/drivers/video/pm2fb.c +++ b/drivers/video/pm2fb.c | |||
@@ -24,7 +24,7 @@ | |||
24 | * License. See the file COPYING in the main directory of this archive for | 24 | * License. See the file COPYING in the main directory of this archive for |
25 | * more details. | 25 | * more details. |
26 | * | 26 | * |
27 | * | 27 | * |
28 | */ | 28 | */ |
29 | 29 | ||
30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
@@ -58,7 +58,7 @@ | |||
58 | #endif | 58 | #endif |
59 | 59 | ||
60 | /* | 60 | /* |
61 | * Driver data | 61 | * Driver data |
62 | */ | 62 | */ |
63 | static char *mode __devinitdata = NULL; | 63 | static char *mode __devinitdata = NULL; |
64 | 64 | ||
@@ -82,12 +82,12 @@ struct pm2fb_par | |||
82 | { | 82 | { |
83 | pm2type_t type; /* Board type */ | 83 | pm2type_t type; /* Board type */ |
84 | unsigned char __iomem *v_regs;/* virtual address of p_regs */ | 84 | unsigned char __iomem *v_regs;/* virtual address of p_regs */ |
85 | u32 memclock; /* memclock */ | 85 | u32 memclock; /* memclock */ |
86 | u32 video; /* video flags before blanking */ | 86 | u32 video; /* video flags before blanking */ |
87 | u32 mem_config; /* MemConfig reg at probe */ | 87 | u32 mem_config; /* MemConfig reg at probe */ |
88 | u32 mem_control; /* MemControl reg at probe */ | 88 | u32 mem_control; /* MemControl reg at probe */ |
89 | u32 boot_address; /* BootAddress reg at probe */ | 89 | u32 boot_address; /* BootAddress reg at probe */ |
90 | u32 palette[16]; | 90 | u32 palette[16]; |
91 | }; | 91 | }; |
92 | 92 | ||
93 | /* | 93 | /* |
@@ -95,12 +95,12 @@ struct pm2fb_par | |||
95 | * if we don't use modedb. | 95 | * if we don't use modedb. |
96 | */ | 96 | */ |
97 | static struct fb_fix_screeninfo pm2fb_fix __devinitdata = { | 97 | static struct fb_fix_screeninfo pm2fb_fix __devinitdata = { |
98 | .id = "", | 98 | .id = "", |
99 | .type = FB_TYPE_PACKED_PIXELS, | 99 | .type = FB_TYPE_PACKED_PIXELS, |
100 | .visual = FB_VISUAL_PSEUDOCOLOR, | 100 | .visual = FB_VISUAL_PSEUDOCOLOR, |
101 | .xpanstep = 1, | 101 | .xpanstep = 1, |
102 | .ypanstep = 1, | 102 | .ypanstep = 1, |
103 | .ywrapstep = 0, | 103 | .ywrapstep = 0, |
104 | .accel = FB_ACCEL_3DLABS_PERMEDIA2, | 104 | .accel = FB_ACCEL_3DLABS_PERMEDIA2, |
105 | }; | 105 | }; |
106 | 106 | ||
@@ -109,26 +109,26 @@ static struct fb_fix_screeninfo pm2fb_fix __devinitdata = { | |||
109 | */ | 109 | */ |
110 | static struct fb_var_screeninfo pm2fb_var __devinitdata = { | 110 | static struct fb_var_screeninfo pm2fb_var __devinitdata = { |
111 | /* "640x480, 8 bpp @ 60 Hz */ | 111 | /* "640x480, 8 bpp @ 60 Hz */ |
112 | .xres = 640, | 112 | .xres = 640, |
113 | .yres = 480, | 113 | .yres = 480, |
114 | .xres_virtual = 640, | 114 | .xres_virtual = 640, |
115 | .yres_virtual = 480, | 115 | .yres_virtual = 480, |
116 | .bits_per_pixel =8, | 116 | .bits_per_pixel = 8, |
117 | .red = {0, 8, 0}, | 117 | .red = {0, 8, 0}, |
118 | .blue = {0, 8, 0}, | 118 | .blue = {0, 8, 0}, |
119 | .green = {0, 8, 0}, | 119 | .green = {0, 8, 0}, |
120 | .activate = FB_ACTIVATE_NOW, | 120 | .activate = FB_ACTIVATE_NOW, |
121 | .height = -1, | 121 | .height = -1, |
122 | .width = -1, | 122 | .width = -1, |
123 | .accel_flags = 0, | 123 | .accel_flags = 0, |
124 | .pixclock = 39721, | 124 | .pixclock = 39721, |
125 | .left_margin = 40, | 125 | .left_margin = 40, |
126 | .right_margin = 24, | 126 | .right_margin = 24, |
127 | .upper_margin = 32, | 127 | .upper_margin = 32, |
128 | .lower_margin = 11, | 128 | .lower_margin = 11, |
129 | .hsync_len = 96, | 129 | .hsync_len = 96, |
130 | .vsync_len = 2, | 130 | .vsync_len = 2, |
131 | .vmode = FB_VMODE_NONINTERLACED | 131 | .vmode = FB_VMODE_NONINTERLACED |
132 | }; | 132 | }; |
133 | 133 | ||
134 | /* | 134 | /* |
@@ -166,7 +166,7 @@ static inline u32 pm2_RDAC_RD(struct pm2fb_par* p, s32 idx) | |||
166 | pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); | 166 | pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); |
167 | index = PM2VR_RD_INDEXED_DATA; | 167 | index = PM2VR_RD_INDEXED_DATA; |
168 | break; | 168 | break; |
169 | } | 169 | } |
170 | mb(); | 170 | mb(); |
171 | return pm2_RD(p, index); | 171 | return pm2_RD(p, index); |
172 | } | 172 | } |
@@ -182,20 +182,22 @@ static inline void pm2_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) | |||
182 | pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); | 182 | pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); |
183 | index = PM2VR_RD_INDEXED_DATA; | 183 | index = PM2VR_RD_INDEXED_DATA; |
184 | break; | 184 | break; |
185 | } | 185 | } |
186 | mb(); | 186 | wmb(); |
187 | pm2_WR(p, index, v); | 187 | pm2_WR(p, index, v); |
188 | wmb(); | ||
188 | } | 189 | } |
189 | 190 | ||
190 | static inline void pm2v_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) | 191 | static inline void pm2v_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) |
191 | { | 192 | { |
192 | pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); | 193 | pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); |
193 | mb(); | 194 | wmb(); |
194 | pm2_WR(p, PM2VR_RD_INDEXED_DATA, v); | 195 | pm2_WR(p, PM2VR_RD_INDEXED_DATA, v); |
196 | wmb(); | ||
195 | } | 197 | } |
196 | 198 | ||
197 | #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT | 199 | #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT |
198 | #define WAIT_FIFO(p,a) | 200 | #define WAIT_FIFO(p, a) |
199 | #else | 201 | #else |
200 | static inline void WAIT_FIFO(struct pm2fb_par* p, u32 a) | 202 | static inline void WAIT_FIFO(struct pm2fb_par* p, u32 a) |
201 | { | 203 | { |
@@ -204,21 +206,10 @@ static inline void WAIT_FIFO(struct pm2fb_par* p, u32 a) | |||
204 | } | 206 | } |
205 | #endif | 207 | #endif |
206 | 208 | ||
207 | static void wait_pm2(struct pm2fb_par* par) { | ||
208 | |||
209 | WAIT_FIFO(par, 1); | ||
210 | pm2_WR(par, PM2R_SYNC, 0); | ||
211 | mb(); | ||
212 | do { | ||
213 | while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0); | ||
214 | rmb(); | ||
215 | } while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC)); | ||
216 | } | ||
217 | |||
218 | /* | 209 | /* |
219 | * partial products for the supported horizontal resolutions. | 210 | * partial products for the supported horizontal resolutions. |
220 | */ | 211 | */ |
221 | #define PACKPP(p0,p1,p2) (((p2) << 6) | ((p1) << 3) | (p0)) | 212 | #define PACKPP(p0, p1, p2) (((p2) << 6) | ((p1) << 3) | (p0)) |
222 | static const struct { | 213 | static const struct { |
223 | u16 width; | 214 | u16 width; |
224 | u16 pp; | 215 | u16 pp; |
@@ -366,7 +357,7 @@ static void reset_card(struct pm2fb_par* p) | |||
366 | static void reset_config(struct pm2fb_par* p) | 357 | static void reset_config(struct pm2fb_par* p) |
367 | { | 358 | { |
368 | WAIT_FIFO(p, 52); | 359 | WAIT_FIFO(p, 52); |
369 | pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG)& | 360 | pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG) & |
370 | ~(PM2F_VGA_ENABLE|PM2F_VGA_FIXED)); | 361 | ~(PM2F_VGA_ENABLE|PM2F_VGA_FIXED)); |
371 | pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L)); | 362 | pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L)); |
372 | pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L)); | 363 | pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L)); |
@@ -376,7 +367,7 @@ static void reset_config(struct pm2fb_par* p) | |||
376 | pm2_WR(p, PM2R_RASTERIZER_MODE, 0); | 367 | pm2_WR(p, PM2R_RASTERIZER_MODE, 0); |
377 | pm2_WR(p, PM2R_DELTA_MODE, PM2F_DELTA_ORDER_RGB); | 368 | pm2_WR(p, PM2R_DELTA_MODE, PM2F_DELTA_ORDER_RGB); |
378 | pm2_WR(p, PM2R_LB_READ_FORMAT, 0); | 369 | pm2_WR(p, PM2R_LB_READ_FORMAT, 0); |
379 | pm2_WR(p, PM2R_LB_WRITE_FORMAT, 0); | 370 | pm2_WR(p, PM2R_LB_WRITE_FORMAT, 0); |
380 | pm2_WR(p, PM2R_LB_READ_MODE, 0); | 371 | pm2_WR(p, PM2R_LB_READ_MODE, 0); |
381 | pm2_WR(p, PM2R_LB_SOURCE_OFFSET, 0); | 372 | pm2_WR(p, PM2R_LB_SOURCE_OFFSET, 0); |
382 | pm2_WR(p, PM2R_FB_SOURCE_OFFSET, 0); | 373 | pm2_WR(p, PM2R_FB_SOURCE_OFFSET, 0); |
@@ -477,11 +468,9 @@ static void set_memclock(struct pm2fb_par* par, u32 clk) | |||
477 | WAIT_FIFO(par, 8); | 468 | WAIT_FIFO(par, 8); |
478 | pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_MCLK_CONTROL >> 8); | 469 | pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_MCLK_CONTROL >> 8); |
479 | pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 0); | 470 | pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 0); |
480 | wmb(); | ||
481 | pm2v_RDAC_WR(par, PM2VI_RD_MCLK_PRESCALE, m); | 471 | pm2v_RDAC_WR(par, PM2VI_RD_MCLK_PRESCALE, m); |
482 | pm2v_RDAC_WR(par, PM2VI_RD_MCLK_FEEDBACK, n); | 472 | pm2v_RDAC_WR(par, PM2VI_RD_MCLK_FEEDBACK, n); |
483 | pm2v_RDAC_WR(par, PM2VI_RD_MCLK_POSTSCALE, p); | 473 | pm2v_RDAC_WR(par, PM2VI_RD_MCLK_POSTSCALE, p); |
484 | wmb(); | ||
485 | pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 1); | 474 | pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 1); |
486 | rmb(); | 475 | rmb(); |
487 | for (i = 256; | 476 | for (i = 256; |
@@ -494,12 +483,9 @@ static void set_memclock(struct pm2fb_par* par, u32 clk) | |||
494 | pm2_mnp(clk, &m, &n, &p); | 483 | pm2_mnp(clk, &m, &n, &p); |
495 | WAIT_FIFO(par, 10); | 484 | WAIT_FIFO(par, 10); |
496 | pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 6); | 485 | pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 6); |
497 | wmb(); | ||
498 | pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_1, m); | 486 | pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_1, m); |
499 | pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_2, n); | 487 | pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_2, n); |
500 | wmb(); | ||
501 | pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 8|p); | 488 | pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 8|p); |
502 | wmb(); | ||
503 | pm2_RDAC_RD(par, PM2I_RD_MEMORY_CLOCK_STATUS); | 489 | pm2_RDAC_RD(par, PM2I_RD_MEMORY_CLOCK_STATUS); |
504 | rmb(); | 490 | rmb(); |
505 | for (i = 256; | 491 | for (i = 256; |
@@ -520,12 +506,9 @@ static void set_pixclock(struct pm2fb_par* par, u32 clk) | |||
520 | pm2_mnp(clk, &m, &n, &p); | 506 | pm2_mnp(clk, &m, &n, &p); |
521 | WAIT_FIFO(par, 8); | 507 | WAIT_FIFO(par, 8); |
522 | pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 0); | 508 | pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 0); |
523 | wmb(); | ||
524 | pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A1, m); | 509 | pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A1, m); |
525 | pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A2, n); | 510 | pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A2, n); |
526 | wmb(); | ||
527 | pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 8|p); | 511 | pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 8|p); |
528 | wmb(); | ||
529 | pm2_RDAC_RD(par, PM2I_RD_PIXEL_CLOCK_STATUS); | 512 | pm2_RDAC_RD(par, PM2I_RD_PIXEL_CLOCK_STATUS); |
530 | rmb(); | 513 | rmb(); |
531 | for (i = 256; | 514 | for (i = 256; |
@@ -552,7 +535,7 @@ static void set_video(struct pm2fb_par* p, u32 video) { | |||
552 | vsync = video; | 535 | vsync = video; |
553 | 536 | ||
554 | DPRINTK("video = 0x%x\n", video); | 537 | DPRINTK("video = 0x%x\n", video); |
555 | 538 | ||
556 | /* | 539 | /* |
557 | * The hardware cursor needs +vsync to recognise vert retrace. | 540 | * The hardware cursor needs +vsync to recognise vert retrace. |
558 | * We may not be using the hardware cursor, but the X Glint | 541 | * We may not be using the hardware cursor, but the X Glint |
@@ -591,9 +574,9 @@ static void set_video(struct pm2fb_par* p, u32 video) { | |||
591 | */ | 574 | */ |
592 | 575 | ||
593 | /** | 576 | /** |
594 | * pm2fb_check_var - Optional function. Validates a var passed in. | 577 | * pm2fb_check_var - Optional function. Validates a var passed in. |
595 | * @var: frame buffer variable screen structure | 578 | * @var: frame buffer variable screen structure |
596 | * @info: frame buffer structure that represents a single frame buffer | 579 | * @info: frame buffer structure that represents a single frame buffer |
597 | * | 580 | * |
598 | * Checks to see if the hardware supports the state requested by | 581 | * Checks to see if the hardware supports the state requested by |
599 | * var passed in. | 582 | * var passed in. |
@@ -632,23 +615,23 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
632 | 615 | ||
633 | var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */ | 616 | var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */ |
634 | lpitch = var->xres * ((var->bits_per_pixel + 7)>>3); | 617 | lpitch = var->xres * ((var->bits_per_pixel + 7)>>3); |
635 | 618 | ||
636 | if (var->xres < 320 || var->xres > 1600) { | 619 | if (var->xres < 320 || var->xres > 1600) { |
637 | DPRINTK("width not supported: %u\n", var->xres); | 620 | DPRINTK("width not supported: %u\n", var->xres); |
638 | return -EINVAL; | 621 | return -EINVAL; |
639 | } | 622 | } |
640 | 623 | ||
641 | if (var->yres < 200 || var->yres > 1200) { | 624 | if (var->yres < 200 || var->yres > 1200) { |
642 | DPRINTK("height not supported: %u\n", var->yres); | 625 | DPRINTK("height not supported: %u\n", var->yres); |
643 | return -EINVAL; | 626 | return -EINVAL; |
644 | } | 627 | } |
645 | 628 | ||
646 | if (lpitch * var->yres_virtual > info->fix.smem_len) { | 629 | if (lpitch * var->yres_virtual > info->fix.smem_len) { |
647 | DPRINTK("no memory for screen (%ux%ux%u)\n", | 630 | DPRINTK("no memory for screen (%ux%ux%u)\n", |
648 | var->xres, var->yres_virtual, var->bits_per_pixel); | 631 | var->xres, var->yres_virtual, var->bits_per_pixel); |
649 | return -EINVAL; | 632 | return -EINVAL; |
650 | } | 633 | } |
651 | 634 | ||
652 | if (PICOS2KHZ(var->pixclock) > PM2_MAX_PIXCLOCK) { | 635 | if (PICOS2KHZ(var->pixclock) > PM2_MAX_PIXCLOCK) { |
653 | DPRINTK("pixclock too high (%ldKHz)\n", PICOS2KHZ(var->pixclock)); | 636 | DPRINTK("pixclock too high (%ldKHz)\n", PICOS2KHZ(var->pixclock)); |
654 | return -EINVAL; | 637 | return -EINVAL; |
@@ -689,17 +672,17 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
689 | break; | 672 | break; |
690 | } | 673 | } |
691 | var->height = var->width = -1; | 674 | var->height = var->width = -1; |
692 | 675 | ||
693 | var->accel_flags = 0; /* Can't mmap if this is on */ | 676 | var->accel_flags = 0; /* Can't mmap if this is on */ |
694 | 677 | ||
695 | DPRINTK("Checking graphics mode at %dx%d depth %d\n", | 678 | DPRINTK("Checking graphics mode at %dx%d depth %d\n", |
696 | var->xres, var->yres, var->bits_per_pixel); | 679 | var->xres, var->yres, var->bits_per_pixel); |
697 | return 0; | 680 | return 0; |
698 | } | 681 | } |
699 | 682 | ||
700 | /** | 683 | /** |
701 | * pm2fb_set_par - Alters the hardware state. | 684 | * pm2fb_set_par - Alters the hardware state. |
702 | * @info: frame buffer structure that represents a single frame buffer | 685 | * @info: frame buffer structure that represents a single frame buffer |
703 | * | 686 | * |
704 | * Using the fb_var_screeninfo in fb_info we set the resolution of the | 687 | * Using the fb_var_screeninfo in fb_info we set the resolution of the |
705 | * this particular framebuffer. | 688 | * this particular framebuffer. |
@@ -726,7 +709,7 @@ static int pm2fb_set_par(struct fb_info *info) | |||
726 | clear_palette(par); | 709 | clear_palette(par); |
727 | if ( par->memclock ) | 710 | if ( par->memclock ) |
728 | set_memclock(par, par->memclock); | 711 | set_memclock(par, par->memclock); |
729 | 712 | ||
730 | width = (info->var.xres_virtual + 7) & ~7; | 713 | width = (info->var.xres_virtual + 7) & ~7; |
731 | height = info->var.yres_virtual; | 714 | height = info->var.yres_virtual; |
732 | depth = (info->var.bits_per_pixel + 7) & ~7; | 715 | depth = (info->var.bits_per_pixel + 7) & ~7; |
@@ -739,7 +722,7 @@ static int pm2fb_set_par(struct fb_info *info) | |||
739 | DPRINTK("pixclock too high (%uKHz)\n", pixclock); | 722 | DPRINTK("pixclock too high (%uKHz)\n", pixclock); |
740 | return -EINVAL; | 723 | return -EINVAL; |
741 | } | 724 | } |
742 | 725 | ||
743 | hsstart = to3264(info->var.right_margin, depth, data64); | 726 | hsstart = to3264(info->var.right_margin, depth, data64); |
744 | hsend = hsstart + to3264(info->var.hsync_len, depth, data64); | 727 | hsend = hsstart + to3264(info->var.hsync_len, depth, data64); |
745 | hbend = hsend + to3264(info->var.left_margin, depth, data64); | 728 | hbend = hsend + to3264(info->var.left_margin, depth, data64); |
@@ -754,7 +737,7 @@ static int pm2fb_set_par(struct fb_info *info) | |||
754 | base = to3264(info->var.yoffset * xres + info->var.xoffset, depth, 1); | 737 | base = to3264(info->var.yoffset * xres + info->var.xoffset, depth, 1); |
755 | if (data64) | 738 | if (data64) |
756 | video |= PM2F_DATA_64_ENABLE; | 739 | video |= PM2F_DATA_64_ENABLE; |
757 | 740 | ||
758 | if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) { | 741 | if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) { |
759 | if (lowhsync) { | 742 | if (lowhsync) { |
760 | DPRINTK("ignoring +hsync, using -hsync.\n"); | 743 | DPRINTK("ignoring +hsync, using -hsync.\n"); |
@@ -795,9 +778,9 @@ static int pm2fb_set_par(struct fb_info *info) | |||
795 | WAIT_FIFO(par, 1); | 778 | WAIT_FIFO(par, 1); |
796 | pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0); | 779 | pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0); |
797 | } | 780 | } |
798 | 781 | ||
799 | set_aperture(par, depth); | 782 | set_aperture(par, depth); |
800 | 783 | ||
801 | mb(); | 784 | mb(); |
802 | WAIT_FIFO(par, 19); | 785 | WAIT_FIFO(par, 19); |
803 | pm2_RDAC_WR(par, PM2I_RD_COLOR_KEY_CONTROL, | 786 | pm2_RDAC_WR(par, PM2I_RD_COLOR_KEY_CONTROL, |
@@ -864,22 +847,22 @@ static int pm2fb_set_par(struct fb_info *info) | |||
864 | set_pixclock(par, pixclock); | 847 | set_pixclock(par, pixclock); |
865 | DPRINTK("Setting graphics mode at %dx%d depth %d\n", | 848 | DPRINTK("Setting graphics mode at %dx%d depth %d\n", |
866 | info->var.xres, info->var.yres, info->var.bits_per_pixel); | 849 | info->var.xres, info->var.yres, info->var.bits_per_pixel); |
867 | return 0; | 850 | return 0; |
868 | } | 851 | } |
869 | 852 | ||
870 | /** | 853 | /** |
871 | * pm2fb_setcolreg - Sets a color register. | 854 | * pm2fb_setcolreg - Sets a color register. |
872 | * @regno: boolean, 0 copy local, 1 get_user() function | 855 | * @regno: boolean, 0 copy local, 1 get_user() function |
873 | * @red: frame buffer colormap structure | 856 | * @red: frame buffer colormap structure |
874 | * @green: The green value which can be up to 16 bits wide | 857 | * @green: The green value which can be up to 16 bits wide |
875 | * @blue: The blue value which can be up to 16 bits wide. | 858 | * @blue: The blue value which can be up to 16 bits wide. |
876 | * @transp: If supported the alpha value which can be up to 16 bits wide. | 859 | * @transp: If supported the alpha value which can be up to 16 bits wide. |
877 | * @info: frame buffer info structure | 860 | * @info: frame buffer info structure |
878 | * | 861 | * |
879 | * Set a single color register. The values supplied have a 16 bit | 862 | * Set a single color register. The values supplied have a 16 bit |
880 | * magnitude which needs to be scaled in this function for the hardware. | 863 | * magnitude which needs to be scaled in this function for the hardware. |
881 | * Pretty much a direct lift from tdfxfb.c. | 864 | * Pretty much a direct lift from tdfxfb.c. |
882 | * | 865 | * |
883 | * Returns negative errno on error, or zero on success. | 866 | * Returns negative errno on error, or zero on success. |
884 | */ | 867 | */ |
885 | static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, | 868 | static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, |
@@ -923,7 +906,7 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
923 | * (blue << blue.offset) | (transp << transp.offset) | 906 | * (blue << blue.offset) | (transp << transp.offset) |
924 | * RAMDAC does not exist | 907 | * RAMDAC does not exist |
925 | */ | 908 | */ |
926 | #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) | 909 | #define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF -(val)) >> 16) |
927 | switch (info->fix.visual) { | 910 | switch (info->fix.visual) { |
928 | case FB_VISUAL_TRUECOLOR: | 911 | case FB_VISUAL_TRUECOLOR: |
929 | case FB_VISUAL_PSEUDOCOLOR: | 912 | case FB_VISUAL_PSEUDOCOLOR: |
@@ -933,9 +916,9 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
933 | transp = CNVT_TOHW(transp, info->var.transp.length); | 916 | transp = CNVT_TOHW(transp, info->var.transp.length); |
934 | break; | 917 | break; |
935 | case FB_VISUAL_DIRECTCOLOR: | 918 | case FB_VISUAL_DIRECTCOLOR: |
936 | /* example here assumes 8 bit DAC. Might be different | 919 | /* example here assumes 8 bit DAC. Might be different |
937 | * for your hardware */ | 920 | * for your hardware */ |
938 | red = CNVT_TOHW(red, 8); | 921 | red = CNVT_TOHW(red, 8); |
939 | green = CNVT_TOHW(green, 8); | 922 | green = CNVT_TOHW(green, 8); |
940 | blue = CNVT_TOHW(blue, 8); | 923 | blue = CNVT_TOHW(blue, 8); |
941 | /* hey, there is bug in transp handling... */ | 924 | /* hey, there is bug in transp handling... */ |
@@ -957,11 +940,11 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
957 | 940 | ||
958 | switch (info->var.bits_per_pixel) { | 941 | switch (info->var.bits_per_pixel) { |
959 | case 8: | 942 | case 8: |
960 | break; | 943 | break; |
961 | case 16: | 944 | case 16: |
962 | case 24: | 945 | case 24: |
963 | case 32: | 946 | case 32: |
964 | par->palette[regno] = v; | 947 | par->palette[regno] = v; |
965 | break; | 948 | break; |
966 | } | 949 | } |
967 | return 0; | 950 | return 0; |
@@ -973,15 +956,15 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
973 | } | 956 | } |
974 | 957 | ||
975 | /** | 958 | /** |
976 | * pm2fb_pan_display - Pans the display. | 959 | * pm2fb_pan_display - Pans the display. |
977 | * @var: frame buffer variable screen structure | 960 | * @var: frame buffer variable screen structure |
978 | * @info: frame buffer structure that represents a single frame buffer | 961 | * @info: frame buffer structure that represents a single frame buffer |
979 | * | 962 | * |
980 | * Pan (or wrap, depending on the `vmode' field) the display using the | 963 | * Pan (or wrap, depending on the `vmode' field) the display using the |
981 | * `xoffset' and `yoffset' fields of the `var' structure. | 964 | * `xoffset' and `yoffset' fields of the `var' structure. |
982 | * If the values don't fit, return -EINVAL. | 965 | * If the values don't fit, return -EINVAL. |
983 | * | 966 | * |
984 | * Returns negative errno on error, or zero on success. | 967 | * Returns negative errno on error, or zero on success. |
985 | * | 968 | * |
986 | */ | 969 | */ |
987 | static int pm2fb_pan_display(struct fb_var_screeninfo *var, | 970 | static int pm2fb_pan_display(struct fb_var_screeninfo *var, |
@@ -997,24 +980,24 @@ static int pm2fb_pan_display(struct fb_var_screeninfo *var, | |||
997 | depth = (depth > 32) ? 32 : depth; | 980 | depth = (depth > 32) ? 32 : depth; |
998 | base = to3264(var->yoffset * xres + var->xoffset, depth, 1); | 981 | base = to3264(var->yoffset * xres + var->xoffset, depth, 1); |
999 | WAIT_FIFO(p, 1); | 982 | WAIT_FIFO(p, 1); |
1000 | pm2_WR(p, PM2R_SCREEN_BASE, base); | 983 | pm2_WR(p, PM2R_SCREEN_BASE, base); |
1001 | return 0; | 984 | return 0; |
1002 | } | 985 | } |
1003 | 986 | ||
1004 | /** | 987 | /** |
1005 | * pm2fb_blank - Blanks the display. | 988 | * pm2fb_blank - Blanks the display. |
1006 | * @blank_mode: the blank mode we want. | 989 | * @blank_mode: the blank mode we want. |
1007 | * @info: frame buffer structure that represents a single frame buffer | 990 | * @info: frame buffer structure that represents a single frame buffer |
1008 | * | 991 | * |
1009 | * Blank the screen if blank_mode != 0, else unblank. Return 0 if | 992 | * Blank the screen if blank_mode != 0, else unblank. Return 0 if |
1010 | * blanking succeeded, != 0 if un-/blanking failed due to e.g. a | 993 | * blanking succeeded, != 0 if un-/blanking failed due to e.g. a |
1011 | * video mode which doesn't support it. Implements VESA suspend | 994 | * video mode which doesn't support it. Implements VESA suspend |
1012 | * and powerdown modes on hardware that supports disabling hsync/vsync: | 995 | * and powerdown modes on hardware that supports disabling hsync/vsync: |
1013 | * blank_mode == 2: suspend vsync | 996 | * blank_mode == 2: suspend vsync |
1014 | * blank_mode == 3: suspend hsync | 997 | * blank_mode == 3: suspend hsync |
1015 | * blank_mode == 4: powerdown | 998 | * blank_mode == 4: powerdown |
1016 | * | 999 | * |
1017 | * Returns negative errno on error, or zero on success. | 1000 | * Returns negative errno on error, or zero on success. |
1018 | * | 1001 | * |
1019 | */ | 1002 | */ |
1020 | static int pm2fb_blank(int blank_mode, struct fb_info *info) | 1003 | static int pm2fb_blank(int blank_mode, struct fb_info *info) |
@@ -1050,20 +1033,36 @@ static int pm2fb_blank(int blank_mode, struct fb_info *info) | |||
1050 | return 0; | 1033 | return 0; |
1051 | } | 1034 | } |
1052 | 1035 | ||
1036 | static int pm2fb_sync(struct fb_info *info) | ||
1037 | { | ||
1038 | struct pm2fb_par *par = info->par; | ||
1039 | |||
1040 | WAIT_FIFO(par, 1); | ||
1041 | pm2_WR(par, PM2R_SYNC, 0); | ||
1042 | mb(); | ||
1043 | do { | ||
1044 | while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0) | ||
1045 | udelay(10); | ||
1046 | rmb(); | ||
1047 | } while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC)); | ||
1048 | |||
1049 | return 0; | ||
1050 | } | ||
1051 | |||
1053 | /* | 1052 | /* |
1054 | * block operation. copy=0: rectangle fill, copy=1: rectangle copy. | 1053 | * block operation. copy=0: rectangle fill, copy=1: rectangle copy. |
1055 | */ | 1054 | */ |
1056 | static void pm2fb_block_op(struct pm2fb_par* par, int copy, | 1055 | static void pm2fb_block_op(struct fb_info* info, int copy, |
1057 | s32 xsrc, s32 ysrc, | 1056 | s32 xsrc, s32 ysrc, |
1058 | s32 x, s32 y, s32 w, s32 h, | 1057 | s32 x, s32 y, s32 w, s32 h, |
1059 | u32 color) { | 1058 | u32 color) { |
1059 | struct pm2fb_par *par = info->par; | ||
1060 | 1060 | ||
1061 | if (!w || !h) | 1061 | if (!w || !h) |
1062 | return; | 1062 | return; |
1063 | WAIT_FIFO(par, 6); | 1063 | WAIT_FIFO(par, 5); |
1064 | pm2_WR(par, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE | | 1064 | pm2_WR(par, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE | |
1065 | PM2F_CONFIG_FB_READ_SOURCE_ENABLE); | 1065 | PM2F_CONFIG_FB_READ_SOURCE_ENABLE); |
1066 | pm2_WR(par, PM2R_FB_PIXEL_OFFSET, 0); | ||
1067 | if (copy) | 1066 | if (copy) |
1068 | pm2_WR(par, PM2R_FB_SOURCE_DELTA, | 1067 | pm2_WR(par, PM2R_FB_SOURCE_DELTA, |
1069 | ((ysrc-y) & 0xfff) << 16 | ((xsrc-x) & 0xfff)); | 1068 | ((ysrc-y) & 0xfff) << 16 | ((xsrc-x) & 0xfff)); |
@@ -1072,17 +1071,15 @@ static void pm2fb_block_op(struct pm2fb_par* par, int copy, | |||
1072 | pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (y << 16) | x); | 1071 | pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (y << 16) | x); |
1073 | pm2_WR(par, PM2R_RECTANGLE_SIZE, (h << 16) | w); | 1072 | pm2_WR(par, PM2R_RECTANGLE_SIZE, (h << 16) | w); |
1074 | wmb(); | 1073 | wmb(); |
1075 | pm2_WR(par, PM2R_RENDER,PM2F_RENDER_RECTANGLE | | 1074 | pm2_WR(par, PM2R_RENDER, PM2F_RENDER_RECTANGLE | |
1076 | (x<xsrc ? PM2F_INCREASE_X : 0) | | 1075 | (x<xsrc ? PM2F_INCREASE_X : 0) | |
1077 | (y<ysrc ? PM2F_INCREASE_Y : 0) | | 1076 | (y<ysrc ? PM2F_INCREASE_Y : 0) | |
1078 | (copy ? 0 : PM2F_RENDER_FASTFILL)); | 1077 | (copy ? 0 : PM2F_RENDER_FASTFILL)); |
1079 | wait_pm2(par); | ||
1080 | } | 1078 | } |
1081 | 1079 | ||
1082 | static void pm2fb_fillrect (struct fb_info *info, | 1080 | static void pm2fb_fillrect (struct fb_info *info, |
1083 | const struct fb_fillrect *region) | 1081 | const struct fb_fillrect *region) |
1084 | { | 1082 | { |
1085 | struct pm2fb_par *par = info->par; | ||
1086 | struct fb_fillrect modded; | 1083 | struct fb_fillrect modded; |
1087 | int vxres, vyres; | 1084 | int vxres, vyres; |
1088 | u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ? | 1085 | u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ? |
@@ -1116,7 +1113,7 @@ static void pm2fb_fillrect (struct fb_info *info, | |||
1116 | color |= color << 16; | 1113 | color |= color << 16; |
1117 | 1114 | ||
1118 | if(info->var.bits_per_pixel != 24) | 1115 | if(info->var.bits_per_pixel != 24) |
1119 | pm2fb_block_op(par, 0, 0, 0, | 1116 | pm2fb_block_op(info, 0, 0, 0, |
1120 | modded.dx, modded.dy, | 1117 | modded.dx, modded.dy, |
1121 | modded.width, modded.height, color); | 1118 | modded.width, modded.height, color); |
1122 | else | 1119 | else |
@@ -1126,7 +1123,6 @@ static void pm2fb_fillrect (struct fb_info *info, | |||
1126 | static void pm2fb_copyarea(struct fb_info *info, | 1123 | static void pm2fb_copyarea(struct fb_info *info, |
1127 | const struct fb_copyarea *area) | 1124 | const struct fb_copyarea *area) |
1128 | { | 1125 | { |
1129 | struct pm2fb_par *par = info->par; | ||
1130 | struct fb_copyarea modded; | 1126 | struct fb_copyarea modded; |
1131 | u32 vxres, vyres; | 1127 | u32 vxres, vyres; |
1132 | 1128 | ||
@@ -1156,7 +1152,7 @@ static void pm2fb_copyarea(struct fb_info *info, | |||
1156 | if(modded.dy + modded.height > vyres) | 1152 | if(modded.dy + modded.height > vyres) |
1157 | modded.height = vyres - modded.dy; | 1153 | modded.height = vyres - modded.dy; |
1158 | 1154 | ||
1159 | pm2fb_block_op(par, 1, modded.sx, modded.sy, | 1155 | pm2fb_block_op(info, 1, modded.sx, modded.sy, |
1160 | modded.dx, modded.dy, | 1156 | modded.dx, modded.dy, |
1161 | modded.width, modded.height, 0); | 1157 | modded.width, modded.height, 0); |
1162 | } | 1158 | } |
@@ -1177,6 +1173,7 @@ static struct fb_ops pm2fb_ops = { | |||
1177 | .fb_fillrect = pm2fb_fillrect, | 1173 | .fb_fillrect = pm2fb_fillrect, |
1178 | .fb_copyarea = pm2fb_copyarea, | 1174 | .fb_copyarea = pm2fb_copyarea, |
1179 | .fb_imageblit = cfb_imageblit, | 1175 | .fb_imageblit = cfb_imageblit, |
1176 | .fb_sync = pm2fb_sync, | ||
1180 | }; | 1177 | }; |
1181 | 1178 | ||
1182 | /* | 1179 | /* |
@@ -1237,7 +1234,7 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, | |||
1237 | DPRINTK("Adjusting register base for big-endian.\n"); | 1234 | DPRINTK("Adjusting register base for big-endian.\n"); |
1238 | #endif | 1235 | #endif |
1239 | DPRINTK("Register base at 0x%lx\n", pm2fb_fix.mmio_start); | 1236 | DPRINTK("Register base at 0x%lx\n", pm2fb_fix.mmio_start); |
1240 | 1237 | ||
1241 | /* Registers - request region and map it. */ | 1238 | /* Registers - request region and map it. */ |
1242 | if ( !request_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len, | 1239 | if ( !request_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len, |
1243 | "pm2fb regbase") ) { | 1240 | "pm2fb regbase") ) { |
@@ -1320,17 +1317,17 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, | |||
1320 | } | 1317 | } |
1321 | 1318 | ||
1322 | info->fbops = &pm2fb_ops; | 1319 | info->fbops = &pm2fb_ops; |
1323 | info->fix = pm2fb_fix; | 1320 | info->fix = pm2fb_fix; |
1324 | info->pseudo_palette = default_par->palette; | 1321 | info->pseudo_palette = default_par->palette; |
1325 | info->flags = FBINFO_DEFAULT | | 1322 | info->flags = FBINFO_DEFAULT | |
1326 | FBINFO_HWACCEL_YPAN | | 1323 | FBINFO_HWACCEL_YPAN | |
1327 | FBINFO_HWACCEL_COPYAREA | | 1324 | FBINFO_HWACCEL_COPYAREA | |
1328 | FBINFO_HWACCEL_FILLRECT; | 1325 | FBINFO_HWACCEL_FILLRECT; |
1329 | 1326 | ||
1330 | if (!mode) | 1327 | if (!mode) |
1331 | mode = "640x480@60"; | 1328 | mode = "640x480@60"; |
1332 | 1329 | ||
1333 | err = fb_find_mode(&info->var, info, mode, NULL, 0, NULL, 8); | 1330 | err = fb_find_mode(&info->var, info, mode, NULL, 0, NULL, 8); |
1334 | if (!err || err == 4) | 1331 | if (!err || err == 4) |
1335 | info->var = pm2fb_var; | 1332 | info->var = pm2fb_var; |
1336 | 1333 | ||
@@ -1351,8 +1348,8 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, | |||
1351 | return 0; | 1348 | return 0; |
1352 | 1349 | ||
1353 | err_exit_all: | 1350 | err_exit_all: |
1354 | fb_dealloc_cmap(&info->cmap); | 1351 | fb_dealloc_cmap(&info->cmap); |
1355 | err_exit_both: | 1352 | err_exit_both: |
1356 | iounmap(info->screen_base); | 1353 | iounmap(info->screen_base); |
1357 | release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len); | 1354 | release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len); |
1358 | err_exit_mmio: | 1355 | err_exit_mmio: |
@@ -1377,7 +1374,7 @@ static void __devexit pm2fb_remove(struct pci_dev *pdev) | |||
1377 | struct pm2fb_par *par = info->par; | 1374 | struct pm2fb_par *par = info->par; |
1378 | 1375 | ||
1379 | unregister_framebuffer(info); | 1376 | unregister_framebuffer(info); |
1380 | 1377 | ||
1381 | iounmap(info->screen_base); | 1378 | iounmap(info->screen_base); |
1382 | release_mem_region(fix->smem_start, fix->smem_len); | 1379 | release_mem_region(fix->smem_start, fix->smem_len); |
1383 | iounmap(par->v_regs); | 1380 | iounmap(par->v_regs); |
@@ -1405,9 +1402,9 @@ static struct pci_device_id pm2fb_id_table[] = { | |||
1405 | 1402 | ||
1406 | static struct pci_driver pm2fb_driver = { | 1403 | static struct pci_driver pm2fb_driver = { |
1407 | .name = "pm2fb", | 1404 | .name = "pm2fb", |
1408 | .id_table = pm2fb_id_table, | 1405 | .id_table = pm2fb_id_table, |
1409 | .probe = pm2fb_probe, | 1406 | .probe = pm2fb_probe, |
1410 | .remove = __devexit_p(pm2fb_remove), | 1407 | .remove = __devexit_p(pm2fb_remove), |
1411 | }; | 1408 | }; |
1412 | 1409 | ||
1413 | MODULE_DEVICE_TABLE(pci, pm2fb_id_table); | 1410 | MODULE_DEVICE_TABLE(pci, pm2fb_id_table); |
@@ -1426,7 +1423,7 @@ static int __init pm2fb_setup(char *options) | |||
1426 | if (!options || !*options) | 1423 | if (!options || !*options) |
1427 | return 0; | 1424 | return 0; |
1428 | 1425 | ||
1429 | while ((this_opt = strsep(&options, ",")) != NULL) { | 1426 | while ((this_opt = strsep(&options, ",")) != NULL) { |
1430 | if (!*this_opt) | 1427 | if (!*this_opt) |
1431 | continue; | 1428 | continue; |
1432 | if(!strcmp(this_opt, "lowhsync")) { | 1429 | if(!strcmp(this_opt, "lowhsync")) { |
diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c index bd787e80177d..5b3f54c0918e 100644 --- a/drivers/video/pm3fb.c +++ b/drivers/video/pm3fb.c | |||
@@ -1,55 +1,25 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/video/pm3fb.c -- 3DLabs Permedia3 frame buffer device | 2 | * linux/drivers/video/pm3fb.c -- 3DLabs Permedia3 frame buffer device |
3 | * | 3 | * |
4 | * Copyright (C) 2001 Romain Dolbeau <dolbeau@irisa.fr> | 4 | * Copyright (C) 2001 Romain Dolbeau <romain@dolbeau.org>. |
5 | * | ||
6 | * Ported to 2.6 kernel on 1 May 2007 by Krzysztof Helt <krzysztof.h1@wp.pl> | ||
7 | * based on pm2fb.c | ||
8 | * | ||
5 | * Based on code written by: | 9 | * Based on code written by: |
6 | * Sven Luther, <luther@dpt-info.u-strasbg.fr> | 10 | * Sven Luther, <luther@dpt-info.u-strasbg.fr> |
7 | * Alan Hourihane, <alanh@fairlite.demon.co.uk> | 11 | * Alan Hourihane, <alanh@fairlite.demon.co.uk> |
8 | * Russell King, <rmk@arm.linux.org.uk> | 12 | * Russell King, <rmk@arm.linux.org.uk> |
9 | * Based on linux/drivers/video/skeletonfb.c: | 13 | * Based on linux/drivers/video/skeletonfb.c: |
10 | * Copyright (C) 1997 Geert Uytterhoeven | 14 | * Copyright (C) 1997 Geert Uytterhoeven |
11 | * Based on linux/driver/video/pm2fb.c: | 15 | * Based on linux/driver/video/pm2fb.c: |
12 | * Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT) | 16 | * Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT) |
13 | * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) | 17 | * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) |
14 | * | 18 | * |
15 | * This file is subject to the terms and conditions of the GNU General Public | 19 | * This file is subject to the terms and conditions of the GNU General Public |
16 | * License. See the file COPYING in the main directory of this archive for | 20 | * License. See the file COPYING in the main directory of this archive for |
17 | * more details. | 21 | * more details. |
18 | * | 22 | * |
19 | * $Header: /cvsroot/linux/drivers/video/pm3fb.c,v 1.1 2002/02/25 19:11:06 marcelo Exp $ | ||
20 | * | ||
21 | * CHANGELOG: | ||
22 | * Mon Feb 11 10:35:48 MET 2002, v 1.4.11B: Cosmetic update. | ||
23 | * Wed Jan 23 14:16:59 MET 2002, v 1.4.11: Preliminary 2.5.x support, patch for 2.5.2. | ||
24 | * Wed Nov 28 11:08:29 MET 2001, v 1.4.10: potential bug fix for SDRAM-based board, patch for 2.4.16. | ||
25 | * Thu Sep 20 10:24:42 MET DST 2001, v 1.4.9: sync bug fix, preliminary flatpanel support, better timings. | ||
26 | * Tue Aug 28 10:13:01 MET DST 2001, v 1.4.8: memory timings check, minor bug fixes. | ||
27 | * Wed Jul 18 19:06:14 CEST 2001, v 1.4.7: Mode fix (800x600-100, 1024x768-100 changed), using HW panning + accel bug fix. | ||
28 | * Mon Jun 25 10:33:56 MET DST 2001, v 1.4.6: Depth 12 fix, chip reset ioctl, moved memory erase ioctl to DEBUG. | ||
29 | * Wed Jun 20 11:13:08 MET DST 2001, v 1.4.5: Fixed missing blinking cursor in 8bpp, code cleaning, memory erase IOCTL. | ||
30 | * Mon Jun 18 16:00:27 CEST 2001, v 1.4.4: Depth 12 (RGBA 4444) support, code cleaning. | ||
31 | * Fri Jun 15 13:53:01 CEST 2001, v 1.4.3: Removed warnings, depth 15 support, add 'depth' option. | ||
32 | * Thu Jun 14 10:13:52 MET DST 2001, v 1.4.2: Fixed depth switching bug, preliminary 15bpp (RGB5551) support. | ||
33 | * Thu Apr 12 11:16:45 MET DST 2001, v 1.4.1B: Doc updates. | ||
34 | * Fri Apr 6 11:12:53 MET DST 2001, v 1.4.1: Configure.help, minor cleanup | ||
35 | * Thu Mar 29 10:56:50 MET DST 2001, v 1.4.0: Module & module options support (note: linux patch changed, 2.2.19 added). | ||
36 | * Thu Mar 15 15:30:31 MET 2001, v 1.3.2: Fixed mirroring bug on little-endian. | ||
37 | * Wed Mar 14 21:25:54 CET 2001, v 1.3.1: Fixed bug in BlockMove (_bmov). | ||
38 | * Tue Mar 13 10:53:19 MET 2001, v 1.3.0: Character drawing hardware support (in all width between 1 and 16), fixes. | ||
39 | * Thu Mar 8 10:20:16 MET 2001, v 1.2.2: Better J2000 support, "font:" option. | ||
40 | * Tue Mar 6 21:25:04 CET 2001, v 1.2.1: Better acceleration support. | ||
41 | * Mon Mar 5 21:54:17 CET 2001, v 1.2.0: Partial acceleration support (clear & bmove) | ||
42 | * Mon Mar 5 12:52:15 CET 2001, v 1.1.3: Big pan_display fix. | ||
43 | * Sun Mar 4 22:21:50 CET 2001, v 1.1.2: (numerous) bug fixes. | ||
44 | * Fri Mar 2 15:54:07 CET 2001, v 1.1.1: Might have Appian J2000 support, resource mangement in 2.4 | ||
45 | * Wed Feb 28 18:21:35 CET 2001, v 1.1.0: Might have multiple boards support (added, but not yest tested) | ||
46 | * Tue Feb 27 17:31:12 CET 2001, v 1.0.6: fixes boot-time mode select, add more default mode | ||
47 | * Tue Feb 27 14:01:36 CET 2001, v 1.0.5: fixes (1.0.4 was broken for 2.2), cleaning up | ||
48 | * Mon Feb 26 23:17:36 CET 2001, v 1.0.4: preliminary 2.4.x support, dropped (useless on pm3) partial product, more OF fix | ||
49 | * Mon Feb 26 20:59:05 CET 2001, v 1.0.3: No more shadow register (and wasted memory), endianess fix, use OF-preset resolution by default | ||
50 | * Wed Feb 21 22:09:30 CET 2001, v 1.0.2: Code cleaning for future multiboard support, better OF support, bugs fix | ||
51 | * Wed Feb 21 19:58:56 CET 2001, v 1.0.1: OpenFirmware support, fixed memory detection, better debug support, code cleaning | ||
52 | * Wed Feb 21 14:47:06 CET 2001, v 1.0.0: First working version | ||
53 | */ | 23 | */ |
54 | 24 | ||
55 | #include <linux/module.h> | 25 | #include <linux/module.h> |
@@ -58,1057 +28,454 @@ | |||
58 | #include <linux/string.h> | 28 | #include <linux/string.h> |
59 | #include <linux/mm.h> | 29 | #include <linux/mm.h> |
60 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
61 | #include <linux/vmalloc.h> | ||
62 | #include <linux/delay.h> | 31 | #include <linux/delay.h> |
63 | #include <linux/interrupt.h> | ||
64 | #include <linux/fb.h> | 32 | #include <linux/fb.h> |
65 | #include <linux/init.h> | 33 | #include <linux/init.h> |
66 | #include <linux/pci.h> | 34 | #include <linux/pci.h> |
67 | #include <linux/ioport.h> | ||
68 | #include <linux/ctype.h> | ||
69 | |||
70 | #include <video/fbcon.h> | ||
71 | #include <video/fbcon-mfb.h> | ||
72 | #include <video/fbcon-cfb2.h> | ||
73 | #include <video/fbcon-cfb4.h> | ||
74 | #include <video/fbcon-cfb8.h> | ||
75 | #include <video/fbcon-cfb16.h> | ||
76 | #include <video/fbcon-cfb24.h> | ||
77 | #include <video/fbcon-cfb32.h> | ||
78 | #include <video/pm3fb.h> | ||
79 | |||
80 | #include <asm/io.h> | ||
81 | #include <asm/uaccess.h> | ||
82 | |||
83 | #ifdef CONFIG_FB_OF | ||
84 | #include <asm/prom.h> | ||
85 | #endif | ||
86 | |||
87 | /* ************************************* */ | ||
88 | /* ***** The various "global" data ***** */ | ||
89 | /* ************************************* */ | ||
90 | |||
91 | /* those will need a rework for multiple board support */ | ||
92 | /* Driver name */ | ||
93 | static const char permedia3_name[16] = "Permedia3"; | ||
94 | |||
95 | /* the fb_par struct, mandatory */ | ||
96 | struct pm3fb_par { | ||
97 | u32 pixclock; /* pixclock in KHz */ | ||
98 | |||
99 | u32 width; /* width of virtual screen */ | ||
100 | u32 height; /* height of virtual screen */ | ||
101 | |||
102 | u32 hsstart; /* horiz. sync start */ | ||
103 | u32 hsend; /* horiz. sync end */ | ||
104 | u32 hbend; /* horiz. blank end (also gate end) */ | ||
105 | u32 htotal; /* total width (w/ sync & blank) */ | ||
106 | 35 | ||
107 | u32 vsstart; /* vert. sync start */ | 36 | #include <video/pm3fb.h> |
108 | u32 vsend; /* vert. sync end */ | ||
109 | u32 vbend; /* vert. blank end */ | ||
110 | u32 vtotal; /* total height (w/ sync & blank) */ | ||
111 | |||
112 | u32 stride; /* screen stride */ | ||
113 | u32 base; /* screen base (xoffset+yoffset) in 128 bits unit */ | ||
114 | /* NOTE : unlike other pm3 stuff above, stored *after* shiftbpp. don't ask */ | ||
115 | u32 depth; /* screen depth (8, 12, 15, 16 or 32) */ | ||
116 | u32 video; /* video control (hsync,vsync) */ | ||
117 | }; | ||
118 | 37 | ||
119 | /* memory timings */ | 38 | #if !defined(CONFIG_PCI) |
120 | struct pm3fb_timings | 39 | #error "Only generic PCI cards supported." |
121 | { | ||
122 | unsigned long caps; | ||
123 | unsigned long timings; | ||
124 | unsigned long control; | ||
125 | unsigned long refresh; | ||
126 | unsigned long powerdown; | ||
127 | }; | ||
128 | typedef enum pm3fb_timing_result { pm3fb_timing_ok, pm3fb_timing_problem, pm3fb_timing_retry } pm3fb_timing_result; | ||
129 | #define PM3FB_UNKNOWN_TIMING_VALUE ((unsigned long)-1) | ||
130 | #define PM3FB_UNKNOWN_TIMINGS { PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE } | ||
131 | |||
132 | /* the fb_info struct, mandatory */ | ||
133 | struct pm3fb_info { | ||
134 | struct fb_info_gen gen; | ||
135 | unsigned long board_num; /* internal board number */ | ||
136 | unsigned long use_current; | ||
137 | struct pm3fb_par *current_par; | ||
138 | struct pci_dev *dev; /* PCI device */ | ||
139 | unsigned long board_type; /* index in the cardbase */ | ||
140 | unsigned char *fb_base; /* framebuffer memory base */ | ||
141 | u32 fb_size; /* framebuffer memory size */ | ||
142 | unsigned char *p_fb; /* physical address of frame buffer */ | ||
143 | unsigned char *v_fb; /* virtual address of frame buffer */ | ||
144 | unsigned char *pIOBase; /* physical address of registers region, must be rg_base or rg_base+PM2_REGS_SIZE depending on the host endianness */ | ||
145 | unsigned char *vIOBase; /* address of registers after ioremap() */ | ||
146 | struct { | ||
147 | u8 transp; | ||
148 | u8 red; | ||
149 | u8 green; | ||
150 | u8 blue; | ||
151 | } palette[256]; | ||
152 | union { | ||
153 | #ifdef FBCON_HAS_CFB16 | ||
154 | u16 cmap12[16]; /* RGBA 4444 */ | ||
155 | u16 cmap15[16]; /* RGBA 5551 */ | ||
156 | u16 cmap16[16]; /* RGBA 5650 */ | ||
157 | #endif | ||
158 | #ifdef FBCON_HAS_CFB32 | ||
159 | u32 cmap32[16]; | ||
160 | #endif | 40 | #endif |
161 | } cmap; | ||
162 | struct pm3fb_timings memt; | ||
163 | }; | ||
164 | |||
165 | /* regular resolution database*/ | ||
166 | static struct { | ||
167 | char name[16]; | ||
168 | struct pm3fb_par user_mode; | ||
169 | } mode_base[] __initdata = { | ||
170 | { | ||
171 | "default-800x600", { | ||
172 | 49500, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625, | ||
173 | 800, 0, 8, | ||
174 | PM3VideoControl_ENABLE | | ||
175 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
176 | | | ||
177 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
178 | | PM3VideoControl_PIXELSIZE_8BIT}}, { | ||
179 | "1024x768-74", { | ||
180 | 78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38, | ||
181 | 806, 1024, 0, 8, | ||
182 | PM3VideoControl_ENABLE | | ||
183 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
184 | | | ||
185 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
186 | | PM3VideoControl_PIXELSIZE_8BIT}}, { | ||
187 | "1024x768-74-32", { | ||
188 | 78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38, | ||
189 | 806, 1024, 0, 32, | ||
190 | PM3VideoControl_ENABLE | | ||
191 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
192 | | | ||
193 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
194 | | PM3VideoControl_PIXELSIZE_32BIT}}, | ||
195 | /* Generated mode : "1600x1024", for the SGI 1600SW flat panel*/ | ||
196 | { | ||
197 | "SGI1600SW", { | ||
198 | 108000, 1600, 1024, 16, 56, 104, 1704, 3, 6, 32, | ||
199 | 1056, 1600, 0, 8, | ||
200 | PM3VideoControl_ENABLE| | ||
201 | PM3VideoControl_HSYNC_ACTIVE_LOW|PM3VideoControl_VSYNC_ACTIVE_LOW| | ||
202 | PM3VideoControl_PIXELSIZE_32BIT}}, | ||
203 | /* ##### auto-generated mode, by fbtimings2pm3 */ | ||
204 | /* Generated mode : "640x480-60" */ | ||
205 | { | ||
206 | "640x480-60", { | ||
207 | 25174, 640, 480, 16, 112, 160, 800, 10, 12, 45, | ||
208 | 525, 640, 0, 8, | ||
209 | PM3VideoControl_ENABLE | | ||
210 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
211 | | | ||
212 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
213 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
214 | /* Generated mode : "640x480-72" */ | ||
215 | { | ||
216 | "640x480-72", { | ||
217 | 31199, 640, 480, 24, 64, 192, 832, 9, 12, 40, 520, | ||
218 | 640, 0, 8, | ||
219 | PM3VideoControl_ENABLE | | ||
220 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
221 | | | ||
222 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
223 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
224 | /* Generated mode : "640x480-75" */ | ||
225 | { | ||
226 | "640x480-75", { | ||
227 | 31499, 640, 480, 16, 80, 200, 840, 1, 4, 20, 500, | ||
228 | 640, 0, 8, | ||
229 | PM3VideoControl_ENABLE | | ||
230 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
231 | | | ||
232 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
233 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
234 | /* Generated mode : "640x480-90" */ | ||
235 | { | ||
236 | "640x480-90", { | ||
237 | 39909, 640, 480, 32, 72, 192, 832, 25, 39, 53, 533, | ||
238 | 640, 0, 8, | ||
239 | PM3VideoControl_ENABLE | | ||
240 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
241 | | | ||
242 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
243 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
244 | /* Generated mode : "640x480-100" */ | ||
245 | { | ||
246 | "640x480-100", { | ||
247 | 44899, 640, 480, 32, 160, 208, 848, 22, 34, 51, | ||
248 | 531, 640, 0, 8, | ||
249 | PM3VideoControl_ENABLE | | ||
250 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
251 | | | ||
252 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
253 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
254 | /* Generated mode : "800x600-48-lace" */ | ||
255 | /* INTERLACED NOT SUPPORTED | ||
256 | {"800x600-48-lace", {35999, 800, 600, 80, 208, 264, 1064, 11, 23, 102, 702, 800, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, | ||
257 | INTERLACED NOT SUPPORTED */ | ||
258 | /* Generated mode : "800x600-56" */ | ||
259 | { | ||
260 | "800x600-56", { | ||
261 | 35999, 800, 600, 24, 96, 224, 1024, 1, 3, 25, 625, | ||
262 | 800, 0, 8, | ||
263 | PM3VideoControl_ENABLE | | ||
264 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
265 | | | ||
266 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
267 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
268 | /* Generated mode : "800x600-60" */ | ||
269 | { | ||
270 | "800x600-60", { | ||
271 | 40000, 800, 600, 40, 168, 256, 1056, 1, 5, 28, 628, | ||
272 | 800, 0, 8, | ||
273 | PM3VideoControl_ENABLE | | ||
274 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
275 | | | ||
276 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
277 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
278 | /* Generated mode : "800x600-70" */ | ||
279 | { | ||
280 | "800x600-70", { | ||
281 | 44899, 800, 600, 24, 168, 208, 1008, 9, 21, 36, | ||
282 | 636, 800, 0, 8, | ||
283 | PM3VideoControl_ENABLE | | ||
284 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
285 | | | ||
286 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
287 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
288 | /* Generated mode : "800x600-72" */ | ||
289 | { | ||
290 | "800x600-72", { | ||
291 | 50000, 800, 600, 56, 176, 240, 1040, 37, 43, 66, | ||
292 | 666, 800, 0, 8, | ||
293 | PM3VideoControl_ENABLE | | ||
294 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
295 | | | ||
296 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
297 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
298 | /* Generated mode : "800x600-75" */ | ||
299 | { | ||
300 | "800x600-75", { | ||
301 | 49497, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625, | ||
302 | 800, 0, 8, | ||
303 | PM3VideoControl_ENABLE | | ||
304 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
305 | | | ||
306 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
307 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
308 | /* Generated mode : "800x600-90" */ | ||
309 | { | ||
310 | "800x600-90", { | ||
311 | 56637, 800, 600, 8, 72, 192, 992, 8, 19, 35, 635, | ||
312 | 800, 0, 8, | ||
313 | PM3VideoControl_ENABLE | | ||
314 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
315 | | | ||
316 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
317 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
318 | /* Generated mode : "800x600-100", from /etc/fb.modes */ | ||
319 | /* DISABLED, hsstart == 0 | ||
320 | { | ||
321 | "800x600-100", { | ||
322 | 67499, 800, 600, 0, 64, 280, 1080, 7, 11, 25, 625, | ||
323 | 800, 0, 8, | ||
324 | PM3VideoControl_ENABLE | | ||
325 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
326 | | | ||
327 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
328 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
329 | */ | ||
330 | /* Generated mode : "800x600-100", from ??? */ | ||
331 | { | ||
332 | "800x600-100", { | ||
333 | 69650, 800, 600, 64, 128, 288, 1088, 4, 10, 40, 640, 800, 0, 8, | ||
334 | PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW| | ||
335 | PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}}, | ||
336 | /* Generated mode : "1024x768-43-lace" */ | ||
337 | /* INTERLACED NOT SUPPORTED | ||
338 | {"1024x768-43-lace", {44899, 1024, 768, 8, 184, 240, 1264, 1, 9, 49, 817, 1024, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, | ||
339 | INTERLACED NOT SUPPORTED */ | ||
340 | /* Generated mode : "1024x768-60" */ | ||
341 | { | ||
342 | "1024x768-60", { | ||
343 | 64998, 1024, 768, 24, 160, 320, 1344, 3, 9, 38, | ||
344 | 806, 1024, 0, 8, | ||
345 | PM3VideoControl_ENABLE | | ||
346 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
347 | | | ||
348 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
349 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
350 | /* Generated mode : "1024x768-70" */ | ||
351 | { | ||
352 | "1024x768-70", { | ||
353 | 74996, 1024, 768, 24, 160, 304, 1328, 3, 9, 38, | ||
354 | 806, 1024, 0, 8, | ||
355 | PM3VideoControl_ENABLE | | ||
356 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
357 | | | ||
358 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
359 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
360 | /* Generated mode : "1024x768-72" */ | ||
361 | { | ||
362 | "1024x768-72", { | ||
363 | 74996, 10224, 768, 24, 160, 264, 10488, 3, 9, 38, | ||
364 | 806, 10224, 0, 8, | ||
365 | PM3VideoControl_ENABLE | | ||
366 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
367 | | | ||
368 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
369 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
370 | /* Generated mode : "1024x768-75" */ | ||
371 | { | ||
372 | "1024x768-75", { | ||
373 | 78746, 1024, 768, 16, 112, 288, 1312, 1, 4, 32, | ||
374 | 800, 1024, 0, 8, | ||
375 | PM3VideoControl_ENABLE | | ||
376 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
377 | | | ||
378 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
379 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
380 | /* Generated mode : "1024x768-90" */ | ||
381 | { | ||
382 | "1024x768-90", { | ||
383 | 100000, 1024, 768, 0, 96, 288, 1312, 21, 36, 77, | ||
384 | 845, 1024, 0, 8, | ||
385 | PM3VideoControl_ENABLE | | ||
386 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
387 | | | ||
388 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
389 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
390 | /* Generated mode : "1024x768-100", from /etc/fb.modes */ | ||
391 | /* DISABLED, vsstart == 0 | ||
392 | { | ||
393 | "1024x768-100", { | ||
394 | 109998, 1024, 768, 0, 88, 368, 1392, 0, 8, 24, 792, | ||
395 | 1024, 0, 8, | ||
396 | PM3VideoControl_ENABLE | | ||
397 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
398 | | | ||
399 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
400 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
401 | */ | ||
402 | /* Generated mode : "1024x768-100", from ??? */ | ||
403 | { | ||
404 | "1024x768-100", { | ||
405 | 115500, 1024, 768, 32, 224, 416, 1440, 3, 13, 34, 802, 1024, 0, 8, | ||
406 | PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW| | ||
407 | PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}}, | ||
408 | /* Generated mode : "1152x864-43-lace" */ | ||
409 | /* INTERLACED NOT SUPPORTED | ||
410 | {"1152x864-43-lace", {64998, 1152, 864, 72, 200, 264, 1416, 78, 87, 191, 1055, 1152, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, | ||
411 | INTERLACED NOT SUPPORTED */ | ||
412 | /* Generated mode : "1152x864-47-lace" */ | ||
413 | /* INTERLACED NOT SUPPORTED | ||
414 | {"1152x864-47-lace", {64998, 1152, 864, 88, 216, 296, 1448, 30, 39, 83, 947, 1152, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, | ||
415 | INTERLACED NOT SUPPORTED */ | ||
416 | /* Generated mode : "1152x864-60" */ | ||
417 | { | ||
418 | "1152x864-60", { | ||
419 | 80000, 1152, 864, 64, 176, 304, 1456, 6, 11, 52, | ||
420 | 916, 1152, 0, 8, | ||
421 | PM3VideoControl_ENABLE | | ||
422 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
423 | | | ||
424 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
425 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
426 | /* Generated mode : "1152x864-70" */ | ||
427 | { | ||
428 | "1152x864-70", { | ||
429 | 100000, 1152, 864, 40, 192, 360, 1512, 13, 24, 81, | ||
430 | 945, 1152, 0, 8, | ||
431 | PM3VideoControl_ENABLE | | ||
432 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
433 | | | ||
434 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
435 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
436 | /* Generated mode : "1152x864-75" */ | ||
437 | { | ||
438 | "1152x864-75", { | ||
439 | 109998, 1152, 864, 24, 168, 312, 1464, 45, 53, 138, | ||
440 | 1002, 1152, 0, 8, | ||
441 | PM3VideoControl_ENABLE | | ||
442 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
443 | | | ||
444 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
445 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
446 | /* Generated mode : "1152x864-80" */ | ||
447 | { | ||
448 | "1152x864-80", { | ||
449 | 109998, 1152, 864, 16, 128, 288, 1440, 30, 37, 94, | ||
450 | 958, 1152, 0, 8, | ||
451 | PM3VideoControl_ENABLE | | ||
452 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
453 | | | ||
454 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
455 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
456 | /* Generated mode : "1280x1024-43-lace" */ | ||
457 | /* INTERLACED NOT SUPPORTED | ||
458 | {"1280x1024-43-lace", {80000, 1024, 1024, 80, 160, 320, 1344, 50, 60, 125, 1149, 1024, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, | ||
459 | INTERLACED NOT SUPPORTED */ | ||
460 | /* Generated mode : "1280x1024-47-lace" */ | ||
461 | /* INTERLACED NOT SUPPORTED | ||
462 | {"1280x1024-47-lace", {80000, 1280, 1024, 80, 160, 320, 1600, 1, 11, 29, 1053, 1280, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, | ||
463 | INTERLACED NOT SUPPORTED */ | ||
464 | /* Generated mode : "1280x1024-60" */ | ||
465 | { | ||
466 | "1280x1024-60", { | ||
467 | 107991, 1280, 1024, 48, 160, 408, 1688, 1, 4, 42, | ||
468 | 1066, 1280, 0, 8, | ||
469 | PM3VideoControl_ENABLE | | ||
470 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
471 | | | ||
472 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
473 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
474 | /* Generated mode : "1280x1024-70" */ | ||
475 | { | ||
476 | "1280x1024-70", { | ||
477 | 125992, 1280, 1024, 80, 192, 408, 1688, 1, 6, 42, | ||
478 | 1066, 1280, 0, 8, | ||
479 | PM3VideoControl_ENABLE | | ||
480 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
481 | | | ||
482 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
483 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
484 | /* Generated mode : "1280x1024-74" */ | ||
485 | { | ||
486 | "1280x1024-74", { | ||
487 | 134989, 1280, 1024, 32, 176, 432, 1712, 0, 30, 40, | ||
488 | 1064, 1280, 0, 8, | ||
489 | PM3VideoControl_ENABLE | | ||
490 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
491 | | | ||
492 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
493 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
494 | /* Generated mode : "1280x1024-75" */ | ||
495 | { | ||
496 | "1280x1024-75", { | ||
497 | 134989, 1280, 1024, 16, 160, 408, 1688, 1, 4, 42, | ||
498 | 1066, 1280, 0, 8, | ||
499 | PM3VideoControl_ENABLE | | ||
500 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
501 | | | ||
502 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
503 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
504 | /* Generated mode : "1600x1200-60" */ | ||
505 | { | ||
506 | "1600x1200-60", { | ||
507 | 155981, 1600, 1200, 32, 192, 448, 2048, 10, 18, 70, | ||
508 | 1270, 1600, 0, 8, | ||
509 | PM3VideoControl_ENABLE | | ||
510 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
511 | | | ||
512 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
513 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
514 | /* Generated mode : "1600x1200-66" */ | ||
515 | { | ||
516 | "1600x1200-66", { | ||
517 | 171998, 1600, 1200, 40, 176, 480, 2080, 3, 6, 53, | ||
518 | 1253, 1600, 0, 8, | ||
519 | PM3VideoControl_ENABLE | | ||
520 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
521 | | | ||
522 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
523 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
524 | /* Generated mode : "1600x1200-76" */ | ||
525 | { | ||
526 | "1600x1200-76", { | ||
527 | 197980, 1600, 1200, 40, 176, 480, 2080, 3, 8, 50, | ||
528 | 1250, 1600, 0, 8, | ||
529 | PM3VideoControl_ENABLE | | ||
530 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
531 | | | ||
532 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
533 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
534 | /* ##### end of auto-generated mode */ | ||
535 | { | ||
536 | "\0",} | ||
537 | }; | ||
538 | 41 | ||
539 | /* more mandatory stuff (see skeletonfb.c + framebuffer driver HOWTO */ | 42 | #undef PM3FB_MASTER_DEBUG |
540 | static struct pm3fb_info fb_info[PM3_MAX_BOARD]; | 43 | #ifdef PM3FB_MASTER_DEBUG |
541 | static struct pm3fb_par current_par[PM3_MAX_BOARD]; | 44 | #define DPRINTK(a,b...) printk(KERN_DEBUG "pm3fb: %s: " a, __FUNCTION__ , ## b) |
542 | static int current_par_valid[PM3_MAX_BOARD]; | 45 | #else |
543 | /* to allow explicit filtering of board */ | 46 | #define DPRINTK(a,b...) |
544 | short bus[PM3_MAX_BOARD]; | ||
545 | short slot[PM3_MAX_BOARD]; | ||
546 | short func[PM3_MAX_BOARD]; | ||
547 | short disable[PM3_MAX_BOARD]; | ||
548 | short noaccel[PM3_MAX_BOARD]; | ||
549 | char fontn[PM3_MAX_BOARD][PM3_FONTNAME_SIZE]; | ||
550 | short depth[PM3_MAX_BOARD]; | ||
551 | short flatpanel[PM3_MAX_BOARD]; | ||
552 | static struct display disp[PM3_MAX_BOARD]; | ||
553 | static char g_options[PM3_OPTIONS_SIZE] __initdata = "pm3fb,dummy"; | ||
554 | short printtimings = 0; | ||
555 | short forcesize[PM3_MAX_BOARD]; | ||
556 | |||
557 | /* ********************* */ | ||
558 | /* ***** prototype ***** */ | ||
559 | /* ********************* */ | ||
560 | /* card-specific */ | ||
561 | static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info); | ||
562 | /* permedia3-specific */ | ||
563 | static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info); | ||
564 | static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info); | ||
565 | static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info); | ||
566 | static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info, | ||
567 | unsigned long r); | ||
568 | static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock, /* In kHz units */ | ||
569 | unsigned long refclock, /* In kHz units */ | ||
570 | unsigned char *prescale, /* ClkPreScale */ | ||
571 | unsigned char *feedback, /* ClkFeedBackScale */ | ||
572 | unsigned char *postscale | ||
573 | /* ClkPostScale */ ); | ||
574 | static void pm3fb_clear_memory(struct pm3fb_info *l_fb_info, u32 cc); | ||
575 | static void pm3fb_clear_colormap(struct pm3fb_info *l_fb_info, unsigned char r, unsigned char g, unsigned char b); | ||
576 | static void pm3fb_common_init(struct pm3fb_info *l_fb_info); | ||
577 | static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info, | ||
578 | unsigned long depth, int v); | ||
579 | static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info, | ||
580 | unsigned long depth, int v); | ||
581 | static void pm3fb_mapIO(struct pm3fb_info *l_fb_info); | ||
582 | static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info); | ||
583 | #if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2) | ||
584 | static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info); | ||
585 | #endif | 47 | #endif |
586 | static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info); | ||
587 | static void pm3fb_write_mode(struct pm3fb_info *l_fb_info); | ||
588 | static void pm3fb_read_mode(struct pm3fb_info *l_fb_info, | ||
589 | struct pm3fb_par *curpar); | ||
590 | static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info); | ||
591 | /* accelerated permedia3-specific */ | ||
592 | #ifdef PM3FB_USE_ACCEL | ||
593 | static void pm3fb_wait_pm3(struct pm3fb_info *l_fb_info); | ||
594 | static void pm3fb_init_engine(struct pm3fb_info *l_fb_info); | ||
595 | #ifdef FBCON_HAS_CFB32 | ||
596 | static void pm3fb_cfb32_clear(struct vc_data *conp, | ||
597 | struct display *p, | ||
598 | int sy, int sx, int height, int width); | ||
599 | static void pm3fb_cfb32_clear_margins(struct vc_data *conp, | ||
600 | struct display *p, int bottom_only); | ||
601 | #endif /* FBCON_HAS_CFB32 */ | ||
602 | #ifdef FBCON_HAS_CFB16 | ||
603 | static void pm3fb_cfb16_clear(struct vc_data *conp, | ||
604 | struct display *p, | ||
605 | int sy, int sx, int height, int width); | ||
606 | static void pm3fb_cfb16_clear_margins(struct vc_data *conp, | ||
607 | struct display *p, int bottom_only); | ||
608 | #endif /* FBCON_HAS_CFB16 */ | ||
609 | #ifdef FBCON_HAS_CFB8 | ||
610 | static void pm3fb_cfb8_clear(struct vc_data *conp, | ||
611 | struct display *p, | ||
612 | int sy, int sx, int height, int width); | ||
613 | static void pm3fb_cfb8_clear_margins(struct vc_data *conp, | ||
614 | struct display *p, int bottom_only); | ||
615 | #endif /* FBCON_HAS_CFB8 */ | ||
616 | #if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32) | ||
617 | static void pm3fb_cfbX_bmove(struct display *p, | ||
618 | int sy, int sx, | ||
619 | int dy, int dx, int height, int width); | ||
620 | static void pm3fb_cfbX_putc(struct vc_data *conp, struct display *p, | ||
621 | int c, int yy, int xx); | ||
622 | static void pm3fb_cfbX_putcs(struct vc_data *conp, struct display *p, | ||
623 | const unsigned short *s, int count, int yy, | ||
624 | int xx); | ||
625 | static void pm3fb_cfbX_revc(struct display *p, int xx, int yy); | ||
626 | #endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */ | ||
627 | #endif /* PM3FB_USE_ACCEL */ | ||
628 | /* pre-init */ | ||
629 | static void pm3fb_mode_setup(char *mode, unsigned long board_num); | ||
630 | static void pm3fb_pciid_setup(char *pciid, unsigned long board_num); | ||
631 | static char *pm3fb_boardnum_setup(char *options, unsigned long *bn); | ||
632 | static void pm3fb_real_setup(char *options); | ||
633 | /* fbdev */ | ||
634 | static int pm3fb_encode_fix(struct fb_fix_screeninfo *fix, | ||
635 | const void *par, struct fb_info_gen *info); | ||
636 | static int pm3fb_decode_var(const struct fb_var_screeninfo *var, | ||
637 | void *par, struct fb_info_gen *info); | ||
638 | static void pm3fb_encode_depth(struct fb_var_screeninfo *var, long d); | ||
639 | static int pm3fb_encode_var(struct fb_var_screeninfo *var, | ||
640 | const void *par, struct fb_info_gen *info); | ||
641 | static void pm3fb_get_par(void *par, struct fb_info_gen *info); | ||
642 | static void pm3fb_set_par(const void *par, struct fb_info_gen *info); | ||
643 | static void pm3fb_set_color(struct pm3fb_info *l_fb_info, | ||
644 | unsigned char regno, unsigned char r, | ||
645 | unsigned char g, unsigned char b); | ||
646 | static int pm3fb_getcolreg(unsigned regno, unsigned *red, unsigned *green, | ||
647 | unsigned *blue, unsigned *transp, | ||
648 | struct fb_info *info); | ||
649 | static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green, | ||
650 | unsigned blue, unsigned transp, | ||
651 | struct fb_info *info); | ||
652 | static int pm3fb_blank(int blank_mode, struct fb_info_gen *info); | ||
653 | static void pm3fb_set_disp(const void *par, struct display *disp, | ||
654 | struct fb_info_gen *info); | ||
655 | static void pm3fb_detect(void); | ||
656 | static int pm3fb_pan_display(const struct fb_var_screeninfo *var, | ||
657 | struct fb_info_gen *info); | ||
658 | static int pm3fb_ioctl(struct fb_info *info, u_int cmd, u_long arg); | ||
659 | |||
660 | |||
661 | /* the struct that hold them together */ | ||
662 | struct fbgen_hwswitch pm3fb_switch = { | ||
663 | pm3fb_detect, pm3fb_encode_fix, pm3fb_decode_var, pm3fb_encode_var, | ||
664 | pm3fb_get_par, pm3fb_set_par, pm3fb_getcolreg, | ||
665 | pm3fb_pan_display, pm3fb_blank, pm3fb_set_disp | ||
666 | }; | ||
667 | |||
668 | static struct fb_ops pm3fb_ops = { | ||
669 | .owner = THIS_MODULE, | ||
670 | .fb_get_fix = fbgen_get_fix, | ||
671 | .fb_get_var = fbgen_get_var, | ||
672 | .fb_set_var = fbgen_set_var, | ||
673 | .fb_get_cmap = fbgen_get_cmap, | ||
674 | .fb_set_cmap = fbgen_set_cmap, | ||
675 | .fb_setcolreg = pm3fb_setcolreg, | ||
676 | .fb_pan_display =fbgen_pan_display, | ||
677 | .fb_blank = fbgen_blank, | ||
678 | .fb_ioctl = pm3fb_ioctl, | ||
679 | }; | ||
680 | 48 | ||
681 | #ifdef PM3FB_USE_ACCEL | 49 | /* |
682 | #ifdef FBCON_HAS_CFB32 | 50 | * Driver data |
683 | static struct display_switch pm3fb_cfb32 = { | 51 | */ |
684 | fbcon_cfb32_setup, pm3fb_cfbX_bmove, pm3fb_cfb32_clear, | 52 | static char *mode_option __devinitdata; |
685 | pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc, | ||
686 | NULL /* cursor() */ , NULL /* set_font() */ , | ||
687 | pm3fb_cfb32_clear_margins, | ||
688 | FONTWIDTHRANGE(1, 16) /* true only if accelerated... */ | ||
689 | }; | ||
690 | #endif /* FBCON_HAS_CFB32 */ | ||
691 | #ifdef FBCON_HAS_CFB16 | ||
692 | static struct display_switch pm3fb_cfb16 = { | ||
693 | fbcon_cfb16_setup, pm3fb_cfbX_bmove, pm3fb_cfb16_clear, | ||
694 | pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc, | ||
695 | NULL /* cursor() */ , NULL /* set_font() */ , | ||
696 | pm3fb_cfb16_clear_margins, | ||
697 | FONTWIDTHRANGE(1, 16) /* true only if accelerated... */ | ||
698 | }; | ||
699 | #endif /* FBCON_HAS_CFB16 */ | ||
700 | #ifdef FBCON_HAS_CFB8 | ||
701 | static struct display_switch pm3fb_cfb8 = { | ||
702 | fbcon_cfb8_setup, pm3fb_cfbX_bmove, pm3fb_cfb8_clear, | ||
703 | pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc, | ||
704 | NULL /* cursor() */ , NULL /* set_font() */ , | ||
705 | pm3fb_cfb8_clear_margins, | ||
706 | FONTWIDTHRANGE(1, 16) /* true only if accelerated... */ | ||
707 | }; | ||
708 | #endif /* FBCON_HAS_CFB8 */ | ||
709 | #endif /* PM3FB_USE_ACCEL */ | ||
710 | |||
711 | /* ****************************** */ | ||
712 | /* ***** card-specific data ***** */ | ||
713 | /* ****************************** */ | ||
714 | struct pm3fb_card_timings { | ||
715 | unsigned long memsize; /* 0 for last value (i.e. default) */ | ||
716 | struct pm3fb_timings memt; | ||
717 | }; | ||
718 | 53 | ||
719 | static struct pm3fb_card_timings t_FormacProFormance3[] = { | 54 | /* |
720 | { 16, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} }, | 55 | * This structure defines the hardware state of the graphics card. Normally |
721 | { 0, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} } /* from 16 MB PF3 */ | 56 | * you place this in a header file in linux/include/video. This file usually |
57 | * also includes register information. That allows other driver subsystems | ||
58 | * and userland applications the ability to use the same header file to | ||
59 | * avoid duplicate work and easy porting of software. | ||
60 | */ | ||
61 | struct pm3_par { | ||
62 | unsigned char __iomem *v_regs;/* virtual address of p_regs */ | ||
63 | u32 video; /* video flags before blanking */ | ||
64 | u32 base; /* screen base (xoffset+yoffset) in 128 bits unit */ | ||
65 | u32 palette[16]; | ||
722 | }; | 66 | }; |
723 | 67 | ||
724 | static struct pm3fb_card_timings t_AppianJeronimo2000[] = { | 68 | /* |
725 | { 32, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} }, | 69 | * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo |
726 | { 0, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} } /* from 32MB J2000 */ | 70 | * if we don't use modedb. If we do use modedb see pm3fb_init how to use it |
71 | * to get a fb_var_screeninfo. Otherwise define a default var as well. | ||
72 | */ | ||
73 | static struct fb_fix_screeninfo pm3fb_fix __devinitdata = { | ||
74 | .id = "Permedia3", | ||
75 | .type = FB_TYPE_PACKED_PIXELS, | ||
76 | .visual = FB_VISUAL_PSEUDOCOLOR, | ||
77 | .xpanstep = 1, | ||
78 | .ypanstep = 1, | ||
79 | .ywrapstep = 0, | ||
80 | .accel = FB_ACCEL_3DLABS_PERMEDIA3, | ||
727 | }; | 81 | }; |
728 | 82 | ||
729 | static struct pm3fb_card_timings t_3DLabsOxygenVX1[] = { | 83 | /* |
730 | { 32, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} }, | 84 | * Utility functions |
731 | { 0, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} } /* from 32MB VX1 */ | 85 | */ |
732 | }; | ||
733 | 86 | ||
734 | static struct { | 87 | static inline u32 PM3_READ_REG(struct pm3_par *par, s32 off) |
735 | char cardname[32]; /* recognized card name */ | 88 | { |
736 | u16 subvendor; /* subvendor of the card */ | 89 | return fb_readl(par->v_regs + off); |
737 | u16 subdevice; /* subdevice of the card */ | 90 | } |
738 | u8 func; /* function of the card to which the extra init apply */ | ||
739 | void (*specific_setup)(struct pm3fb_info *l_fb_info); /* card/func specific setup, done before _any_ FB access */ | ||
740 | struct pm3fb_card_timings *c_memt; /* defauls timings for the boards */ | ||
741 | } cardbase[] = { | ||
742 | { "Unknown Permedia3 board", 0xFFFF, 0xFFFF, 0xFF, NULL, NULL }, | ||
743 | { "Appian Jeronimo 2000 head 1", 0x1097, 0x3d32, 1, NULL, | ||
744 | t_AppianJeronimo2000 | ||
745 | }, | ||
746 | { "Appian Jeronimo 2000 head 2", 0x1097, 0x3d32, 2, pm3fb_j2000_setup, | ||
747 | t_AppianJeronimo2000 | ||
748 | }, | ||
749 | { "Formac ProFormance 3", PCI_VENDOR_ID_3DLABS, 0x000a, 0, NULL, /* Formac use 3DLabs ID ?!? */ | ||
750 | t_FormacProFormance3 | ||
751 | }, | ||
752 | { "3DLabs Permedia3 Create!", PCI_VENDOR_ID_3DLABS, 0x0127, 0, NULL, NULL }, | ||
753 | { "3DLabs Oxygen VX1 PCI", PCI_VENDOR_ID_3DLABS, 0x0121, 0, NULL, | ||
754 | t_3DLabsOxygenVX1 | ||
755 | }, | ||
756 | { "3DLabs Oxygen VX1 AGP", PCI_VENDOR_ID_3DLABS, 0x0125, 0, NULL, NULL }, | ||
757 | { "3DLabs Oxygen VX1-16 AGP", PCI_VENDOR_ID_3DLABS, 0x0140, 0, NULL, NULL }, | ||
758 | { "3DLabs Oxygen VX1-1600SW PCI", PCI_VENDOR_ID_3DLABS, 0x0800, 0, NULL, NULL }, | ||
759 | { "\0", 0x0, 0x0, 0, NULL, NULL } | ||
760 | }; | ||
761 | 91 | ||
762 | /* ********************************** */ | 92 | static inline void PM3_WRITE_REG(struct pm3_par *par, s32 off, u32 v) |
763 | /* ***** card-specific function ***** */ | 93 | { |
764 | /* ********************************** */ | 94 | fb_writel(v, par->v_regs + off); |
765 | static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info) | ||
766 | { /* the appian j2000 require more initialization of the second head */ | ||
767 | /* l_fb_info must point to the _second_ head of the J2000 */ | ||
768 | |||
769 | DTRACE; | ||
770 | |||
771 | l_fb_info->memt = t_AppianJeronimo2000[0].memt; /* 32 MB, first and only j2000 ? */ | ||
772 | |||
773 | pm3fb_write_memory_timings(l_fb_info); | ||
774 | } | 95 | } |
775 | 96 | ||
776 | /* *************************************** */ | 97 | static inline void PM3_WAIT(struct pm3_par *par, u32 n) |
777 | /* ***** permedia3-specific function ***** */ | ||
778 | /* *************************************** */ | ||
779 | static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info) | ||
780 | { | 98 | { |
781 | l_fb_info->memt.caps = PM3_READ_REG(PM3LocalMemCaps); | 99 | while (PM3_READ_REG(par, PM3InFIFOSpace) < n); |
782 | l_fb_info->memt.timings = PM3_READ_REG(PM3LocalMemTimings); | ||
783 | l_fb_info->memt.control = PM3_READ_REG(PM3LocalMemControl); | ||
784 | l_fb_info->memt.refresh = PM3_READ_REG(PM3LocalMemRefresh); | ||
785 | l_fb_info->memt.powerdown = PM3_READ_REG(PM3LocalMemPowerDown); | ||
786 | |||
787 | if ((l_fb_info->memt.caps == PM3FB_UNKNOWN_TIMING_VALUE) || | ||
788 | (l_fb_info->memt.timings == PM3FB_UNKNOWN_TIMING_VALUE) || | ||
789 | (l_fb_info->memt.control == PM3FB_UNKNOWN_TIMING_VALUE) || | ||
790 | (l_fb_info->memt.refresh == PM3FB_UNKNOWN_TIMING_VALUE) || | ||
791 | (l_fb_info->memt.powerdown == PM3FB_UNKNOWN_TIMING_VALUE)) | ||
792 | { | ||
793 | printk(KERN_ERR "pm3fb: invalid memory timings in permedia3 board #%ld\n", l_fb_info->board_num); | ||
794 | return(pm3fb_try_memory_timings(l_fb_info)); | ||
795 | } | ||
796 | return(pm3fb_timing_ok); | ||
797 | } | 100 | } |
798 | 101 | ||
799 | static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info) | 102 | static inline void PM3_WRITE_DAC_REG(struct pm3_par *par, unsigned r, u8 v) |
800 | { | 103 | { |
801 | if (cardbase[l_fb_info->board_type].c_memt) | 104 | PM3_WAIT(par, 3); |
802 | { | 105 | PM3_WRITE_REG(par, PM3RD_IndexHigh, (r >> 8) & 0xff); |
803 | int i = 0, done = 0; | 106 | PM3_WRITE_REG(par, PM3RD_IndexLow, r & 0xff); |
804 | while (!done) | 107 | wmb(); |
805 | { | 108 | PM3_WRITE_REG(par, PM3RD_IndexedData, v); |
806 | if ((cardbase[l_fb_info->board_type].c_memt[i].memsize == l_fb_info->fb_size) | 109 | wmb(); |
807 | || !(cardbase[l_fb_info->board_type].c_memt[i].memsize)) | ||
808 | { /* will use the 0-sized timings by default */ | ||
809 | done = 1; | ||
810 | l_fb_info->memt = cardbase[l_fb_info->board_type].c_memt[i].memt; | ||
811 | printk(KERN_WARNING "pm3fb: trying to use predefined memory timings for permedia3 board #%ld (%s, %ld MB)\n", | ||
812 | l_fb_info->board_num, | ||
813 | cardbase[l_fb_info->board_type].cardname, | ||
814 | cardbase[l_fb_info->board_type].c_memt[i].memsize); | ||
815 | pm3fb_write_memory_timings(l_fb_info); | ||
816 | return(pm3fb_timing_retry); | ||
817 | } | ||
818 | i++; | ||
819 | } | ||
820 | } else | ||
821 | return(pm3fb_timing_problem); | ||
822 | return(pm3fb_timing_ok); | ||
823 | } | 110 | } |
824 | 111 | ||
825 | static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info) | 112 | static inline void pm3fb_set_color(struct pm3_par *par, unsigned char regno, |
113 | unsigned char r, unsigned char g, unsigned char b) | ||
826 | { | 114 | { |
827 | unsigned char m, n, p; | 115 | PM3_WAIT(par, 4); |
828 | unsigned long clockused; | 116 | PM3_WRITE_REG(par, PM3RD_PaletteWriteAddress, regno); |
829 | 117 | wmb(); | |
830 | PM3_SLOW_WRITE_REG(PM3LocalMemCaps, l_fb_info->memt.caps); | 118 | PM3_WRITE_REG(par, PM3RD_PaletteData, r); |
831 | PM3_SLOW_WRITE_REG(PM3LocalMemTimings, l_fb_info->memt.timings); | 119 | wmb(); |
832 | PM3_SLOW_WRITE_REG(PM3LocalMemControl, l_fb_info->memt.control); | 120 | PM3_WRITE_REG(par, PM3RD_PaletteData, g); |
833 | PM3_SLOW_WRITE_REG(PM3LocalMemRefresh, l_fb_info->memt.refresh); | 121 | wmb(); |
834 | PM3_SLOW_WRITE_REG(PM3LocalMemPowerDown, l_fb_info->memt.powerdown); | 122 | PM3_WRITE_REG(par, PM3RD_PaletteData, b); |
835 | 123 | wmb(); | |
836 | clockused = | ||
837 | pm3fb_CalculateClock(l_fb_info, 2 * 105000, PM3_REF_CLOCK, &m, | ||
838 | &n, &p); | ||
839 | |||
840 | PM3_WRITE_DAC_REG(PM3RD_KClkPreScale, m); | ||
841 | PM3_WRITE_DAC_REG(PM3RD_KClkFeedbackScale, n); | ||
842 | PM3_WRITE_DAC_REG(PM3RD_KClkPostScale, p); | ||
843 | PM3_WRITE_DAC_REG(PM3RD_KClkControl, | ||
844 | PM3RD_KClkControl_STATE_RUN | | ||
845 | PM3RD_KClkControl_SOURCE_PLL | | ||
846 | PM3RD_KClkControl_ENABLE); | ||
847 | PM3_WRITE_DAC_REG(PM3RD_MClkControl, | ||
848 | PM3RD_MClkControl_STATE_RUN | | ||
849 | PM3RD_MClkControl_SOURCE_KCLK | | ||
850 | PM3RD_MClkControl_ENABLE); | ||
851 | PM3_WRITE_DAC_REG(PM3RD_SClkControl, | ||
852 | PM3RD_SClkControl_STATE_RUN | | ||
853 | PM3RD_SClkControl_SOURCE_PCLK | | ||
854 | PM3RD_SClkControl_ENABLE); | ||
855 | } | 124 | } |
856 | 125 | ||
857 | static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info, | 126 | static void pm3fb_clear_colormap(struct pm3_par *par, |
858 | unsigned long r) | 127 | unsigned char r, unsigned char g, unsigned char b) |
859 | { | 128 | { |
860 | DASSERT((l_fb_info->vIOBase != (unsigned char *) (-1)), | 129 | int i; |
861 | "l_fb_info->vIOBase mapped in read dac reg\n"); | 130 | |
862 | PM3_SET_INDEX(r); | 131 | for (i = 0; i < 256 ; i++) |
863 | mb(); | 132 | pm3fb_set_color(par, i, r, g, b); |
864 | return (PM3_READ_REG(PM3RD_IndexedData)); | 133 | |
865 | } | 134 | } |
866 | 135 | ||
867 | /* Calculating various clock parameter */ | 136 | /* Calculating various clock parameter */ |
868 | static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock, /* In kHz units */ | 137 | static void pm3fb_calculate_clock(unsigned long reqclock, |
869 | unsigned long refclock, /* In kHz units */ | 138 | unsigned char *prescale, |
870 | unsigned char *prescale, /* ClkPreScale */ | 139 | unsigned char *feedback, |
871 | unsigned char *feedback, /* ClkFeedBackScale */ | 140 | unsigned char *postscale) |
872 | unsigned char *postscale | ||
873 | /* ClkPostScale */ ) | ||
874 | { | 141 | { |
875 | int f, pre, post; | 142 | int f, pre, post; |
876 | unsigned long freq; | 143 | unsigned long freq; |
877 | long freqerr = 1000; | 144 | long freqerr = 1000; |
878 | unsigned long actualclock = 0; | 145 | long currerr; |
879 | |||
880 | DTRACE; | ||
881 | 146 | ||
882 | for (f = 1; f < 256; f++) { | 147 | for (f = 1; f < 256; f++) { |
883 | for (pre = 1; pre < 256; pre++) { | 148 | for (pre = 1; pre < 256; pre++) { |
884 | for (post = 0; post < 5; post++) { | 149 | for (post = 0; post < 5; post++) { |
885 | freq = | 150 | freq = ((2*PM3_REF_CLOCK * f) >> post) / pre; |
886 | ((2 * refclock * f) / | 151 | currerr = (reqclock > freq) |
887 | (pre * (1 << post))); | 152 | ? reqclock - freq |
888 | if ((reqclock > freq - freqerr) | 153 | : freq - reqclock; |
889 | && (reqclock < freq + freqerr)) { | 154 | if (currerr < freqerr) { |
890 | freqerr = | 155 | freqerr = currerr; |
891 | (reqclock > | ||
892 | freq) ? reqclock - | ||
893 | freq : freq - reqclock; | ||
894 | *feedback = f; | 156 | *feedback = f; |
895 | *prescale = pre; | 157 | *prescale = pre; |
896 | *postscale = post; | 158 | *postscale = post; |
897 | actualclock = freq; | ||
898 | } | 159 | } |
899 | } | 160 | } |
900 | } | 161 | } |
901 | } | 162 | } |
163 | } | ||
164 | |||
165 | static inline int pm3fb_depth(const struct fb_var_screeninfo *var) | ||
166 | { | ||
167 | if ( var->bits_per_pixel == 16 ) | ||
168 | return var->red.length + var->green.length | ||
169 | + var->blue.length; | ||
902 | 170 | ||
903 | return (actualclock); | 171 | return var->bits_per_pixel; |
904 | } | 172 | } |
905 | 173 | ||
906 | static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info, | 174 | static inline int pm3fb_shift_bpp(unsigned bpp, int v) |
907 | unsigned long depth, int v) | ||
908 | { | 175 | { |
909 | DTRACE; | 176 | switch (bpp) { |
910 | |||
911 | switch (depth) { | ||
912 | case 8: | 177 | case 8: |
913 | return (v >> 4); | 178 | return (v >> 4); |
914 | case 12: | ||
915 | case 15: | ||
916 | case 16: | 179 | case 16: |
917 | return (v >> 3); | 180 | return (v >> 3); |
918 | case 32: | 181 | case 32: |
919 | return (v >> 2); | 182 | return (v >> 2); |
920 | } | 183 | } |
921 | DPRINTK(1, "Unsupported depth %ld\n", depth); | 184 | DPRINTK("Unsupported depth %u\n", bpp); |
922 | return (0); | 185 | return 0; |
923 | } | 186 | } |
924 | 187 | ||
925 | static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info, | 188 | /* acceleration */ |
926 | unsigned long depth, int v) | 189 | static int pm3fb_sync(struct fb_info *info) |
927 | { | 190 | { |
928 | DTRACE; | 191 | struct pm3_par *par = info->par; |
929 | 192 | ||
930 | switch (depth) { | 193 | PM3_WAIT(par, 2); |
931 | case 8: | 194 | PM3_WRITE_REG(par, PM3FilterMode, PM3FilterModeSync); |
932 | return (v << 4); | 195 | PM3_WRITE_REG(par, PM3Sync, 0); |
933 | case 12: | 196 | mb(); |
934 | case 15: | 197 | do { |
935 | case 16: | 198 | while ((PM3_READ_REG(par, PM3OutFIFOWords)) == 0); |
936 | return (v << 3); | 199 | rmb(); |
937 | case 32: | 200 | } while ((PM3_READ_REG(par, PM3OutputFifo)) != PM3Sync_Tag); |
938 | return (v << 2); | ||
939 | } | ||
940 | DPRINTK(1, "Unsupported depth %ld\n", depth); | ||
941 | return (0); | ||
942 | } | ||
943 | 201 | ||
944 | static void pm3fb_mapIO(struct pm3fb_info *l_fb_info) | 202 | return 0; |
945 | { | ||
946 | DTRACE; | ||
947 | |||
948 | l_fb_info->vIOBase = | ||
949 | ioremap((unsigned long) l_fb_info->pIOBase, PM3_REGS_SIZE); | ||
950 | l_fb_info->v_fb = | ||
951 | ioremap((unsigned long) l_fb_info->p_fb, l_fb_info->fb_size); | ||
952 | DPRINTK(2, "IO mapping : IOBase %lx / %lx, fb %lx / %lx\n", | ||
953 | (unsigned long) l_fb_info->pIOBase, | ||
954 | (unsigned long) l_fb_info->vIOBase, | ||
955 | (unsigned long) l_fb_info->p_fb, | ||
956 | (unsigned long) l_fb_info->v_fb); | ||
957 | } | 203 | } |
958 | 204 | ||
959 | static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info) | 205 | static void pm3fb_init_engine(struct fb_info *info) |
960 | { | 206 | { |
961 | DTRACE; | 207 | struct pm3_par *par = info->par; |
208 | const u32 width = (info->var.xres_virtual + 7) & ~7; | ||
209 | |||
210 | PM3_WAIT(par, 50); | ||
211 | PM3_WRITE_REG(par, PM3FilterMode, PM3FilterModeSync); | ||
212 | PM3_WRITE_REG(par, PM3StatisticMode, 0x0); | ||
213 | PM3_WRITE_REG(par, PM3DeltaMode, 0x0); | ||
214 | PM3_WRITE_REG(par, PM3RasterizerMode, 0x0); | ||
215 | PM3_WRITE_REG(par, PM3ScissorMode, 0x0); | ||
216 | PM3_WRITE_REG(par, PM3LineStippleMode, 0x0); | ||
217 | PM3_WRITE_REG(par, PM3AreaStippleMode, 0x0); | ||
218 | PM3_WRITE_REG(par, PM3GIDMode, 0x0); | ||
219 | PM3_WRITE_REG(par, PM3DepthMode, 0x0); | ||
220 | PM3_WRITE_REG(par, PM3StencilMode, 0x0); | ||
221 | PM3_WRITE_REG(par, PM3StencilData, 0x0); | ||
222 | PM3_WRITE_REG(par, PM3ColorDDAMode, 0x0); | ||
223 | PM3_WRITE_REG(par, PM3TextureCoordMode, 0x0); | ||
224 | PM3_WRITE_REG(par, PM3TextureIndexMode0, 0x0); | ||
225 | PM3_WRITE_REG(par, PM3TextureIndexMode1, 0x0); | ||
226 | PM3_WRITE_REG(par, PM3TextureReadMode, 0x0); | ||
227 | PM3_WRITE_REG(par, PM3LUTMode, 0x0); | ||
228 | PM3_WRITE_REG(par, PM3TextureFilterMode, 0x0); | ||
229 | PM3_WRITE_REG(par, PM3TextureCompositeMode, 0x0); | ||
230 | PM3_WRITE_REG(par, PM3TextureApplicationMode, 0x0); | ||
231 | PM3_WRITE_REG(par, PM3TextureCompositeColorMode1, 0x0); | ||
232 | PM3_WRITE_REG(par, PM3TextureCompositeAlphaMode1, 0x0); | ||
233 | PM3_WRITE_REG(par, PM3TextureCompositeColorMode0, 0x0); | ||
234 | PM3_WRITE_REG(par, PM3TextureCompositeAlphaMode0, 0x0); | ||
235 | PM3_WRITE_REG(par, PM3FogMode, 0x0); | ||
236 | PM3_WRITE_REG(par, PM3ChromaTestMode, 0x0); | ||
237 | PM3_WRITE_REG(par, PM3AlphaTestMode, 0x0); | ||
238 | PM3_WRITE_REG(par, PM3AntialiasMode, 0x0); | ||
239 | PM3_WRITE_REG(par, PM3YUVMode, 0x0); | ||
240 | PM3_WRITE_REG(par, PM3AlphaBlendColorMode, 0x0); | ||
241 | PM3_WRITE_REG(par, PM3AlphaBlendAlphaMode, 0x0); | ||
242 | PM3_WRITE_REG(par, PM3DitherMode, 0x0); | ||
243 | PM3_WRITE_REG(par, PM3LogicalOpMode, 0x0); | ||
244 | PM3_WRITE_REG(par, PM3RouterMode, 0x0); | ||
245 | PM3_WRITE_REG(par, PM3Window, 0x0); | ||
246 | |||
247 | PM3_WRITE_REG(par, PM3Config2D, 0x0); | ||
248 | |||
249 | PM3_WRITE_REG(par, PM3SpanColorMask, 0xffffffff); | ||
250 | |||
251 | PM3_WRITE_REG(par, PM3XBias, 0x0); | ||
252 | PM3_WRITE_REG(par, PM3YBias, 0x0); | ||
253 | PM3_WRITE_REG(par, PM3DeltaControl, 0x0); | ||
254 | |||
255 | PM3_WRITE_REG(par, PM3BitMaskPattern, 0xffffffff); | ||
256 | |||
257 | PM3_WRITE_REG(par, PM3FBDestReadEnables, | ||
258 | PM3FBDestReadEnables_E(0xff) | | ||
259 | PM3FBDestReadEnables_R(0xff) | | ||
260 | PM3FBDestReadEnables_ReferenceAlpha(0xff)); | ||
261 | PM3_WRITE_REG(par, PM3FBDestReadBufferAddr0, 0x0); | ||
262 | PM3_WRITE_REG(par, PM3FBDestReadBufferOffset0, 0x0); | ||
263 | PM3_WRITE_REG(par, PM3FBDestReadBufferWidth0, | ||
264 | PM3FBDestReadBufferWidth_Width(width)); | ||
962 | 265 | ||
963 | iounmap(l_fb_info->vIOBase); | 266 | PM3_WRITE_REG(par, PM3FBDestReadMode, |
964 | iounmap(l_fb_info->v_fb); | 267 | PM3FBDestReadMode_ReadEnable | |
965 | l_fb_info->vIOBase = (unsigned char *) -1; | 268 | PM3FBDestReadMode_Enable0); |
966 | l_fb_info->v_fb = (unsigned char *) -1; | 269 | PM3_WRITE_REG(par, PM3FBSourceReadBufferAddr, 0x0); |
967 | } | 270 | PM3_WRITE_REG(par, PM3FBSourceReadBufferOffset, 0x0); |
271 | PM3_WRITE_REG(par, PM3FBSourceReadBufferWidth, | ||
272 | PM3FBSourceReadBufferWidth_Width(width)); | ||
273 | PM3_WRITE_REG(par, PM3FBSourceReadMode, | ||
274 | PM3FBSourceReadMode_Blocking | | ||
275 | PM3FBSourceReadMode_ReadEnable); | ||
968 | 276 | ||
969 | #if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2) | 277 | PM3_WAIT(par, 2); |
970 | static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info) | 278 | { |
971 | { | 279 | unsigned long rm = 1; |
972 | DPRINTK(2, "PM3Aperture0: 0x%08x\n", PM3_READ_REG(PM3Aperture0)); | 280 | switch (info->var.bits_per_pixel) { |
973 | DPRINTK(2, "PM3Aperture1: 0x%08x\n", PM3_READ_REG(PM3Aperture1)); | 281 | case 8: |
974 | DPRINTK(2, "PM3ByAperture1Mode: 0x%08x\n", | 282 | PM3_WRITE_REG(par, PM3PixelSize, |
975 | PM3_READ_REG(PM3ByAperture1Mode)); | 283 | PM3PixelSize_GLOBAL_8BIT); |
976 | DPRINTK(2, "PM3ByAperture2Mode: 0x%08x\n", | 284 | break; |
977 | PM3_READ_REG(PM3ByAperture2Mode)); | 285 | case 16: |
978 | DPRINTK(2, "PM3ChipConfig: 0x%08x\n", PM3_READ_REG(PM3ChipConfig)); | 286 | PM3_WRITE_REG(par, PM3PixelSize, |
979 | DPRINTK(2, "PM3FIFODis: 0x%08x\n", PM3_READ_REG(PM3FIFODis)); | 287 | PM3PixelSize_GLOBAL_16BIT); |
980 | DPRINTK(2, "PM3HTotal: 0x%08x\n", PM3_READ_REG(PM3HTotal)); | 288 | break; |
981 | DPRINTK(2, "PM3HbEnd: 0x%08x\n", PM3_READ_REG(PM3HbEnd)); | 289 | case 32: |
982 | DPRINTK(2, "PM3HgEnd: 0x%08x\n", PM3_READ_REG(PM3HgEnd)); | 290 | PM3_WRITE_REG(par, PM3PixelSize, |
983 | DPRINTK(2, "PM3HsEnd: 0x%08x\n", PM3_READ_REG(PM3HsEnd)); | 291 | PM3PixelSize_GLOBAL_32BIT); |
984 | DPRINTK(2, "PM3HsStart: 0x%08x\n", PM3_READ_REG(PM3HsStart)); | 292 | break; |
985 | DPRINTK(2, "PM3MemBypassWriteMask: 0x%08x\n", | 293 | default: |
986 | PM3_READ_REG(PM3MemBypassWriteMask)); | 294 | DPRINTK(1, "Unsupported depth %d\n", |
987 | DPRINTK(2, "PM3RD_IndexControl: 0x%08x\n", | 295 | info->var.bits_per_pixel); |
988 | PM3_READ_REG(PM3RD_IndexControl)); | 296 | break; |
989 | DPRINTK(2, "PM3ScreenBase: 0x%08x\n", PM3_READ_REG(PM3ScreenBase)); | 297 | } |
990 | DPRINTK(2, "PM3ScreenStride: 0x%08x\n", | 298 | PM3_WRITE_REG(par, PM3RasterizerMode, rm); |
991 | PM3_READ_REG(PM3ScreenStride)); | 299 | } |
992 | DPRINTK(2, "PM3VClkCtl: 0x%08x\n", PM3_READ_REG(PM3VClkCtl)); | 300 | |
993 | DPRINTK(2, "PM3VTotal: 0x%08x\n", PM3_READ_REG(PM3VTotal)); | 301 | PM3_WAIT(par, 20); |
994 | DPRINTK(2, "PM3VbEnd: 0x%08x\n", PM3_READ_REG(PM3VbEnd)); | 302 | PM3_WRITE_REG(par, PM3FBSoftwareWriteMask, 0xffffffff); |
995 | DPRINTK(2, "PM3VideoControl: 0x%08x\n", | 303 | PM3_WRITE_REG(par, PM3FBHardwareWriteMask, 0xffffffff); |
996 | PM3_READ_REG(PM3VideoControl)); | 304 | PM3_WRITE_REG(par, PM3FBWriteMode, |
997 | DPRINTK(2, "PM3VsEnd: 0x%08x\n", PM3_READ_REG(PM3VsEnd)); | 305 | PM3FBWriteMode_WriteEnable | |
998 | DPRINTK(2, "PM3VsStart: 0x%08x\n", PM3_READ_REG(PM3VsStart)); | 306 | PM3FBWriteMode_OpaqueSpan | |
999 | 307 | PM3FBWriteMode_Enable0); | |
1000 | DPRINTK(2, "PM3RD_ColorFormat: %ld\n", | 308 | PM3_WRITE_REG(par, PM3FBWriteBufferAddr0, 0x0); |
1001 | PM3_READ_DAC_REG(PM3RD_ColorFormat)); | 309 | PM3_WRITE_REG(par, PM3FBWriteBufferOffset0, 0x0); |
1002 | DPRINTK(2, "PM3RD_DACControl: %ld\n", | 310 | PM3_WRITE_REG(par, PM3FBWriteBufferWidth0, |
1003 | PM3_READ_DAC_REG(PM3RD_DACControl)); | 311 | PM3FBWriteBufferWidth_Width(width)); |
1004 | DPRINTK(2, "PM3RD_DClk0FeedbackScale: %ld\n", | 312 | |
1005 | PM3_READ_DAC_REG(PM3RD_DClk0FeedbackScale)); | 313 | PM3_WRITE_REG(par, PM3SizeOfFramebuffer, 0x0); |
1006 | DPRINTK(2, "PM3RD_DClk0PostScale: %ld\n", | 314 | { |
1007 | PM3_READ_DAC_REG(PM3RD_DClk0PostScale)); | 315 | /* size in lines of FB */ |
1008 | DPRINTK(2, "PM3RD_DClk0PreScale: %ld\n", | 316 | unsigned long sofb = info->screen_size / |
1009 | PM3_READ_DAC_REG(PM3RD_DClk0PreScale)); | 317 | info->fix.line_length; |
1010 | DPRINTK(2, "[not set] PM3RD_IndexControl: %ld\n", | 318 | if (sofb > 4095) |
1011 | PM3_READ_DAC_REG(PM3RD_IndexControl)); | 319 | PM3_WRITE_REG(par, PM3SizeOfFramebuffer, 4095); |
1012 | DPRINTK(2, "PM3RD_MiscControl: %ld\n", | 320 | else |
1013 | PM3_READ_DAC_REG(PM3RD_MiscControl)); | 321 | PM3_WRITE_REG(par, PM3SizeOfFramebuffer, sofb); |
1014 | DPRINTK(2, "PM3RD_PixelSize: %ld\n", | 322 | |
1015 | PM3_READ_DAC_REG(PM3RD_PixelSize)); | 323 | switch (info->var.bits_per_pixel) { |
1016 | DPRINTK(2, "PM3RD_SyncControl: %ld\n", | 324 | case 8: |
1017 | PM3_READ_DAC_REG(PM3RD_SyncControl)); | 325 | PM3_WRITE_REG(par, PM3DitherMode, |
326 | (1 << 10) | (2 << 3)); | ||
327 | break; | ||
328 | case 16: | ||
329 | PM3_WRITE_REG(par, PM3DitherMode, | ||
330 | (1 << 10) | (1 << 3)); | ||
331 | break; | ||
332 | case 32: | ||
333 | PM3_WRITE_REG(par, PM3DitherMode, | ||
334 | (1 << 10) | (0 << 3)); | ||
335 | break; | ||
336 | default: | ||
337 | DPRINTK(1, "Unsupported depth %d\n", | ||
338 | info->current_par->depth); | ||
339 | break; | ||
340 | } | ||
341 | } | ||
342 | |||
343 | PM3_WRITE_REG(par, PM3dXDom, 0x0); | ||
344 | PM3_WRITE_REG(par, PM3dXSub, 0x0); | ||
345 | PM3_WRITE_REG(par, PM3dY, (1 << 16)); | ||
346 | PM3_WRITE_REG(par, PM3StartXDom, 0x0); | ||
347 | PM3_WRITE_REG(par, PM3StartXSub, 0x0); | ||
348 | PM3_WRITE_REG(par, PM3StartY, 0x0); | ||
349 | PM3_WRITE_REG(par, PM3Count, 0x0); | ||
350 | |||
351 | /* Disable LocalBuffer. better safe than sorry */ | ||
352 | PM3_WRITE_REG(par, PM3LBDestReadMode, 0x0); | ||
353 | PM3_WRITE_REG(par, PM3LBDestReadEnables, 0x0); | ||
354 | PM3_WRITE_REG(par, PM3LBSourceReadMode, 0x0); | ||
355 | PM3_WRITE_REG(par, PM3LBWriteMode, 0x0); | ||
356 | |||
357 | pm3fb_sync(info); | ||
1018 | } | 358 | } |
1019 | 359 | ||
1020 | #endif /* defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2) */ | 360 | static void pm3fb_fillrect (struct fb_info *info, |
1021 | static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info) | 361 | const struct fb_fillrect *region) |
1022 | { | 362 | { |
1023 | u16 subvendor, subdevice; | 363 | struct pm3_par *par = info->par; |
1024 | 364 | struct fb_fillrect modded; | |
1025 | if ((!pci_read_config_word | 365 | int vxres, vyres; |
1026 | (l_fb_info->dev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor)) | 366 | u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ? |
1027 | && | 367 | ((u32*)info->pseudo_palette)[region->color] : region->color; |
1028 | (!pci_read_config_word | 368 | |
1029 | (l_fb_info->dev, PCI_SUBSYSTEM_ID, &subdevice))) { | 369 | if (info->state != FBINFO_STATE_RUNNING) |
1030 | /* well, nothing... */ | 370 | return; |
1031 | } else { | 371 | if ((info->flags & FBINFO_HWACCEL_DISABLED) || |
1032 | subvendor = subdevice = (u16)-1; | 372 | region->rop != ROP_COPY ) { |
373 | cfb_fillrect(info, region); | ||
374 | return; | ||
1033 | } | 375 | } |
1034 | 376 | ||
1035 | printk(KERN_INFO "pm3fb: memory timings for board #%ld (subvendor: 0x%hx, subdevice: 0x%hx)\n", l_fb_info->board_num, subvendor, subdevice); | 377 | vxres = info->var.xres_virtual; |
1036 | printk(KERN_INFO " PM3LocalMemCaps: 0x%08x\n", | 378 | vyres = info->var.yres_virtual; |
1037 | PM3_READ_REG(PM3LocalMemCaps)); | 379 | |
1038 | printk(KERN_INFO " PM3LocalMemTimings: 0x%08x\n", | 380 | memcpy(&modded, region, sizeof(struct fb_fillrect)); |
1039 | PM3_READ_REG(PM3LocalMemTimings)); | 381 | |
1040 | printk(KERN_INFO " PM3LocalMemControl: 0x%08x\n", | 382 | if(!modded.width || !modded.height || |
1041 | PM3_READ_REG(PM3LocalMemControl)); | 383 | modded.dx >= vxres || modded.dy >= vyres) |
1042 | printk(KERN_INFO " PM3LocalMemRefresh: 0x%08x\n", | 384 | return; |
1043 | PM3_READ_REG(PM3LocalMemRefresh)); | 385 | |
1044 | printk(KERN_INFO " PM3LocalMemPowerDown: 0x%08x\n", | 386 | if(modded.dx + modded.width > vxres) |
1045 | PM3_READ_REG(PM3LocalMemPowerDown)); | 387 | modded.width = vxres - modded.dx; |
388 | if(modded.dy + modded.height > vyres) | ||
389 | modded.height = vyres - modded.dy; | ||
390 | |||
391 | if(info->var.bits_per_pixel == 8) | ||
392 | color |= color << 8; | ||
393 | if(info->var.bits_per_pixel <= 16) | ||
394 | color |= color << 16; | ||
395 | |||
396 | PM3_WAIT(par, 4); | ||
397 | |||
398 | PM3_WRITE_REG(par, PM3Config2D, | ||
399 | PM3Config2D_UseConstantSource | | ||
400 | PM3Config2D_ForegroundROPEnable | | ||
401 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
402 | PM3Config2D_FBWriteEnable); | ||
403 | |||
404 | PM3_WRITE_REG(par, PM3ForegroundColor, color); | ||
405 | |||
406 | PM3_WRITE_REG(par, PM3RectanglePosition, | ||
407 | (PM3RectanglePosition_XOffset(modded.dx)) | | ||
408 | (PM3RectanglePosition_YOffset(modded.dy))); | ||
409 | |||
410 | PM3_WRITE_REG(par, PM3Render2D, | ||
411 | PM3Render2D_XPositive | | ||
412 | PM3Render2D_YPositive | | ||
413 | PM3Render2D_Operation_Normal | | ||
414 | PM3Render2D_SpanOperation | | ||
415 | (PM3Render2D_Width(modded.width)) | | ||
416 | (PM3Render2D_Height(modded.height))); | ||
1046 | } | 417 | } |
418 | /* end of acceleration functions */ | ||
1047 | 419 | ||
1048 | /* write the mode to registers */ | 420 | /* write the mode to registers */ |
1049 | static void pm3fb_write_mode(struct pm3fb_info *l_fb_info) | 421 | static void pm3fb_write_mode(struct fb_info *info) |
1050 | { | 422 | { |
423 | struct pm3_par *par = info->par; | ||
1051 | char tempsync = 0x00, tempmisc = 0x00; | 424 | char tempsync = 0x00, tempmisc = 0x00; |
1052 | DTRACE; | 425 | const u32 hsstart = info->var.right_margin; |
1053 | 426 | const u32 hsend = hsstart + info->var.hsync_len; | |
1054 | PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, 0xffffffff); | 427 | const u32 hbend = hsend + info->var.left_margin; |
1055 | PM3_SLOW_WRITE_REG(PM3Aperture0, 0x00000000); | 428 | const u32 xres = (info->var.xres + 31) & ~31; |
1056 | PM3_SLOW_WRITE_REG(PM3Aperture1, 0x00000000); | 429 | const u32 htotal = xres + hbend; |
1057 | PM3_SLOW_WRITE_REG(PM3FIFODis, 0x00000007); | 430 | const u32 vsstart = info->var.lower_margin; |
1058 | 431 | const u32 vsend = vsstart + info->var.vsync_len; | |
1059 | PM3_SLOW_WRITE_REG(PM3HTotal, | 432 | const u32 vbend = vsend + info->var.upper_margin; |
1060 | pm3fb_Shiftbpp(l_fb_info, | 433 | const u32 vtotal = info->var.yres + vbend; |
1061 | l_fb_info->current_par->depth, | 434 | const u32 width = (info->var.xres_virtual + 7) & ~7; |
1062 | l_fb_info->current_par->htotal - | 435 | const unsigned bpp = info->var.bits_per_pixel; |
1063 | 1)); | 436 | |
1064 | PM3_SLOW_WRITE_REG(PM3HsEnd, | 437 | PM3_WAIT(par, 20); |
1065 | pm3fb_Shiftbpp(l_fb_info, | 438 | PM3_WRITE_REG(par, PM3MemBypassWriteMask, 0xffffffff); |
1066 | l_fb_info->current_par->depth, | 439 | PM3_WRITE_REG(par, PM3Aperture0, 0x00000000); |
1067 | l_fb_info->current_par->hsend)); | 440 | PM3_WRITE_REG(par, PM3Aperture1, 0x00000000); |
1068 | PM3_SLOW_WRITE_REG(PM3HsStart, | 441 | PM3_WRITE_REG(par, PM3FIFODis, 0x00000007); |
1069 | pm3fb_Shiftbpp(l_fb_info, | 442 | |
1070 | l_fb_info->current_par->depth, | 443 | PM3_WRITE_REG(par, PM3HTotal, |
1071 | l_fb_info->current_par-> | 444 | pm3fb_shift_bpp(bpp, htotal - 1)); |
1072 | hsstart)); | 445 | PM3_WRITE_REG(par, PM3HsEnd, |
1073 | PM3_SLOW_WRITE_REG(PM3HbEnd, | 446 | pm3fb_shift_bpp(bpp, hsend)); |
1074 | pm3fb_Shiftbpp(l_fb_info, | 447 | PM3_WRITE_REG(par, PM3HsStart, |
1075 | l_fb_info->current_par->depth, | 448 | pm3fb_shift_bpp(bpp, hsstart)); |
1076 | l_fb_info->current_par->hbend)); | 449 | PM3_WRITE_REG(par, PM3HbEnd, |
1077 | PM3_SLOW_WRITE_REG(PM3HgEnd, | 450 | pm3fb_shift_bpp(bpp, hbend)); |
1078 | pm3fb_Shiftbpp(l_fb_info, | 451 | PM3_WRITE_REG(par, PM3HgEnd, |
1079 | l_fb_info->current_par->depth, | 452 | pm3fb_shift_bpp(bpp, hbend)); |
1080 | l_fb_info->current_par->hbend)); | 453 | PM3_WRITE_REG(par, PM3ScreenStride, |
1081 | PM3_SLOW_WRITE_REG(PM3ScreenStride, | 454 | pm3fb_shift_bpp(bpp, width)); |
1082 | pm3fb_Shiftbpp(l_fb_info, | 455 | PM3_WRITE_REG(par, PM3VTotal, vtotal - 1); |
1083 | l_fb_info->current_par->depth, | 456 | PM3_WRITE_REG(par, PM3VsEnd, vsend - 1); |
1084 | l_fb_info->current_par->stride)); | 457 | PM3_WRITE_REG(par, PM3VsStart, vsstart - 1); |
1085 | PM3_SLOW_WRITE_REG(PM3VTotal, l_fb_info->current_par->vtotal - 1); | 458 | PM3_WRITE_REG(par, PM3VbEnd, vbend); |
1086 | PM3_SLOW_WRITE_REG(PM3VsEnd, l_fb_info->current_par->vsend - 1); | 459 | |
1087 | PM3_SLOW_WRITE_REG(PM3VsStart, | 460 | switch (bpp) { |
1088 | l_fb_info->current_par->vsstart - 1); | ||
1089 | PM3_SLOW_WRITE_REG(PM3VbEnd, l_fb_info->current_par->vbend); | ||
1090 | |||
1091 | switch (l_fb_info->current_par->depth) { | ||
1092 | case 8: | 461 | case 8: |
1093 | PM3_SLOW_WRITE_REG(PM3ByAperture1Mode, | 462 | PM3_WRITE_REG(par, PM3ByAperture1Mode, |
1094 | PM3ByApertureMode_PIXELSIZE_8BIT); | 463 | PM3ByApertureMode_PIXELSIZE_8BIT); |
1095 | PM3_SLOW_WRITE_REG(PM3ByAperture2Mode, | 464 | PM3_WRITE_REG(par, PM3ByAperture2Mode, |
1096 | PM3ByApertureMode_PIXELSIZE_8BIT); | 465 | PM3ByApertureMode_PIXELSIZE_8BIT); |
1097 | break; | 466 | break; |
1098 | 467 | ||
1099 | case 12: | ||
1100 | case 15: | ||
1101 | case 16: | 468 | case 16: |
1102 | #ifndef __BIG_ENDIAN | 469 | #ifndef __BIG_ENDIAN |
1103 | PM3_SLOW_WRITE_REG(PM3ByAperture1Mode, | 470 | PM3_WRITE_REG(par, PM3ByAperture1Mode, |
1104 | PM3ByApertureMode_PIXELSIZE_16BIT); | 471 | PM3ByApertureMode_PIXELSIZE_16BIT); |
1105 | PM3_SLOW_WRITE_REG(PM3ByAperture2Mode, | 472 | PM3_WRITE_REG(par, PM3ByAperture2Mode, |
1106 | PM3ByApertureMode_PIXELSIZE_16BIT); | 473 | PM3ByApertureMode_PIXELSIZE_16BIT); |
1107 | #else | 474 | #else |
1108 | PM3_SLOW_WRITE_REG(PM3ByAperture1Mode, | 475 | PM3_WRITE_REG(par, PM3ByAperture1Mode, |
1109 | PM3ByApertureMode_PIXELSIZE_16BIT | | 476 | PM3ByApertureMode_PIXELSIZE_16BIT | |
1110 | PM3ByApertureMode_BYTESWAP_BADC); | 477 | PM3ByApertureMode_BYTESWAP_BADC); |
1111 | PM3_SLOW_WRITE_REG(PM3ByAperture2Mode, | 478 | PM3_WRITE_REG(par, PM3ByAperture2Mode, |
1112 | PM3ByApertureMode_PIXELSIZE_16BIT | | 479 | PM3ByApertureMode_PIXELSIZE_16BIT | |
1113 | PM3ByApertureMode_BYTESWAP_BADC); | 480 | PM3ByApertureMode_BYTESWAP_BADC); |
1114 | #endif /* ! __BIG_ENDIAN */ | 481 | #endif /* ! __BIG_ENDIAN */ |
@@ -1116,23 +483,22 @@ static void pm3fb_write_mode(struct pm3fb_info *l_fb_info) | |||
1116 | 483 | ||
1117 | case 32: | 484 | case 32: |
1118 | #ifndef __BIG_ENDIAN | 485 | #ifndef __BIG_ENDIAN |
1119 | PM3_SLOW_WRITE_REG(PM3ByAperture1Mode, | 486 | PM3_WRITE_REG(par, PM3ByAperture1Mode, |
1120 | PM3ByApertureMode_PIXELSIZE_32BIT); | 487 | PM3ByApertureMode_PIXELSIZE_32BIT); |
1121 | PM3_SLOW_WRITE_REG(PM3ByAperture2Mode, | 488 | PM3_WRITE_REG(par, PM3ByAperture2Mode, |
1122 | PM3ByApertureMode_PIXELSIZE_32BIT); | 489 | PM3ByApertureMode_PIXELSIZE_32BIT); |
1123 | #else | 490 | #else |
1124 | PM3_SLOW_WRITE_REG(PM3ByAperture1Mode, | 491 | PM3_WRITE_REG(par, PM3ByAperture1Mode, |
1125 | PM3ByApertureMode_PIXELSIZE_32BIT | | 492 | PM3ByApertureMode_PIXELSIZE_32BIT | |
1126 | PM3ByApertureMode_BYTESWAP_DCBA); | 493 | PM3ByApertureMode_BYTESWAP_DCBA); |
1127 | PM3_SLOW_WRITE_REG(PM3ByAperture2Mode, | 494 | PM3_WRITE_REG(par, PM3ByAperture2Mode, |
1128 | PM3ByApertureMode_PIXELSIZE_32BIT | | 495 | PM3ByApertureMode_PIXELSIZE_32BIT | |
1129 | PM3ByApertureMode_BYTESWAP_DCBA); | 496 | PM3ByApertureMode_BYTESWAP_DCBA); |
1130 | #endif /* ! __BIG_ENDIAN */ | 497 | #endif /* ! __BIG_ENDIAN */ |
1131 | break; | 498 | break; |
1132 | 499 | ||
1133 | default: | 500 | default: |
1134 | DPRINTK(1, "Unsupported depth %d\n", | 501 | DPRINTK("Unsupported depth %d\n", bpp); |
1135 | l_fb_info->current_par->depth); | ||
1136 | break; | 502 | break; |
1137 | } | 503 | } |
1138 | 504 | ||
@@ -1143,95 +509,87 @@ static void pm3fb_write_mode(struct pm3fb_info *l_fb_info) | |||
1143 | * sync options in PM3RD_SyncControl. --rmk | 509 | * sync options in PM3RD_SyncControl. --rmk |
1144 | */ | 510 | */ |
1145 | { | 511 | { |
1146 | unsigned int video = l_fb_info->current_par->video; | 512 | unsigned int video = par->video; |
1147 | 513 | ||
1148 | video &= ~(PM3VideoControl_HSYNC_MASK | | 514 | video &= ~(PM3VideoControl_HSYNC_MASK | |
1149 | PM3VideoControl_VSYNC_MASK); | 515 | PM3VideoControl_VSYNC_MASK); |
1150 | video |= PM3VideoControl_HSYNC_ACTIVE_HIGH | | 516 | video |= PM3VideoControl_HSYNC_ACTIVE_HIGH | |
1151 | PM3VideoControl_VSYNC_ACTIVE_HIGH; | 517 | PM3VideoControl_VSYNC_ACTIVE_HIGH; |
1152 | PM3_SLOW_WRITE_REG(PM3VideoControl, video); | 518 | PM3_WRITE_REG(par, PM3VideoControl, video); |
1153 | } | 519 | } |
1154 | PM3_SLOW_WRITE_REG(PM3VClkCtl, | 520 | PM3_WRITE_REG(par, PM3VClkCtl, |
1155 | (PM3_READ_REG(PM3VClkCtl) & 0xFFFFFFFC)); | 521 | (PM3_READ_REG(par, PM3VClkCtl) & 0xFFFFFFFC)); |
1156 | PM3_SLOW_WRITE_REG(PM3ScreenBase, l_fb_info->current_par->base); | 522 | PM3_WRITE_REG(par, PM3ScreenBase, par->base); |
1157 | PM3_SLOW_WRITE_REG(PM3ChipConfig, | 523 | PM3_WRITE_REG(par, PM3ChipConfig, |
1158 | (PM3_READ_REG(PM3ChipConfig) & 0xFFFFFFFD)); | 524 | (PM3_READ_REG(par, PM3ChipConfig) & 0xFFFFFFFD)); |
1159 | 525 | ||
526 | wmb(); | ||
1160 | { | 527 | { |
1161 | unsigned char m; /* ClkPreScale */ | 528 | unsigned char uninitialized_var(m); /* ClkPreScale */ |
1162 | unsigned char n; /* ClkFeedBackScale */ | 529 | unsigned char uninitialized_var(n); /* ClkFeedBackScale */ |
1163 | unsigned char p; /* ClkPostScale */ | 530 | unsigned char uninitialized_var(p); /* ClkPostScale */ |
1164 | (void)pm3fb_CalculateClock(l_fb_info, l_fb_info->current_par->pixclock, PM3_REF_CLOCK, &m, &n, &p); | 531 | unsigned long pixclock = PICOS2KHZ(info->var.pixclock); |
1165 | 532 | ||
1166 | DPRINTK(2, | 533 | (void)pm3fb_calculate_clock(pixclock, &m, &n, &p); |
1167 | "Pixclock: %d, Pre: %d, Feedback: %d, Post: %d\n", | 534 | |
1168 | l_fb_info->current_par->pixclock, (int) m, (int) n, | 535 | DPRINTK("Pixclock: %ld, Pre: %d, Feedback: %d, Post: %d\n", |
1169 | (int) p); | 536 | pixclock, (int) m, (int) n, (int) p); |
1170 | 537 | ||
1171 | PM3_WRITE_DAC_REG(PM3RD_DClk0PreScale, m); | 538 | PM3_WRITE_DAC_REG(par, PM3RD_DClk0PreScale, m); |
1172 | PM3_WRITE_DAC_REG(PM3RD_DClk0FeedbackScale, n); | 539 | PM3_WRITE_DAC_REG(par, PM3RD_DClk0FeedbackScale, n); |
1173 | PM3_WRITE_DAC_REG(PM3RD_DClk0PostScale, p); | 540 | PM3_WRITE_DAC_REG(par, PM3RD_DClk0PostScale, p); |
1174 | } | 541 | } |
1175 | /* | 542 | /* |
1176 | PM3_WRITE_DAC_REG(PM3RD_IndexControl, 0x00); | 543 | PM3_WRITE_DAC_REG(par, PM3RD_IndexControl, 0x00); |
1177 | */ | 544 | */ |
1178 | /* | 545 | /* |
1179 | PM3_SLOW_WRITE_REG(PM3RD_IndexControl, 0x00); | 546 | PM3_SLOW_WRITE_REG(par, PM3RD_IndexControl, 0x00); |
1180 | */ | 547 | */ |
1181 | if ((l_fb_info->current_par->video & PM3VideoControl_HSYNC_MASK) == | 548 | if ((par->video & PM3VideoControl_HSYNC_MASK) == |
1182 | PM3VideoControl_HSYNC_ACTIVE_HIGH) | 549 | PM3VideoControl_HSYNC_ACTIVE_HIGH) |
1183 | tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH; | 550 | tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH; |
1184 | if ((l_fb_info->current_par->video & PM3VideoControl_VSYNC_MASK) == | 551 | if ((par->video & PM3VideoControl_VSYNC_MASK) == |
1185 | PM3VideoControl_VSYNC_ACTIVE_HIGH) | 552 | PM3VideoControl_VSYNC_ACTIVE_HIGH) |
1186 | tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH; | 553 | tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH; |
1187 | |||
1188 | PM3_WRITE_DAC_REG(PM3RD_SyncControl, tempsync); | ||
1189 | DPRINTK(2, "PM3RD_SyncControl: %d\n", tempsync); | ||
1190 | |||
1191 | if (flatpanel[l_fb_info->board_num]) | ||
1192 | { | ||
1193 | PM3_WRITE_DAC_REG(PM3RD_DACControl, PM3RD_DACControl_BLANK_PEDESTAL_ENABLE); | ||
1194 | PM3_WAIT(2); | ||
1195 | PM3_WRITE_REG(PM3VSConfiguration, 0x06); | ||
1196 | PM3_WRITE_REG(0x5a00, 1 << 14); /* black magic... */ | ||
1197 | tempmisc = PM3RD_MiscControl_VSB_OUTPUT_ENABLE; | ||
1198 | } | ||
1199 | else | ||
1200 | PM3_WRITE_DAC_REG(PM3RD_DACControl, 0x00); | ||
1201 | 554 | ||
1202 | switch (l_fb_info->current_par->depth) { | 555 | PM3_WRITE_DAC_REG(par, PM3RD_SyncControl, tempsync); |
556 | DPRINTK("PM3RD_SyncControl: %d\n", tempsync); | ||
557 | |||
558 | PM3_WRITE_DAC_REG(par, PM3RD_DACControl, 0x00); | ||
559 | |||
560 | switch (pm3fb_depth(&info->var)) { | ||
1203 | case 8: | 561 | case 8: |
1204 | PM3_WRITE_DAC_REG(PM3RD_PixelSize, | 562 | PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, |
1205 | PM3RD_PixelSize_8_BIT_PIXELS); | 563 | PM3RD_PixelSize_8_BIT_PIXELS); |
1206 | PM3_WRITE_DAC_REG(PM3RD_ColorFormat, | 564 | PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, |
1207 | PM3RD_ColorFormat_CI8_COLOR | | 565 | PM3RD_ColorFormat_CI8_COLOR | |
1208 | PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW); | 566 | PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW); |
1209 | tempmisc |= PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; | 567 | tempmisc |= PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; |
1210 | break; | 568 | break; |
1211 | case 12: | 569 | case 12: |
1212 | PM3_WRITE_DAC_REG(PM3RD_PixelSize, | 570 | PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, |
1213 | PM3RD_PixelSize_16_BIT_PIXELS); | 571 | PM3RD_PixelSize_16_BIT_PIXELS); |
1214 | PM3_WRITE_DAC_REG(PM3RD_ColorFormat, | 572 | PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, |
1215 | PM3RD_ColorFormat_4444_COLOR | | 573 | PM3RD_ColorFormat_4444_COLOR | |
1216 | PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | | 574 | PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | |
1217 | PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); | 575 | PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); |
1218 | tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | | 576 | tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | |
1219 | PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; | 577 | PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; |
1220 | break; | 578 | break; |
1221 | case 15: | 579 | case 15: |
1222 | PM3_WRITE_DAC_REG(PM3RD_PixelSize, | 580 | PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, |
1223 | PM3RD_PixelSize_16_BIT_PIXELS); | 581 | PM3RD_PixelSize_16_BIT_PIXELS); |
1224 | PM3_WRITE_DAC_REG(PM3RD_ColorFormat, | 582 | PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, |
1225 | PM3RD_ColorFormat_5551_FRONT_COLOR | | 583 | PM3RD_ColorFormat_5551_FRONT_COLOR | |
1226 | PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | | 584 | PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | |
1227 | PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); | 585 | PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); |
1228 | tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | | 586 | tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | |
1229 | PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; | 587 | PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; |
1230 | break; | 588 | break; |
1231 | case 16: | 589 | case 16: |
1232 | PM3_WRITE_DAC_REG(PM3RD_PixelSize, | 590 | PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, |
1233 | PM3RD_PixelSize_16_BIT_PIXELS); | 591 | PM3RD_PixelSize_16_BIT_PIXELS); |
1234 | PM3_WRITE_DAC_REG(PM3RD_ColorFormat, | 592 | PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, |
1235 | PM3RD_ColorFormat_565_FRONT_COLOR | | 593 | PM3RD_ColorFormat_565_FRONT_COLOR | |
1236 | PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | | 594 | PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | |
1237 | PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); | 595 | PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); |
@@ -1239,1936 +597,263 @@ static void pm3fb_write_mode(struct pm3fb_info *l_fb_info) | |||
1239 | PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; | 597 | PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; |
1240 | break; | 598 | break; |
1241 | case 32: | 599 | case 32: |
1242 | PM3_WRITE_DAC_REG(PM3RD_PixelSize, | 600 | PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, |
1243 | PM3RD_PixelSize_32_BIT_PIXELS); | 601 | PM3RD_PixelSize_32_BIT_PIXELS); |
1244 | PM3_WRITE_DAC_REG(PM3RD_ColorFormat, | 602 | PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, |
1245 | PM3RD_ColorFormat_8888_COLOR | | 603 | PM3RD_ColorFormat_8888_COLOR | |
1246 | PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW); | 604 | PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW); |
1247 | tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | | 605 | tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | |
1248 | PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; | 606 | PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; |
1249 | break; | 607 | break; |
1250 | } | 608 | } |
1251 | PM3_WRITE_DAC_REG(PM3RD_MiscControl, tempmisc); | 609 | PM3_WRITE_DAC_REG(par, PM3RD_MiscControl, tempmisc); |
1252 | |||
1253 | PM3_SHOW_CUR_MODE; | ||
1254 | } | ||
1255 | |||
1256 | static void pm3fb_read_mode(struct pm3fb_info *l_fb_info, | ||
1257 | struct pm3fb_par *curpar) | ||
1258 | { | ||
1259 | unsigned long pixsize1, pixsize2, clockused; | ||
1260 | unsigned long pre, feedback, post; | ||
1261 | |||
1262 | DTRACE; | ||
1263 | |||
1264 | clockused = PM3_READ_REG(PM3VClkCtl); | ||
1265 | |||
1266 | switch (clockused) { | ||
1267 | case 3: | ||
1268 | pre = PM3_READ_DAC_REG(PM3RD_DClk3PreScale); | ||
1269 | feedback = PM3_READ_DAC_REG(PM3RD_DClk3FeedbackScale); | ||
1270 | post = PM3_READ_DAC_REG(PM3RD_DClk3PostScale); | ||
1271 | |||
1272 | DPRINTK(2, | ||
1273 | "DClk3 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n", | ||
1274 | pre, feedback, post, PM3_SCALE_TO_CLOCK(pre, | ||
1275 | feedback, | ||
1276 | post)); | ||
1277 | break; | ||
1278 | case 2: | ||
1279 | pre = PM3_READ_DAC_REG(PM3RD_DClk2PreScale); | ||
1280 | feedback = PM3_READ_DAC_REG(PM3RD_DClk2FeedbackScale); | ||
1281 | post = PM3_READ_DAC_REG(PM3RD_DClk2PostScale); | ||
1282 | |||
1283 | DPRINTK(2, | ||
1284 | "DClk2 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n", | ||
1285 | pre, feedback, post, PM3_SCALE_TO_CLOCK(pre, | ||
1286 | feedback, | ||
1287 | post)); | ||
1288 | break; | ||
1289 | case 1: | ||
1290 | pre = PM3_READ_DAC_REG(PM3RD_DClk1PreScale); | ||
1291 | feedback = PM3_READ_DAC_REG(PM3RD_DClk1FeedbackScale); | ||
1292 | post = PM3_READ_DAC_REG(PM3RD_DClk1PostScale); | ||
1293 | |||
1294 | DPRINTK(2, | ||
1295 | "DClk1 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n", | ||
1296 | pre, feedback, post, PM3_SCALE_TO_CLOCK(pre, | ||
1297 | feedback, | ||
1298 | post)); | ||
1299 | break; | ||
1300 | case 0: | ||
1301 | pre = PM3_READ_DAC_REG(PM3RD_DClk0PreScale); | ||
1302 | feedback = PM3_READ_DAC_REG(PM3RD_DClk0FeedbackScale); | ||
1303 | post = PM3_READ_DAC_REG(PM3RD_DClk0PostScale); | ||
1304 | |||
1305 | DPRINTK(2, | ||
1306 | "DClk0 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n", | ||
1307 | pre, feedback, post, PM3_SCALE_TO_CLOCK(pre, | ||
1308 | feedback, | ||
1309 | post)); | ||
1310 | break; | ||
1311 | default: | ||
1312 | pre = feedback = post = 0; | ||
1313 | DPRINTK(1, "Unknowk D clock used : %ld\n", clockused); | ||
1314 | break; | ||
1315 | } | ||
1316 | |||
1317 | curpar->pixclock = PM3_SCALE_TO_CLOCK(pre, feedback, post); | ||
1318 | |||
1319 | pixsize1 = | ||
1320 | PM3ByApertureMode_PIXELSIZE_MASK & | ||
1321 | (PM3_READ_REG(PM3ByAperture1Mode)); | ||
1322 | pixsize2 = | ||
1323 | PM3ByApertureMode_PIXELSIZE_MASK & | ||
1324 | (PM3_READ_REG(PM3ByAperture2Mode)); | ||
1325 | |||
1326 | DASSERT((pixsize1 == pixsize2), | ||
1327 | "pixsize the same in both aperture\n"); | ||
1328 | |||
1329 | if (pixsize1 & PM3ByApertureMode_PIXELSIZE_32BIT) | ||
1330 | curpar->depth = 32; | ||
1331 | else if (pixsize1 & PM3ByApertureMode_PIXELSIZE_16BIT) | ||
1332 | { | ||
1333 | curpar->depth = 16; | ||
1334 | } | ||
1335 | else | ||
1336 | curpar->depth = 8; | ||
1337 | |||
1338 | /* not sure if I need to add one on the next ; it give better result with */ | ||
1339 | curpar->htotal = | ||
1340 | pm3fb_Unshiftbpp(l_fb_info, curpar->depth, | ||
1341 | 1 + PM3_READ_REG(PM3HTotal)); | ||
1342 | curpar->hsend = | ||
1343 | pm3fb_Unshiftbpp(l_fb_info, curpar->depth, | ||
1344 | PM3_READ_REG(PM3HsEnd)); | ||
1345 | curpar->hsstart = | ||
1346 | pm3fb_Unshiftbpp(l_fb_info, curpar->depth, | ||
1347 | PM3_READ_REG(PM3HsStart)); | ||
1348 | curpar->hbend = | ||
1349 | pm3fb_Unshiftbpp(l_fb_info, curpar->depth, | ||
1350 | PM3_READ_REG(PM3HbEnd)); | ||
1351 | |||
1352 | curpar->stride = | ||
1353 | pm3fb_Unshiftbpp(l_fb_info, curpar->depth, | ||
1354 | PM3_READ_REG(PM3ScreenStride)); | ||
1355 | |||
1356 | curpar->vtotal = 1 + PM3_READ_REG(PM3VTotal); | ||
1357 | curpar->vsend = 1 + PM3_READ_REG(PM3VsEnd); | ||
1358 | curpar->vsstart = 1 + PM3_READ_REG(PM3VsStart); | ||
1359 | curpar->vbend = PM3_READ_REG(PM3VbEnd); | ||
1360 | |||
1361 | curpar->video = PM3_READ_REG(PM3VideoControl); | ||
1362 | |||
1363 | curpar->base = PM3_READ_REG(PM3ScreenBase); | ||
1364 | curpar->width = curpar->htotal - curpar->hbend; /* make virtual == displayed resolution */ | ||
1365 | curpar->height = curpar->vtotal - curpar->vbend; | ||
1366 | |||
1367 | DPRINTK(2, "Found : %d * %d, %d Khz, stride is %08x\n", | ||
1368 | curpar->width, curpar->height, curpar->pixclock, | ||
1369 | curpar->stride); | ||
1370 | } | ||
1371 | |||
1372 | static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info) | ||
1373 | { | ||
1374 | unsigned long memsize = 0, tempBypass, i, temp1, temp2; | ||
1375 | u16 subvendor, subdevice; | ||
1376 | pm3fb_timing_result ptr; | ||
1377 | |||
1378 | DTRACE; | ||
1379 | |||
1380 | l_fb_info->fb_size = 64 * 1024 * 1024; /* pm3 aperture always 64 MB */ | ||
1381 | pm3fb_mapIO(l_fb_info); /* temporary map IO */ | ||
1382 | |||
1383 | DASSERT((l_fb_info->vIOBase != NULL), | ||
1384 | "IO successfully mapped before mem detect\n"); | ||
1385 | DASSERT((l_fb_info->v_fb != NULL), | ||
1386 | "FB successfully mapped before mem detect\n"); | ||
1387 | |||
1388 | /* card-specific stuff, *before* accessing *any* FB memory */ | ||
1389 | if ((!pci_read_config_word | ||
1390 | (l_fb_info->dev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor)) | ||
1391 | && | ||
1392 | (!pci_read_config_word | ||
1393 | (l_fb_info->dev, PCI_SUBSYSTEM_ID, &subdevice))) { | ||
1394 | i = 0; l_fb_info->board_type = 0; | ||
1395 | while ((cardbase[i].cardname[0]) && !(l_fb_info->board_type)) { | ||
1396 | if ((cardbase[i].subvendor == subvendor) && | ||
1397 | (cardbase[i].subdevice == subdevice) && | ||
1398 | (cardbase[i].func == PCI_FUNC(l_fb_info->dev->devfn))) { | ||
1399 | DPRINTK(2, "Card #%ld is an %s\n", | ||
1400 | l_fb_info->board_num, | ||
1401 | cardbase[i].cardname); | ||
1402 | if (cardbase[i].specific_setup) | ||
1403 | cardbase[i].specific_setup(l_fb_info); | ||
1404 | l_fb_info->board_type = i; | ||
1405 | } | ||
1406 | i++; | ||
1407 | } | ||
1408 | if (!l_fb_info->board_type) { | ||
1409 | DPRINTK(1, "Card #%ld is an unknown 0x%04x / 0x%04x\n", | ||
1410 | l_fb_info->board_num, subvendor, subdevice); | ||
1411 | } | ||
1412 | } else { | ||
1413 | printk(KERN_ERR "pm3fb: Error: pci_read_config_word failed, board #%ld\n", | ||
1414 | l_fb_info->board_num); | ||
1415 | } | ||
1416 | |||
1417 | if (printtimings) | ||
1418 | pm3fb_show_cur_timing(l_fb_info); | ||
1419 | |||
1420 | /* card-specific setup is done, we preserve the final | ||
1421 | memory timing for future reference */ | ||
1422 | if ((ptr = pm3fb_preserve_memory_timings(l_fb_info)) == pm3fb_timing_problem) { /* memory timings were wrong ! oops.... */ | ||
1423 | return(0); | ||
1424 | } | ||
1425 | |||
1426 | tempBypass = PM3_READ_REG(PM3MemBypassWriteMask); | ||
1427 | |||
1428 | DPRINTK(2, "PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass); | ||
1429 | |||
1430 | PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, 0xFFFFFFFF); | ||
1431 | |||
1432 | /* pm3 split up memory, replicates, and do a lot of nasty stuff IMHO ;-) */ | ||
1433 | for (i = 0; i < 32; i++) { | ||
1434 | fb_writel(i * 0x00345678, | ||
1435 | (l_fb_info->v_fb + (i * 1048576))); | ||
1436 | mb(); | ||
1437 | temp1 = fb_readl((l_fb_info->v_fb + (i * 1048576))); | ||
1438 | |||
1439 | /* Let's check for wrapover, write will fail at 16MB boundary */ | ||
1440 | if (temp1 == (i * 0x00345678)) | ||
1441 | memsize = i; | ||
1442 | else | ||
1443 | break; | ||
1444 | } | ||
1445 | |||
1446 | DPRINTK(2, "First detect pass already got %ld MB\n", memsize + 1); | ||
1447 | |||
1448 | if (memsize == i) { | ||
1449 | for (i = 0; i < 32; i++) { | ||
1450 | /* Clear first 32MB ; 0 is 0, no need to byteswap */ | ||
1451 | writel(0x0000000, | ||
1452 | (l_fb_info->v_fb + (i * 1048576))); | ||
1453 | mb(); | ||
1454 | } | ||
1455 | |||
1456 | for (i = 32; i < 64; i++) { | ||
1457 | fb_writel(i * 0x00345678, | ||
1458 | (l_fb_info->v_fb + (i * 1048576))); | ||
1459 | mb(); | ||
1460 | temp1 = | ||
1461 | fb_readl((l_fb_info->v_fb + (i * 1048576))); | ||
1462 | temp2 = | ||
1463 | fb_readl((l_fb_info->v_fb + | ||
1464 | ((i - 32) * 1048576))); | ||
1465 | if ((temp1 == (i * 0x00345678)) && (temp2 == 0)) /* different value, different RAM... */ | ||
1466 | memsize = i; | ||
1467 | else | ||
1468 | break; | ||
1469 | } | ||
1470 | } | ||
1471 | |||
1472 | DPRINTK(2, "Second detect pass got %ld MB\n", memsize + 1); | ||
1473 | |||
1474 | PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, tempBypass); | ||
1475 | |||
1476 | pm3fb_unmapIO(l_fb_info); | ||
1477 | memsize = 1048576 * (memsize + 1); | ||
1478 | |||
1479 | DPRINTK(2, "Returning 0x%08lx bytes\n", memsize); | ||
1480 | |||
1481 | if (forcesize[l_fb_info->board_num] && ((forcesize[l_fb_info->board_num] * 1048576) != memsize)) | ||
1482 | { | ||
1483 | printk(KERN_WARNING "pm3fb: mismatch between probed (%ld MB) and specified (%hd MB) memory size, using SPECIFIED !\n", memsize, forcesize[l_fb_info->board_num]); | ||
1484 | memsize = 1048576 * forcesize[l_fb_info->board_num]; | ||
1485 | } | ||
1486 | |||
1487 | l_fb_info->fb_size = memsize; | ||
1488 | |||
1489 | if (ptr == pm3fb_timing_retry) | ||
1490 | { | ||
1491 | printk(KERN_WARNING "pm3fb: retrying memory timings check"); | ||
1492 | if (pm3fb_try_memory_timings(l_fb_info) == pm3fb_timing_problem) | ||
1493 | return(0); | ||
1494 | } | ||
1495 | |||
1496 | return (memsize); | ||
1497 | } | ||
1498 | |||
1499 | static void pm3fb_clear_memory(struct pm3fb_info *l_fb_info, u32 cc) | ||
1500 | { | ||
1501 | int i; | ||
1502 | |||
1503 | DTRACE; | ||
1504 | |||
1505 | for (i = 0; i < (l_fb_info->fb_size / sizeof(u32)) ; i++) /* clear entire FB memory to black */ | ||
1506 | { | ||
1507 | fb_writel(cc, (l_fb_info->v_fb + (i * sizeof(u32)))); | ||
1508 | } | ||
1509 | } | ||
1510 | |||
1511 | static void pm3fb_clear_colormap(struct pm3fb_info *l_fb_info, unsigned char r, unsigned char g, unsigned char b) | ||
1512 | { | ||
1513 | int i; | ||
1514 | |||
1515 | DTRACE; | ||
1516 | |||
1517 | for (i = 0; i < 256 ; i++) /* fill color map with white */ | ||
1518 | pm3fb_set_color(l_fb_info, i, r, g, b); | ||
1519 | |||
1520 | } | ||
1521 | |||
1522 | /* common initialisation */ | ||
1523 | static void pm3fb_common_init(struct pm3fb_info *l_fb_info) | ||
1524 | { | ||
1525 | DTRACE; | ||
1526 | |||
1527 | DPRINTK(2, "Initializing board #%ld @ %lx\n", l_fb_info->board_num, | ||
1528 | (unsigned long) l_fb_info); | ||
1529 | |||
1530 | strcpy(l_fb_info->gen.info.modename, permedia3_name); | ||
1531 | disp[l_fb_info->board_num].scrollmode = 0; /* SCROLL_YNOMOVE; *//* 0 means "let fbcon choose" */ | ||
1532 | l_fb_info->gen.parsize = sizeof(struct pm3fb_par); | ||
1533 | l_fb_info->gen.info.changevar = NULL; | ||
1534 | l_fb_info->gen.info.fbops = &pm3fb_ops; | ||
1535 | l_fb_info->gen.info.disp = &(disp[l_fb_info->board_num]); | ||
1536 | if (fontn[l_fb_info->board_num][0]) | ||
1537 | strcpy(l_fb_info->gen.info.fontname, | ||
1538 | fontn[l_fb_info->board_num]); | ||
1539 | l_fb_info->gen.info.switch_con = &fbgen_switch; | ||
1540 | l_fb_info->gen.info.updatevar = &fbgen_update_var; /* */ | ||
1541 | l_fb_info->gen.info.flags = FBINFO_FLAG_DEFAULT; | ||
1542 | |||
1543 | pm3fb_mapIO(l_fb_info); | ||
1544 | |||
1545 | pm3fb_clear_memory(l_fb_info, 0); | ||
1546 | pm3fb_clear_colormap(l_fb_info, 0, 0, 0); | ||
1547 | |||
1548 | (void) fbgen_get_var(&(disp[l_fb_info->board_num]).var, -1, | ||
1549 | &l_fb_info->gen.info); | ||
1550 | |||
1551 | if (depth[l_fb_info->board_num]) /* override mode-defined depth */ | ||
1552 | { | ||
1553 | pm3fb_encode_depth(&(disp[l_fb_info->board_num]).var, depth[l_fb_info->board_num]); | ||
1554 | (disp[l_fb_info->board_num]).var.bits_per_pixel = depth2bpp(depth[l_fb_info->board_num]); | ||
1555 | } | ||
1556 | |||
1557 | (void) fbgen_do_set_var(&(disp[l_fb_info->board_num]).var, 1, | ||
1558 | &l_fb_info->gen); | ||
1559 | |||
1560 | fbgen_set_disp(-1, &l_fb_info->gen); | ||
1561 | |||
1562 | do_install_cmap(0, &l_fb_info->gen.info); | ||
1563 | |||
1564 | if (register_framebuffer(&l_fb_info->gen.info) < 0) { | ||
1565 | DPRINTK(1, "Couldn't register framebuffer\n"); | ||
1566 | return; | ||
1567 | } | ||
1568 | |||
1569 | PM3_WRITE_DAC_REG(PM3RD_CursorMode, | ||
1570 | PM3RD_CursorMode_CURSOR_DISABLE); | ||
1571 | |||
1572 | PM3_SHOW_CUR_MODE; | ||
1573 | |||
1574 | pm3fb_write_mode(l_fb_info); | ||
1575 | |||
1576 | printk("fb%d: %s, using %uK of video memory (%s)\n", | ||
1577 | l_fb_info->gen.info.node, | ||
1578 | permedia3_name, (u32) (l_fb_info->fb_size >> 10), | ||
1579 | cardbase[l_fb_info->board_type].cardname); | ||
1580 | } | 610 | } |
1581 | 611 | ||
1582 | /* **************************************************** */ | 612 | /* |
1583 | /* ***** accelerated permedia3-specific functions ***** */ | 613 | * hardware independent functions |
1584 | /* **************************************************** */ | 614 | */ |
1585 | #ifdef PM3FB_USE_ACCEL | 615 | static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) |
1586 | static void pm3fb_wait_pm3(struct pm3fb_info *l_fb_info) | ||
1587 | { | 616 | { |
1588 | DTRACE; | 617 | u32 lpitch; |
618 | unsigned bpp = var->red.length + var->green.length | ||
619 | + var->blue.length + var->transp.length; | ||
1589 | 620 | ||
1590 | PM3_SLOW_WRITE_REG(PM3FilterMode, PM3FilterModeSync); | 621 | if ( bpp != var->bits_per_pixel ) { |
1591 | PM3_SLOW_WRITE_REG(PM3Sync, 0); | 622 | /* set predefined mode for bits_per_pixel settings */ |
1592 | mb(); | ||
1593 | do { | ||
1594 | while ((PM3_READ_REG(PM3OutFIFOWords)) == 0); | ||
1595 | rmb(); | ||
1596 | } while ((PM3_READ_REG(PM3OutputFifo)) != PM3Sync_Tag); | ||
1597 | } | ||
1598 | 623 | ||
1599 | static void pm3fb_init_engine(struct pm3fb_info *l_fb_info) | 624 | switch(var->bits_per_pixel) { |
1600 | { | ||
1601 | PM3_SLOW_WRITE_REG(PM3FilterMode, PM3FilterModeSync); | ||
1602 | PM3_SLOW_WRITE_REG(PM3StatisticMode, 0x0); | ||
1603 | PM3_SLOW_WRITE_REG(PM3DeltaMode, 0x0); | ||
1604 | PM3_SLOW_WRITE_REG(PM3RasterizerMode, 0x0); | ||
1605 | PM3_SLOW_WRITE_REG(PM3ScissorMode, 0x0); | ||
1606 | PM3_SLOW_WRITE_REG(PM3LineStippleMode, 0x0); | ||
1607 | PM3_SLOW_WRITE_REG(PM3AreaStippleMode, 0x0); | ||
1608 | PM3_SLOW_WRITE_REG(PM3GIDMode, 0x0); | ||
1609 | PM3_SLOW_WRITE_REG(PM3DepthMode, 0x0); | ||
1610 | PM3_SLOW_WRITE_REG(PM3StencilMode, 0x0); | ||
1611 | PM3_SLOW_WRITE_REG(PM3StencilData, 0x0); | ||
1612 | PM3_SLOW_WRITE_REG(PM3ColorDDAMode, 0x0); | ||
1613 | PM3_SLOW_WRITE_REG(PM3TextureCoordMode, 0x0); | ||
1614 | PM3_SLOW_WRITE_REG(PM3TextureIndexMode0, 0x0); | ||
1615 | PM3_SLOW_WRITE_REG(PM3TextureIndexMode1, 0x0); | ||
1616 | PM3_SLOW_WRITE_REG(PM3TextureReadMode, 0x0); | ||
1617 | PM3_SLOW_WRITE_REG(PM3LUTMode, 0x0); | ||
1618 | PM3_SLOW_WRITE_REG(PM3TextureFilterMode, 0x0); | ||
1619 | PM3_SLOW_WRITE_REG(PM3TextureCompositeMode, 0x0); | ||
1620 | PM3_SLOW_WRITE_REG(PM3TextureApplicationMode, 0x0); | ||
1621 | PM3_SLOW_WRITE_REG(PM3TextureCompositeColorMode1, 0x0); | ||
1622 | PM3_SLOW_WRITE_REG(PM3TextureCompositeAlphaMode1, 0x0); | ||
1623 | PM3_SLOW_WRITE_REG(PM3TextureCompositeColorMode0, 0x0); | ||
1624 | PM3_SLOW_WRITE_REG(PM3TextureCompositeAlphaMode0, 0x0); | ||
1625 | PM3_SLOW_WRITE_REG(PM3FogMode, 0x0); | ||
1626 | PM3_SLOW_WRITE_REG(PM3ChromaTestMode, 0x0); | ||
1627 | PM3_SLOW_WRITE_REG(PM3AlphaTestMode, 0x0); | ||
1628 | PM3_SLOW_WRITE_REG(PM3AntialiasMode, 0x0); | ||
1629 | PM3_SLOW_WRITE_REG(PM3YUVMode, 0x0); | ||
1630 | PM3_SLOW_WRITE_REG(PM3AlphaBlendColorMode, 0x0); | ||
1631 | PM3_SLOW_WRITE_REG(PM3AlphaBlendAlphaMode, 0x0); | ||
1632 | PM3_SLOW_WRITE_REG(PM3DitherMode, 0x0); | ||
1633 | PM3_SLOW_WRITE_REG(PM3LogicalOpMode, 0x0); | ||
1634 | PM3_SLOW_WRITE_REG(PM3RouterMode, 0x0); | ||
1635 | PM3_SLOW_WRITE_REG(PM3Window, 0x0); | ||
1636 | |||
1637 | PM3_SLOW_WRITE_REG(PM3Config2D, 0x0); | ||
1638 | |||
1639 | PM3_SLOW_WRITE_REG(PM3SpanColorMask, 0xffffffff); | ||
1640 | |||
1641 | PM3_SLOW_WRITE_REG(PM3XBias, 0x0); | ||
1642 | PM3_SLOW_WRITE_REG(PM3YBias, 0x0); | ||
1643 | PM3_SLOW_WRITE_REG(PM3DeltaControl, 0x0); | ||
1644 | |||
1645 | PM3_SLOW_WRITE_REG(PM3BitMaskPattern, 0xffffffff); | ||
1646 | |||
1647 | PM3_SLOW_WRITE_REG(PM3FBDestReadEnables, | ||
1648 | PM3FBDestReadEnables_E(0xff) | | ||
1649 | PM3FBDestReadEnables_R(0xff) | | ||
1650 | PM3FBDestReadEnables_ReferenceAlpha(0xff)); | ||
1651 | PM3_SLOW_WRITE_REG(PM3FBDestReadBufferAddr0, 0x0); | ||
1652 | PM3_SLOW_WRITE_REG(PM3FBDestReadBufferOffset0, 0x0); | ||
1653 | PM3_SLOW_WRITE_REG(PM3FBDestReadBufferWidth0, | ||
1654 | PM3FBDestReadBufferWidth_Width(l_fb_info-> | ||
1655 | current_par-> | ||
1656 | width)); | ||
1657 | |||
1658 | PM3_SLOW_WRITE_REG(PM3FBDestReadMode, | ||
1659 | PM3FBDestReadMode_ReadEnable | | ||
1660 | PM3FBDestReadMode_Enable0); | ||
1661 | PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferAddr, 0x0); | ||
1662 | PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferOffset, 0x0); | ||
1663 | PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferWidth, | ||
1664 | PM3FBSourceReadBufferWidth_Width(l_fb_info-> | ||
1665 | current_par-> | ||
1666 | width)); | ||
1667 | PM3_SLOW_WRITE_REG(PM3FBSourceReadMode, | ||
1668 | PM3FBSourceReadMode_Blocking | | ||
1669 | PM3FBSourceReadMode_ReadEnable); | ||
1670 | |||
1671 | { | ||
1672 | unsigned long rm = 1; | ||
1673 | switch (l_fb_info->current_par->depth) { | ||
1674 | case 8: | 625 | case 8: |
1675 | PM3_SLOW_WRITE_REG(PM3PixelSize, | 626 | var->red.length = var->green.length = var->blue.length = 8; |
1676 | PM3PixelSize_GLOBAL_8BIT); | 627 | var->red.offset = var->green.offset = var->blue.offset = 0; |
628 | var->transp.offset = 0; | ||
629 | var->transp.length = 0; | ||
1677 | break; | 630 | break; |
1678 | case 12: | ||
1679 | case 15: | ||
1680 | case 16: | 631 | case 16: |
1681 | PM3_SLOW_WRITE_REG(PM3PixelSize, | 632 | var->red.length = var->blue.length = 5; |
1682 | PM3PixelSize_GLOBAL_16BIT); | 633 | var->green.length = 6; |
634 | var->transp.length = 0; | ||
1683 | break; | 635 | break; |
1684 | case 32: | 636 | case 32: |
1685 | PM3_SLOW_WRITE_REG(PM3PixelSize, | 637 | var->red.length = var->green.length = var->blue.length = 8; |
1686 | PM3PixelSize_GLOBAL_32BIT); | 638 | var->transp.length = 8; |
1687 | break; | 639 | break; |
1688 | default: | 640 | default: |
1689 | DPRINTK(1, "Unsupported depth %d\n", | 641 | DPRINTK("depth not supported: %u\n", var->bits_per_pixel); |
1690 | l_fb_info->current_par->depth); | 642 | return -EINVAL; |
1691 | break; | ||
1692 | } | 643 | } |
1693 | PM3_SLOW_WRITE_REG(PM3RasterizerMode, rm); | ||
1694 | } | 644 | } |
1695 | 645 | /* it is assumed BGRA order */ | |
1696 | PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xffffffff); | 646 | if (var->bits_per_pixel > 8 ) |
1697 | PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xffffffff); | ||
1698 | PM3_SLOW_WRITE_REG(PM3FBWriteMode, | ||
1699 | PM3FBWriteMode_WriteEnable | | ||
1700 | PM3FBWriteMode_OpaqueSpan | | ||
1701 | PM3FBWriteMode_Enable0); | ||
1702 | PM3_SLOW_WRITE_REG(PM3FBWriteBufferAddr0, 0x0); | ||
1703 | PM3_SLOW_WRITE_REG(PM3FBWriteBufferOffset0, 0x0); | ||
1704 | PM3_SLOW_WRITE_REG(PM3FBWriteBufferWidth0, | ||
1705 | PM3FBWriteBufferWidth_Width(l_fb_info-> | ||
1706 | current_par-> | ||
1707 | width)); | ||
1708 | |||
1709 | PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, 0x0); | ||
1710 | { | 647 | { |
1711 | unsigned long sofb = (8UL * l_fb_info->fb_size) / | 648 | var->blue.offset = 0; |
1712 | ((depth2bpp(l_fb_info->current_par->depth)) | 649 | var->green.offset = var->blue.length; |
1713 | * l_fb_info->current_par->width); /* size in lines of FB */ | 650 | var->red.offset = var->green.offset + var->green.length; |
1714 | if (sofb > 4095) | 651 | var->transp.offset = var->red.offset + var->red.length; |
1715 | PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, 4095); | ||
1716 | else | ||
1717 | PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, sofb); | ||
1718 | |||
1719 | switch (l_fb_info->current_par->depth) { | ||
1720 | case 8: | ||
1721 | PM3_SLOW_WRITE_REG(PM3DitherMode, | ||
1722 | (1 << 10) | (2 << 3)); | ||
1723 | break; | ||
1724 | case 12: | ||
1725 | case 15: | ||
1726 | case 16: | ||
1727 | PM3_SLOW_WRITE_REG(PM3DitherMode, | ||
1728 | (1 << 10) | (1 << 3)); | ||
1729 | break; | ||
1730 | case 32: | ||
1731 | PM3_SLOW_WRITE_REG(PM3DitherMode, | ||
1732 | (1 << 10) | (0 << 3)); | ||
1733 | break; | ||
1734 | default: | ||
1735 | DPRINTK(1, "Unsupported depth %d\n", | ||
1736 | l_fb_info->current_par->depth); | ||
1737 | break; | ||
1738 | } | ||
1739 | } | ||
1740 | |||
1741 | PM3_SLOW_WRITE_REG(PM3dXDom, 0x0); | ||
1742 | PM3_SLOW_WRITE_REG(PM3dXSub, 0x0); | ||
1743 | PM3_SLOW_WRITE_REG(PM3dY, (1 << 16)); | ||
1744 | PM3_SLOW_WRITE_REG(PM3StartXDom, 0x0); | ||
1745 | PM3_SLOW_WRITE_REG(PM3StartXSub, 0x0); | ||
1746 | PM3_SLOW_WRITE_REG(PM3StartY, 0x0); | ||
1747 | PM3_SLOW_WRITE_REG(PM3Count, 0x0); | ||
1748 | |||
1749 | /* Disable LocalBuffer. better safe than sorry */ | ||
1750 | PM3_SLOW_WRITE_REG(PM3LBDestReadMode, 0x0); | ||
1751 | PM3_SLOW_WRITE_REG(PM3LBDestReadEnables, 0x0); | ||
1752 | PM3_SLOW_WRITE_REG(PM3LBSourceReadMode, 0x0); | ||
1753 | PM3_SLOW_WRITE_REG(PM3LBWriteMode, 0x0); | ||
1754 | |||
1755 | pm3fb_wait_pm3(l_fb_info); | ||
1756 | } | ||
1757 | |||
1758 | #ifdef FBCON_HAS_CFB32 | ||
1759 | static void pm3fb_cfb32_clear(struct vc_data *conp, | ||
1760 | struct display *p, | ||
1761 | int sy, int sx, int height, int width) | ||
1762 | { | ||
1763 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; | ||
1764 | u32 c; | ||
1765 | |||
1766 | DTRACE; | ||
1767 | |||
1768 | sx = sx * fontwidth(p); | ||
1769 | width = width * fontwidth(p); | ||
1770 | sy = sy * fontheight(p); | ||
1771 | height = height * fontheight(p); | ||
1772 | c = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)]; | ||
1773 | |||
1774 | /* block fills in 32bpp are hard, but in low res (width <= 1600 :-) | ||
1775 | we can use 16bpp operations, but not if NoWriteMask is on (SDRAM) */ | ||
1776 | if ((l_fb_info->current_par->width > 1600) || | ||
1777 | (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)) { | ||
1778 | PM3_WAIT(4); | ||
1779 | |||
1780 | PM3_WRITE_REG(PM3Config2D, | ||
1781 | PM3Config2D_UseConstantSource | | ||
1782 | PM3Config2D_ForegroundROPEnable | | ||
1783 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
1784 | PM3Config2D_FBWriteEnable); | ||
1785 | |||
1786 | PM3_WRITE_REG(PM3ForegroundColor, c); | ||
1787 | |||
1788 | PM3_WRITE_REG(PM3RectanglePosition, | ||
1789 | (PM3RectanglePosition_XOffset(sx)) | | ||
1790 | (PM3RectanglePosition_YOffset(sy))); | ||
1791 | |||
1792 | PM3_WRITE_REG(PM3Render2D, | ||
1793 | PM3Render2D_XPositive | | ||
1794 | PM3Render2D_YPositive | | ||
1795 | PM3Render2D_Operation_Normal | | ||
1796 | PM3Render2D_SpanOperation | | ||
1797 | (PM3Render2D_Width(width)) | | ||
1798 | (PM3Render2D_Height(height))); | ||
1799 | } else { | ||
1800 | PM3_WAIT(8); | ||
1801 | |||
1802 | PM3_WRITE_REG(PM3FBBlockColor, c); | ||
1803 | |||
1804 | PM3_WRITE_REG(PM3PixelSize, PM3PixelSize_GLOBAL_16BIT); | ||
1805 | |||
1806 | PM3_WRITE_REG(PM3FBWriteBufferWidth0, | ||
1807 | PM3FBWriteBufferWidth_Width(l_fb_info-> | ||
1808 | current_par-> | ||
1809 | width << 1)); | ||
1810 | |||
1811 | PM3_WRITE_REG(PM3Config2D, | ||
1812 | PM3Config2D_UseConstantSource | | ||
1813 | PM3Config2D_ForegroundROPEnable | | ||
1814 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
1815 | PM3Config2D_FBWriteEnable); | ||
1816 | |||
1817 | PM3_WRITE_REG(PM3RectanglePosition, | ||
1818 | (PM3RectanglePosition_XOffset(sx << 1)) | | ||
1819 | (PM3RectanglePosition_YOffset(sy))); | ||
1820 | |||
1821 | PM3_WRITE_REG(PM3Render2D, | ||
1822 | PM3Render2D_XPositive | | ||
1823 | PM3Render2D_YPositive | | ||
1824 | PM3Render2D_Operation_Normal | | ||
1825 | (PM3Render2D_Width(width << 1)) | | ||
1826 | (PM3Render2D_Height(height))); | ||
1827 | |||
1828 | PM3_WRITE_REG(PM3FBWriteBufferWidth0, | ||
1829 | PM3FBWriteBufferWidth_Width(l_fb_info-> | ||
1830 | current_par-> | ||
1831 | width)); | ||
1832 | |||
1833 | PM3_WRITE_REG(PM3PixelSize, PM3PixelSize_GLOBAL_32BIT); | ||
1834 | } | ||
1835 | |||
1836 | pm3fb_wait_pm3(l_fb_info); | ||
1837 | } | ||
1838 | |||
1839 | static void pm3fb_cfb32_clear_margins(struct vc_data *conp, | ||
1840 | struct display *p, int bottom_only) | ||
1841 | { | ||
1842 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; | ||
1843 | int sx, sy; | ||
1844 | u32 c; | ||
1845 | |||
1846 | DTRACE; | ||
1847 | |||
1848 | sx = conp->vc_cols * fontwidth(p); /* right margin */ | ||
1849 | sy = conp->vc_rows * fontheight(p); /* bottom margin */ | ||
1850 | c = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)]; | ||
1851 | |||
1852 | if (!bottom_only) { /* right margin top->bottom */ | ||
1853 | PM3_WAIT(4); | ||
1854 | |||
1855 | PM3_WRITE_REG(PM3Config2D, | ||
1856 | PM3Config2D_UseConstantSource | | ||
1857 | PM3Config2D_ForegroundROPEnable | | ||
1858 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
1859 | PM3Config2D_FBWriteEnable); | ||
1860 | |||
1861 | PM3_WRITE_REG(PM3ForegroundColor, c); | ||
1862 | |||
1863 | PM3_WRITE_REG(PM3RectanglePosition, | ||
1864 | (PM3RectanglePosition_XOffset | ||
1865 | (p->var.xoffset + | ||
1866 | sx)) | (PM3RectanglePosition_YOffset(p-> | ||
1867 | var. | ||
1868 | yoffset))); | ||
1869 | |||
1870 | PM3_WRITE_REG(PM3Render2D, | ||
1871 | PM3Render2D_XPositive | | ||
1872 | PM3Render2D_YPositive | | ||
1873 | PM3Render2D_Operation_Normal | | ||
1874 | PM3Render2D_SpanOperation | | ||
1875 | (PM3Render2D_Width(p->var.xres - sx)) | | ||
1876 | (PM3Render2D_Height(p->var.yres))); | ||
1877 | } | ||
1878 | |||
1879 | /* bottom margin left -> right */ | ||
1880 | PM3_WAIT(4); | ||
1881 | |||
1882 | PM3_WRITE_REG(PM3Config2D, | ||
1883 | PM3Config2D_UseConstantSource | | ||
1884 | PM3Config2D_ForegroundROPEnable | | ||
1885 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
1886 | PM3Config2D_FBWriteEnable); | ||
1887 | |||
1888 | PM3_WRITE_REG(PM3ForegroundColor, c); | ||
1889 | |||
1890 | PM3_WRITE_REG(PM3RectanglePosition, | ||
1891 | (PM3RectanglePosition_XOffset(p->var.xoffset)) | | ||
1892 | (PM3RectanglePosition_YOffset(p->var.yoffset + sy))); | ||
1893 | |||
1894 | PM3_WRITE_REG(PM3Render2D, | ||
1895 | PM3Render2D_XPositive | | ||
1896 | PM3Render2D_YPositive | | ||
1897 | PM3Render2D_Operation_Normal | | ||
1898 | PM3Render2D_SpanOperation | | ||
1899 | (PM3Render2D_Width(p->var.xres)) | | ||
1900 | (PM3Render2D_Height(p->var.yres - sy))); | ||
1901 | |||
1902 | pm3fb_wait_pm3(l_fb_info); | ||
1903 | } | ||
1904 | #endif /* FBCON_HAS_CFB32 */ | ||
1905 | #ifdef FBCON_HAS_CFB16 | ||
1906 | static void pm3fb_cfb16_clear(struct vc_data *conp, | ||
1907 | struct display *p, | ||
1908 | int sy, int sx, int height, int width) | ||
1909 | { | ||
1910 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; | ||
1911 | u32 c; | ||
1912 | |||
1913 | DTRACE; | ||
1914 | |||
1915 | sx = sx * fontwidth(p); | ||
1916 | width = width * fontwidth(p); | ||
1917 | sy = sy * fontheight(p); | ||
1918 | height = height * fontheight(p); | ||
1919 | c = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)]; | ||
1920 | c = c | (c << 16); | ||
1921 | |||
1922 | PM3_WAIT(4); | ||
1923 | |||
1924 | if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) | ||
1925 | PM3_WRITE_REG(PM3ForegroundColor, c); | ||
1926 | else | ||
1927 | PM3_WRITE_REG(PM3FBBlockColor, c); | ||
1928 | |||
1929 | PM3_WRITE_REG(PM3Config2D, | ||
1930 | PM3Config2D_UseConstantSource | | ||
1931 | PM3Config2D_ForegroundROPEnable | | ||
1932 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
1933 | PM3Config2D_FBWriteEnable); | ||
1934 | |||
1935 | PM3_WRITE_REG(PM3RectanglePosition, | ||
1936 | (PM3RectanglePosition_XOffset(sx)) | | ||
1937 | (PM3RectanglePosition_YOffset(sy))); | ||
1938 | |||
1939 | if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) | ||
1940 | PM3_WRITE_REG(PM3Render2D, | ||
1941 | PM3Render2D_XPositive | | ||
1942 | PM3Render2D_YPositive | | ||
1943 | PM3Render2D_Operation_Normal | | ||
1944 | PM3Render2D_SpanOperation | | ||
1945 | (PM3Render2D_Width(width)) | | ||
1946 | (PM3Render2D_Height(height))); | ||
1947 | else | ||
1948 | PM3_WRITE_REG(PM3Render2D, | ||
1949 | PM3Render2D_XPositive | | ||
1950 | PM3Render2D_YPositive | | ||
1951 | PM3Render2D_Operation_Normal | | ||
1952 | (PM3Render2D_Width(width)) | | ||
1953 | (PM3Render2D_Height(height))); | ||
1954 | |||
1955 | pm3fb_wait_pm3(l_fb_info); | ||
1956 | } | ||
1957 | |||
1958 | static void pm3fb_cfb16_clear_margins(struct vc_data *conp, | ||
1959 | struct display *p, int bottom_only) | ||
1960 | { | ||
1961 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; | ||
1962 | int sx, sy; | ||
1963 | u32 c; | ||
1964 | |||
1965 | DTRACE; | ||
1966 | |||
1967 | sx = conp->vc_cols * fontwidth(p); /* right margin */ | ||
1968 | sy = conp->vc_rows * fontheight(p); /* bottom margin */ | ||
1969 | c = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)]; | ||
1970 | c = c | (c << 16); | ||
1971 | |||
1972 | if (!bottom_only) { /* right margin top->bottom */ | ||
1973 | PM3_WAIT(4); | ||
1974 | |||
1975 | PM3_WRITE_REG(PM3Config2D, | ||
1976 | PM3Config2D_UseConstantSource | | ||
1977 | PM3Config2D_ForegroundROPEnable | | ||
1978 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
1979 | PM3Config2D_FBWriteEnable); | ||
1980 | |||
1981 | if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) | ||
1982 | PM3_WRITE_REG(PM3ForegroundColor, c); | ||
1983 | else | ||
1984 | PM3_WRITE_REG(PM3FBBlockColor, c); | ||
1985 | |||
1986 | PM3_WRITE_REG(PM3RectanglePosition, | ||
1987 | (PM3RectanglePosition_XOffset | ||
1988 | (p->var.xoffset + | ||
1989 | sx)) | (PM3RectanglePosition_YOffset(p-> | ||
1990 | var. | ||
1991 | yoffset))); | ||
1992 | if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) | ||
1993 | PM3_WRITE_REG(PM3Render2D, | ||
1994 | PM3Render2D_XPositive | | ||
1995 | PM3Render2D_YPositive | | ||
1996 | PM3Render2D_Operation_Normal | | ||
1997 | PM3Render2D_SpanOperation | | ||
1998 | (PM3Render2D_Width(p->var.xres - sx)) | | ||
1999 | (PM3Render2D_Height(p->var.yres))); | ||
2000 | else | ||
2001 | PM3_WRITE_REG(PM3Render2D, | ||
2002 | PM3Render2D_XPositive | | ||
2003 | PM3Render2D_YPositive | | ||
2004 | PM3Render2D_Operation_Normal | | ||
2005 | (PM3Render2D_Width(p->var.xres - sx)) | | ||
2006 | (PM3Render2D_Height(p->var.yres))); | ||
2007 | } | ||
2008 | |||
2009 | /* bottom margin left -> right */ | ||
2010 | PM3_WAIT(4); | ||
2011 | |||
2012 | PM3_WRITE_REG(PM3Config2D, | ||
2013 | PM3Config2D_UseConstantSource | | ||
2014 | PM3Config2D_ForegroundROPEnable | | ||
2015 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
2016 | PM3Config2D_FBWriteEnable); | ||
2017 | |||
2018 | if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) | ||
2019 | PM3_WRITE_REG(PM3ForegroundColor, c); | ||
2020 | else | ||
2021 | PM3_WRITE_REG(PM3FBBlockColor, c); | ||
2022 | |||
2023 | |||
2024 | PM3_WRITE_REG(PM3RectanglePosition, | ||
2025 | (PM3RectanglePosition_XOffset(p->var.xoffset)) | | ||
2026 | (PM3RectanglePosition_YOffset(p->var.yoffset + sy))); | ||
2027 | |||
2028 | if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) | ||
2029 | PM3_WRITE_REG(PM3Render2D, | ||
2030 | PM3Render2D_XPositive | | ||
2031 | PM3Render2D_YPositive | | ||
2032 | PM3Render2D_Operation_Normal | | ||
2033 | PM3Render2D_SpanOperation | | ||
2034 | (PM3Render2D_Width(p->var.xres)) | | ||
2035 | (PM3Render2D_Height(p->var.yres - sy))); | ||
2036 | else | ||
2037 | PM3_WRITE_REG(PM3Render2D, | ||
2038 | PM3Render2D_XPositive | | ||
2039 | PM3Render2D_YPositive | | ||
2040 | PM3Render2D_Operation_Normal | | ||
2041 | (PM3Render2D_Width(p->var.xres)) | | ||
2042 | (PM3Render2D_Height(p->var.yres - sy))); | ||
2043 | |||
2044 | pm3fb_wait_pm3(l_fb_info); | ||
2045 | } | ||
2046 | #endif /* FBCON_HAS_CFB16 */ | ||
2047 | #ifdef FBCON_HAS_CFB8 | ||
2048 | static void pm3fb_cfb8_clear(struct vc_data *conp, | ||
2049 | struct display *p, | ||
2050 | int sy, int sx, int height, int width) | ||
2051 | { | ||
2052 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; | ||
2053 | u32 c; | ||
2054 | |||
2055 | DTRACE; | ||
2056 | |||
2057 | sx = sx * fontwidth(p); | ||
2058 | width = width * fontwidth(p); | ||
2059 | sy = sy * fontheight(p); | ||
2060 | height = height * fontheight(p); | ||
2061 | |||
2062 | c = attr_bgcol_ec(p, conp); | ||
2063 | c |= c << 8; | ||
2064 | c |= c << 16; | ||
2065 | |||
2066 | PM3_WAIT(4); | ||
2067 | |||
2068 | PM3_WRITE_REG(PM3Config2D, | ||
2069 | PM3Config2D_UseConstantSource | | ||
2070 | PM3Config2D_ForegroundROPEnable | | ||
2071 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
2072 | PM3Config2D_FBWriteEnable); | ||
2073 | |||
2074 | PM3_WRITE_REG(PM3ForegroundColor, c); | ||
2075 | |||
2076 | PM3_WRITE_REG(PM3RectanglePosition, | ||
2077 | (PM3RectanglePosition_XOffset(sx)) | | ||
2078 | (PM3RectanglePosition_YOffset(sy))); | ||
2079 | |||
2080 | PM3_WRITE_REG(PM3Render2D, | ||
2081 | PM3Render2D_XPositive | | ||
2082 | PM3Render2D_YPositive | | ||
2083 | PM3Render2D_Operation_Normal | | ||
2084 | PM3Render2D_SpanOperation | | ||
2085 | (PM3Render2D_Width(width)) | | ||
2086 | (PM3Render2D_Height(height))); | ||
2087 | |||
2088 | pm3fb_wait_pm3(l_fb_info); | ||
2089 | } | ||
2090 | |||
2091 | static void pm3fb_cfb8_clear_margins(struct vc_data *conp, | ||
2092 | struct display *p, int bottom_only) | ||
2093 | { | ||
2094 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; | ||
2095 | int sx, sy; | ||
2096 | u32 c; | ||
2097 | |||
2098 | DTRACE; | ||
2099 | |||
2100 | sx = conp->vc_cols * fontwidth(p); /* right margin */ | ||
2101 | sy = conp->vc_rows * fontheight(p); /* bottom margin */ | ||
2102 | c = attr_bgcol_ec(p, conp); | ||
2103 | c |= c << 8; | ||
2104 | c |= c << 16; | ||
2105 | |||
2106 | if (!bottom_only) { /* right margin top->bottom */ | ||
2107 | PM3_WAIT(4); | ||
2108 | |||
2109 | PM3_WRITE_REG(PM3Config2D, | ||
2110 | PM3Config2D_UseConstantSource | | ||
2111 | PM3Config2D_ForegroundROPEnable | | ||
2112 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
2113 | PM3Config2D_FBWriteEnable); | ||
2114 | |||
2115 | PM3_WRITE_REG(PM3ForegroundColor, c); | ||
2116 | |||
2117 | PM3_WRITE_REG(PM3RectanglePosition, | ||
2118 | (PM3RectanglePosition_XOffset | ||
2119 | (p->var.xoffset + | ||
2120 | sx)) | (PM3RectanglePosition_YOffset(p-> | ||
2121 | var. | ||
2122 | yoffset))); | ||
2123 | |||
2124 | PM3_WRITE_REG(PM3Render2D, | ||
2125 | PM3Render2D_XPositive | | ||
2126 | PM3Render2D_YPositive | | ||
2127 | PM3Render2D_Operation_Normal | | ||
2128 | PM3Render2D_SpanOperation | | ||
2129 | (PM3Render2D_Width(p->var.xres - sx)) | | ||
2130 | (PM3Render2D_Height(p->var.yres))); | ||
2131 | } | ||
2132 | |||
2133 | /* bottom margin left -> right */ | ||
2134 | PM3_WAIT(4); | ||
2135 | |||
2136 | PM3_WRITE_REG(PM3Config2D, | ||
2137 | PM3Config2D_UseConstantSource | | ||
2138 | PM3Config2D_ForegroundROPEnable | | ||
2139 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
2140 | PM3Config2D_FBWriteEnable); | ||
2141 | |||
2142 | PM3_WRITE_REG(PM3ForegroundColor, c); | ||
2143 | |||
2144 | PM3_WRITE_REG(PM3RectanglePosition, | ||
2145 | (PM3RectanglePosition_XOffset(p->var.xoffset)) | | ||
2146 | (PM3RectanglePosition_YOffset(p->var.yoffset + sy))); | ||
2147 | |||
2148 | PM3_WRITE_REG(PM3Render2D, | ||
2149 | PM3Render2D_XPositive | | ||
2150 | PM3Render2D_YPositive | | ||
2151 | PM3Render2D_Operation_Normal | | ||
2152 | PM3Render2D_SpanOperation | | ||
2153 | (PM3Render2D_Width(p->var.xres)) | | ||
2154 | (PM3Render2D_Height(p->var.yres - sy))); | ||
2155 | |||
2156 | pm3fb_wait_pm3(l_fb_info); | ||
2157 | } | ||
2158 | #endif /* FBCON_HAS_CFB8 */ | ||
2159 | #if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32) | ||
2160 | static void pm3fb_cfbX_bmove(struct display *p, | ||
2161 | int sy, int sx, | ||
2162 | int dy, int dx, int height, int width) | ||
2163 | { | ||
2164 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; | ||
2165 | int x_align, o_x, o_y; | ||
2166 | |||
2167 | DTRACE; | ||
2168 | |||
2169 | sx = sx * fontwidth(p); | ||
2170 | dx = dx * fontwidth(p); | ||
2171 | width = width * fontwidth(p); | ||
2172 | sy = sy * fontheight(p); | ||
2173 | dy = dy * fontheight(p); | ||
2174 | height = height * fontheight(p); | ||
2175 | |||
2176 | o_x = sx - dx; /*(sx > dx ) ? (sx - dx) : (dx - sx); */ | ||
2177 | o_y = sy - dy; /*(sy > dy ) ? (sy - dy) : (dy - sy); */ | ||
2178 | |||
2179 | x_align = (sx & 0x1f); | ||
2180 | |||
2181 | PM3_WAIT(6); | ||
2182 | |||
2183 | PM3_WRITE_REG(PM3Config2D, | ||
2184 | PM3Config2D_UserScissorEnable | | ||
2185 | PM3Config2D_ForegroundROPEnable | | ||
2186 | PM3Config2D_Blocking | | ||
2187 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
2188 | PM3Config2D_FBWriteEnable); | ||
2189 | |||
2190 | PM3_WRITE_REG(PM3ScissorMinXY, | ||
2191 | ((dy & 0x0fff) << 16) | (dx & 0x0fff)); | ||
2192 | PM3_WRITE_REG(PM3ScissorMaxXY, | ||
2193 | (((dy + height) & 0x0fff) << 16) | | ||
2194 | ((dx + width) & 0x0fff)); | ||
2195 | |||
2196 | PM3_WRITE_REG(PM3FBSourceReadBufferOffset, | ||
2197 | PM3FBSourceReadBufferOffset_XOffset(o_x) | | ||
2198 | PM3FBSourceReadBufferOffset_YOffset(o_y)); | ||
2199 | |||
2200 | PM3_WRITE_REG(PM3RectanglePosition, | ||
2201 | (PM3RectanglePosition_XOffset(dx - x_align)) | | ||
2202 | (PM3RectanglePosition_YOffset(dy))); | ||
2203 | |||
2204 | PM3_WRITE_REG(PM3Render2D, | ||
2205 | ((sx > dx) ? PM3Render2D_XPositive : 0) | | ||
2206 | ((sy > dy) ? PM3Render2D_YPositive : 0) | | ||
2207 | PM3Render2D_Operation_Normal | | ||
2208 | PM3Render2D_SpanOperation | | ||
2209 | PM3Render2D_FBSourceReadEnable | | ||
2210 | (PM3Render2D_Width(width + x_align)) | | ||
2211 | (PM3Render2D_Height(height))); | ||
2212 | |||
2213 | pm3fb_wait_pm3(l_fb_info); | ||
2214 | } | ||
2215 | |||
2216 | static void pm3fb_cfbX_putc(struct vc_data *conp, struct display *p, | ||
2217 | int c, int yy, int xx) | ||
2218 | { | ||
2219 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; | ||
2220 | u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0; | ||
2221 | u32 fgx, bgx, ldat; | ||
2222 | int sx, sy, i; | ||
2223 | |||
2224 | DTRACE; | ||
2225 | |||
2226 | if (l_fb_info->current_par->depth == 8) | ||
2227 | fgx = attr_fgcol(p, c); | ||
2228 | else if (depth2bpp(l_fb_info->current_par->depth) == 16) | ||
2229 | fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, c)]; | ||
2230 | else | ||
2231 | fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, c)]; | ||
2232 | |||
2233 | PM3_COLOR(fgx); | ||
2234 | |||
2235 | if (l_fb_info->current_par->depth == 8) | ||
2236 | bgx = attr_bgcol(p, c); | ||
2237 | else if (depth2bpp(l_fb_info->current_par->depth) == 16) | ||
2238 | bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, c)]; | ||
2239 | else | ||
2240 | bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, c)]; | ||
2241 | |||
2242 | PM3_COLOR(bgx); | ||
2243 | |||
2244 | PM3_WAIT(4); | ||
2245 | |||
2246 | PM3_WRITE_REG(PM3Config2D, | ||
2247 | PM3Config2D_UseConstantSource | | ||
2248 | PM3Config2D_ForegroundROPEnable | | ||
2249 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
2250 | PM3Config2D_FBWriteEnable | PM3Config2D_OpaqueSpan); | ||
2251 | |||
2252 | PM3_WRITE_REG(PM3ForegroundColor, fgx); | ||
2253 | PM3_WRITE_REG(PM3FillBackgroundColor, bgx); | ||
2254 | |||
2255 | /* WARNING : address select X need to specify 8 bits for fontwidth <= 8 */ | ||
2256 | /* and 16 bits for fontwidth <= 16 */ | ||
2257 | /* same in _putcs, same for Y and fontheight */ | ||
2258 | if (fontwidth(p) <= 8) | ||
2259 | asx = 2; | ||
2260 | else if (fontwidth(p) <= 16) | ||
2261 | asx = 3; /* look OK */ | ||
2262 | if (fontheight(p) <= 8) | ||
2263 | asy = 2; | ||
2264 | else if (fontheight(p) <= 16) | ||
2265 | asy = 3; /* look OK */ | ||
2266 | else if (fontheight(p) <= 32) | ||
2267 | asy = 4; /* look OK */ | ||
2268 | |||
2269 | sx = xx * fontwidth(p); | ||
2270 | sy = yy * fontheight(p); | ||
2271 | |||
2272 | if (fontwidth(p) <= 8) | ||
2273 | o_x = (8 - (sx & 0x7)) & 0x7; | ||
2274 | else if (fontwidth(p) <= 16) | ||
2275 | o_x = (16 - (sx & 0xF)) & 0xF; | ||
2276 | if (fontheight(p) <= 8) | ||
2277 | o_y = (8 - (sy & 0x7)) & 0x7; | ||
2278 | else if (fontheight(p) <= 16) | ||
2279 | o_y = (16 - (sy & 0xF)) & 0xF; | ||
2280 | else if (fontheight(p) <= 32) | ||
2281 | o_y = (32 - (sy & 0x1F)) & 0x1F; | ||
2282 | |||
2283 | PM3_WRITE_REG(PM3AreaStippleMode, (o_x << 7) | (o_y << 12) | /* x_offset, y_offset in pattern */ | ||
2284 | (1 << 18) | /* BE */ | ||
2285 | 1 | (asx << 1) | (asy << 4) | /* address select x/y */ | ||
2286 | (1 << 20)); /* OpaqueSpan */ | ||
2287 | |||
2288 | if (fontwidth(p) <= 8) { | ||
2289 | cdat = p->fontdata + (c & p->charmask) * fontheight(p); | ||
2290 | } else { | ||
2291 | cdat = | ||
2292 | p->fontdata + | ||
2293 | ((c & p->charmask) * (fontheight(p) << 1)); | ||
2294 | } | ||
2295 | |||
2296 | PM3_WAIT(2 + fontheight(p)); | ||
2297 | |||
2298 | for (i = 0; i < fontheight(p); i++) { /* assume fontheight <= 32 */ | ||
2299 | if (fontwidth(p) <= 8) { | ||
2300 | ldat = *cdat++; | ||
2301 | } else { /* assume fontwidth <= 16 ATM */ | ||
2302 | |||
2303 | ldat = ((*cdat++) << 8); | ||
2304 | ldat |= *cdat++; | ||
2305 | } | ||
2306 | PM3_WRITE_REG(AreaStipplePattern_indexed(i), ldat); | ||
2307 | } | ||
2308 | |||
2309 | PM3_WRITE_REG(PM3RectanglePosition, | ||
2310 | (PM3RectanglePosition_XOffset(sx)) | | ||
2311 | (PM3RectanglePosition_YOffset(sy))); | ||
2312 | |||
2313 | PM3_WRITE_REG(PM3Render2D, | ||
2314 | PM3Render2D_AreaStippleEnable | | ||
2315 | PM3Render2D_XPositive | | ||
2316 | PM3Render2D_YPositive | | ||
2317 | PM3Render2D_Operation_Normal | | ||
2318 | PM3Render2D_SpanOperation | | ||
2319 | (PM3Render2D_Width(fontwidth(p))) | | ||
2320 | (PM3Render2D_Height(fontheight(p)))); | ||
2321 | |||
2322 | pm3fb_wait_pm3(l_fb_info); | ||
2323 | } | ||
2324 | |||
2325 | static void pm3fb_cfbX_putcs(struct vc_data *conp, struct display *p, | ||
2326 | const unsigned short *s, int count, int yy, | ||
2327 | int xx) | ||
2328 | { | ||
2329 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; | ||
2330 | u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0; | ||
2331 | u32 fgx, bgx, ldat; | ||
2332 | int sx, sy, i, j; | ||
2333 | u16 sc; | ||
2334 | |||
2335 | DTRACE; | ||
2336 | |||
2337 | sc = scr_readw(s); | ||
2338 | if (l_fb_info->current_par->depth == 8) | ||
2339 | fgx = attr_fgcol(p, sc); | ||
2340 | else if (depth2bpp(l_fb_info->current_par->depth) == 16) | ||
2341 | fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, sc)]; | ||
2342 | else | ||
2343 | fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, sc)]; | ||
2344 | |||
2345 | PM3_COLOR(fgx); | ||
2346 | |||
2347 | if (l_fb_info->current_par->depth == 8) | ||
2348 | bgx = attr_bgcol(p, sc); | ||
2349 | else if (depth2bpp(l_fb_info->current_par->depth) == 16) | ||
2350 | bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, sc)]; | ||
2351 | else | ||
2352 | bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, sc)]; | ||
2353 | |||
2354 | PM3_COLOR(bgx); | ||
2355 | |||
2356 | PM3_WAIT(4); | ||
2357 | |||
2358 | PM3_WRITE_REG(PM3Config2D, | ||
2359 | PM3Config2D_UseConstantSource | | ||
2360 | PM3Config2D_ForegroundROPEnable | | ||
2361 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
2362 | PM3Config2D_FBWriteEnable | | ||
2363 | PM3Config2D_OpaqueSpan); | ||
2364 | |||
2365 | PM3_WRITE_REG(PM3ForegroundColor, fgx); | ||
2366 | PM3_WRITE_REG(PM3FillBackgroundColor, bgx); | ||
2367 | |||
2368 | /* WARNING : address select X need to specify 8 bits for fontwidth <= 8 */ | ||
2369 | /* and 16 bits for fontwidth <= 16 */ | ||
2370 | /* same in _putc, same for Y and fontheight */ | ||
2371 | if (fontwidth(p) <= 8) | ||
2372 | asx = 2; | ||
2373 | else if (fontwidth(p) <= 16) | ||
2374 | asx = 3; /* look OK */ | ||
2375 | if (fontheight(p) <= 8) | ||
2376 | asy = 2; | ||
2377 | else if (fontheight(p) <= 16) | ||
2378 | asy = 3; /* look OK */ | ||
2379 | else if (fontheight(p) <= 32) | ||
2380 | asy = 4; /* look OK */ | ||
2381 | |||
2382 | sy = yy * fontheight(p); | ||
2383 | |||
2384 | if (fontheight(p) <= 8) | ||
2385 | o_y = (8 - (sy & 0x7)) & 0x7; | ||
2386 | else if (fontheight(p) <= 16) | ||
2387 | o_y = (16 - (sy & 0xF)) & 0xF; | ||
2388 | else if (fontheight(p) <= 32) | ||
2389 | o_y = (32 - (sy & 0x1F)) & 0x1F; | ||
2390 | |||
2391 | for (j = 0; j < count; j++) { | ||
2392 | sc = scr_readw(s + j); | ||
2393 | if (fontwidth(p) <= 8) | ||
2394 | cdat = p->fontdata + | ||
2395 | (sc & p->charmask) * fontheight(p); | ||
2396 | else | ||
2397 | cdat = p->fontdata + | ||
2398 | ((sc & p->charmask) * fontheight(p) << 1); | ||
2399 | |||
2400 | sx = (xx + j) * fontwidth(p); | ||
2401 | |||
2402 | if (fontwidth(p) <= 8) | ||
2403 | o_x = (8 - (sx & 0x7)) & 0x7; | ||
2404 | else if (fontwidth(p) <= 16) | ||
2405 | o_x = (16 - (sx & 0xF)) & 0xF; | ||
2406 | |||
2407 | PM3_WAIT(3 + fontheight(p)); | ||
2408 | |||
2409 | PM3_WRITE_REG(PM3AreaStippleMode, (o_x << 7) | (o_y << 12) | /* x_offset, y_offset in pattern */ | ||
2410 | (1 << 18) | /* BE */ | ||
2411 | 1 | (asx << 1) | (asy << 4) | /* address select x/y */ | ||
2412 | (1 << 20)); /* OpaqueSpan */ | ||
2413 | |||
2414 | for (i = 0; i < fontheight(p); i++) { /* assume fontheight <= 32 */ | ||
2415 | if (fontwidth(p) <= 8) { | ||
2416 | ldat = *cdat++; | ||
2417 | } else { /* assume fontwidth <= 16 ATM */ | ||
2418 | ldat = ((*cdat++) << 8); | ||
2419 | ldat |= *cdat++; | ||
2420 | } | ||
2421 | PM3_WRITE_REG(AreaStipplePattern_indexed(i), ldat); | ||
2422 | } | ||
2423 | |||
2424 | PM3_WRITE_REG(PM3RectanglePosition, | ||
2425 | (PM3RectanglePosition_XOffset(sx)) | | ||
2426 | (PM3RectanglePosition_YOffset(sy))); | ||
2427 | |||
2428 | PM3_WRITE_REG(PM3Render2D, | ||
2429 | PM3Render2D_AreaStippleEnable | | ||
2430 | PM3Render2D_XPositive | | ||
2431 | PM3Render2D_YPositive | | ||
2432 | PM3Render2D_Operation_Normal | | ||
2433 | PM3Render2D_SpanOperation | | ||
2434 | (PM3Render2D_Width(fontwidth(p))) | | ||
2435 | (PM3Render2D_Height(fontheight(p)))); | ||
2436 | } | 652 | } |
2437 | pm3fb_wait_pm3(l_fb_info); | 653 | var->height = var->width = -1; |
2438 | } | ||
2439 | |||
2440 | static void pm3fb_cfbX_revc(struct display *p, int xx, int yy) | ||
2441 | { | ||
2442 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; | ||
2443 | |||
2444 | xx = xx * fontwidth(p); | ||
2445 | yy = yy * fontheight(p); | ||
2446 | 654 | ||
2447 | if (l_fb_info->current_par->depth == 8) | 655 | if (var->xres != var->xres_virtual) { |
2448 | { | 656 | DPRINTK("virtual x resolution != physical x resolution not supported\n"); |
2449 | if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) | 657 | return -EINVAL; |
2450 | PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0x0F0F0F0F); | ||
2451 | else | ||
2452 | PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0x0F0F0F0F); | ||
2453 | } | 658 | } |
2454 | 659 | ||
2455 | PM3_WAIT(3); | 660 | if (var->yres > var->yres_virtual) { |
2456 | 661 | DPRINTK("virtual y resolution < physical y resolution not possible\n"); | |
2457 | PM3_WRITE_REG(PM3Config2D, | 662 | return -EINVAL; |
2458 | PM3Config2D_UseConstantSource | | ||
2459 | PM3Config2D_ForegroundROPEnable | | ||
2460 | (PM3Config2D_ForegroundROP(0xa)) | /* Oxa is GXinvert */ | ||
2461 | PM3Config2D_FBDestReadEnable | | ||
2462 | PM3Config2D_FBWriteEnable); | ||
2463 | |||
2464 | PM3_WRITE_REG(PM3RectanglePosition, | ||
2465 | (PM3RectanglePosition_XOffset(xx)) | | ||
2466 | (PM3RectanglePosition_YOffset(yy))); | ||
2467 | |||
2468 | PM3_WRITE_REG(PM3Render2D, | ||
2469 | PM3Render2D_XPositive | | ||
2470 | PM3Render2D_YPositive | | ||
2471 | PM3Render2D_Operation_Normal | | ||
2472 | PM3Render2D_SpanOperation | | ||
2473 | (PM3Render2D_Width(fontwidth(p))) | | ||
2474 | (PM3Render2D_Height(fontheight(p)))); | ||
2475 | |||
2476 | pm3fb_wait_pm3(l_fb_info); | ||
2477 | |||
2478 | if (l_fb_info->current_par->depth == 8) | ||
2479 | { | ||
2480 | if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) | ||
2481 | PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xFFFFFFFF); | ||
2482 | else | ||
2483 | PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xFFFFFFFF); | ||
2484 | } | 663 | } |
2485 | } | ||
2486 | 664 | ||
2487 | #endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */ | 665 | if (var->xoffset) { |
2488 | #endif /* PM3FB_USE_ACCEL */ | 666 | DPRINTK("xoffset not supported\n"); |
2489 | /* *********************************** */ | 667 | return -EINVAL; |
2490 | /* ***** pre-init board(s) setup ***** */ | ||
2491 | /* *********************************** */ | ||
2492 | |||
2493 | static void pm3fb_mode_setup(char *mode, unsigned long board_num) | ||
2494 | { | ||
2495 | struct pm3fb_info *l_fb_info = &(fb_info[board_num]); | ||
2496 | struct pm3fb_par *l_fb_par = &(current_par[board_num]); | ||
2497 | unsigned long i = 0; | ||
2498 | |||
2499 | current_par_valid[board_num] = 0; | ||
2500 | |||
2501 | if (!strncmp(mode, "current", 7)) { | ||
2502 | l_fb_info->use_current = 1; /* default w/ OpenFirmware */ | ||
2503 | } else { | ||
2504 | while ((mode_base[i].name[0]) | ||
2505 | && (!current_par_valid[board_num])) { | ||
2506 | if (! | ||
2507 | (strncmp | ||
2508 | (mode, mode_base[i].name, | ||
2509 | strlen(mode_base[i].name)))) { | ||
2510 | memcpy(l_fb_par, &(mode_base[i].user_mode), | ||
2511 | sizeof(struct pm3fb_par)); | ||
2512 | current_par_valid[board_num] = 1; | ||
2513 | DPRINTK(2, "Mode set to %s\n", | ||
2514 | mode_base[i].name); | ||
2515 | } | ||
2516 | i++; | ||
2517 | } | ||
2518 | DASSERT(current_par_valid[board_num], | ||
2519 | "Valid mode on command line\n"); | ||
2520 | } | 668 | } |
2521 | } | ||
2522 | 669 | ||
2523 | static void pm3fb_pciid_setup(char *pciid, unsigned long board_num) | 670 | if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { |
2524 | { | 671 | DPRINTK("interlace not supported\n"); |
2525 | short l_bus = -1, l_slot = -1, l_func = -1; | 672 | return -EINVAL; |
2526 | char *next; | ||
2527 | |||
2528 | if (pciid) { | ||
2529 | l_bus = simple_strtoul(pciid, &next, 10); | ||
2530 | if (next && (next[0] == ':')) { | ||
2531 | pciid = next + 1; | ||
2532 | l_slot = simple_strtoul(pciid, &next, 10); | ||
2533 | if (next && (next[0] == ':')) { | ||
2534 | pciid = next + 1; | ||
2535 | l_func = | ||
2536 | simple_strtoul(pciid, (char **) NULL, | ||
2537 | 10); | ||
2538 | } | ||
2539 | } | ||
2540 | } else | ||
2541 | return; | ||
2542 | |||
2543 | if ((l_bus >= 0) && (l_slot >= 0) && (l_func >= 0)) { | ||
2544 | bus[board_num] = l_bus; | ||
2545 | slot[board_num] = l_slot; | ||
2546 | func[board_num] = l_func; | ||
2547 | DPRINTK(2, "Board #%ld will be PciId: %hd:%hd:%hd\n", | ||
2548 | board_num, l_bus, l_slot, l_func); | ||
2549 | } else { | ||
2550 | DPRINTK(1, "Invalid PciId: %hd:%hd:%hd for board #%ld\n", | ||
2551 | l_bus, l_slot, l_func, board_num); | ||
2552 | } | 673 | } |
2553 | } | ||
2554 | 674 | ||
2555 | static void pm3fb_font_setup(char *lf, unsigned long board_num) | 675 | var->xres = (var->xres + 31) & ~31; /* could sometimes be 8 */ |
2556 | { | 676 | lpitch = var->xres * ((var->bits_per_pixel + 7)>>3); |
2557 | unsigned long lfs = strlen(lf); | ||
2558 | 677 | ||
2559 | if (lfs > (PM3_FONTNAME_SIZE - 1)) { | 678 | if (var->xres < 200 || var->xres > 2048) { |
2560 | DPRINTK(1, "Fontname %s too long\n", lf); | 679 | DPRINTK("width not supported: %u\n", var->xres); |
2561 | return; | 680 | return -EINVAL; |
2562 | } | 681 | } |
2563 | strlcpy(fontn[board_num], lf, lfs + 1); | ||
2564 | } | ||
2565 | |||
2566 | static void pm3fb_bootdepth_setup(char *bds, unsigned long board_num) | ||
2567 | { | ||
2568 | unsigned long bd = simple_strtoul(bds, (char **) NULL, 10); | ||
2569 | 682 | ||
2570 | if (!(depth_supported(bd))) { | 683 | if (var->yres < 200 || var->yres > 4095) { |
2571 | printk(KERN_WARNING "pm3fb: ignoring invalid depth %s for board #%ld\n", | 684 | DPRINTK("height not supported: %u\n", var->yres); |
2572 | bds, board_num); | 685 | return -EINVAL; |
2573 | return; | ||
2574 | } | 686 | } |
2575 | depth[board_num] = bd; | ||
2576 | } | ||
2577 | 687 | ||
2578 | static void pm3fb_forcesize_setup(char *bds, unsigned long board_num) | 688 | if (lpitch * var->yres_virtual > info->fix.smem_len) { |
2579 | { | 689 | DPRINTK("no memory for screen (%ux%ux%u)\n", |
2580 | unsigned long bd = simple_strtoul(bds, (char **) NULL, 10); | 690 | var->xres, var->yres_virtual, var->bits_per_pixel); |
2581 | 691 | return -EINVAL; | |
2582 | if (bd > 64) { | ||
2583 | printk(KERN_WARNING "pm3fb: ignoring invalid memory size %s for board #%ld\n", | ||
2584 | bds, board_num); | ||
2585 | return; | ||
2586 | } | 692 | } |
2587 | forcesize[board_num] = bd; | ||
2588 | } | ||
2589 | |||
2590 | static char *pm3fb_boardnum_setup(char *options, unsigned long *bn) | ||
2591 | { | ||
2592 | char *next; | ||
2593 | 693 | ||
2594 | if (!(isdigit(options[0]))) { | 694 | if (PICOS2KHZ(var->pixclock) > PM3_MAX_PIXCLOCK) { |
2595 | (*bn) = 0; | 695 | DPRINTK("pixclock too high (%ldKHz)\n", PICOS2KHZ(var->pixclock)); |
2596 | return (options); | 696 | return -EINVAL; |
2597 | } | 697 | } |
2598 | 698 | ||
2599 | (*bn) = simple_strtoul(options, &next, 10); | 699 | var->accel_flags = 0; /* Can't mmap if this is on */ |
2600 | 700 | ||
2601 | if (next && (next[0] == ':') && ((*bn) >= 0) | 701 | DPRINTK("Checking graphics mode at %dx%d depth %d\n", |
2602 | && ((*bn) <= PM3_MAX_BOARD)) { | 702 | var->xres, var->yres, var->bits_per_pixel); |
2603 | DPRINTK(2, "Board_num seen as %ld\n", (*bn)); | 703 | return 0; |
2604 | return (next + 1); | ||
2605 | } else { | ||
2606 | (*bn) = 0; | ||
2607 | DPRINTK(2, "Board_num default to %ld\n", (*bn)); | ||
2608 | return (options); | ||
2609 | } | ||
2610 | } | 704 | } |
2611 | 705 | ||
2612 | static void pm3fb_real_setup(char *options) | 706 | static int pm3fb_set_par(struct fb_info *info) |
2613 | { | 707 | { |
2614 | char *next; | 708 | struct pm3_par *par = info->par; |
2615 | unsigned long i, bn; | 709 | const u32 xres = (info->var.xres + 31) & ~31; |
2616 | struct pm3fb_info *l_fb_info; | 710 | const unsigned bpp = info->var.bits_per_pixel; |
2617 | |||
2618 | DTRACE; | ||
2619 | |||
2620 | DPRINTK(2, "Options : %s\n", options); | ||
2621 | |||
2622 | for (i = 0; i < PM3_MAX_BOARD; i++) { | ||
2623 | l_fb_info = &(fb_info[i]); | ||
2624 | memset(l_fb_info, 0, sizeof(struct pm3fb_info)); | ||
2625 | l_fb_info->gen.fbhw = &pm3fb_switch; | ||
2626 | l_fb_info->board_num = i; | ||
2627 | current_par_valid[i] = 0; | ||
2628 | slot[i] = -1; | ||
2629 | func[i] = -1; | ||
2630 | bus[i] = -1; | ||
2631 | disable[i] = 0; | ||
2632 | noaccel[i] = 0; | ||
2633 | fontn[i][0] = '\0'; | ||
2634 | depth[i] = 0; | ||
2635 | l_fb_info->current_par = &(current_par[i]); | ||
2636 | } | ||
2637 | |||
2638 | /* eat up prefix pm3fb and whatever is used as separator i.e. :,= */ | ||
2639 | if (!strncmp(options, "pm3fb", 5)) { | ||
2640 | options += 5; | ||
2641 | while (((*options) == ',') || ((*options) == ':') | ||
2642 | || ((*options) == '=')) | ||
2643 | options++; | ||
2644 | } | ||
2645 | 711 | ||
2646 | while (options) { | 712 | par->base = pm3fb_shift_bpp(bpp,(info->var.yoffset * xres) |
2647 | bn = 0; | 713 | + info->var.xoffset); |
2648 | if ((next = strchr(options, ','))) { | 714 | par->video = 0; |
2649 | (*next) = '\0'; | ||
2650 | next++; | ||
2651 | } | ||
2652 | 715 | ||
2653 | if (!strncmp(options, "mode:", 5)) { | 716 | if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) |
2654 | options = pm3fb_boardnum_setup(options + 5, &bn); | 717 | par->video |= PM3VideoControl_HSYNC_ACTIVE_HIGH; |
2655 | DPRINTK(2, "Setting mode for board #%ld\n", bn); | ||
2656 | pm3fb_mode_setup(options, bn); | ||
2657 | } else if (!strncmp(options, "off:", 4)) { | ||
2658 | options = pm3fb_boardnum_setup(options + 4, &bn); | ||
2659 | DPRINTK(2, "Disabling board #%ld\n", bn); | ||
2660 | disable[bn] = 1; | ||
2661 | } else if (!strncmp(options, "off", 3)) { /* disable everything */ | ||
2662 | for (i = 0; i < PM3_MAX_BOARD; i++) | ||
2663 | disable[i] = 1; | ||
2664 | } else if (!strncmp(options, "disable:", 8)) { | ||
2665 | options = pm3fb_boardnum_setup(options + 8, &bn); | ||
2666 | DPRINTK(2, "Disabling board #%ld\n", bn); | ||
2667 | disable[bn] = 1; | ||
2668 | } else if (!strncmp(options, "pciid:", 6)) { | ||
2669 | options = pm3fb_boardnum_setup(options + 6, &bn); | ||
2670 | DPRINTK(2, "Setting PciID for board #%ld\n", bn); | ||
2671 | pm3fb_pciid_setup(options, bn); | ||
2672 | } else if (!strncmp(options, "noaccel:", 8)) { | ||
2673 | options = pm3fb_boardnum_setup(options + 8, &bn); | ||
2674 | noaccel[bn] = 1; | ||
2675 | } else if (!strncmp(options, "font:", 5)) { | ||
2676 | options = pm3fb_boardnum_setup(options + 5, &bn); | ||
2677 | pm3fb_font_setup(options, bn); | ||
2678 | } else if (!strncmp(options, "depth:", 6)) { | ||
2679 | options = pm3fb_boardnum_setup(options + 6, &bn); | ||
2680 | pm3fb_bootdepth_setup(options, bn); | ||
2681 | } else if (!strncmp(options, "printtimings", 12)) { | ||
2682 | printtimings = 1; | ||
2683 | } else if (!strncmp(options, "flatpanel:", 10)) { | ||
2684 | options = pm3fb_boardnum_setup(options + 10, &bn); | ||
2685 | flatpanel[bn] = 1; | ||
2686 | } else if (!strncmp(options, "forcesize:", 10)) { | ||
2687 | options = pm3fb_boardnum_setup(options + 10, &bn); | ||
2688 | pm3fb_forcesize_setup(options, bn); | ||
2689 | } | ||
2690 | options = next; | ||
2691 | } | ||
2692 | } | ||
2693 | |||
2694 | /* ********************************************** */ | ||
2695 | /* ***** framebuffer API standard functions ***** */ | ||
2696 | /* ********************************************** */ | ||
2697 | |||
2698 | static int pm3fb_encode_fix(struct fb_fix_screeninfo *fix, | ||
2699 | const void *par, struct fb_info_gen *info) | ||
2700 | { | ||
2701 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; | ||
2702 | struct pm3fb_par *p = (struct pm3fb_par *) par; | ||
2703 | |||
2704 | DTRACE; | ||
2705 | |||
2706 | strcpy(fix->id, permedia3_name); | ||
2707 | fix->smem_start = (unsigned long)l_fb_info->p_fb; | ||
2708 | fix->smem_len = l_fb_info->fb_size; | ||
2709 | fix->mmio_start = (unsigned long)l_fb_info->pIOBase; | ||
2710 | fix->mmio_len = PM3_REGS_SIZE; | ||
2711 | #ifdef PM3FB_USE_ACCEL | ||
2712 | if (!(noaccel[l_fb_info->board_num])) | ||
2713 | fix->accel = FB_ACCEL_3DLABS_PERMEDIA3; | ||
2714 | else | 718 | else |
2715 | #endif /* PM3FB_USE_ACCEL */ | 719 | par->video |= PM3VideoControl_HSYNC_ACTIVE_LOW; |
2716 | fix->accel = FB_ACCEL_NONE; | ||
2717 | fix->type = FB_TYPE_PACKED_PIXELS; | ||
2718 | fix->visual = | ||
2719 | (p->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; | ||
2720 | if (current_par_valid[l_fb_info->board_num]) | ||
2721 | fix->line_length = | ||
2722 | l_fb_info->current_par->width * | ||
2723 | depth2ByPP(l_fb_info->current_par->depth); | ||
2724 | else | ||
2725 | fix->line_length = 0; | ||
2726 | fix->xpanstep = 64 / depth2bpp(p->depth); | ||
2727 | fix->ypanstep = 1; | ||
2728 | fix->ywrapstep = 0; | ||
2729 | return (0); | ||
2730 | } | ||
2731 | |||
2732 | static int pm3fb_decode_var(const struct fb_var_screeninfo *var, | ||
2733 | void *par, struct fb_info_gen *info) | ||
2734 | { | ||
2735 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; | ||
2736 | struct pm3fb_par *p = (struct pm3fb_par *) par; | ||
2737 | struct pm3fb_par temp_p; | ||
2738 | u32 xres; | ||
2739 | |||
2740 | DTRACE; | ||
2741 | |||
2742 | DASSERT((var != NULL), "fb_var_screeninfo* not NULL"); | ||
2743 | DASSERT((p != NULL), "pm3fb_par* not NULL"); | ||
2744 | DASSERT((l_fb_info != NULL), "pm3fb_info* not NULL"); | ||
2745 | 720 | ||
2746 | memset(&temp_p, 0, sizeof(struct pm3fb_par)); | 721 | if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) |
2747 | temp_p.width = (var->xres_virtual + 7) & ~7; | 722 | par->video |= PM3VideoControl_VSYNC_ACTIVE_HIGH; |
2748 | temp_p.height = var->yres_virtual; | ||
2749 | |||
2750 | if (!(depth_supported(var->bits_per_pixel))) /* round unsupported up to a multiple of 8 */ | ||
2751 | temp_p.depth = depth2bpp(var->bits_per_pixel); | ||
2752 | else | 723 | else |
2753 | temp_p.depth = var->bits_per_pixel; | 724 | par->video |= PM3VideoControl_VSYNC_ACTIVE_LOW; |
2754 | |||
2755 | temp_p.depth = (temp_p.depth > 32) ? 32 : temp_p.depth; /* max 32 */ | ||
2756 | temp_p.depth = (temp_p.depth == 24) ? 32 : temp_p.depth; /* 24 unsupported, round-up to 32 */ | ||
2757 | |||
2758 | if ((temp_p.depth == 16) && (var->red.length == 5) && (var->green.length == 5) && (var->blue.length == 5)) | ||
2759 | temp_p.depth = 15; /* RGBA 5551 is stored as depth 15 */ | ||
2760 | |||
2761 | if ((temp_p.depth == 16) && (var->red.length == 4) && (var->green.length == 4) && (var->blue.length == 4)) | ||
2762 | temp_p.depth = 12; /* RGBA 4444 is stored as depth 12 */ | ||
2763 | |||
2764 | |||
2765 | DPRINTK(2, | ||
2766 | "xres: %d, yres: %d, vxres: %d, vyres: %d ; xoffset:%d, yoffset: %d\n", | ||
2767 | var->xres, var->yres, var->xres_virtual, var->yres_virtual, | ||
2768 | var->xoffset, var->yoffset); | ||
2769 | |||
2770 | xres = (var->xres + 31) & ~31; | ||
2771 | if (temp_p.width < xres + var->xoffset) | ||
2772 | temp_p.width = xres + var->xoffset; | ||
2773 | if (temp_p.height < var->yres + var->yoffset) | ||
2774 | temp_p.height = var->yres + var->yoffset; | ||
2775 | |||
2776 | if (temp_p.width > 2048) { | ||
2777 | DPRINTK(1, "virtual width not supported: %u\n", | ||
2778 | temp_p.width); | ||
2779 | return (-EINVAL); | ||
2780 | } | ||
2781 | if (var->yres < 200) { | ||
2782 | DPRINTK(1, "height not supported: %u\n", (u32) var->yres); | ||
2783 | return (-EINVAL); | ||
2784 | } | ||
2785 | if (temp_p.height < 200 || temp_p.height > 4095) { | ||
2786 | DPRINTK(1, "virtual height not supported: %u\n", | ||
2787 | temp_p.height); | ||
2788 | return (-EINVAL); | ||
2789 | } | ||
2790 | if (!(depth_supported(temp_p.depth))) { | ||
2791 | DPRINTK(1, "depth not supported: %u\n", temp_p.depth); | ||
2792 | return (-EINVAL); | ||
2793 | } | ||
2794 | if ((temp_p.width * temp_p.height * depth2ByPP(temp_p.depth)) > | ||
2795 | l_fb_info->fb_size) { | ||
2796 | DPRINTK(1, "no memory for screen (%ux%ux%u)\n", | ||
2797 | temp_p.width, temp_p.height, temp_p.depth); | ||
2798 | return (-EINVAL); | ||
2799 | } | ||
2800 | 725 | ||
2801 | if ((!var->pixclock) || | 726 | if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) |
2802 | (!var->right_margin) || | 727 | par->video |= PM3VideoControl_LINE_DOUBLE_ON; |
2803 | (!var->hsync_len) || | ||
2804 | (!var->left_margin) || | ||
2805 | (!var->lower_margin) || | ||
2806 | (!var->vsync_len) || (!var->upper_margin) | ||
2807 | ) { | ||
2808 | unsigned long i = 0, done = 0; | ||
2809 | printk(KERN_WARNING "pm3fb: refusing to use a likely wrong timing\n"); | ||
2810 | |||
2811 | while ((mode_base[i].user_mode.width) && !done) { | ||
2812 | if ((mode_base[i].user_mode.width == temp_p.width) | ||
2813 | && (mode_base[i].user_mode.height == | ||
2814 | temp_p.height)) { | ||
2815 | printk(KERN_NOTICE "pm3fb: using close match %s\n", | ||
2816 | mode_base[i].name); | ||
2817 | temp_p = mode_base[i].user_mode; | ||
2818 | done = 1; | ||
2819 | } | ||
2820 | i++; | ||
2821 | } | ||
2822 | if (!done) | ||
2823 | return (-EINVAL); | ||
2824 | } else { | ||
2825 | temp_p.pixclock = PICOS2KHZ(var->pixclock); | ||
2826 | if (temp_p.pixclock > PM3_MAX_PIXCLOCK) { | ||
2827 | DPRINTK(1, "pixclock too high (%uKHz)\n", | ||
2828 | temp_p.pixclock); | ||
2829 | return (-EINVAL); | ||
2830 | } | ||
2831 | |||
2832 | temp_p.hsstart = var->right_margin; | ||
2833 | temp_p.hsend = var->right_margin + var->hsync_len; | ||
2834 | temp_p.hbend = | ||
2835 | var->right_margin + var->hsync_len + var->left_margin; | ||
2836 | temp_p.htotal = xres + temp_p.hbend; | ||
2837 | |||
2838 | temp_p.vsstart = var->lower_margin; | ||
2839 | temp_p.vsend = var->lower_margin + var->vsync_len; | ||
2840 | temp_p.vbend = | ||
2841 | var->lower_margin + var->vsync_len + var->upper_margin; | ||
2842 | temp_p.vtotal = var->yres + temp_p.vbend; | ||
2843 | |||
2844 | temp_p.stride = temp_p.width; | ||
2845 | |||
2846 | DPRINTK(2, "Using %d * %d, %d Khz, stride is %08x\n", | ||
2847 | temp_p.width, temp_p.height, temp_p.pixclock, | ||
2848 | temp_p.stride); | ||
2849 | |||
2850 | temp_p.base = | ||
2851 | pm3fb_Shiftbpp(l_fb_info, temp_p.depth, | ||
2852 | (var->yoffset * xres) + var->xoffset); | ||
2853 | |||
2854 | temp_p.video = 0; | ||
2855 | |||
2856 | if (var->sync & FB_SYNC_HOR_HIGH_ACT) | ||
2857 | temp_p.video |= PM3VideoControl_HSYNC_ACTIVE_HIGH; | ||
2858 | else | ||
2859 | temp_p.video |= PM3VideoControl_HSYNC_ACTIVE_LOW; | ||
2860 | |||
2861 | if (var->sync & FB_SYNC_VERT_HIGH_ACT) | ||
2862 | temp_p.video |= PM3VideoControl_VSYNC_ACTIVE_HIGH; | ||
2863 | else | ||
2864 | temp_p.video |= PM3VideoControl_VSYNC_ACTIVE_LOW; | ||
2865 | |||
2866 | if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { | ||
2867 | DPRINTK(1, "Interlaced mode not supported\n\n"); | ||
2868 | return (-EINVAL); | ||
2869 | } | ||
2870 | |||
2871 | if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) | ||
2872 | temp_p.video |= PM3VideoControl_LINE_DOUBLE_ON; | ||
2873 | else | ||
2874 | temp_p.video |= PM3VideoControl_LINE_DOUBLE_OFF; | ||
2875 | |||
2876 | if (var->activate == FB_ACTIVATE_NOW) | ||
2877 | temp_p.video |= PM3VideoControl_ENABLE; | ||
2878 | else { | ||
2879 | temp_p.video |= PM3VideoControl_DISABLE; | ||
2880 | DPRINTK(2, "PM3Video disabled\n"); | ||
2881 | } | ||
2882 | |||
2883 | switch (temp_p.depth) { | ||
2884 | case 8: | ||
2885 | temp_p.video |= PM3VideoControl_PIXELSIZE_8BIT; | ||
2886 | break; | ||
2887 | case 12: | ||
2888 | case 15: | ||
2889 | case 16: | ||
2890 | temp_p.video |= PM3VideoControl_PIXELSIZE_16BIT; | ||
2891 | break; | ||
2892 | case 32: | ||
2893 | temp_p.video |= PM3VideoControl_PIXELSIZE_32BIT; | ||
2894 | break; | ||
2895 | default: | ||
2896 | DPRINTK(1, "Unsupported depth\n"); | ||
2897 | break; | ||
2898 | } | ||
2899 | } | ||
2900 | (*p) = temp_p; | ||
2901 | |||
2902 | #ifdef PM3FB_USE_ACCEL | ||
2903 | if (var->accel_flags & FB_ACCELF_TEXT) | ||
2904 | noaccel[l_fb_info->board_num] = 0; | ||
2905 | else | 728 | else |
2906 | noaccel[l_fb_info->board_num] = 1; | 729 | par->video |= PM3VideoControl_LINE_DOUBLE_OFF; |
2907 | #endif /* PM3FB_USE_ACCEL */ | ||
2908 | |||
2909 | return (0); | ||
2910 | } | ||
2911 | 730 | ||
2912 | static void pm3fb_encode_depth(struct fb_var_screeninfo *var, long d) | 731 | if ((info->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) |
2913 | { | 732 | par->video |= PM3VideoControl_ENABLE; |
2914 | switch (d) { | 733 | else { |
734 | par->video |= PM3VideoControl_DISABLE; | ||
735 | DPRINTK("PM3Video disabled\n"); | ||
736 | } | ||
737 | switch (bpp) { | ||
2915 | case 8: | 738 | case 8: |
2916 | var->red.length = var->green.length = var->blue.length = 8; | 739 | par->video |= PM3VideoControl_PIXELSIZE_8BIT; |
2917 | var->red.offset = var->green.offset = var->blue.offset = 0; | ||
2918 | var->transp.offset = var->transp.length = 0; | ||
2919 | break; | ||
2920 | |||
2921 | case 12: | ||
2922 | var->red.offset = 8; | ||
2923 | var->red.length = 4; | ||
2924 | var->green.offset = 4; | ||
2925 | var->green.length = 4; | ||
2926 | var->blue.offset = 0; | ||
2927 | var->blue.length = 4; | ||
2928 | var->transp.offset = 12; | ||
2929 | var->transp.length = 4; | ||
2930 | break; | 740 | break; |
2931 | |||
2932 | case 15: | ||
2933 | var->red.offset = 10; | ||
2934 | var->red.length = 5; | ||
2935 | var->green.offset = 5; | ||
2936 | var->green.length = 5; | ||
2937 | var->blue.offset = 0; | ||
2938 | var->blue.length = 5; | ||
2939 | var->transp.offset = 15; | ||
2940 | var->transp.length = 1; | ||
2941 | break; | ||
2942 | |||
2943 | case 16: | 741 | case 16: |
2944 | var->red.offset = 11; | 742 | par->video |= PM3VideoControl_PIXELSIZE_16BIT; |
2945 | var->red.length = 5; | ||
2946 | var->green.offset = 5; | ||
2947 | var->green.length = 6; | ||
2948 | var->blue.offset = 0; | ||
2949 | var->blue.length = 5; | ||
2950 | var->transp.offset = var->transp.length = 0; | ||
2951 | break; | 743 | break; |
2952 | |||
2953 | case 32: | 744 | case 32: |
2954 | var->transp.offset = 24; | 745 | par->video |= PM3VideoControl_PIXELSIZE_32BIT; |
2955 | var->red.offset = 16; | ||
2956 | var->green.offset = 8; | ||
2957 | var->blue.offset = 0; | ||
2958 | var->red.length = var->green.length = | ||
2959 | var->blue.length = var->transp.length = 8; | ||
2960 | break; | 746 | break; |
2961 | |||
2962 | default: | 747 | default: |
2963 | DPRINTK(1, "Unsupported depth %ld\n", d); | 748 | DPRINTK("Unsupported depth\n"); |
2964 | break; | 749 | break; |
2965 | } | 750 | } |
2966 | } | ||
2967 | |||
2968 | static int pm3fb_encode_var(struct fb_var_screeninfo *var, | ||
2969 | const void *par, struct fb_info_gen *info) | ||
2970 | { | ||
2971 | struct pm3fb_par *p = (struct pm3fb_par *) par; | ||
2972 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; | ||
2973 | |||
2974 | u32 base; | ||
2975 | |||
2976 | DTRACE; | ||
2977 | |||
2978 | DASSERT((var != NULL), "fb_var_screeninfo* not NULL"); | ||
2979 | DASSERT((p != NULL), "pm3fb_par* not NULL"); | ||
2980 | DASSERT((info != NULL), "fb_info_gen* not NULL"); | ||
2981 | |||
2982 | memset(var, 0, sizeof(struct fb_var_screeninfo)); | ||
2983 | |||
2984 | #ifdef PM3FB_USE_ACCEL | ||
2985 | if (!(noaccel[l_fb_info->board_num])) | ||
2986 | var->accel_flags |= FB_ACCELF_TEXT; | ||
2987 | #endif /* PM3FB_USE_ACCEL */ | ||
2988 | |||
2989 | var->xres_virtual = p->width; | ||
2990 | var->yres_virtual = p->height; | ||
2991 | var->xres = p->htotal - p->hbend; | ||
2992 | var->yres = p->vtotal - p->vbend; | ||
2993 | |||
2994 | DPRINTK(2, "xres = %d, yres : %d\n", var->xres, var->yres); | ||
2995 | |||
2996 | var->right_margin = p->hsstart; | ||
2997 | var->hsync_len = p->hsend - p->hsstart; | ||
2998 | var->left_margin = p->hbend - p->hsend; | ||
2999 | var->lower_margin = p->vsstart; | ||
3000 | var->vsync_len = p->vsend - p->vsstart; | ||
3001 | var->upper_margin = p->vbend - p->vsend; | ||
3002 | var->bits_per_pixel = depth2bpp(p->depth); | ||
3003 | |||
3004 | pm3fb_encode_depth(var, p->depth); | ||
3005 | |||
3006 | base = pm3fb_Unshiftbpp(l_fb_info, p->depth, p->base); | ||
3007 | |||
3008 | var->xoffset = base % var->xres; | ||
3009 | var->yoffset = base / var->xres; | ||
3010 | |||
3011 | var->height = var->width = -1; | ||
3012 | |||
3013 | var->pixclock = KHZ2PICOS(p->pixclock); | ||
3014 | |||
3015 | if ((p->video & PM3VideoControl_HSYNC_MASK) == | ||
3016 | PM3VideoControl_HSYNC_ACTIVE_HIGH) | ||
3017 | var->sync |= FB_SYNC_HOR_HIGH_ACT; | ||
3018 | if ((p->video & PM3VideoControl_VSYNC_MASK) == | ||
3019 | PM3VideoControl_VSYNC_ACTIVE_HIGH) | ||
3020 | var->sync |= FB_SYNC_VERT_HIGH_ACT; | ||
3021 | if (p->video & PM3VideoControl_LINE_DOUBLE_ON) | ||
3022 | var->vmode = FB_VMODE_DOUBLE; | ||
3023 | |||
3024 | return (0); | ||
3025 | } | ||
3026 | |||
3027 | static void pm3fb_get_par(void *par, struct fb_info_gen *info) | ||
3028 | { | ||
3029 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; | ||
3030 | |||
3031 | DTRACE; | ||
3032 | |||
3033 | if (!current_par_valid[l_fb_info->board_num]) { | ||
3034 | if (l_fb_info->use_current) | ||
3035 | pm3fb_read_mode(l_fb_info, l_fb_info->current_par); | ||
3036 | else | ||
3037 | memcpy(l_fb_info->current_par, | ||
3038 | &(mode_base[0].user_mode), | ||
3039 | sizeof(struct pm3fb_par)); | ||
3040 | current_par_valid[l_fb_info->board_num] = 1; | ||
3041 | } | ||
3042 | *((struct pm3fb_par *) par) = *(l_fb_info->current_par); | ||
3043 | } | ||
3044 | |||
3045 | static void pm3fb_set_par(const void *par, struct fb_info_gen *info) | ||
3046 | { | ||
3047 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; | ||
3048 | |||
3049 | DTRACE; | ||
3050 | |||
3051 | *(l_fb_info->current_par) = *((struct pm3fb_par *) par); | ||
3052 | current_par_valid[l_fb_info->board_num] = 1; | ||
3053 | |||
3054 | pm3fb_write_mode(l_fb_info); | ||
3055 | 751 | ||
3056 | #ifdef PM3FB_USE_ACCEL | 752 | info->fix.visual = |
3057 | pm3fb_init_engine(l_fb_info); | 753 | (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; |
3058 | #endif /* PM3FB_USE_ACCEL */ | 754 | info->fix.line_length = ((info->var.xres_virtual + 7) & ~7) |
3059 | } | 755 | * bpp / 8; |
3060 | |||
3061 | static void pm3fb_set_color(struct pm3fb_info *l_fb_info, | ||
3062 | unsigned char regno, unsigned char r, | ||
3063 | unsigned char g, unsigned char b) | ||
3064 | { | ||
3065 | DTRACE; | ||
3066 | 756 | ||
3067 | PM3_SLOW_WRITE_REG(PM3RD_PaletteWriteAddress, regno); | 757 | /* pm3fb_clear_memory(info, 0);*/ |
3068 | PM3_SLOW_WRITE_REG(PM3RD_PaletteData, r); | 758 | pm3fb_clear_colormap(par, 0, 0, 0); |
3069 | PM3_SLOW_WRITE_REG(PM3RD_PaletteData, g); | 759 | PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, |
3070 | PM3_SLOW_WRITE_REG(PM3RD_PaletteData, b); | 760 | PM3RD_CursorMode_CURSOR_DISABLE); |
3071 | } | 761 | pm3fb_init_engine(info); |
3072 | 762 | pm3fb_write_mode(info); | |
3073 | static int pm3fb_getcolreg(unsigned regno, unsigned *red, unsigned *green, | 763 | return 0; |
3074 | unsigned *blue, unsigned *transp, | ||
3075 | struct fb_info *info) | ||
3076 | { | ||
3077 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; | ||
3078 | |||
3079 | DTRACE; | ||
3080 | |||
3081 | if (regno < 256) { | ||
3082 | *red = | ||
3083 | l_fb_info->palette[regno].red << 8 | l_fb_info-> | ||
3084 | palette[regno].red; | ||
3085 | *green = | ||
3086 | l_fb_info->palette[regno].green << 8 | l_fb_info-> | ||
3087 | palette[regno].green; | ||
3088 | *blue = | ||
3089 | l_fb_info->palette[regno].blue << 8 | l_fb_info-> | ||
3090 | palette[regno].blue; | ||
3091 | *transp = | ||
3092 | l_fb_info->palette[regno].transp << 8 | l_fb_info-> | ||
3093 | palette[regno].transp; | ||
3094 | } | ||
3095 | return (regno > 255); | ||
3096 | } | 764 | } |
3097 | 765 | ||
3098 | static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green, | 766 | static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green, |
3099 | unsigned blue, unsigned transp, | 767 | unsigned blue, unsigned transp, |
3100 | struct fb_info *info) | 768 | struct fb_info *info) |
3101 | { | 769 | { |
3102 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; | 770 | struct pm3_par *par = info->par; |
3103 | 771 | ||
3104 | DTRACE; | 772 | if (regno >= 256) /* no. of hw registers */ |
773 | return -EINVAL; | ||
774 | |||
775 | /* grayscale works only partially under directcolor */ | ||
776 | if (info->var.grayscale) { | ||
777 | /* grayscale = 0.30*R + 0.59*G + 0.11*B */ | ||
778 | red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; | ||
779 | } | ||
780 | |||
781 | /* Directcolor: | ||
782 | * var->{color}.offset contains start of bitfield | ||
783 | * var->{color}.length contains length of bitfield | ||
784 | * {hardwarespecific} contains width of DAC | ||
785 | * pseudo_palette[X] is programmed to (X << red.offset) | | ||
786 | * (X << green.offset) | | ||
787 | * (X << blue.offset) | ||
788 | * RAMDAC[X] is programmed to (red, green, blue) | ||
789 | * color depth = SUM(var->{color}.length) | ||
790 | * | ||
791 | * Pseudocolor: | ||
792 | * var->{color}.offset is 0 | ||
793 | * var->{color}.length contains width of DAC or the number of unique | ||
794 | * colors available (color depth) | ||
795 | * pseudo_palette is not used | ||
796 | * RAMDAC[X] is programmed to (red, green, blue) | ||
797 | * color depth = var->{color}.length | ||
798 | */ | ||
3105 | 799 | ||
3106 | if (regno < 16) { | 800 | /* |
3107 | switch (l_fb_info->current_par->depth) { | 801 | * This is the point where the color is converted to something that |
3108 | #ifdef FBCON_HAS_CFB8 | 802 | * is acceptable by the hardware. |
803 | */ | ||
804 | #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) | ||
805 | red = CNVT_TOHW(red, info->var.red.length); | ||
806 | green = CNVT_TOHW(green, info->var.green.length); | ||
807 | blue = CNVT_TOHW(blue, info->var.blue.length); | ||
808 | transp = CNVT_TOHW(transp, info->var.transp.length); | ||
809 | #undef CNVT_TOHW | ||
810 | |||
811 | if (info->fix.visual == FB_VISUAL_TRUECOLOR || | ||
812 | info->fix.visual == FB_VISUAL_DIRECTCOLOR) { | ||
813 | u32 v; | ||
814 | |||
815 | if (regno >= 16) | ||
816 | return -EINVAL; | ||
817 | |||
818 | v = (red << info->var.red.offset) | | ||
819 | (green << info->var.green.offset) | | ||
820 | (blue << info->var.blue.offset) | | ||
821 | (transp << info->var.transp.offset); | ||
822 | |||
823 | switch (info->var.bits_per_pixel) { | ||
3109 | case 8: | 824 | case 8: |
3110 | break; | 825 | break; |
3111 | #endif | ||
3112 | #ifdef FBCON_HAS_CFB16 | ||
3113 | case 12: | ||
3114 | l_fb_info->cmap.cmap12[regno] = | ||
3115 | (((u32) red & 0xf000) >> 4) | | ||
3116 | (((u32) green & 0xf000) >> 8) | | ||
3117 | (((u32) blue & 0xf000) >> 12); | ||
3118 | break; | ||
3119 | |||
3120 | case 15: | ||
3121 | l_fb_info->cmap.cmap15[regno] = | ||
3122 | (((u32) red & 0xf800) >> 1) | | ||
3123 | (((u32) green & 0xf800) >> 6) | | ||
3124 | (((u32) blue & 0xf800) >> 11); | ||
3125 | break; | ||
3126 | |||
3127 | case 16: | 826 | case 16: |
3128 | l_fb_info->cmap.cmap16[regno] = | ||
3129 | ((u32) red & 0xf800) | | ||
3130 | (((u32) green & 0xfc00) >> 5) | | ||
3131 | (((u32) blue & 0xf800) >> 11); | ||
3132 | break; | ||
3133 | #endif | ||
3134 | #ifdef FBCON_HAS_CFB32 | ||
3135 | case 32: | 827 | case 32: |
3136 | l_fb_info->cmap.cmap32[regno] = | 828 | ((u32*)(info->pseudo_palette))[regno] = v; |
3137 | (((u32) transp & 0xff00) << 16) | | ||
3138 | (((u32) red & 0xff00) << 8) | | ||
3139 | (((u32) green & 0xff00)) | | ||
3140 | (((u32) blue & 0xff00) >> 8); | ||
3141 | break; | ||
3142 | #endif | ||
3143 | default: | ||
3144 | DPRINTK(1, "bad depth %u\n", | ||
3145 | l_fb_info->current_par->depth); | ||
3146 | break; | 829 | break; |
3147 | } | 830 | } |
831 | return 0; | ||
3148 | } | 832 | } |
3149 | if (regno < 256) { | 833 | else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) |
3150 | l_fb_info->palette[regno].red = red >> 8; | 834 | pm3fb_set_color(par, regno, red, green, blue); |
3151 | l_fb_info->palette[regno].green = green >> 8; | 835 | |
3152 | l_fb_info->palette[regno].blue = blue >> 8; | 836 | return 0; |
3153 | l_fb_info->palette[regno].transp = transp >> 8; | ||
3154 | if (l_fb_info->current_par->depth == 8) | ||
3155 | pm3fb_set_color(l_fb_info, regno, red >> 8, | ||
3156 | green >> 8, blue >> 8); | ||
3157 | } | ||
3158 | return (regno > 255); | ||
3159 | } | 837 | } |
3160 | 838 | ||
3161 | static int pm3fb_blank(int blank_mode, struct fb_info_gen *info) | 839 | static int pm3fb_pan_display(struct fb_var_screeninfo *var, |
840 | struct fb_info *info) | ||
3162 | { | 841 | { |
3163 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; | 842 | struct pm3_par *par = info->par; |
3164 | u32 video; | 843 | const u32 xres = (var->xres + 31) & ~31; |
3165 | 844 | ||
3166 | DTRACE; | 845 | par->base = pm3fb_shift_bpp(var->bits_per_pixel, |
3167 | 846 | (var->yoffset * xres) | |
3168 | if (!current_par_valid[l_fb_info->board_num]) | 847 | + var->xoffset); |
3169 | return (1); | 848 | PM3_WAIT(par, 1); |
849 | PM3_WRITE_REG(par, PM3ScreenBase, par->base); | ||
850 | return 0; | ||
851 | } | ||
3170 | 852 | ||
3171 | video = l_fb_info->current_par->video; | 853 | static int pm3fb_blank(int blank_mode, struct fb_info *info) |
854 | { | ||
855 | struct pm3_par *par = info->par; | ||
856 | u32 video = par->video; | ||
3172 | 857 | ||
3173 | /* | 858 | /* |
3174 | * Oxygen VX1 - it appears that setting PM3VideoControl and | 859 | * Oxygen VX1 - it appears that setting PM3VideoControl and |
@@ -3181,454 +866,323 @@ static int pm3fb_blank(int blank_mode, struct fb_info_gen *info) | |||
3181 | video |= PM3VideoControl_HSYNC_ACTIVE_HIGH | | 866 | video |= PM3VideoControl_HSYNC_ACTIVE_HIGH | |
3182 | PM3VideoControl_VSYNC_ACTIVE_HIGH; | 867 | PM3VideoControl_VSYNC_ACTIVE_HIGH; |
3183 | 868 | ||
3184 | if (blank_mode > 0) { | 869 | switch (blank_mode) { |
3185 | switch (blank_mode - 1) { | 870 | case FB_BLANK_UNBLANK: |
3186 | 871 | video |= PM3VideoControl_ENABLE; | |
3187 | case VESA_NO_BLANKING: /* FIXME */ | ||
3188 | video = video & ~(PM3VideoControl_ENABLE); | ||
3189 | break; | ||
3190 | |||
3191 | case VESA_HSYNC_SUSPEND: | ||
3192 | video = video & ~(PM3VideoControl_HSYNC_MASK | | ||
3193 | PM3VideoControl_BLANK_ACTIVE_LOW); | ||
3194 | break; | ||
3195 | case VESA_VSYNC_SUSPEND: | ||
3196 | video = video & ~(PM3VideoControl_VSYNC_MASK | | ||
3197 | PM3VideoControl_BLANK_ACTIVE_LOW); | ||
3198 | break; | ||
3199 | case VESA_POWERDOWN: | ||
3200 | video = video & ~(PM3VideoControl_HSYNC_MASK | | ||
3201 | PM3VideoControl_VSYNC_MASK | | ||
3202 | PM3VideoControl_BLANK_ACTIVE_LOW); | ||
3203 | break; | ||
3204 | default: | ||
3205 | DPRINTK(1, "Unsupported blanking %d\n", | ||
3206 | blank_mode); | ||
3207 | return (1); | ||
3208 | break; | ||
3209 | } | ||
3210 | } | ||
3211 | |||
3212 | PM3_SLOW_WRITE_REG(PM3VideoControl, video); | ||
3213 | |||
3214 | return (0); | ||
3215 | } | ||
3216 | |||
3217 | static void pm3fb_set_disp(const void *par, struct display *disp, | ||
3218 | struct fb_info_gen *info) | ||
3219 | { | ||
3220 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; | ||
3221 | struct pm3fb_par *p = (struct pm3fb_par *) par; | ||
3222 | u32 flags; | ||
3223 | |||
3224 | DTRACE; | ||
3225 | |||
3226 | local_irq_save(flags); | ||
3227 | info->info.screen_base = l_fb_info->v_fb; | ||
3228 | switch (p->depth) { | ||
3229 | #ifdef FBCON_HAS_CFB8 | ||
3230 | case 8: | ||
3231 | #ifdef PM3FB_USE_ACCEL | ||
3232 | if (!(noaccel[l_fb_info->board_num])) | ||
3233 | disp->dispsw = &pm3fb_cfb8; | ||
3234 | else | ||
3235 | #endif /* PM3FB_USE_ACCEL */ | ||
3236 | disp->dispsw = &fbcon_cfb8; | ||
3237 | break; | 872 | break; |
3238 | #endif | 873 | case FB_BLANK_NORMAL: |
3239 | #ifdef FBCON_HAS_CFB16 | 874 | video &= ~(PM3VideoControl_ENABLE); |
3240 | case 12: | ||
3241 | #ifdef PM3FB_USE_ACCEL | ||
3242 | if (!(noaccel[l_fb_info->board_num])) | ||
3243 | disp->dispsw = &pm3fb_cfb16; | ||
3244 | else | ||
3245 | #endif /* PM3FB_USE_ACCEL */ | ||
3246 | disp->dispsw = &fbcon_cfb16; | ||
3247 | disp->dispsw_data = l_fb_info->cmap.cmap12; | ||
3248 | break; | 875 | break; |
3249 | case 15: | 876 | case FB_BLANK_HSYNC_SUSPEND: |
3250 | #ifdef PM3FB_USE_ACCEL | 877 | video &= ~(PM3VideoControl_HSYNC_MASK | |
3251 | if (!(noaccel[l_fb_info->board_num])) | 878 | PM3VideoControl_BLANK_ACTIVE_LOW); |
3252 | disp->dispsw = &pm3fb_cfb16; | ||
3253 | else | ||
3254 | #endif /* PM3FB_USE_ACCEL */ | ||
3255 | disp->dispsw = &fbcon_cfb16; | ||
3256 | disp->dispsw_data = l_fb_info->cmap.cmap15; | ||
3257 | break; | 879 | break; |
3258 | case 16: | 880 | case FB_BLANK_VSYNC_SUSPEND: |
3259 | #ifdef PM3FB_USE_ACCEL | 881 | video &= ~(PM3VideoControl_VSYNC_MASK | |
3260 | if (!(noaccel[l_fb_info->board_num])) | 882 | PM3VideoControl_BLANK_ACTIVE_LOW); |
3261 | disp->dispsw = &pm3fb_cfb16; | ||
3262 | else | ||
3263 | #endif /* PM3FB_USE_ACCEL */ | ||
3264 | disp->dispsw = &fbcon_cfb16; | ||
3265 | disp->dispsw_data = l_fb_info->cmap.cmap16; | ||
3266 | break; | 883 | break; |
3267 | #endif | 884 | case FB_BLANK_POWERDOWN: |
3268 | #ifdef FBCON_HAS_CFB32 | 885 | video &= ~(PM3VideoControl_HSYNC_MASK | |
3269 | case 32: | 886 | PM3VideoControl_VSYNC_MASK | |
3270 | #ifdef PM3FB_USE_ACCEL | 887 | PM3VideoControl_BLANK_ACTIVE_LOW); |
3271 | if (!(noaccel[l_fb_info->board_num])) | ||
3272 | disp->dispsw = &pm3fb_cfb32; | ||
3273 | else | ||
3274 | #endif /* PM3FB_USE_ACCEL */ | ||
3275 | disp->dispsw = &fbcon_cfb32; | ||
3276 | disp->dispsw_data = l_fb_info->cmap.cmap32; | ||
3277 | break; | 888 | break; |
3278 | #endif /* FBCON_HAS_CFB32 */ | ||
3279 | default: | 889 | default: |
3280 | disp->dispsw = &fbcon_dummy; | 890 | DPRINTK("Unsupported blanking %d\n", blank_mode); |
3281 | DPRINTK(1, "Invalid depth, using fbcon_dummy\n"); | 891 | return 1; |
3282 | break; | ||
3283 | } | 892 | } |
3284 | local_irq_restore(flags); | 893 | |
894 | PM3_WAIT(par, 1); | ||
895 | PM3_WRITE_REG(par,PM3VideoControl, video); | ||
896 | return 0; | ||
3285 | } | 897 | } |
3286 | 898 | ||
3287 | /* */ | 899 | /* |
3288 | static void pm3fb_detect(void) | 900 | * Frame buffer operations |
3289 | { | 901 | */ |
3290 | struct pci_dev *dev_array[PM3_MAX_BOARD]; | ||
3291 | struct pci_dev *dev = NULL; | ||
3292 | struct pm3fb_info *l_fb_info = &(fb_info[0]); | ||
3293 | unsigned long i, j, done; | ||
3294 | 902 | ||
3295 | DTRACE; | 903 | static struct fb_ops pm3fb_ops = { |
904 | .owner = THIS_MODULE, | ||
905 | .fb_check_var = pm3fb_check_var, | ||
906 | .fb_set_par = pm3fb_set_par, | ||
907 | .fb_setcolreg = pm3fb_setcolreg, | ||
908 | .fb_pan_display = pm3fb_pan_display, | ||
909 | .fb_fillrect = pm3fb_fillrect, | ||
910 | .fb_copyarea = cfb_copyarea, | ||
911 | .fb_imageblit = cfb_imageblit, | ||
912 | .fb_blank = pm3fb_blank, | ||
913 | .fb_sync = pm3fb_sync, | ||
914 | }; | ||
3296 | 915 | ||
3297 | for (i = 0; i < PM3_MAX_BOARD; i++) { | 916 | /* ------------------------------------------------------------------------- */ |
3298 | dev_array[i] = NULL; | ||
3299 | fb_info[i].dev = NULL; | ||
3300 | } | ||
3301 | 917 | ||
3302 | dev = pci_get_device(PCI_VENDOR_ID_3DLABS, | 918 | /* |
3303 | PCI_DEVICE_ID_3DLABS_PERMEDIA3, dev); | 919 | * Initialization |
920 | */ | ||
3304 | 921 | ||
3305 | for (i = 0; ((i < PM3_MAX_BOARD) && dev); i++) { | 922 | /* mmio register are already mapped when this function is called */ |
3306 | dev_array[i] = dev; | 923 | /* the pm3fb_fix.smem_start is also set */ |
3307 | dev = pci_get_device(PCI_VENDOR_ID_3DLABS, | 924 | static unsigned long pm3fb_size_memory(struct pm3_par *par) |
3308 | PCI_DEVICE_ID_3DLABS_PERMEDIA3, dev); | 925 | { |
3309 | } | 926 | unsigned long memsize = 0, tempBypass, i, temp1, temp2; |
927 | unsigned char __iomem *screen_mem; | ||
3310 | 928 | ||
3311 | if (dev) { /* more than PM3_MAX_BOARD */ | 929 | pm3fb_fix.smem_len = 64 * 1024l * 1024; /* request full aperture size */ |
3312 | printk(KERN_WARNING "pm3fb: Warning: more than %d boards found\n", | 930 | /* Linear frame buffer - request region and map it. */ |
3313 | PM3_MAX_BOARD); | 931 | if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len, |
932 | "pm3fb smem")) { | ||
933 | printk(KERN_WARNING "pm3fb: Can't reserve smem.\n"); | ||
934 | return 0; | ||
3314 | } | 935 | } |
3315 | 936 | screen_mem = | |
3316 | if (!dev_array[0]) { /* not a single board, abort */ | 937 | ioremap_nocache(pm3fb_fix.smem_start, pm3fb_fix.smem_len); |
3317 | return; | 938 | if (!screen_mem) { |
939 | printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n"); | ||
940 | release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); | ||
941 | return 0; | ||
3318 | } | 942 | } |
3319 | 943 | ||
3320 | /* allocate user-defined boards */ | 944 | /* TODO: card-specific stuff, *before* accessing *any* FB memory */ |
3321 | for (i = 0; i < PM3_MAX_BOARD; i++) { | 945 | /* For Appian Jeronimo 2000 board second head */ |
3322 | if ((bus[i] >= 0) && (slot[i] >= 0) && (func[i] >= 0)) { | 946 | |
3323 | for (j = 0; j < PM3_MAX_BOARD; j++) { | 947 | tempBypass = PM3_READ_REG(par, PM3MemBypassWriteMask); |
3324 | if ((dev_array[j] != NULL) && | 948 | |
3325 | (dev_array[j]->bus->number == bus[i]) | 949 | DPRINTK("PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass); |
3326 | && (PCI_SLOT(dev_array[j]->devfn) == | 950 | |
3327 | slot[i]) | 951 | PM3_WAIT(par, 1); |
3328 | && (PCI_FUNC(dev_array[j]->devfn) == | 952 | PM3_WRITE_REG(par, PM3MemBypassWriteMask, 0xFFFFFFFF); |
3329 | func[i])) { | 953 | |
3330 | fb_info[i].dev = dev_array[j]; | 954 | /* pm3 split up memory, replicates, and do a lot of nasty stuff IMHO ;-) */ |
3331 | dev_array[j] = NULL; | 955 | for (i = 0; i < 32; i++) { |
3332 | } | 956 | fb_writel(i * 0x00345678, |
3333 | } | 957 | (screen_mem + (i * 1048576))); |
3334 | } | 958 | mb(); |
959 | temp1 = fb_readl((screen_mem + (i * 1048576))); | ||
960 | |||
961 | /* Let's check for wrapover, write will fail at 16MB boundary */ | ||
962 | if (temp1 == (i * 0x00345678)) | ||
963 | memsize = i; | ||
964 | else | ||
965 | break; | ||
3335 | } | 966 | } |
3336 | /* allocate remaining boards */ | 967 | |
3337 | for (i = 0; i < PM3_MAX_BOARD; i++) { | 968 | DPRINTK("First detect pass already got %ld MB\n", memsize + 1); |
3338 | if (fb_info[i].dev == NULL) { | 969 | |
3339 | done = 0; | 970 | if (memsize + 1 == i) { |
3340 | for (j = 0; ((j < PM3_MAX_BOARD) && (!done)); j++) { | 971 | for (i = 0; i < 32; i++) { |
3341 | if (dev_array[j] != NULL) { | 972 | /* Clear first 32MB ; 0 is 0, no need to byteswap */ |
3342 | fb_info[i].dev = dev_array[j]; | 973 | writel(0x0000000, (screen_mem + (i * 1048576))); |
3343 | dev_array[j] = NULL; | ||
3344 | done = 1; | ||
3345 | } | ||
3346 | } | ||
3347 | } | 974 | } |
3348 | } | 975 | wmb(); |
3349 | 976 | ||
3350 | /* at that point, all PCI Permedia3 are detected and allocated */ | 977 | for (i = 32; i < 64; i++) { |
3351 | /* now, initialize... or not */ | 978 | fb_writel(i * 0x00345678, |
3352 | for (i = 0; i < PM3_MAX_BOARD; i++) { | 979 | (screen_mem + (i * 1048576))); |
3353 | l_fb_info = &(fb_info[i]); | 980 | mb(); |
3354 | if (l_fb_info->dev && !disable[i]) { /* PCI device was found and not disabled by user */ | 981 | temp1 = |
3355 | DPRINTK(2, | 982 | fb_readl((screen_mem + (i * 1048576))); |
3356 | "found @%lx Vendor %lx Device %lx ; base @ : %lx - %lx - %lx - %lx - %lx - %lx, irq %ld\n", | 983 | temp2 = |
3357 | (unsigned long) l_fb_info->dev, | 984 | fb_readl((screen_mem + ((i - 32) * 1048576))); |
3358 | (unsigned long) l_fb_info->dev->vendor, | 985 | /* different value, different RAM... */ |
3359 | (unsigned long) l_fb_info->dev->device, | 986 | if ((temp1 == (i * 0x00345678)) && (temp2 == 0)) |
3360 | (unsigned long) | 987 | memsize = i; |
3361 | pci_resource_start(l_fb_info->dev, 0), | 988 | else |
3362 | (unsigned long) | 989 | break; |
3363 | pci_resource_start(l_fb_info->dev, 1), | ||
3364 | (unsigned long) | ||
3365 | pci_resource_start(l_fb_info->dev, 2), | ||
3366 | (unsigned long) | ||
3367 | pci_resource_start(l_fb_info->dev, 3), | ||
3368 | (unsigned long) | ||
3369 | pci_resource_start(l_fb_info->dev, 4), | ||
3370 | (unsigned long) | ||
3371 | pci_resource_start(l_fb_info->dev, 5), | ||
3372 | (unsigned long) l_fb_info->dev->irq); | ||
3373 | |||
3374 | l_fb_info->pIOBase = | ||
3375 | (unsigned char *) | ||
3376 | pci_resource_start(l_fb_info->dev, 0); | ||
3377 | #ifdef __BIG_ENDIAN | ||
3378 | l_fb_info->pIOBase += PM3_REGS_SIZE; | ||
3379 | #endif | ||
3380 | l_fb_info->vIOBase = (unsigned char *) -1; | ||
3381 | l_fb_info->p_fb = | ||
3382 | (unsigned char *) | ||
3383 | pci_resource_start(l_fb_info->dev, 1); | ||
3384 | l_fb_info->v_fb = (unsigned char *) -1; | ||
3385 | |||
3386 | if (!request_mem_region | ||
3387 | ((unsigned long)l_fb_info->p_fb, 64 * 1024 * 1024, /* request full aperture size */ | ||
3388 | "pm3fb")) { | ||
3389 | printk | ||
3390 | (KERN_ERR "pm3fb: Error: couldn't request framebuffer memory, board #%ld\n", | ||
3391 | l_fb_info->board_num); | ||
3392 | continue; | ||
3393 | } | ||
3394 | if (!request_mem_region | ||
3395 | ((unsigned long)l_fb_info->pIOBase, PM3_REGS_SIZE, | ||
3396 | "pm3fb I/O regs")) { | ||
3397 | printk | ||
3398 | (KERN_ERR "pm3fb: Error: couldn't request IObase memory, board #%ld\n", | ||
3399 | l_fb_info->board_num); | ||
3400 | continue; | ||
3401 | } | ||
3402 | if (forcesize[l_fb_info->board_num]) | ||
3403 | l_fb_info->fb_size = forcesize[l_fb_info->board_num]; | ||
3404 | |||
3405 | l_fb_info->fb_size = | ||
3406 | pm3fb_size_memory(l_fb_info); | ||
3407 | if (l_fb_info->fb_size) { | ||
3408 | (void) pci_enable_device(l_fb_info->dev); | ||
3409 | pm3fb_common_init(l_fb_info); | ||
3410 | } else | ||
3411 | printk(KERN_ERR "pm3fb: memory problem, not enabling board #%ld\n", l_fb_info->board_num); | ||
3412 | } | 990 | } |
3413 | } | 991 | } |
3414 | } | 992 | DPRINTK("Second detect pass got %ld MB\n", memsize + 1); |
3415 | 993 | ||
3416 | static int pm3fb_pan_display(const struct fb_var_screeninfo *var, | 994 | PM3_WAIT(par, 1); |
3417 | struct fb_info_gen *info) | 995 | PM3_WRITE_REG(par, PM3MemBypassWriteMask, tempBypass); |
3418 | { | ||
3419 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; | ||
3420 | 996 | ||
3421 | DTRACE; | 997 | iounmap(screen_mem); |
998 | release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); | ||
999 | memsize = 1048576 * (memsize + 1); | ||
3422 | 1000 | ||
3423 | if (!current_par_valid[l_fb_info->board_num]) | 1001 | DPRINTK("Returning 0x%08lx bytes\n", memsize); |
3424 | return -EINVAL; | ||
3425 | 1002 | ||
3426 | l_fb_info->current_par->base = /* in 128 bits chunk - i.e. AFTER Shiftbpp */ | 1003 | return memsize; |
3427 | pm3fb_Shiftbpp(l_fb_info, | ||
3428 | l_fb_info->current_par->depth, | ||
3429 | (var->yoffset * l_fb_info->current_par->width) + | ||
3430 | var->xoffset); | ||
3431 | PM3_SLOW_WRITE_REG(PM3ScreenBase, l_fb_info->current_par->base); | ||
3432 | return 0; | ||
3433 | } | 1004 | } |
3434 | 1005 | ||
3435 | static int pm3fb_ioctl(struct fb_info *info, u_int cmd, u_long arg) | 1006 | static int __devinit pm3fb_probe(struct pci_dev *dev, |
1007 | const struct pci_device_id *ent) | ||
3436 | { | 1008 | { |
3437 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; | 1009 | struct fb_info *info; |
3438 | u32 cm, i; | 1010 | struct pm3_par *par; |
3439 | #ifdef PM3FB_MASTER_DEBUG | 1011 | struct device* device = &dev->dev; /* for pci drivers */ |
3440 | char cc[3]; | 1012 | int err, retval = -ENXIO; |
3441 | #endif /* PM3FB_MASTER_DEBUG */ | ||
3442 | 1013 | ||
3443 | switch(cmd) | 1014 | err = pci_enable_device(dev); |
3444 | { | 1015 | if (err) { |
3445 | #ifdef PM3FB_MASTER_DEBUG | 1016 | printk(KERN_WARNING "pm3fb: Can't enable PCI dev: %d\n", err); |
3446 | case PM3FBIO_CLEARMEMORY: | 1017 | return err; |
3447 | if (copy_from_user(&cm, (void *)arg, sizeof(u32))) | 1018 | } |
3448 | return(-EFAULT); | 1019 | /* |
3449 | pm3fb_clear_memory(l_fb_info, cm); | 1020 | * Dynamically allocate info and par |
3450 | return(0); | 1021 | */ |
3451 | break; | 1022 | info = framebuffer_alloc(sizeof(struct pm3_par), device); |
3452 | 1023 | ||
3453 | case PM3FBIO_CLEARCMAP: | 1024 | if (!info) |
3454 | if (copy_from_user(cc, (void*)arg, 3 * sizeof(char))) | 1025 | return -ENOMEM; |
3455 | return(-EFAULT); | 1026 | par = info->par; |
3456 | pm3fb_clear_colormap(l_fb_info, cc[0], cc[1], cc[2]); | ||
3457 | return(0); | ||
3458 | break; | ||
3459 | #endif /* PM3FB_MASTER_DEBUG */ | ||
3460 | |||
3461 | case PM3FBIO_RESETCHIP: | ||
3462 | cm = 1; | ||
3463 | PM3_SLOW_WRITE_REG(PM3ResetStatus, 1); | ||
3464 | for (i = 0 ; (i < 10000) && cm ; i++) | ||
3465 | { | ||
3466 | PM3_DELAY(10); | ||
3467 | cm = PM3_READ_REG(PM3ResetStatus); | ||
3468 | } | ||
3469 | if (cm) | ||
3470 | { | ||
3471 | printk(KERN_ERR "pm3fb: chip reset failed with status 0x%x\n", cm); | ||
3472 | return(-EIO); | ||
3473 | } | ||
3474 | /* first thing first, reload memory timings */ | ||
3475 | pm3fb_write_memory_timings(l_fb_info); | ||
3476 | #ifdef PM3FB_USE_ACCEL | ||
3477 | pm3fb_init_engine(l_fb_info); | ||
3478 | #endif /* PM3FB_USE_ACCEL */ | ||
3479 | pm3fb_write_mode(l_fb_info); | ||
3480 | return(0); | ||
3481 | break; | ||
3482 | 1027 | ||
3483 | default: | 1028 | /* |
3484 | DPRINTK(2, "unknown ioctl: %d (%x)\n", cmd, cmd); | 1029 | * Here we set the screen_base to the virtual memory address |
3485 | return(-EINVAL); | 1030 | * for the framebuffer. |
1031 | */ | ||
1032 | pm3fb_fix.mmio_start = pci_resource_start(dev, 0); | ||
1033 | pm3fb_fix.mmio_len = PM3_REGS_SIZE; | ||
1034 | |||
1035 | /* Registers - request region and map it. */ | ||
1036 | if (!request_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len, | ||
1037 | "pm3fb regbase")) { | ||
1038 | printk(KERN_WARNING "pm3fb: Can't reserve regbase.\n"); | ||
1039 | goto err_exit_neither; | ||
1040 | } | ||
1041 | par->v_regs = | ||
1042 | ioremap_nocache(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len); | ||
1043 | if (!par->v_regs) { | ||
1044 | printk(KERN_WARNING "pm3fb: Can't remap %s register area.\n", | ||
1045 | pm3fb_fix.id); | ||
1046 | release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len); | ||
1047 | goto err_exit_neither; | ||
1048 | } | ||
1049 | |||
1050 | #if defined(__BIG_ENDIAN) | ||
1051 | pm3fb_fix.mmio_start += PM3_REGS_SIZE; | ||
1052 | DPRINTK("Adjusting register base for big-endian.\n"); | ||
1053 | #endif | ||
1054 | /* Linear frame buffer - request region and map it. */ | ||
1055 | pm3fb_fix.smem_start = pci_resource_start(dev, 1); | ||
1056 | pm3fb_fix.smem_len = pm3fb_size_memory(par); | ||
1057 | if (!pm3fb_fix.smem_len) | ||
1058 | { | ||
1059 | printk(KERN_WARNING "pm3fb: Can't find memory on board.\n"); | ||
1060 | goto err_exit_mmio; | ||
3486 | } | 1061 | } |
3487 | } | 1062 | if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len, |
3488 | 1063 | "pm3fb smem")) { | |
3489 | /* ****************************************** */ | 1064 | printk(KERN_WARNING "pm3fb: Can't reserve smem.\n"); |
3490 | /* ***** standard FB API init functions ***** */ | 1065 | goto err_exit_mmio; |
3491 | /* ****************************************** */ | 1066 | } |
1067 | info->screen_base = | ||
1068 | ioremap_nocache(pm3fb_fix.smem_start, pm3fb_fix.smem_len); | ||
1069 | if (!info->screen_base) { | ||
1070 | printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n"); | ||
1071 | release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); | ||
1072 | goto err_exit_mmio; | ||
1073 | } | ||
1074 | info->screen_size = pm3fb_fix.smem_len; | ||
3492 | 1075 | ||
3493 | int __init pm3fb_setup(char *options) | 1076 | info->fbops = &pm3fb_ops; |
3494 | { | ||
3495 | long opsi = strlen(options); | ||
3496 | 1077 | ||
3497 | DTRACE; | 1078 | par->video = PM3_READ_REG(par, PM3VideoControl); |
3498 | 1079 | ||
3499 | memcpy(g_options, options, | 1080 | info->fix = pm3fb_fix; |
3500 | ((opsi + 1) > | 1081 | info->pseudo_palette = par->palette; |
3501 | PM3_OPTIONS_SIZE) ? PM3_OPTIONS_SIZE : (opsi + 1)); | 1082 | info->flags = FBINFO_DEFAULT | |
3502 | g_options[PM3_OPTIONS_SIZE - 1] = 0; | 1083 | FBINFO_HWACCEL_FILLRECT;/* | FBINFO_HWACCEL_YPAN;*/ |
3503 | 1084 | ||
3504 | return (0); | 1085 | /* |
3505 | } | 1086 | * This should give a reasonable default video mode. The following is |
1087 | * done when we can set a video mode. | ||
1088 | */ | ||
1089 | if (!mode_option) | ||
1090 | mode_option = "640x480@60"; | ||
3506 | 1091 | ||
3507 | int __init pm3fb_init(void) | 1092 | retval = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); |
3508 | { | ||
3509 | DTRACE; | ||
3510 | 1093 | ||
3511 | DPRINTK(2, "This is pm3fb.c, CVS version: $Header: /cvsroot/linux/drivers/video/pm3fb.c,v 1.1 2002/02/25 19:11:06 marcelo Exp $"); | 1094 | if (!retval || retval == 4) { |
1095 | retval = -EINVAL; | ||
1096 | goto err_exit_both; | ||
1097 | } | ||
3512 | 1098 | ||
3513 | pm3fb_real_setup(g_options); | 1099 | if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { |
1100 | retval = -ENOMEM; | ||
1101 | goto err_exit_both; | ||
1102 | } | ||
3514 | 1103 | ||
3515 | pm3fb_detect(); | 1104 | /* |
1105 | * For drivers that can... | ||
1106 | */ | ||
1107 | pm3fb_check_var(&info->var, info); | ||
3516 | 1108 | ||
3517 | if (!fb_info[0].dev) { /* not even one board ??? */ | 1109 | if (register_framebuffer(info) < 0) { |
3518 | DPRINTK(1, "No PCI Permedia3 board detected\n"); | 1110 | retval = -EINVAL; |
1111 | goto err_exit_all; | ||
3519 | } | 1112 | } |
3520 | return (0); | 1113 | printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, |
3521 | } | 1114 | info->fix.id); |
1115 | pci_set_drvdata(dev, info); | ||
1116 | return 0; | ||
3522 | 1117 | ||
3523 | /* ************************* */ | 1118 | err_exit_all: |
3524 | /* **** Module support ***** */ | 1119 | fb_dealloc_cmap(&info->cmap); |
3525 | /* ************************* */ | 1120 | err_exit_both: |
3526 | 1121 | iounmap(info->screen_base); | |
3527 | #ifdef MODULE | 1122 | release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); |
3528 | MODULE_AUTHOR("Romain Dolbeau"); | 1123 | err_exit_mmio: |
3529 | MODULE_DESCRIPTION("Permedia3 framebuffer device driver"); | 1124 | iounmap(par->v_regs); |
3530 | static char *mode[PM3_MAX_BOARD]; | 1125 | release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len); |
3531 | module_param_array(mode, charp, NULL, 0); | 1126 | err_exit_neither: |
3532 | MODULE_PARM_DESC(mode,"video mode"); | 1127 | framebuffer_release(info); |
3533 | module_param_array(disable, short, NULL, 0); | 1128 | return retval; |
3534 | MODULE_PARM_DESC(disable,"disable board"); | 1129 | } |
3535 | static short off[PM3_MAX_BOARD]; | ||
3536 | module_param_array(off, short, NULL, 0); | ||
3537 | MODULE_PARM_DESC(off,"disable board"); | ||
3538 | static char *pciid[PM3_MAX_BOARD]; | ||
3539 | module_param_array(pciid, charp, NULL, 0); | ||
3540 | MODULE_PARM_DESC(pciid,"board PCI Id"); | ||
3541 | module_param_array(noaccel, short, NULL, 0); | ||
3542 | MODULE_PARM_DESC(noaccel,"disable accel"); | ||
3543 | static char *font[PM3_MAX_BOARD]; | ||
3544 | module_param_array(font, charp, NULL, 0); | ||
3545 | MODULE_PARM_DESC(font,"choose font"); | ||
3546 | module_param(depth, short, NULL, 0); | ||
3547 | MODULE_PARM_DESC(depth,"boot-time depth"); | ||
3548 | module_param(printtimings, short, NULL, 0); | ||
3549 | MODULE_PARM_DESC(printtimings, "print the memory timings of the card(s)"); | ||
3550 | module_param(forcesize, short, NULL, 0); | ||
3551 | MODULE_PARM_DESC(forcesize, "force specified memory size"); | ||
3552 | /* | ||
3553 | MODULE_SUPPORTED_DEVICE("Permedia3 PCI boards") | ||
3554 | MODULE_GENERIC_TABLE(gtype,name) | ||
3555 | MODULE_DEVICE_TABLE(type,name) | ||
3556 | */ | ||
3557 | 1130 | ||
3558 | void pm3fb_build_options(void) | 1131 | /* |
1132 | * Cleanup | ||
1133 | */ | ||
1134 | static void __devexit pm3fb_remove(struct pci_dev *dev) | ||
3559 | { | 1135 | { |
3560 | int i; | 1136 | struct fb_info *info = pci_get_drvdata(dev); |
3561 | char ts[128]; | ||
3562 | 1137 | ||
3563 | strcpy(g_options, "pm3fb"); | 1138 | if (info) { |
3564 | for (i = 0; i < PM3_MAX_BOARD ; i++) | 1139 | struct fb_fix_screeninfo *fix = &info->fix; |
3565 | { | 1140 | struct pm3_par *par = info->par; |
3566 | if (mode[i]) | 1141 | |
3567 | { | 1142 | unregister_framebuffer(info); |
3568 | sprintf(ts, ",mode:%d:%s", i, mode[i]); | 1143 | fb_dealloc_cmap(&info->cmap); |
3569 | strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); | 1144 | |
3570 | } | 1145 | iounmap(info->screen_base); |
3571 | if (disable[i] || off[i]) | 1146 | release_mem_region(fix->smem_start, fix->smem_len); |
3572 | { | 1147 | iounmap(par->v_regs); |
3573 | sprintf(ts, ",disable:%d:", i); | 1148 | release_mem_region(fix->mmio_start, fix->mmio_len); |
3574 | strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); | 1149 | |
3575 | } | 1150 | pci_set_drvdata(dev, NULL); |
3576 | if (pciid[i]) | 1151 | framebuffer_release(info); |
3577 | { | ||
3578 | sprintf(ts, ",pciid:%d:%s", i, pciid[i]); | ||
3579 | strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); | ||
3580 | } | ||
3581 | if (noaccel[i]) | ||
3582 | { | ||
3583 | sprintf(ts, ",noaccel:%d:", i); | ||
3584 | strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); | ||
3585 | } | ||
3586 | if (font[i]) | ||
3587 | { | ||
3588 | sprintf(ts, ",font:%d:%s", i, font[i]); | ||
3589 | strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); | ||
3590 | } | ||
3591 | if (depth[i]) | ||
3592 | { | ||
3593 | sprintf(ts, ",depth:%d:%d", i, depth[i]); | ||
3594 | strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); | ||
3595 | } | ||
3596 | } | 1152 | } |
3597 | g_options[PM3_OPTIONS_SIZE - 1] = '\0'; | ||
3598 | DPRINTK(1, "pm3fb use options: %s\n", g_options); | ||
3599 | } | 1153 | } |
3600 | 1154 | ||
3601 | int init_module(void) | 1155 | static struct pci_device_id pm3fb_id_table[] = { |
3602 | { | 1156 | { PCI_VENDOR_ID_3DLABS, 0x0a, |
3603 | DTRACE; | 1157 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, |
1158 | { 0, } | ||
1159 | }; | ||
3604 | 1160 | ||
3605 | pm3fb_build_options(); | 1161 | /* For PCI drivers */ |
1162 | static struct pci_driver pm3fb_driver = { | ||
1163 | .name = "pm3fb", | ||
1164 | .id_table = pm3fb_id_table, | ||
1165 | .probe = pm3fb_probe, | ||
1166 | .remove = __devexit_p(pm3fb_remove), | ||
1167 | }; | ||
3606 | 1168 | ||
3607 | pm3fb_init(); | 1169 | MODULE_DEVICE_TABLE(pci, pm3fb_id_table); |
3608 | 1170 | ||
3609 | return 0; | 1171 | static int __init pm3fb_init(void) |
1172 | { | ||
1173 | #ifndef MODULE | ||
1174 | if (fb_get_options("pm3fb", NULL)) | ||
1175 | return -ENODEV; | ||
1176 | #endif | ||
1177 | return pci_register_driver(&pm3fb_driver); | ||
3610 | } | 1178 | } |
3611 | 1179 | ||
3612 | void cleanup_module(void) | 1180 | static void __exit pm3fb_exit(void) |
3613 | { | 1181 | { |
3614 | DTRACE; | 1182 | pci_unregister_driver(&pm3fb_driver); |
3615 | { | ||
3616 | unsigned long i; | ||
3617 | struct pm3fb_info *l_fb_info; | ||
3618 | for (i = 0; i < PM3_MAX_BOARD; i++) { | ||
3619 | l_fb_info = &(fb_info[i]); | ||
3620 | pci_dev_put(l_fb_info->dev); | ||
3621 | if (l_fb_info->dev != NULL && !(disable[l_fb_info->board_num])) { | ||
3622 | if (l_fb_info->vIOBase != (unsigned char *) -1) { | ||
3623 | pm3fb_unmapIO(l_fb_info); | ||
3624 | release_mem_region(l_fb_info->p_fb, | ||
3625 | l_fb_info->fb_size); | ||
3626 | release_mem_region(l_fb_info->pIOBase, | ||
3627 | PM3_REGS_SIZE); | ||
3628 | } | ||
3629 | unregister_framebuffer(&l_fb_info->gen.info); | ||
3630 | } | ||
3631 | } | ||
3632 | } | ||
3633 | } | 1183 | } |
3634 | #endif /* MODULE */ | 1184 | |
1185 | module_init(pm3fb_init); | ||
1186 | module_exit(pm3fb_exit); | ||
1187 | |||
1188 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index 9756a728b74f..646ec823c168 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c | |||
@@ -27,7 +27,6 @@ | |||
27 | #include <linux/vmalloc.h> | 27 | #include <linux/vmalloc.h> |
28 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
29 | #include <linux/interrupt.h> | 29 | #include <linux/interrupt.h> |
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/console.h> | 30 | #include <linux/console.h> |
32 | #include <linux/ioctl.h> | 31 | #include <linux/ioctl.h> |
33 | #include <linux/notifier.h> | 32 | #include <linux/notifier.h> |
@@ -46,6 +45,9 @@ | |||
46 | #include <asm/ps3fb.h> | 45 | #include <asm/ps3fb.h> |
47 | #include <asm/ps3.h> | 46 | #include <asm/ps3.h> |
48 | 47 | ||
48 | |||
49 | #define DEVICE_NAME "ps3fb" | ||
50 | |||
49 | #ifdef PS3FB_DEBUG | 51 | #ifdef PS3FB_DEBUG |
50 | #define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ##args) | 52 | #define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ##args) |
51 | #else | 53 | #else |
@@ -126,7 +128,6 @@ struct gpu_driver_info { | |||
126 | 128 | ||
127 | struct ps3fb_priv { | 129 | struct ps3fb_priv { |
128 | unsigned int irq_no; | 130 | unsigned int irq_no; |
129 | void *dev; | ||
130 | 131 | ||
131 | u64 context_handle, memory_handle; | 132 | u64 context_handle, memory_handle; |
132 | void *xdr_ea; | 133 | void *xdr_ea; |
@@ -171,7 +172,7 @@ static const struct ps3fb_res_table ps3fb_res[] = { | |||
171 | { 0, 0, 0, 0 , 0} }; | 172 | { 0, 0, 0, 0 , 0} }; |
172 | 173 | ||
173 | /* default resolution */ | 174 | /* default resolution */ |
174 | #define GPU_RES_INDEX 0 /* 720 x 480 */ | 175 | #define GPU_RES_INDEX 0 /* 720 x 480 */ |
175 | 176 | ||
176 | static const struct fb_videomode ps3fb_modedb[] = { | 177 | static const struct fb_videomode ps3fb_modedb[] = { |
177 | /* 60 Hz broadcast modes (modes "1" to "5") */ | 178 | /* 60 Hz broadcast modes (modes "1" to "5") */ |
@@ -298,10 +299,9 @@ static const struct fb_videomode ps3fb_modedb[] = { | |||
298 | #define FB_OFF(i) (GPU_OFFSET - VP_OFF(i) % GPU_OFFSET) | 299 | #define FB_OFF(i) (GPU_OFFSET - VP_OFF(i) % GPU_OFFSET) |
299 | 300 | ||
300 | static int ps3fb_mode; | 301 | static int ps3fb_mode; |
301 | module_param(ps3fb_mode, bool, 0); | 302 | module_param(ps3fb_mode, int, 0); |
302 | |||
303 | static char *mode_option __initdata; | ||
304 | 303 | ||
304 | static char *mode_option __devinitdata; | ||
305 | 305 | ||
306 | static int ps3fb_get_res_table(u32 xres, u32 yres) | 306 | static int ps3fb_get_res_table(u32 xres, u32 yres) |
307 | { | 307 | { |
@@ -681,15 +681,15 @@ int ps3fb_wait_for_vsync(u32 crtc) | |||
681 | 681 | ||
682 | EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync); | 682 | EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync); |
683 | 683 | ||
684 | void ps3fb_flip_ctl(int on) | 684 | void ps3fb_flip_ctl(int on, void *data) |
685 | { | 685 | { |
686 | struct ps3fb_priv *priv = data; | ||
686 | if (on) | 687 | if (on) |
687 | atomic_dec_if_positive(&ps3fb.ext_flip); | 688 | atomic_dec_if_positive(&priv->ext_flip); |
688 | else | 689 | else |
689 | atomic_inc(&ps3fb.ext_flip); | 690 | atomic_inc(&priv->ext_flip); |
690 | } | 691 | } |
691 | 692 | ||
692 | EXPORT_SYMBOL_GPL(ps3fb_flip_ctl); | ||
693 | 693 | ||
694 | /* | 694 | /* |
695 | * ioctl | 695 | * ioctl |
@@ -812,6 +812,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, | |||
812 | 812 | ||
813 | static int ps3fbd(void *arg) | 813 | static int ps3fbd(void *arg) |
814 | { | 814 | { |
815 | set_freezable(); | ||
815 | while (!kthread_should_stop()) { | 816 | while (!kthread_should_stop()) { |
816 | try_to_freeze(); | 817 | try_to_freeze(); |
817 | set_current_state(TASK_INTERRUPTIBLE); | 818 | set_current_state(TASK_INTERRUPTIBLE); |
@@ -851,37 +852,9 @@ static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr) | |||
851 | return IRQ_HANDLED; | 852 | return IRQ_HANDLED; |
852 | } | 853 | } |
853 | 854 | ||
854 | #ifndef MODULE | ||
855 | static int __init ps3fb_setup(char *options) | ||
856 | { | ||
857 | char *this_opt; | ||
858 | int mode = 0; | ||
859 | |||
860 | if (!options || !*options) | ||
861 | return 0; /* no options */ | ||
862 | |||
863 | while ((this_opt = strsep(&options, ",")) != NULL) { | ||
864 | if (!*this_opt) | ||
865 | continue; | ||
866 | if (!strncmp(this_opt, "mode:", 5)) | ||
867 | mode = simple_strtoul(this_opt + 5, NULL, 0); | ||
868 | else | ||
869 | mode_option = this_opt; | ||
870 | } | ||
871 | return mode; | ||
872 | } | ||
873 | #endif /* MODULE */ | ||
874 | |||
875 | /* | ||
876 | * Initialisation | ||
877 | */ | ||
878 | 855 | ||
879 | static void ps3fb_platform_release(struct device *device) | 856 | static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, |
880 | { | 857 | struct ps3_system_bus_device *dev) |
881 | /* This is called when the reference count goes to zero. */ | ||
882 | } | ||
883 | |||
884 | static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev) | ||
885 | { | 858 | { |
886 | int error; | 859 | int error; |
887 | 860 | ||
@@ -897,7 +870,6 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev) | |||
897 | return -EINVAL; | 870 | return -EINVAL; |
898 | } | 871 | } |
899 | 872 | ||
900 | ps3fb.dev = dev; | ||
901 | error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, | 873 | error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, |
902 | &ps3fb.irq_no); | 874 | &ps3fb.irq_no); |
903 | if (error) { | 875 | if (error) { |
@@ -907,7 +879,7 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev) | |||
907 | } | 879 | } |
908 | 880 | ||
909 | error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED, | 881 | error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED, |
910 | "ps3fb vsync", ps3fb.dev); | 882 | DEVICE_NAME, dev); |
911 | if (error) { | 883 | if (error) { |
912 | printk(KERN_ERR "%s: request_irq failed %d\n", __func__, | 884 | printk(KERN_ERR "%s: request_irq failed %d\n", __func__, |
913 | error); | 885 | error); |
@@ -951,12 +923,14 @@ static int ps3fb_xdr_settings(u64 xdr_lpar) | |||
951 | static struct fb_ops ps3fb_ops = { | 923 | static struct fb_ops ps3fb_ops = { |
952 | .fb_open = ps3fb_open, | 924 | .fb_open = ps3fb_open, |
953 | .fb_release = ps3fb_release, | 925 | .fb_release = ps3fb_release, |
926 | .fb_read = fb_sys_read, | ||
927 | .fb_write = fb_sys_write, | ||
954 | .fb_check_var = ps3fb_check_var, | 928 | .fb_check_var = ps3fb_check_var, |
955 | .fb_set_par = ps3fb_set_par, | 929 | .fb_set_par = ps3fb_set_par, |
956 | .fb_setcolreg = ps3fb_setcolreg, | 930 | .fb_setcolreg = ps3fb_setcolreg, |
957 | .fb_fillrect = cfb_fillrect, | 931 | .fb_fillrect = sys_fillrect, |
958 | .fb_copyarea = cfb_copyarea, | 932 | .fb_copyarea = sys_copyarea, |
959 | .fb_imageblit = cfb_imageblit, | 933 | .fb_imageblit = sys_imageblit, |
960 | .fb_mmap = ps3fb_mmap, | 934 | .fb_mmap = ps3fb_mmap, |
961 | .fb_blank = ps3fb_blank, | 935 | .fb_blank = ps3fb_blank, |
962 | .fb_ioctl = ps3fb_ioctl, | 936 | .fb_ioctl = ps3fb_ioctl, |
@@ -964,16 +938,45 @@ static struct fb_ops ps3fb_ops = { | |||
964 | }; | 938 | }; |
965 | 939 | ||
966 | static struct fb_fix_screeninfo ps3fb_fix __initdata = { | 940 | static struct fb_fix_screeninfo ps3fb_fix __initdata = { |
967 | .id = "PS3 FB", | 941 | .id = DEVICE_NAME, |
968 | .type = FB_TYPE_PACKED_PIXELS, | 942 | .type = FB_TYPE_PACKED_PIXELS, |
969 | .visual = FB_VISUAL_TRUECOLOR, | 943 | .visual = FB_VISUAL_TRUECOLOR, |
970 | .accel = FB_ACCEL_NONE, | 944 | .accel = FB_ACCEL_NONE, |
971 | }; | 945 | }; |
972 | 946 | ||
973 | static int __init ps3fb_probe(struct platform_device *dev) | 947 | static int ps3fb_set_sync(void) |
948 | { | ||
949 | int status; | ||
950 | |||
951 | #ifdef HEAD_A | ||
952 | status = lv1_gpu_context_attribute(0x0, | ||
953 | L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, | ||
954 | 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); | ||
955 | if (status) { | ||
956 | printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_SYNC " | ||
957 | "failed: %d\n", __func__, status); | ||
958 | return -1; | ||
959 | } | ||
960 | #endif | ||
961 | #ifdef HEAD_B | ||
962 | status = lv1_gpu_context_attribute(0x0, | ||
963 | L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, | ||
964 | 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); | ||
965 | |||
966 | if (status) { | ||
967 | printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_MODE " | ||
968 | "failed: %d\n", __func__, status); | ||
969 | return -1; | ||
970 | } | ||
971 | #endif | ||
972 | return 0; | ||
973 | } | ||
974 | |||
975 | static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) | ||
974 | { | 976 | { |
975 | struct fb_info *info; | 977 | struct fb_info *info; |
976 | int retval = -ENOMEM; | 978 | int retval = -ENOMEM; |
979 | u32 xres, yres; | ||
977 | u64 ddr_lpar = 0; | 980 | u64 ddr_lpar = 0; |
978 | u64 lpar_dma_control = 0; | 981 | u64 lpar_dma_control = 0; |
979 | u64 lpar_driver_info = 0; | 982 | u64 lpar_driver_info = 0; |
@@ -984,6 +987,30 @@ static int __init ps3fb_probe(struct platform_device *dev) | |||
984 | unsigned long offset; | 987 | unsigned long offset; |
985 | struct task_struct *task; | 988 | struct task_struct *task; |
986 | 989 | ||
990 | status = ps3_open_hv_device(dev); | ||
991 | if (status) { | ||
992 | printk(KERN_ERR "%s: ps3_open_hv_device failed\n", __func__); | ||
993 | goto err; | ||
994 | } | ||
995 | |||
996 | if (!ps3fb_mode) | ||
997 | ps3fb_mode = ps3av_get_mode(); | ||
998 | DPRINTK("ps3av_mode:%d\n", ps3fb_mode); | ||
999 | |||
1000 | if (ps3fb_mode > 0 && | ||
1001 | !ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) { | ||
1002 | ps3fb.res_index = ps3fb_get_res_table(xres, yres); | ||
1003 | DPRINTK("res_index:%d\n", ps3fb.res_index); | ||
1004 | } else | ||
1005 | ps3fb.res_index = GPU_RES_INDEX; | ||
1006 | |||
1007 | atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */ | ||
1008 | atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ | ||
1009 | init_waitqueue_head(&ps3fb.wait_vsync); | ||
1010 | ps3fb.num_frames = 1; | ||
1011 | |||
1012 | ps3fb_set_sync(); | ||
1013 | |||
987 | /* get gpu context handle */ | 1014 | /* get gpu context handle */ |
988 | status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0, | 1015 | status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0, |
989 | &ps3fb.memory_handle, &ddr_lpar); | 1016 | &ps3fb.memory_handle, &ddr_lpar); |
@@ -1027,7 +1054,7 @@ static int __init ps3fb_probe(struct platform_device *dev) | |||
1027 | * leakage into userspace | 1054 | * leakage into userspace |
1028 | */ | 1055 | */ |
1029 | memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size); | 1056 | memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size); |
1030 | info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev); | 1057 | info = framebuffer_alloc(sizeof(u32) * 16, &dev->core); |
1031 | if (!info) | 1058 | if (!info) |
1032 | goto err_free_irq; | 1059 | goto err_free_irq; |
1033 | 1060 | ||
@@ -1040,7 +1067,7 @@ static int __init ps3fb_probe(struct platform_device *dev) | |||
1040 | info->fix.smem_len = ps3fb_videomemory.size - offset; | 1067 | info->fix.smem_len = ps3fb_videomemory.size - offset; |
1041 | info->pseudo_palette = info->par; | 1068 | info->pseudo_palette = info->par; |
1042 | info->par = NULL; | 1069 | info->par = NULL; |
1043 | info->flags = FBINFO_FLAG_DEFAULT; | 1070 | info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST; |
1044 | 1071 | ||
1045 | retval = fb_alloc_cmap(&info->cmap, 256, 0); | 1072 | retval = fb_alloc_cmap(&info->cmap, 256, 0); |
1046 | if (retval < 0) | 1073 | if (retval < 0) |
@@ -1059,19 +1086,20 @@ static int __init ps3fb_probe(struct platform_device *dev) | |||
1059 | if (retval < 0) | 1086 | if (retval < 0) |
1060 | goto err_fb_dealloc; | 1087 | goto err_fb_dealloc; |
1061 | 1088 | ||
1062 | platform_set_drvdata(dev, info); | 1089 | dev->core.driver_data = info; |
1063 | 1090 | ||
1064 | printk(KERN_INFO | 1091 | printk(KERN_INFO |
1065 | "fb%d: PS3 frame buffer device, using %ld KiB of video memory\n", | 1092 | "fb%d: PS3 frame buffer device, using %ld KiB of video memory\n", |
1066 | info->node, ps3fb_videomemory.size >> 10); | 1093 | info->node, ps3fb_videomemory.size >> 10); |
1067 | 1094 | ||
1068 | task = kthread_run(ps3fbd, info, "ps3fbd"); | 1095 | task = kthread_run(ps3fbd, info, DEVICE_NAME); |
1069 | if (IS_ERR(task)) { | 1096 | if (IS_ERR(task)) { |
1070 | retval = PTR_ERR(task); | 1097 | retval = PTR_ERR(task); |
1071 | goto err_unregister_framebuffer; | 1098 | goto err_unregister_framebuffer; |
1072 | } | 1099 | } |
1073 | 1100 | ||
1074 | ps3fb.task = task; | 1101 | ps3fb.task = task; |
1102 | ps3av_register_flip_ctl(ps3fb_flip_ctl, &ps3fb); | ||
1075 | 1103 | ||
1076 | return 0; | 1104 | return 0; |
1077 | 1105 | ||
@@ -1082,7 +1110,7 @@ err_fb_dealloc: | |||
1082 | err_framebuffer_release: | 1110 | err_framebuffer_release: |
1083 | framebuffer_release(info); | 1111 | framebuffer_release(info); |
1084 | err_free_irq: | 1112 | err_free_irq: |
1085 | free_irq(ps3fb.irq_no, ps3fb.dev); | 1113 | free_irq(ps3fb.irq_no, dev); |
1086 | ps3_irq_plug_destroy(ps3fb.irq_no); | 1114 | ps3_irq_plug_destroy(ps3fb.irq_no); |
1087 | err_iounmap_dinfo: | 1115 | err_iounmap_dinfo: |
1088 | iounmap((u8 __iomem *)ps3fb.dinfo); | 1116 | iounmap((u8 __iomem *)ps3fb.dinfo); |
@@ -1094,26 +1122,30 @@ err: | |||
1094 | return retval; | 1122 | return retval; |
1095 | } | 1123 | } |
1096 | 1124 | ||
1097 | static void ps3fb_shutdown(struct platform_device *dev) | 1125 | static int ps3fb_shutdown(struct ps3_system_bus_device *dev) |
1098 | { | 1126 | { |
1099 | ps3fb_flip_ctl(0); /* flip off */ | 1127 | int status; |
1128 | struct fb_info *info = dev->core.driver_data; | ||
1129 | |||
1130 | DPRINTK(" -> %s:%d\n", __func__, __LINE__); | ||
1131 | |||
1132 | ps3fb_flip_ctl(0, &ps3fb); /* flip off */ | ||
1100 | ps3fb.dinfo->irq.mask = 0; | 1133 | ps3fb.dinfo->irq.mask = 0; |
1101 | free_irq(ps3fb.irq_no, ps3fb.dev); | ||
1102 | ps3_irq_plug_destroy(ps3fb.irq_no); | ||
1103 | iounmap((u8 __iomem *)ps3fb.dinfo); | ||
1104 | } | ||
1105 | 1134 | ||
1106 | void ps3fb_cleanup(void) | 1135 | if (info) { |
1107 | { | 1136 | unregister_framebuffer(info); |
1108 | int status; | 1137 | fb_dealloc_cmap(&info->cmap); |
1138 | framebuffer_release(info); | ||
1139 | } | ||
1109 | 1140 | ||
1141 | ps3av_register_flip_ctl(NULL, NULL); | ||
1110 | if (ps3fb.task) { | 1142 | if (ps3fb.task) { |
1111 | struct task_struct *task = ps3fb.task; | 1143 | struct task_struct *task = ps3fb.task; |
1112 | ps3fb.task = NULL; | 1144 | ps3fb.task = NULL; |
1113 | kthread_stop(task); | 1145 | kthread_stop(task); |
1114 | } | 1146 | } |
1115 | if (ps3fb.irq_no) { | 1147 | if (ps3fb.irq_no) { |
1116 | free_irq(ps3fb.irq_no, ps3fb.dev); | 1148 | free_irq(ps3fb.irq_no, dev); |
1117 | ps3_irq_plug_destroy(ps3fb.irq_no); | 1149 | ps3_irq_plug_destroy(ps3fb.irq_no); |
1118 | } | 1150 | } |
1119 | iounmap((u8 __iomem *)ps3fb.dinfo); | 1151 | iounmap((u8 __iomem *)ps3fb.dinfo); |
@@ -1126,134 +1158,69 @@ void ps3fb_cleanup(void) | |||
1126 | if (status) | 1158 | if (status) |
1127 | DPRINTK("lv1_gpu_memory_free failed: %d\n", status); | 1159 | DPRINTK("lv1_gpu_memory_free failed: %d\n", status); |
1128 | 1160 | ||
1129 | ps3av_dev_close(); | 1161 | ps3_close_hv_device(dev); |
1130 | } | 1162 | DPRINTK(" <- %s:%d\n", __func__, __LINE__); |
1131 | 1163 | ||
1132 | EXPORT_SYMBOL_GPL(ps3fb_cleanup); | ||
1133 | |||
1134 | static int ps3fb_remove(struct platform_device *dev) | ||
1135 | { | ||
1136 | struct fb_info *info = platform_get_drvdata(dev); | ||
1137 | |||
1138 | if (info) { | ||
1139 | unregister_framebuffer(info); | ||
1140 | fb_dealloc_cmap(&info->cmap); | ||
1141 | framebuffer_release(info); | ||
1142 | } | ||
1143 | ps3fb_cleanup(); | ||
1144 | return 0; | 1164 | return 0; |
1145 | } | 1165 | } |
1146 | 1166 | ||
1147 | static struct platform_driver ps3fb_driver = { | 1167 | static struct ps3_system_bus_driver ps3fb_driver = { |
1148 | .probe = ps3fb_probe, | 1168 | .match_id = PS3_MATCH_ID_GRAPHICS, |
1149 | .remove = ps3fb_remove, | 1169 | .core.name = DEVICE_NAME, |
1150 | .shutdown = ps3fb_shutdown, | 1170 | .core.owner = THIS_MODULE, |
1151 | .driver = { .name = "ps3fb" } | 1171 | .probe = ps3fb_probe, |
1152 | }; | 1172 | .remove = ps3fb_shutdown, |
1153 | 1173 | .shutdown = ps3fb_shutdown, | |
1154 | static struct platform_device ps3fb_device = { | ||
1155 | .name = "ps3fb", | ||
1156 | .id = 0, | ||
1157 | .dev = { .release = ps3fb_platform_release } | ||
1158 | }; | 1174 | }; |
1159 | 1175 | ||
1160 | int ps3fb_set_sync(void) | 1176 | static int __init ps3fb_setup(void) |
1161 | { | 1177 | { |
1162 | int status; | 1178 | char *options; |
1163 | 1179 | ||
1164 | #ifdef HEAD_A | 1180 | #ifdef MODULE |
1165 | status = lv1_gpu_context_attribute(0x0, | ||
1166 | L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, | ||
1167 | 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); | ||
1168 | if (status) { | ||
1169 | printk(KERN_ERR | ||
1170 | "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: %d\n", | ||
1171 | __func__, status); | ||
1172 | return -1; | ||
1173 | } | ||
1174 | #endif | ||
1175 | #ifdef HEAD_B | ||
1176 | status = lv1_gpu_context_attribute(0x0, | ||
1177 | L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, | ||
1178 | 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); | ||
1179 | |||
1180 | if (status) { | ||
1181 | printk(KERN_ERR | ||
1182 | "%s: lv1_gpu_context_attribute DISPLAY_MODE failed: %d\n", | ||
1183 | __func__, status); | ||
1184 | return -1; | ||
1185 | } | ||
1186 | #endif | ||
1187 | return 0; | 1181 | return 0; |
1188 | } | ||
1189 | |||
1190 | EXPORT_SYMBOL_GPL(ps3fb_set_sync); | ||
1191 | |||
1192 | static int __init ps3fb_init(void) | ||
1193 | { | ||
1194 | int error; | ||
1195 | #ifndef MODULE | ||
1196 | int mode; | ||
1197 | char *option = NULL; | ||
1198 | |||
1199 | if (fb_get_options("ps3fb", &option)) | ||
1200 | goto err; | ||
1201 | #endif | 1182 | #endif |
1202 | 1183 | ||
1203 | if (!ps3fb_videomemory.address) | 1184 | if (fb_get_options(DEVICE_NAME, &options)) |
1204 | goto err; | 1185 | return -ENXIO; |
1205 | |||
1206 | error = ps3av_dev_open(); | ||
1207 | if (error) { | ||
1208 | printk(KERN_ERR "%s: ps3av_dev_open failed\n", __func__); | ||
1209 | goto err; | ||
1210 | } | ||
1211 | 1186 | ||
1212 | ps3fb_mode = ps3av_get_mode(); | 1187 | if (!options || !*options) |
1213 | DPRINTK("ps3av_mode:%d\n", ps3fb_mode); | 1188 | return 0; |
1214 | #ifndef MODULE | ||
1215 | mode = ps3fb_setup(option); /* check boot option */ | ||
1216 | if (mode) | ||
1217 | ps3fb_mode = mode; | ||
1218 | #endif | ||
1219 | if (ps3fb_mode > 0) { | ||
1220 | u32 xres, yres; | ||
1221 | ps3av_video_mode2res(ps3fb_mode, &xres, &yres); | ||
1222 | ps3fb.res_index = ps3fb_get_res_table(xres, yres); | ||
1223 | DPRINTK("res_index:%d\n", ps3fb.res_index); | ||
1224 | } else | ||
1225 | ps3fb.res_index = GPU_RES_INDEX; | ||
1226 | 1189 | ||
1227 | atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */ | 1190 | while (1) { |
1228 | atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ | 1191 | char *this_opt = strsep(&options, ","); |
1229 | init_waitqueue_head(&ps3fb.wait_vsync); | ||
1230 | ps3fb.num_frames = 1; | ||
1231 | 1192 | ||
1232 | error = platform_driver_register(&ps3fb_driver); | 1193 | if (!this_opt) |
1233 | if (!error) { | 1194 | break; |
1234 | error = platform_device_register(&ps3fb_device); | 1195 | if (!*this_opt) |
1235 | if (error) | 1196 | continue; |
1236 | platform_driver_unregister(&ps3fb_driver); | 1197 | if (!strncmp(this_opt, "mode:", 5)) |
1198 | ps3fb_mode = simple_strtoul(this_opt + 5, NULL, 0); | ||
1199 | else | ||
1200 | mode_option = this_opt; | ||
1237 | } | 1201 | } |
1202 | return 0; | ||
1203 | } | ||
1238 | 1204 | ||
1239 | ps3fb_set_sync(); | 1205 | static int __init ps3fb_init(void) |
1240 | 1206 | { | |
1241 | return error; | 1207 | if (!ps3fb_videomemory.address || ps3fb_setup()) |
1208 | return -ENXIO; | ||
1242 | 1209 | ||
1243 | err: | 1210 | return ps3_system_bus_driver_register(&ps3fb_driver); |
1244 | return -ENXIO; | ||
1245 | } | 1211 | } |
1246 | 1212 | ||
1247 | module_init(ps3fb_init); | ||
1248 | |||
1249 | #ifdef MODULE | ||
1250 | static void __exit ps3fb_exit(void) | 1213 | static void __exit ps3fb_exit(void) |
1251 | { | 1214 | { |
1252 | platform_device_unregister(&ps3fb_device); | 1215 | DPRINTK(" -> %s:%d\n", __func__, __LINE__); |
1253 | platform_driver_unregister(&ps3fb_driver); | 1216 | ps3_system_bus_driver_unregister(&ps3fb_driver); |
1217 | DPRINTK(" <- %s:%d\n", __func__, __LINE__); | ||
1254 | } | 1218 | } |
1255 | 1219 | ||
1220 | module_init(ps3fb_init); | ||
1256 | module_exit(ps3fb_exit); | 1221 | module_exit(ps3fb_exit); |
1257 | 1222 | ||
1258 | MODULE_LICENSE("GPL"); | 1223 | MODULE_LICENSE("GPL"); |
1259 | #endif /* MODULE */ | 1224 | MODULE_DESCRIPTION("PS3 GPU Frame Buffer Driver"); |
1225 | MODULE_AUTHOR("Sony Computer Entertainment Inc."); | ||
1226 | MODULE_ALIAS(PS3_MODULE_ALIAS_GRAPHICS); | ||
diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c index df2909ae704c..f9300266044d 100644 --- a/drivers/video/pvr2fb.c +++ b/drivers/video/pvr2fb.c | |||
@@ -115,11 +115,11 @@ enum { VO_PAL, VO_NTSC, VO_VGA }; | |||
115 | enum { PAL_ARGB1555, PAL_RGB565, PAL_ARGB4444, PAL_ARGB8888 }; | 115 | enum { PAL_ARGB1555, PAL_RGB565, PAL_ARGB4444, PAL_ARGB8888 }; |
116 | 116 | ||
117 | struct pvr2_params { unsigned int val; char *name; }; | 117 | struct pvr2_params { unsigned int val; char *name; }; |
118 | static struct pvr2_params cables[] __initdata = { | 118 | static struct pvr2_params cables[] __devinitdata = { |
119 | { CT_VGA, "VGA" }, { CT_RGB, "RGB" }, { CT_COMPOSITE, "COMPOSITE" }, | 119 | { CT_VGA, "VGA" }, { CT_RGB, "RGB" }, { CT_COMPOSITE, "COMPOSITE" }, |
120 | }; | 120 | }; |
121 | 121 | ||
122 | static struct pvr2_params outputs[] __initdata = { | 122 | static struct pvr2_params outputs[] __devinitdata = { |
123 | { VO_PAL, "PAL" }, { VO_NTSC, "NTSC" }, { VO_VGA, "VGA" }, | 123 | { VO_PAL, "PAL" }, { VO_NTSC, "NTSC" }, { VO_VGA, "VGA" }, |
124 | }; | 124 | }; |
125 | 125 | ||
@@ -147,16 +147,16 @@ static struct pvr2fb_par { | |||
147 | 147 | ||
148 | static struct fb_info *fb_info; | 148 | static struct fb_info *fb_info; |
149 | 149 | ||
150 | static struct fb_fix_screeninfo pvr2_fix __initdata = { | 150 | static struct fb_fix_screeninfo pvr2_fix __devinitdata = { |
151 | .id = "NEC PowerVR2", | 151 | .id = "NEC PowerVR2", |
152 | .type = FB_TYPE_PACKED_PIXELS, | 152 | .type = FB_TYPE_PACKED_PIXELS, |
153 | .visual = FB_VISUAL_TRUECOLOR, | 153 | .visual = FB_VISUAL_TRUECOLOR, |
154 | .ypanstep = 1, | 154 | .ypanstep = 1, |
155 | .ywrapstep = 1, | 155 | .ywrapstep = 1, |
156 | .accel = FB_ACCEL_NONE, | 156 | .accel = FB_ACCEL_NONE, |
157 | }; | 157 | }; |
158 | 158 | ||
159 | static struct fb_var_screeninfo pvr2_var __initdata = { | 159 | static struct fb_var_screeninfo pvr2_var __devinitdata = { |
160 | .xres = 640, | 160 | .xres = 640, |
161 | .yres = 480, | 161 | .yres = 480, |
162 | .xres_virtual = 640, | 162 | .xres_virtual = 640, |
@@ -195,10 +195,6 @@ static unsigned int shdma = PVR2_CASCADE_CHAN; | |||
195 | static unsigned int pvr2dma = ONCHIP_NR_DMA_CHANNELS; | 195 | static unsigned int pvr2dma = ONCHIP_NR_DMA_CHANNELS; |
196 | #endif | 196 | #endif |
197 | 197 | ||
198 | /* Interface used by the world */ | ||
199 | |||
200 | int pvr2fb_setup(char*); | ||
201 | |||
202 | static int pvr2fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, unsigned int blue, | 198 | static int pvr2fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, unsigned int blue, |
203 | unsigned int transp, struct fb_info *info); | 199 | unsigned int transp, struct fb_info *info); |
204 | static int pvr2fb_blank(int blank, struct fb_info *info); | 200 | static int pvr2fb_blank(int blank, struct fb_info *info); |
@@ -227,12 +223,12 @@ static struct fb_ops pvr2fb_ops = { | |||
227 | #ifdef CONFIG_SH_DMA | 223 | #ifdef CONFIG_SH_DMA |
228 | .fb_write = pvr2fb_write, | 224 | .fb_write = pvr2fb_write, |
229 | #endif | 225 | #endif |
230 | .fb_fillrect = cfb_fillrect, | 226 | .fb_fillrect = cfb_fillrect, |
231 | .fb_copyarea = cfb_copyarea, | 227 | .fb_copyarea = cfb_copyarea, |
232 | .fb_imageblit = cfb_imageblit, | 228 | .fb_imageblit = cfb_imageblit, |
233 | }; | 229 | }; |
234 | 230 | ||
235 | static struct fb_videomode pvr2_modedb[] __initdata = { | 231 | static struct fb_videomode pvr2_modedb[] __devinitdata = { |
236 | /* | 232 | /* |
237 | * Broadcast video modes (PAL and NTSC). I'm unfamiliar with | 233 | * Broadcast video modes (PAL and NTSC). I'm unfamiliar with |
238 | * PAL-M and PAL-N, but from what I've read both modes parallel PAL and | 234 | * PAL-M and PAL-N, but from what I've read both modes parallel PAL and |
@@ -252,7 +248,7 @@ static struct fb_videomode pvr2_modedb[] __initdata = { | |||
252 | /* 640x480 @ 60hz (VGA) */ | 248 | /* 640x480 @ 60hz (VGA) */ |
253 | "vga_640x480", 60, 640, 480, VGA_CLK, 38, 33, 0, 18, 146, 26, | 249 | "vga_640x480", 60, 640, 480, VGA_CLK, 38, 33, 0, 18, 146, 26, |
254 | 0, FB_VMODE_YWRAP | 250 | 0, FB_VMODE_YWRAP |
255 | }, | 251 | }, |
256 | }; | 252 | }; |
257 | 253 | ||
258 | #define NUM_TOTAL_MODES ARRAY_SIZE(pvr2_modedb) | 254 | #define NUM_TOTAL_MODES ARRAY_SIZE(pvr2_modedb) |
@@ -262,7 +258,7 @@ static struct fb_videomode pvr2_modedb[] __initdata = { | |||
262 | #define DEFMODE_VGA 2 | 258 | #define DEFMODE_VGA 2 |
263 | 259 | ||
264 | static int defmode = DEFMODE_NTSC; | 260 | static int defmode = DEFMODE_NTSC; |
265 | static char *mode_option __initdata = NULL; | 261 | static char *mode_option __devinitdata = NULL; |
266 | 262 | ||
267 | static inline void pvr2fb_set_pal_type(unsigned int type) | 263 | static inline void pvr2fb_set_pal_type(unsigned int type) |
268 | { | 264 | { |
@@ -293,7 +289,7 @@ static void set_color_bitfields(struct fb_var_screeninfo *var) | |||
293 | { | 289 | { |
294 | switch (var->bits_per_pixel) { | 290 | switch (var->bits_per_pixel) { |
295 | case 16: /* RGB 565 */ | 291 | case 16: /* RGB 565 */ |
296 | pvr2fb_set_pal_type(PAL_RGB565); | 292 | pvr2fb_set_pal_type(PAL_RGB565); |
297 | var->red.offset = 11; var->red.length = 5; | 293 | var->red.offset = 11; var->red.length = 5; |
298 | var->green.offset = 5; var->green.length = 6; | 294 | var->green.offset = 5; var->green.length = 6; |
299 | var->blue.offset = 0; var->blue.length = 5; | 295 | var->blue.offset = 0; var->blue.length = 5; |
@@ -306,7 +302,7 @@ static void set_color_bitfields(struct fb_var_screeninfo *var) | |||
306 | var->transp.offset = 0; var->transp.length = 0; | 302 | var->transp.offset = 0; var->transp.length = 0; |
307 | break; | 303 | break; |
308 | case 32: /* ARGB 8888 */ | 304 | case 32: /* ARGB 8888 */ |
309 | pvr2fb_set_pal_type(PAL_ARGB8888); | 305 | pvr2fb_set_pal_type(PAL_ARGB8888); |
310 | var->red.offset = 16; var->red.length = 8; | 306 | var->red.offset = 16; var->red.length = 8; |
311 | var->green.offset = 8; var->green.length = 8; | 307 | var->green.offset = 8; var->green.length = 8; |
312 | var->blue.offset = 0; var->blue.length = 8; | 308 | var->blue.offset = 0; var->blue.length = 8; |
@@ -337,24 +333,25 @@ static int pvr2fb_setcolreg(unsigned int regno, unsigned int red, | |||
337 | ((blue & 0xf800) >> 11); | 333 | ((blue & 0xf800) >> 11); |
338 | 334 | ||
339 | pvr2fb_set_pal_entry(par, regno, tmp); | 335 | pvr2fb_set_pal_entry(par, regno, tmp); |
340 | ((u16*)(info->pseudo_palette))[regno] = tmp; | ||
341 | break; | 336 | break; |
342 | case 24: /* RGB 888 */ | 337 | case 24: /* RGB 888 */ |
343 | red >>= 8; green >>= 8; blue >>= 8; | 338 | red >>= 8; green >>= 8; blue >>= 8; |
344 | ((u32*)(info->pseudo_palette))[regno] = (red << 16) | (green << 8) | blue; | 339 | tmp = (red << 16) | (green << 8) | blue; |
345 | break; | 340 | break; |
346 | case 32: /* ARGB 8888 */ | 341 | case 32: /* ARGB 8888 */ |
347 | red >>= 8; green >>= 8; blue >>= 8; | 342 | red >>= 8; green >>= 8; blue >>= 8; |
348 | tmp = (transp << 24) | (red << 16) | (green << 8) | blue; | 343 | tmp = (transp << 24) | (red << 16) | (green << 8) | blue; |
349 | 344 | ||
350 | pvr2fb_set_pal_entry(par, regno, tmp); | 345 | pvr2fb_set_pal_entry(par, regno, tmp); |
351 | ((u32*)(info->pseudo_palette))[regno] = tmp; | ||
352 | break; | 346 | break; |
353 | default: | 347 | default: |
354 | pr_debug("Invalid bit depth %d?!?\n", info->var.bits_per_pixel); | 348 | pr_debug("Invalid bit depth %d?!?\n", info->var.bits_per_pixel); |
355 | return 1; | 349 | return 1; |
356 | } | 350 | } |
357 | 351 | ||
352 | if (regno < 16) | ||
353 | ((u32*)(info->pseudo_palette))[regno] = tmp; | ||
354 | |||
358 | return 0; | 355 | return 0; |
359 | } | 356 | } |
360 | 357 | ||
@@ -379,13 +376,13 @@ static int pvr2fb_set_par(struct fb_info *info) | |||
379 | var->vmode &= FB_VMODE_MASK; | 376 | var->vmode &= FB_VMODE_MASK; |
380 | if (var->vmode & FB_VMODE_INTERLACED && video_output != VO_VGA) | 377 | if (var->vmode & FB_VMODE_INTERLACED && video_output != VO_VGA) |
381 | par->is_interlaced = 1; | 378 | par->is_interlaced = 1; |
382 | /* | 379 | /* |
383 | * XXX: Need to be more creative with this (i.e. allow doublecan for | 380 | * XXX: Need to be more creative with this (i.e. allow doublecan for |
384 | * PAL/NTSC output). | 381 | * PAL/NTSC output). |
385 | */ | 382 | */ |
386 | if (var->vmode & FB_VMODE_DOUBLE && video_output == VO_VGA) | 383 | if (var->vmode & FB_VMODE_DOUBLE && video_output == VO_VGA) |
387 | par->is_doublescan = 1; | 384 | par->is_doublescan = 1; |
388 | 385 | ||
389 | par->hsync_total = var->left_margin + var->xres + var->right_margin + | 386 | par->hsync_total = var->left_margin + var->xres + var->right_margin + |
390 | var->hsync_len; | 387 | var->hsync_len; |
391 | par->vsync_total = var->upper_margin + var->yres + var->lower_margin + | 388 | par->vsync_total = var->upper_margin + var->yres + var->lower_margin + |
@@ -408,7 +405,7 @@ static int pvr2fb_set_par(struct fb_info *info) | |||
408 | } else { | 405 | } else { |
409 | /* VGA mode */ | 406 | /* VGA mode */ |
410 | /* XXX: What else needs to be checked? */ | 407 | /* XXX: What else needs to be checked? */ |
411 | /* | 408 | /* |
412 | * XXX: We have a little freedom in VGA modes, what ranges | 409 | * XXX: We have a little freedom in VGA modes, what ranges |
413 | * should be here (i.e. hsync/vsync totals, etc.)? | 410 | * should be here (i.e. hsync/vsync totals, etc.)? |
414 | */ | 411 | */ |
@@ -419,8 +416,8 @@ static int pvr2fb_set_par(struct fb_info *info) | |||
419 | /* Calculate the remainding offsets */ | 416 | /* Calculate the remainding offsets */ |
420 | par->diwstart_h = par->borderstart_h + var->left_margin; | 417 | par->diwstart_h = par->borderstart_h + var->left_margin; |
421 | par->diwstart_v = par->borderstart_v + var->upper_margin; | 418 | par->diwstart_v = par->borderstart_v + var->upper_margin; |
422 | par->borderstop_h = par->diwstart_h + var->xres + | 419 | par->borderstop_h = par->diwstart_h + var->xres + |
423 | var->right_margin; | 420 | var->right_margin; |
424 | par->borderstop_v = par->diwstart_v + var->yres + | 421 | par->borderstop_v = par->diwstart_v + var->yres + |
425 | var->lower_margin; | 422 | var->lower_margin; |
426 | 423 | ||
@@ -465,12 +462,12 @@ static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
465 | set_color_bitfields(var); | 462 | set_color_bitfields(var); |
466 | 463 | ||
467 | if (var->vmode & FB_VMODE_YWRAP) { | 464 | if (var->vmode & FB_VMODE_YWRAP) { |
468 | if (var->xoffset || var->yoffset < 0 || | 465 | if (var->xoffset || var->yoffset < 0 || |
469 | var->yoffset >= var->yres_virtual) { | 466 | var->yoffset >= var->yres_virtual) { |
470 | var->xoffset = var->yoffset = 0; | 467 | var->xoffset = var->yoffset = 0; |
471 | } else { | 468 | } else { |
472 | if (var->xoffset > var->xres_virtual - var->xres || | 469 | if (var->xoffset > var->xres_virtual - var->xres || |
473 | var->yoffset > var->yres_virtual - var->yres || | 470 | var->yoffset > var->yres_virtual - var->yres || |
474 | var->xoffset < 0 || var->yoffset < 0) | 471 | var->xoffset < 0 || var->yoffset < 0) |
475 | var->xoffset = var->yoffset = 0; | 472 | var->xoffset = var->yoffset = 0; |
476 | } | 473 | } |
@@ -478,7 +475,7 @@ static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
478 | var->xoffset = var->yoffset = 0; | 475 | var->xoffset = var->yoffset = 0; |
479 | } | 476 | } |
480 | 477 | ||
481 | /* | 478 | /* |
482 | * XXX: Need to be more creative with this (i.e. allow doublecan for | 479 | * XXX: Need to be more creative with this (i.e. allow doublecan for |
483 | * PAL/NTSC output). | 480 | * PAL/NTSC output). |
484 | */ | 481 | */ |
@@ -507,7 +504,7 @@ static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
507 | var->vsync_len = par->borderstop_v + | 504 | var->vsync_len = par->borderstop_v + |
508 | (par->vsync_total - par->borderstop_v); | 505 | (par->vsync_total - par->borderstop_v); |
509 | } | 506 | } |
510 | 507 | ||
511 | hsync_total = var->left_margin + var->xres + var->right_margin + | 508 | hsync_total = var->left_margin + var->xres + var->right_margin + |
512 | var->hsync_len; | 509 | var->hsync_len; |
513 | vtotal = var->upper_margin + var->yres + var->lower_margin + | 510 | vtotal = var->upper_margin + var->yres + var->lower_margin + |
@@ -531,7 +528,7 @@ static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
531 | } | 528 | } |
532 | } | 529 | } |
533 | } | 530 | } |
534 | 531 | ||
535 | /* Check memory sizes */ | 532 | /* Check memory sizes */ |
536 | line_length = get_line_length(var->xres_virtual, var->bits_per_pixel); | 533 | line_length = get_line_length(var->xres_virtual, var->bits_per_pixel); |
537 | if (line_length * var->yres_virtual > info->fix.smem_len) | 534 | if (line_length * var->yres_virtual > info->fix.smem_len) |
@@ -552,7 +549,7 @@ static void pvr2_update_display(struct fb_info *info) | |||
552 | DISP_DIWADDRS); | 549 | DISP_DIWADDRS); |
553 | } | 550 | } |
554 | 551 | ||
555 | /* | 552 | /* |
556 | * Initialize the video mode. Currently, the 16bpp and 24bpp modes aren't | 553 | * Initialize the video mode. Currently, the 16bpp and 24bpp modes aren't |
557 | * very stable. It's probably due to the fact that a lot of the 2D video | 554 | * very stable. It's probably due to the fact that a lot of the 2D video |
558 | * registers are still undocumented. | 555 | * registers are still undocumented. |
@@ -592,18 +589,18 @@ static void pvr2_init_display(struct fb_info *info) | |||
592 | /* display window start position */ | 589 | /* display window start position */ |
593 | fb_writel(par->diwstart_h, DISP_DIWHSTRT); | 590 | fb_writel(par->diwstart_h, DISP_DIWHSTRT); |
594 | fb_writel((par->diwstart_v << 16) | par->diwstart_v, DISP_DIWVSTRT); | 591 | fb_writel((par->diwstart_v << 16) | par->diwstart_v, DISP_DIWVSTRT); |
595 | 592 | ||
596 | /* misc. settings */ | 593 | /* misc. settings */ |
597 | fb_writel((0x16 << 16) | par->is_lowres, DISP_DIWCONF); | 594 | fb_writel((0x16 << 16) | par->is_lowres, DISP_DIWCONF); |
598 | 595 | ||
599 | /* clock doubler (for VGA), scan doubler, display enable */ | 596 | /* clock doubler (for VGA), scan doubler, display enable */ |
600 | fb_writel(((video_output == VO_VGA) << 23) | | 597 | fb_writel(((video_output == VO_VGA) << 23) | |
601 | (par->is_doublescan << 1) | 1, DISP_DIWMODE); | 598 | (par->is_doublescan << 1) | 1, DISP_DIWMODE); |
602 | 599 | ||
603 | /* bits per pixel */ | 600 | /* bits per pixel */ |
604 | fb_writel(fb_readl(DISP_DIWMODE) | (--bytesperpixel << 2), DISP_DIWMODE); | 601 | fb_writel(fb_readl(DISP_DIWMODE) | (--bytesperpixel << 2), DISP_DIWMODE); |
605 | 602 | ||
606 | /* video enable, color sync, interlace, | 603 | /* video enable, color sync, interlace, |
607 | * hsync and vsync polarity (currently unused) */ | 604 | * hsync and vsync polarity (currently unused) */ |
608 | fb_writel(0x100 | ((par->is_interlaced /*|4*/) << 4), DISP_SYNCCONF); | 605 | fb_writel(0x100 | ((par->is_interlaced /*|4*/) << 4), DISP_SYNCCONF); |
609 | } | 606 | } |
@@ -657,7 +654,7 @@ static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id) | |||
657 | static int pvr2_init_cable(void) | 654 | static int pvr2_init_cable(void) |
658 | { | 655 | { |
659 | if (cable_type < 0) { | 656 | if (cable_type < 0) { |
660 | fb_writel((fb_readl(PCTRA) & 0xfff0ffff) | 0x000a0000, | 657 | fb_writel((fb_readl(PCTRA) & 0xfff0ffff) | 0x000a0000, |
661 | PCTRA); | 658 | PCTRA); |
662 | cable_type = (fb_readw(PDTRA) >> 8) & 3; | 659 | cable_type = (fb_readw(PDTRA) >> 8) & 3; |
663 | } | 660 | } |
@@ -687,7 +684,7 @@ static ssize_t pvr2fb_write(struct fb_info *info, const char *buf, | |||
687 | pages = kmalloc(nr_pages * sizeof(struct page *), GFP_KERNEL); | 684 | pages = kmalloc(nr_pages * sizeof(struct page *), GFP_KERNEL); |
688 | if (!pages) | 685 | if (!pages) |
689 | return -ENOMEM; | 686 | return -ENOMEM; |
690 | 687 | ||
691 | down_read(¤t->mm->mmap_sem); | 688 | down_read(¤t->mm->mmap_sem); |
692 | ret = get_user_pages(current, current->mm, (unsigned long)buf, | 689 | ret = get_user_pages(current, current->mm, (unsigned long)buf, |
693 | nr_pages, WRITE, 0, pages, NULL); | 690 | nr_pages, WRITE, 0, pages, NULL); |
@@ -700,7 +697,7 @@ static ssize_t pvr2fb_write(struct fb_info *info, const char *buf, | |||
700 | } | 697 | } |
701 | 698 | ||
702 | dma_configure_channel(shdma, 0x12c1); | 699 | dma_configure_channel(shdma, 0x12c1); |
703 | 700 | ||
704 | dst = (unsigned long)fb_info->screen_base + *ppos; | 701 | dst = (unsigned long)fb_info->screen_base + *ppos; |
705 | start = (unsigned long)page_address(pages[0]); | 702 | start = (unsigned long)page_address(pages[0]); |
706 | end = (unsigned long)page_address(pages[nr_pages]); | 703 | end = (unsigned long)page_address(pages[nr_pages]); |
@@ -744,7 +741,7 @@ out_unmap: | |||
744 | kfree(pages); | 741 | kfree(pages); |
745 | 742 | ||
746 | return ret; | 743 | return ret; |
747 | } | 744 | } |
748 | #endif /* CONFIG_SH_DMA */ | 745 | #endif /* CONFIG_SH_DMA */ |
749 | 746 | ||
750 | /** | 747 | /** |
@@ -765,21 +762,21 @@ out_unmap: | |||
765 | * in for flexibility anyways. Who knows, maybe someone has tv-out on a | 762 | * in for flexibility anyways. Who knows, maybe someone has tv-out on a |
766 | * PCI-based version of these things ;-) | 763 | * PCI-based version of these things ;-) |
767 | */ | 764 | */ |
768 | static int __init pvr2fb_common_init(void) | 765 | static int __devinit pvr2fb_common_init(void) |
769 | { | 766 | { |
770 | struct pvr2fb_par *par = currentpar; | 767 | struct pvr2fb_par *par = currentpar; |
771 | unsigned long modememused, rev; | 768 | unsigned long modememused, rev; |
772 | 769 | ||
773 | fb_info->screen_base = ioremap_nocache(pvr2_fix.smem_start, | 770 | fb_info->screen_base = ioremap_nocache(pvr2_fix.smem_start, |
774 | pvr2_fix.smem_len); | 771 | pvr2_fix.smem_len); |
775 | 772 | ||
776 | if (!fb_info->screen_base) { | 773 | if (!fb_info->screen_base) { |
777 | printk(KERN_ERR "pvr2fb: Failed to remap smem space\n"); | 774 | printk(KERN_ERR "pvr2fb: Failed to remap smem space\n"); |
778 | goto out_err; | 775 | goto out_err; |
779 | } | 776 | } |
780 | 777 | ||
781 | par->mmio_base = (unsigned long)ioremap_nocache(pvr2_fix.mmio_start, | 778 | par->mmio_base = (unsigned long)ioremap_nocache(pvr2_fix.mmio_start, |
782 | pvr2_fix.mmio_len); | 779 | pvr2_fix.mmio_len); |
783 | if (!par->mmio_base) { | 780 | if (!par->mmio_base) { |
784 | printk(KERN_ERR "pvr2fb: Failed to remap mmio space\n"); | 781 | printk(KERN_ERR "pvr2fb: Failed to remap mmio space\n"); |
785 | goto out_err; | 782 | goto out_err; |
@@ -820,7 +817,7 @@ static int __init pvr2fb_common_init(void) | |||
820 | printk("fb%d: %s (rev %ld.%ld) frame buffer device, using %ldk/%ldk of video memory\n", | 817 | printk("fb%d: %s (rev %ld.%ld) frame buffer device, using %ldk/%ldk of video memory\n", |
821 | fb_info->node, fb_info->fix.id, (rev >> 4) & 0x0f, rev & 0x0f, | 818 | fb_info->node, fb_info->fix.id, (rev >> 4) & 0x0f, rev & 0x0f, |
822 | modememused >> 10, (unsigned long)(fb_info->fix.smem_len >> 10)); | 819 | modememused >> 10, (unsigned long)(fb_info->fix.smem_len >> 10)); |
823 | printk("fb%d: Mode %dx%d-%d pitch = %ld cable: %s video output: %s\n", | 820 | printk("fb%d: Mode %dx%d-%d pitch = %ld cable: %s video output: %s\n", |
824 | fb_info->node, fb_info->var.xres, fb_info->var.yres, | 821 | fb_info->node, fb_info->var.xres, fb_info->var.yres, |
825 | fb_info->var.bits_per_pixel, | 822 | fb_info->var.bits_per_pixel, |
826 | get_line_length(fb_info->var.xres, fb_info->var.bits_per_pixel), | 823 | get_line_length(fb_info->var.xres, fb_info->var.bits_per_pixel), |
@@ -878,8 +875,8 @@ static int __init pvr2fb_dc_init(void) | |||
878 | video_output = VO_NTSC; | 875 | video_output = VO_NTSC; |
879 | } | 876 | } |
880 | } | 877 | } |
881 | 878 | ||
882 | /* | 879 | /* |
883 | * Nothing exciting about the DC PVR2 .. only a measly 8MiB. | 880 | * Nothing exciting about the DC PVR2 .. only a measly 8MiB. |
884 | */ | 881 | */ |
885 | pvr2_fix.smem_start = 0xa5000000; /* RAM starts here */ | 882 | pvr2_fix.smem_start = 0xa5000000; /* RAM starts here */ |
@@ -903,7 +900,7 @@ static int __init pvr2fb_dc_init(void) | |||
903 | return pvr2fb_common_init(); | 900 | return pvr2fb_common_init(); |
904 | } | 901 | } |
905 | 902 | ||
906 | static void pvr2fb_dc_exit(void) | 903 | static void __exit pvr2fb_dc_exit(void) |
907 | { | 904 | { |
908 | if (fb_info->screen_base) { | 905 | if (fb_info->screen_base) { |
909 | iounmap(fb_info->screen_base); | 906 | iounmap(fb_info->screen_base); |
@@ -987,13 +984,13 @@ static int __init pvr2fb_pci_init(void) | |||
987 | return pci_register_driver(&pvr2fb_pci_driver); | 984 | return pci_register_driver(&pvr2fb_pci_driver); |
988 | } | 985 | } |
989 | 986 | ||
990 | static void pvr2fb_pci_exit(void) | 987 | static void __exit pvr2fb_pci_exit(void) |
991 | { | 988 | { |
992 | pci_unregister_driver(&pvr2fb_pci_driver); | 989 | pci_unregister_driver(&pvr2fb_pci_driver); |
993 | } | 990 | } |
994 | #endif /* CONFIG_PCI */ | 991 | #endif /* CONFIG_PCI */ |
995 | 992 | ||
996 | static int __init pvr2_get_param(const struct pvr2_params *p, const char *s, | 993 | static int __devinit pvr2_get_param(const struct pvr2_params *p, const char *s, |
997 | int val, int size) | 994 | int val, int size) |
998 | { | 995 | { |
999 | int i; | 996 | int i; |
@@ -1021,7 +1018,7 @@ static int __init pvr2_get_param(const struct pvr2_params *p, const char *s, | |||
1021 | */ | 1018 | */ |
1022 | 1019 | ||
1023 | #ifndef MODULE | 1020 | #ifndef MODULE |
1024 | int __init pvr2fb_setup(char *options) | 1021 | static int __init pvr2fb_setup(char *options) |
1025 | { | 1022 | { |
1026 | char *this_opt; | 1023 | char *this_opt; |
1027 | char cable_arg[80]; | 1024 | char cable_arg[80]; |
@@ -1061,7 +1058,7 @@ static struct pvr2_board { | |||
1061 | int (*init)(void); | 1058 | int (*init)(void); |
1062 | void (*exit)(void); | 1059 | void (*exit)(void); |
1063 | char name[16]; | 1060 | char name[16]; |
1064 | } board_list[] = { | 1061 | } board_driver[] = { |
1065 | #ifdef CONFIG_SH_DREAMCAST | 1062 | #ifdef CONFIG_SH_DREAMCAST |
1066 | { pvr2fb_dc_init, pvr2fb_dc_exit, "Sega DC PVR2" }, | 1063 | { pvr2fb_dc_init, pvr2fb_dc_exit, "Sega DC PVR2" }, |
1067 | #endif | 1064 | #endif |
@@ -1071,7 +1068,7 @@ static struct pvr2_board { | |||
1071 | { 0, }, | 1068 | { 0, }, |
1072 | }; | 1069 | }; |
1073 | 1070 | ||
1074 | int __init pvr2fb_init(void) | 1071 | static int __init pvr2fb_init(void) |
1075 | { | 1072 | { |
1076 | int i, ret = -ENODEV; | 1073 | int i, ret = -ENODEV; |
1077 | int size; | 1074 | int size; |
@@ -1085,18 +1082,17 @@ int __init pvr2fb_init(void) | |||
1085 | #endif | 1082 | #endif |
1086 | size = sizeof(struct fb_info) + sizeof(struct pvr2fb_par) + 16 * sizeof(u32); | 1083 | size = sizeof(struct fb_info) + sizeof(struct pvr2fb_par) + 16 * sizeof(u32); |
1087 | 1084 | ||
1088 | fb_info = kmalloc(size, GFP_KERNEL); | 1085 | fb_info = kzalloc(size, GFP_KERNEL); |
1089 | if (!fb_info) { | 1086 | if (!fb_info) { |
1090 | printk(KERN_ERR "Failed to allocate memory for fb_info\n"); | 1087 | printk(KERN_ERR "Failed to allocate memory for fb_info\n"); |
1091 | return -ENOMEM; | 1088 | return -ENOMEM; |
1092 | } | 1089 | } |
1093 | 1090 | ||
1094 | memset(fb_info, 0, size); | ||
1095 | 1091 | ||
1096 | currentpar = (struct pvr2fb_par *)(fb_info + 1); | 1092 | currentpar = (struct pvr2fb_par *)(fb_info + 1); |
1097 | 1093 | ||
1098 | for (i = 0; i < ARRAY_SIZE(board_list); i++) { | 1094 | for (i = 0; i < ARRAY_SIZE(board_driver); i++) { |
1099 | struct pvr2_board *pvr_board = board_list + i; | 1095 | struct pvr2_board *pvr_board = board_driver + i; |
1100 | 1096 | ||
1101 | if (!pvr_board->init) | 1097 | if (!pvr_board->init) |
1102 | continue; | 1098 | continue; |
@@ -1118,13 +1114,13 @@ static void __exit pvr2fb_exit(void) | |||
1118 | { | 1114 | { |
1119 | int i; | 1115 | int i; |
1120 | 1116 | ||
1121 | for (i = 0; i < ARRAY_SIZE(board_list); i++) { | 1117 | for (i = 0; i < ARRAY_SIZE(board_driver); i++) { |
1122 | struct pvr2_board *pvr_board = board_list + i; | 1118 | struct pvr2_board *pvr_board = board_driver + i; |
1123 | 1119 | ||
1124 | if (pvr_board->exit) | 1120 | if (pvr_board->exit) |
1125 | pvr_board->exit(); | 1121 | pvr_board->exit(); |
1126 | } | 1122 | } |
1127 | 1123 | ||
1128 | #ifdef CONFIG_SH_STORE_QUEUES | 1124 | #ifdef CONFIG_SH_STORE_QUEUES |
1129 | sq_unmap(pvr2fb_map); | 1125 | sq_unmap(pvr2fb_map); |
1130 | #endif | 1126 | #endif |
@@ -1139,4 +1135,3 @@ module_exit(pvr2fb_exit); | |||
1139 | MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>"); | 1135 | MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>"); |
1140 | MODULE_DESCRIPTION("Framebuffer driver for NEC PowerVR 2 based graphics boards"); | 1136 | MODULE_DESCRIPTION("Framebuffer driver for NEC PowerVR 2 based graphics boards"); |
1141 | MODULE_LICENSE("GPL"); | 1137 | MODULE_LICENSE("GPL"); |
1142 | |||
diff --git a/drivers/video/q40fb.c b/drivers/video/q40fb.c index 48536c3e58a4..4beac1df617b 100644 --- a/drivers/video/q40fb.c +++ b/drivers/video/q40fb.c | |||
@@ -95,7 +95,7 @@ static int __init q40fb_probe(struct platform_device *dev) | |||
95 | /* mapped in q40/config.c */ | 95 | /* mapped in q40/config.c */ |
96 | q40fb_fix.smem_start = Q40_PHYS_SCREEN_ADDR; | 96 | q40fb_fix.smem_start = Q40_PHYS_SCREEN_ADDR; |
97 | 97 | ||
98 | info = framebuffer_alloc(sizeof(u32) * 256, &dev->dev); | 98 | info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev); |
99 | if (!info) | 99 | if (!info) |
100 | return -ENOMEM; | 100 | return -ENOMEM; |
101 | 101 | ||
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index 0fe547842c64..41381e61832c 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c | |||
@@ -2146,7 +2146,7 @@ static void __devexit rivafb_remove(struct pci_dev *pd) | |||
2146 | * ------------------------------------------------------------------------- */ | 2146 | * ------------------------------------------------------------------------- */ |
2147 | 2147 | ||
2148 | #ifndef MODULE | 2148 | #ifndef MODULE |
2149 | static int __init rivafb_setup(char *options) | 2149 | static int __devinit rivafb_setup(char *options) |
2150 | { | 2150 | { |
2151 | char *this_opt; | 2151 | char *this_opt; |
2152 | 2152 | ||
diff --git a/drivers/video/riva/riva_hw.c b/drivers/video/riva/riva_hw.c index 70bfd78eca81..13307703a9f0 100644 --- a/drivers/video/riva/riva_hw.c +++ b/drivers/video/riva/riva_hw.c | |||
@@ -1223,6 +1223,8 @@ static int CalcVClock | |||
1223 | } | 1223 | } |
1224 | } | 1224 | } |
1225 | } | 1225 | } |
1226 | |||
1227 | /* non-zero: M/N/P/clock values assigned. zero: error (not set) */ | ||
1226 | return (DeltaOld != 0xFFFFFFFF); | 1228 | return (DeltaOld != 0xFFFFFFFF); |
1227 | } | 1229 | } |
1228 | /* | 1230 | /* |
@@ -1240,7 +1242,10 @@ int CalcStateExt | |||
1240 | int dotClock | 1242 | int dotClock |
1241 | ) | 1243 | ) |
1242 | { | 1244 | { |
1243 | int pixelDepth, VClk, m, n, p; | 1245 | int pixelDepth; |
1246 | int uninitialized_var(VClk),uninitialized_var(m), | ||
1247 | uninitialized_var(n), uninitialized_var(p); | ||
1248 | |||
1244 | /* | 1249 | /* |
1245 | * Save mode parameters. | 1250 | * Save mode parameters. |
1246 | */ | 1251 | */ |
diff --git a/drivers/video/riva/rivafb-i2c.c b/drivers/video/riva/rivafb-i2c.c index 76e6ce353c8e..a0e22ac483a3 100644 --- a/drivers/video/riva/rivafb-i2c.c +++ b/drivers/video/riva/rivafb-i2c.c | |||
@@ -70,8 +70,6 @@ static int riva_gpio_getscl(void* data) | |||
70 | if (VGA_RD08(par->riva.PCIO, 0x3d5) & 0x04) | 70 | if (VGA_RD08(par->riva.PCIO, 0x3d5) & 0x04) |
71 | val = 1; | 71 | val = 1; |
72 | 72 | ||
73 | val = VGA_RD08(par->riva.PCIO, 0x3d5); | ||
74 | |||
75 | return val; | 73 | return val; |
76 | } | 74 | } |
77 | 75 | ||
diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index 756fafb41d78..d11735895a01 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c | |||
@@ -796,23 +796,6 @@ static int s3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) | |||
796 | return 0; | 796 | return 0; |
797 | } | 797 | } |
798 | 798 | ||
799 | /* Get capabilities of accelerator based on the mode */ | ||
800 | |||
801 | static void s3fb_get_caps(struct fb_info *info, struct fb_blit_caps *caps, | ||
802 | struct fb_var_screeninfo *var) | ||
803 | { | ||
804 | if (var->bits_per_pixel == 0) { | ||
805 | /* can only support 256 8x16 bitmap */ | ||
806 | caps->x = 1 << (8 - 1); | ||
807 | caps->y = 1 << (16 - 1); | ||
808 | caps->len = 256; | ||
809 | } else { | ||
810 | caps->x = ~(u32)0; | ||
811 | caps->y = ~(u32)0; | ||
812 | caps->len = ~(u32)0; | ||
813 | } | ||
814 | } | ||
815 | |||
816 | /* ------------------------------------------------------------------------- */ | 799 | /* ------------------------------------------------------------------------- */ |
817 | 800 | ||
818 | /* Frame buffer operations */ | 801 | /* Frame buffer operations */ |
@@ -829,7 +812,7 @@ static struct fb_ops s3fb_ops = { | |||
829 | .fb_fillrect = s3fb_fillrect, | 812 | .fb_fillrect = s3fb_fillrect, |
830 | .fb_copyarea = cfb_copyarea, | 813 | .fb_copyarea = cfb_copyarea, |
831 | .fb_imageblit = s3fb_imageblit, | 814 | .fb_imageblit = s3fb_imageblit, |
832 | .fb_get_caps = s3fb_get_caps, | 815 | .fb_get_caps = svga_get_caps, |
833 | }; | 816 | }; |
834 | 817 | ||
835 | /* ------------------------------------------------------------------------- */ | 818 | /* ------------------------------------------------------------------------- */ |
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index 3d7507ad55f6..b855f4a34afe 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c | |||
@@ -2174,11 +2174,10 @@ static int __devinit savage_init_fb_info(struct fb_info *info, | |||
2174 | 2174 | ||
2175 | #if defined(CONFIG_FB_SAVAGE_ACCEL) | 2175 | #if defined(CONFIG_FB_SAVAGE_ACCEL) |
2176 | /* FIFO size + padding for commands */ | 2176 | /* FIFO size + padding for commands */ |
2177 | info->pixmap.addr = kmalloc(8*1024, GFP_KERNEL); | 2177 | info->pixmap.addr = kcalloc(8, 1024, GFP_KERNEL); |
2178 | 2178 | ||
2179 | err = -ENOMEM; | 2179 | err = -ENOMEM; |
2180 | if (info->pixmap.addr) { | 2180 | if (info->pixmap.addr) { |
2181 | memset(info->pixmap.addr, 0, 8*1024); | ||
2182 | info->pixmap.size = 8*1024; | 2181 | info->pixmap.size = 8*1024; |
2183 | info->pixmap.scan_align = 4; | 2182 | info->pixmap.scan_align = 4; |
2184 | info->pixmap.buf_align = 4; | 2183 | info->pixmap.buf_align = 4; |
diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c index ebb6756aea08..4fb16240c04d 100644 --- a/drivers/video/sgivwfb.c +++ b/drivers/video/sgivwfb.c | |||
@@ -752,7 +752,7 @@ static int __init sgivwfb_probe(struct platform_device *dev) | |||
752 | struct fb_info *info; | 752 | struct fb_info *info; |
753 | char *monitor; | 753 | char *monitor; |
754 | 754 | ||
755 | info = framebuffer_alloc(sizeof(struct sgivw_par) + sizeof(u32) * 256, &dev->dev); | 755 | info = framebuffer_alloc(sizeof(struct sgivw_par) + sizeof(u32) * 16, &dev->dev); |
756 | if (!info) | 756 | if (!info) |
757 | return -ENOMEM; | 757 | return -ENOMEM; |
758 | par = info->par; | 758 | par = info->par; |
diff --git a/drivers/video/sis/sis.h b/drivers/video/sis/sis.h index d5e2d9c27847..d53bf6945f0c 100644 --- a/drivers/video/sis/sis.h +++ b/drivers/video/sis/sis.h | |||
@@ -479,7 +479,7 @@ struct sis_video_info { | |||
479 | struct fb_var_screeninfo default_var; | 479 | struct fb_var_screeninfo default_var; |
480 | 480 | ||
481 | struct fb_fix_screeninfo sisfb_fix; | 481 | struct fb_fix_screeninfo sisfb_fix; |
482 | u32 pseudo_palette[17]; | 482 | u32 pseudo_palette[16]; |
483 | 483 | ||
484 | struct sisfb_monitor { | 484 | struct sisfb_monitor { |
485 | u16 hmin; | 485 | u16 hmin; |
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index a30e1e13d8be..e8ccace01252 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c | |||
@@ -1405,12 +1405,18 @@ sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, | |||
1405 | } | 1405 | } |
1406 | break; | 1406 | break; |
1407 | case 16: | 1407 | case 16: |
1408 | if (regno >= 16) | ||
1409 | break; | ||
1410 | |||
1408 | ((u32 *)(info->pseudo_palette))[regno] = | 1411 | ((u32 *)(info->pseudo_palette))[regno] = |
1409 | (red & 0xf800) | | 1412 | (red & 0xf800) | |
1410 | ((green & 0xfc00) >> 5) | | 1413 | ((green & 0xfc00) >> 5) | |
1411 | ((blue & 0xf800) >> 11); | 1414 | ((blue & 0xf800) >> 11); |
1412 | break; | 1415 | break; |
1413 | case 32: | 1416 | case 32: |
1417 | if (regno >= 16) | ||
1418 | break; | ||
1419 | |||
1414 | red >>= 8; | 1420 | red >>= 8; |
1415 | green >>= 8; | 1421 | green >>= 8; |
1416 | blue >>= 8; | 1422 | blue >>= 8; |
@@ -5789,7 +5795,7 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
5789 | ivideo->warncount = 0; | 5795 | ivideo->warncount = 0; |
5790 | ivideo->chip_id = pdev->device; | 5796 | ivideo->chip_id = pdev->device; |
5791 | ivideo->chip_vendor = pdev->vendor; | 5797 | ivideo->chip_vendor = pdev->vendor; |
5792 | pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id); | 5798 | ivideo->revision_id = pdev->revision; |
5793 | ivideo->SiS_Pr.ChipRevision = ivideo->revision_id; | 5799 | ivideo->SiS_Pr.ChipRevision = ivideo->revision_id; |
5794 | pci_read_config_word(pdev, PCI_COMMAND, ®16); | 5800 | pci_read_config_word(pdev, PCI_COMMAND, ®16); |
5795 | ivideo->sisvga_enabled = reg16 & 0x01; | 5801 | ivideo->sisvga_enabled = reg16 & 0x01; |
diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c index 842b5cd054c6..64779e70408f 100644 --- a/drivers/video/skeletonfb.c +++ b/drivers/video/skeletonfb.c | |||
@@ -14,7 +14,7 @@ | |||
14 | * of it. | 14 | * of it. |
15 | * | 15 | * |
16 | * First the roles of struct fb_info and struct display have changed. Struct | 16 | * First the roles of struct fb_info and struct display have changed. Struct |
17 | * display will go away. The way the the new framebuffer console code will | 17 | * display will go away. The way the new framebuffer console code will |
18 | * work is that it will act to translate data about the tty/console in | 18 | * work is that it will act to translate data about the tty/console in |
19 | * struct vc_data to data in a device independent way in struct fb_info. Then | 19 | * struct vc_data to data in a device independent way in struct fb_info. Then |
20 | * various functions in struct fb_ops will be called to store the device | 20 | * various functions in struct fb_ops will be called to store the device |
@@ -132,7 +132,6 @@ static struct fb_info info; | |||
132 | static struct xxx_par __initdata current_par; | 132 | static struct xxx_par __initdata current_par; |
133 | 133 | ||
134 | int xxxfb_init(void); | 134 | int xxxfb_init(void); |
135 | int xxxfb_setup(char*); | ||
136 | 135 | ||
137 | /** | 136 | /** |
138 | * xxxfb_open - Optional function. Called when the framebuffer is | 137 | * xxxfb_open - Optional function. Called when the framebuffer is |
@@ -975,6 +974,21 @@ static struct platform_device xxxfb_device = { | |||
975 | .name = "xxxfb", | 974 | .name = "xxxfb", |
976 | }; | 975 | }; |
977 | 976 | ||
977 | #ifndef MODULE | ||
978 | /* | ||
979 | * Setup | ||
980 | */ | ||
981 | |||
982 | /* | ||
983 | * Only necessary if your driver takes special options, | ||
984 | * otherwise we fall back on the generic fb_setup(). | ||
985 | */ | ||
986 | int __init xxxfb_setup(char *options) | ||
987 | { | ||
988 | /* Parse user speficied options (`video=xxxfb:') */ | ||
989 | } | ||
990 | #endif /* MODULE */ | ||
991 | |||
978 | static int __init xxxfb_init(void) | 992 | static int __init xxxfb_init(void) |
979 | { | 993 | { |
980 | int ret; | 994 | int ret; |
@@ -1006,21 +1020,6 @@ static void __exit xxxfb_exit(void) | |||
1006 | } | 1020 | } |
1007 | #endif /* CONFIG_PCI */ | 1021 | #endif /* CONFIG_PCI */ |
1008 | 1022 | ||
1009 | #ifdef MODULE | ||
1010 | /* | ||
1011 | * Setup | ||
1012 | */ | ||
1013 | |||
1014 | /* | ||
1015 | * Only necessary if your driver takes special options, | ||
1016 | * otherwise we fall back on the generic fb_setup(). | ||
1017 | */ | ||
1018 | int __init xxxfb_setup(char *options) | ||
1019 | { | ||
1020 | /* Parse user speficied options (`video=xxxfb:') */ | ||
1021 | } | ||
1022 | #endif /* MODULE */ | ||
1023 | |||
1024 | /* ------------------------------------------------------------------------- */ | 1023 | /* ------------------------------------------------------------------------- */ |
1025 | 1024 | ||
1026 | 1025 | ||
diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c index 62fa5500361d..5eff28ce4f4d 100644 --- a/drivers/video/sstfb.c +++ b/drivers/video/sstfb.c | |||
@@ -1348,7 +1348,7 @@ static int __devinit sstfb_probe(struct pci_dev *pdev, | |||
1348 | f_ddprintk("found device : %s\n", spec->name); | 1348 | f_ddprintk("found device : %s\n", spec->name); |
1349 | 1349 | ||
1350 | par->dev = pdev; | 1350 | par->dev = pdev; |
1351 | pci_read_config_byte(pdev, PCI_REVISION_ID, &par->revision); | 1351 | par->revision = pdev->revision; |
1352 | 1352 | ||
1353 | fix->mmio_start = pci_resource_start(pdev,0); | 1353 | fix->mmio_start = pci_resource_start(pdev,0); |
1354 | fix->mmio_len = 0x400000; | 1354 | fix->mmio_len = 0x400000; |
diff --git a/drivers/video/sunxvr2500.c b/drivers/video/sunxvr2500.c index 4316c7fe8e21..c3869a96ab58 100644 --- a/drivers/video/sunxvr2500.c +++ b/drivers/video/sunxvr2500.c | |||
@@ -28,7 +28,7 @@ struct s3d_info { | |||
28 | unsigned int depth; | 28 | unsigned int depth; |
29 | unsigned int fb_size; | 29 | unsigned int fb_size; |
30 | 30 | ||
31 | u32 pseudo_palette[256]; | 31 | u32 pseudo_palette[16]; |
32 | }; | 32 | }; |
33 | 33 | ||
34 | static int __devinit s3d_get_props(struct s3d_info *sp) | 34 | static int __devinit s3d_get_props(struct s3d_info *sp) |
@@ -52,15 +52,14 @@ static int s3d_setcolreg(unsigned regno, | |||
52 | { | 52 | { |
53 | u32 value; | 53 | u32 value; |
54 | 54 | ||
55 | if (regno >= 256) | 55 | if (regno < 16) { |
56 | return 1; | 56 | red >>= 8; |
57 | green >>= 8; | ||
58 | blue >>= 8; | ||
57 | 59 | ||
58 | red >>= 8; | 60 | value = (blue << 24) | (green << 16) | (red << 8); |
59 | green >>= 8; | 61 | ((u32 *)info->pseudo_palette)[regno] = value; |
60 | blue >>= 8; | 62 | } |
61 | |||
62 | value = (blue << 24) | (green << 16) | (red << 8); | ||
63 | ((u32 *)info->pseudo_palette)[regno] = value; | ||
64 | 63 | ||
65 | return 0; | 64 | return 0; |
66 | } | 65 | } |
diff --git a/drivers/video/sunxvr500.c b/drivers/video/sunxvr500.c index 08880a62bfa3..71bf3f1f00bc 100644 --- a/drivers/video/sunxvr500.c +++ b/drivers/video/sunxvr500.c | |||
@@ -50,7 +50,7 @@ struct e3d_info { | |||
50 | u32 fb8_0_off; | 50 | u32 fb8_0_off; |
51 | u32 fb8_1_off; | 51 | u32 fb8_1_off; |
52 | 52 | ||
53 | u32 pseudo_palette[256]; | 53 | u32 pseudo_palette[16]; |
54 | }; | 54 | }; |
55 | 55 | ||
56 | static int __devinit e3d_get_props(struct e3d_info *ep) | 56 | static int __devinit e3d_get_props(struct e3d_info *ep) |
@@ -126,7 +126,9 @@ static int e3d_setcolreg(unsigned regno, | |||
126 | blue_8 = blue >> 8; | 126 | blue_8 = blue >> 8; |
127 | 127 | ||
128 | value = (blue_8 << 24) | (green_8 << 16) | (red_8 << 8); | 128 | value = (blue_8 << 24) | (green_8 << 16) | (red_8 << 8); |
129 | ((u32 *)info->pseudo_palette)[regno] = value; | 129 | |
130 | if (info->fix.visual == FB_VISUAL_TRUECOLOR && regno < 16) | ||
131 | ((u32 *)info->pseudo_palette)[regno] = value; | ||
130 | 132 | ||
131 | 133 | ||
132 | red_10 = red >> 6; | 134 | red_10 = red >> 6; |
diff --git a/drivers/video/svgalib.c b/drivers/video/svgalib.c index 079cdc911e48..25df928d37d8 100644 --- a/drivers/video/svgalib.c +++ b/drivers/video/svgalib.c | |||
@@ -347,6 +347,23 @@ int svga_get_tilemax(struct fb_info *info) | |||
347 | return 256; | 347 | return 256; |
348 | } | 348 | } |
349 | 349 | ||
350 | /* Get capabilities of accelerator based on the mode */ | ||
351 | |||
352 | void svga_get_caps(struct fb_info *info, struct fb_blit_caps *caps, | ||
353 | struct fb_var_screeninfo *var) | ||
354 | { | ||
355 | if (var->bits_per_pixel == 0) { | ||
356 | /* can only support 256 8x16 bitmap */ | ||
357 | caps->x = 1 << (8 - 1); | ||
358 | caps->y = 1 << (16 - 1); | ||
359 | caps->len = 256; | ||
360 | } else { | ||
361 | caps->x = (var->bits_per_pixel == 4) ? 1 << (8 - 1) : ~(u32)0; | ||
362 | caps->y = ~(u32)0; | ||
363 | caps->len = ~(u32)0; | ||
364 | } | ||
365 | } | ||
366 | EXPORT_SYMBOL(svga_get_caps); | ||
350 | 367 | ||
351 | /* ------------------------------------------------------------------------- */ | 368 | /* ------------------------------------------------------------------------- */ |
352 | 369 | ||
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c index f0fde6ea7c36..89facb73edfc 100644 --- a/drivers/video/tgafb.c +++ b/drivers/video/tgafb.c | |||
@@ -1625,8 +1625,7 @@ tgafb_register(struct device *dev) | |||
1625 | par->tga_regs_base = mem_base + TGA_REGS_OFFSET; | 1625 | par->tga_regs_base = mem_base + TGA_REGS_OFFSET; |
1626 | par->tga_type = tga_type; | 1626 | par->tga_type = tga_type; |
1627 | if (tga_bus_pci) | 1627 | if (tga_bus_pci) |
1628 | pci_read_config_byte(to_pci_dev(dev), PCI_REVISION_ID, | 1628 | par->tga_chip_rev = (to_pci_dev(dev))->revision; |
1629 | &par->tga_chip_rev); | ||
1630 | if (tga_bus_tc) | 1629 | if (tga_bus_tc) |
1631 | par->tga_chip_rev = TGA_READ_REG(par, TGA_START_REG) & 0xff; | 1630 | par->tga_chip_rev = TGA_READ_REG(par, TGA_START_REG) & 0xff; |
1632 | 1631 | ||
@@ -1635,7 +1634,7 @@ tgafb_register(struct device *dev) | |||
1635 | FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT; | 1634 | FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT; |
1636 | info->fbops = &tgafb_ops; | 1635 | info->fbops = &tgafb_ops; |
1637 | info->screen_base = par->tga_fb_base; | 1636 | info->screen_base = par->tga_fb_base; |
1638 | info->pseudo_palette = (void *)(par + 1); | 1637 | info->pseudo_palette = par->palette; |
1639 | 1638 | ||
1640 | /* This should give a reasonable default video mode. */ | 1639 | /* This should give a reasonable default video mode. */ |
1641 | if (tga_bus_pci) { | 1640 | if (tga_bus_pci) { |
diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c index 55e8aa450bfa..c699864b6f4a 100644 --- a/drivers/video/tridentfb.c +++ b/drivers/video/tridentfb.c | |||
@@ -976,7 +976,7 @@ static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
976 | return 1; | 976 | return 1; |
977 | 977 | ||
978 | 978 | ||
979 | if (bpp==8) { | 979 | if (bpp == 8) { |
980 | t_outb(0xFF,0x3C6); | 980 | t_outb(0xFF,0x3C6); |
981 | t_outb(regno,0x3C8); | 981 | t_outb(regno,0x3C8); |
982 | 982 | ||
@@ -984,19 +984,21 @@ static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
984 | t_outb(green>>10,0x3C9); | 984 | t_outb(green>>10,0x3C9); |
985 | t_outb(blue>>10,0x3C9); | 985 | t_outb(blue>>10,0x3C9); |
986 | 986 | ||
987 | } else if (bpp == 16) { /* RGB 565 */ | 987 | } else if (regno < 16) { |
988 | u32 col; | 988 | if (bpp == 16) { /* RGB 565 */ |
989 | 989 | u32 col; | |
990 | col = (red & 0xF800) | ((green & 0xFC00) >> 5) | | 990 | |
991 | ((blue & 0xF800) >> 11); | 991 | col = (red & 0xF800) | ((green & 0xFC00) >> 5) | |
992 | col |= col << 16; | 992 | ((blue & 0xF800) >> 11); |
993 | ((u32 *)(info->pseudo_palette))[regno] = col; | 993 | col |= col << 16; |
994 | } else if (bpp == 32) /* ARGB 8888 */ | 994 | ((u32 *)(info->pseudo_palette))[regno] = col; |
995 | ((u32*)info->pseudo_palette)[regno] = | 995 | } else if (bpp == 32) /* ARGB 8888 */ |
996 | ((transp & 0xFF00) <<16) | | 996 | ((u32*)info->pseudo_palette)[regno] = |
997 | ((red & 0xFF00) << 8) | | 997 | ((transp & 0xFF00) <<16) | |
998 | ((green & 0xFF00)) | | 998 | ((red & 0xFF00) << 8) | |
999 | ((blue & 0xFF00)>>8); | 999 | ((green & 0xFF00)) | |
1000 | ((blue & 0xFF00)>>8); | ||
1001 | } | ||
1000 | 1002 | ||
1001 | // debug("exit\n"); | 1003 | // debug("exit\n"); |
1002 | return 0; | 1004 | return 0; |
diff --git a/drivers/video/tx3912fb.c b/drivers/video/tx3912fb.c index 07389ba01eff..e6f7c78da68b 100644 --- a/drivers/video/tx3912fb.c +++ b/drivers/video/tx3912fb.c | |||
@@ -291,7 +291,7 @@ int __init tx3912fb_init(void) | |||
291 | fb_info.fbops = &tx3912fb_ops; | 291 | fb_info.fbops = &tx3912fb_ops; |
292 | fb_info.var = tx3912fb_var; | 292 | fb_info.var = tx3912fb_var; |
293 | fb_info.fix = tx3912fb_fix; | 293 | fb_info.fix = tx3912fb_fix; |
294 | fb_info.pseudo_palette = pseudo_palette; | 294 | fb_info.pseudo_palette = cfb8; |
295 | fb_info.flags = FBINFO_DEFAULT; | 295 | fb_info.flags = FBINFO_DEFAULT; |
296 | 296 | ||
297 | /* Clear the framebuffer */ | 297 | /* Clear the framebuffer */ |
diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c index ad66f070acb8..7b0cef9ca8f9 100644 --- a/drivers/video/valkyriefb.c +++ b/drivers/video/valkyriefb.c | |||
@@ -356,10 +356,9 @@ int __init valkyriefb_init(void) | |||
356 | } | 356 | } |
357 | #endif /* ppc (!CONFIG_MAC) */ | 357 | #endif /* ppc (!CONFIG_MAC) */ |
358 | 358 | ||
359 | p = kmalloc(sizeof(*p), GFP_ATOMIC); | 359 | p = kzalloc(sizeof(*p), GFP_ATOMIC); |
360 | if (p == 0) | 360 | if (p == 0) |
361 | return -ENOMEM; | 361 | return -ENOMEM; |
362 | memset(p, 0, sizeof(*p)); | ||
363 | 362 | ||
364 | /* Map in frame buffer and registers */ | 363 | /* Map in frame buffer and registers */ |
365 | if (!request_mem_region(frame_buffer_phys, 0x100000, "valkyriefb")) { | 364 | if (!request_mem_region(frame_buffer_phys, 0x100000, "valkyriefb")) { |
diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c new file mode 100644 index 000000000000..4c3a63308df1 --- /dev/null +++ b/drivers/video/vt8623fb.c | |||
@@ -0,0 +1,928 @@ | |||
1 | /* | ||
2 | * linux/drivers/video/vt8623fb.c - fbdev driver for | ||
3 | * integrated graphic core in VIA VT8623 [CLE266] chipset | ||
4 | * | ||
5 | * Copyright (c) 2006-2007 Ondrej Zajicek <santiago@crfreenet.org> | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General Public | ||
8 | * License. See the file COPYING in the main directory of this archive for | ||
9 | * more details. | ||
10 | * | ||
11 | * Code is based on s3fb, some parts are from David Boucher's viafb | ||
12 | * (http://davesdomain.org.uk/viafb/) | ||
13 | */ | ||
14 | |||
15 | #include <linux/version.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <linux/mm.h> | ||
21 | #include <linux/tty.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/fb.h> | ||
25 | #include <linux/svga.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/pci.h> | ||
28 | #include <linux/console.h> /* Why should fb driver call console functions? because acquire_console_sem() */ | ||
29 | #include <video/vga.h> | ||
30 | |||
31 | #ifdef CONFIG_MTRR | ||
32 | #include <asm/mtrr.h> | ||
33 | #endif | ||
34 | |||
35 | struct vt8623fb_info { | ||
36 | char __iomem *mmio_base; | ||
37 | int mtrr_reg; | ||
38 | struct vgastate state; | ||
39 | struct mutex open_lock; | ||
40 | unsigned int ref_count; | ||
41 | u32 pseudo_palette[16]; | ||
42 | }; | ||
43 | |||
44 | |||
45 | |||
46 | /* ------------------------------------------------------------------------- */ | ||
47 | |||
48 | static const struct svga_fb_format vt8623fb_formats[] = { | ||
49 | { 0, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0, | ||
50 | FB_TYPE_TEXT, FB_AUX_TEXT_SVGA_STEP8, FB_VISUAL_PSEUDOCOLOR, 16, 16}, | ||
51 | { 4, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0, | ||
52 | FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 16, 16}, | ||
53 | { 4, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 1, | ||
54 | FB_TYPE_INTERLEAVED_PLANES, 1, FB_VISUAL_PSEUDOCOLOR, 16, 16}, | ||
55 | { 8, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0, | ||
56 | FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 8, 8}, | ||
57 | /* {16, {10, 5, 0}, {5, 5, 0}, {0, 5, 0}, {0, 0, 0}, 0, | ||
58 | FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 4, 4}, */ | ||
59 | {16, {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, 0, | ||
60 | FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 4, 4}, | ||
61 | {32, {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, | ||
62 | FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 2, 2}, | ||
63 | SVGA_FORMAT_END | ||
64 | }; | ||
65 | |||
66 | static const struct svga_pll vt8623_pll = {2, 127, 2, 7, 0, 3, | ||
67 | 60000, 300000, 14318}; | ||
68 | |||
69 | /* CRT timing register sets */ | ||
70 | |||
71 | static struct vga_regset vt8623_h_total_regs[] = {{0x00, 0, 7}, {0x36, 3, 3}, VGA_REGSET_END}; | ||
72 | static struct vga_regset vt8623_h_display_regs[] = {{0x01, 0, 7}, VGA_REGSET_END}; | ||
73 | static struct vga_regset vt8623_h_blank_start_regs[] = {{0x02, 0, 7}, VGA_REGSET_END}; | ||
74 | static struct vga_regset vt8623_h_blank_end_regs[] = {{0x03, 0, 4}, {0x05, 7, 7}, {0x33, 5, 5}, VGA_REGSET_END}; | ||
75 | static struct vga_regset vt8623_h_sync_start_regs[] = {{0x04, 0, 7}, {0x33, 4, 4}, VGA_REGSET_END}; | ||
76 | static struct vga_regset vt8623_h_sync_end_regs[] = {{0x05, 0, 4}, VGA_REGSET_END}; | ||
77 | |||
78 | static struct vga_regset vt8623_v_total_regs[] = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x35, 0, 0}, VGA_REGSET_END}; | ||
79 | static struct vga_regset vt8623_v_display_regs[] = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x35, 2, 2}, VGA_REGSET_END}; | ||
80 | static struct vga_regset vt8623_v_blank_start_regs[] = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x35, 3, 3}, VGA_REGSET_END}; | ||
81 | static struct vga_regset vt8623_v_blank_end_regs[] = {{0x16, 0, 7}, VGA_REGSET_END}; | ||
82 | static struct vga_regset vt8623_v_sync_start_regs[] = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x35, 1, 1}, VGA_REGSET_END}; | ||
83 | static struct vga_regset vt8623_v_sync_end_regs[] = {{0x11, 0, 3}, VGA_REGSET_END}; | ||
84 | |||
85 | static struct vga_regset vt8623_offset_regs[] = {{0x13, 0, 7}, {0x35, 5, 7}, VGA_REGSET_END}; | ||
86 | static struct vga_regset vt8623_line_compare_regs[] = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, {0x33, 0, 2}, {0x35, 4, 4}, VGA_REGSET_END}; | ||
87 | static struct vga_regset vt8623_fetch_count_regs[] = {{0x1C, 0, 7}, {0x1D, 0, 1}, VGA_REGSET_END}; | ||
88 | static struct vga_regset vt8623_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x34, 0, 7}, {0x48, 0, 1}, VGA_REGSET_END}; | ||
89 | |||
90 | static struct svga_timing_regs vt8623_timing_regs = { | ||
91 | vt8623_h_total_regs, vt8623_h_display_regs, vt8623_h_blank_start_regs, | ||
92 | vt8623_h_blank_end_regs, vt8623_h_sync_start_regs, vt8623_h_sync_end_regs, | ||
93 | vt8623_v_total_regs, vt8623_v_display_regs, vt8623_v_blank_start_regs, | ||
94 | vt8623_v_blank_end_regs, vt8623_v_sync_start_regs, vt8623_v_sync_end_regs, | ||
95 | }; | ||
96 | |||
97 | |||
98 | /* ------------------------------------------------------------------------- */ | ||
99 | |||
100 | |||
101 | /* Module parameters */ | ||
102 | |||
103 | static char *mode = "640x480-8@60"; | ||
104 | |||
105 | #ifdef CONFIG_MTRR | ||
106 | static int mtrr = 1; | ||
107 | #endif | ||
108 | |||
109 | MODULE_AUTHOR("(c) 2006 Ondrej Zajicek <santiago@crfreenet.org>"); | ||
110 | MODULE_LICENSE("GPL"); | ||
111 | MODULE_DESCRIPTION("fbdev driver for integrated graphics core in VIA VT8623 [CLE266]"); | ||
112 | |||
113 | module_param(mode, charp, 0644); | ||
114 | MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)"); | ||
115 | |||
116 | #ifdef CONFIG_MTRR | ||
117 | module_param(mtrr, int, 0444); | ||
118 | MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)"); | ||
119 | #endif | ||
120 | |||
121 | |||
122 | /* ------------------------------------------------------------------------- */ | ||
123 | |||
124 | |||
125 | static struct fb_tile_ops vt8623fb_tile_ops = { | ||
126 | .fb_settile = svga_settile, | ||
127 | .fb_tilecopy = svga_tilecopy, | ||
128 | .fb_tilefill = svga_tilefill, | ||
129 | .fb_tileblit = svga_tileblit, | ||
130 | .fb_tilecursor = svga_tilecursor, | ||
131 | .fb_get_tilemax = svga_get_tilemax, | ||
132 | }; | ||
133 | |||
134 | |||
135 | /* ------------------------------------------------------------------------- */ | ||
136 | |||
137 | |||
138 | /* image data is MSB-first, fb structure is MSB-first too */ | ||
139 | static inline u32 expand_color(u32 c) | ||
140 | { | ||
141 | return ((c & 1) | ((c & 2) << 7) | ((c & 4) << 14) | ((c & 8) << 21)) * 0xFF; | ||
142 | } | ||
143 | |||
144 | /* vt8623fb_iplan_imageblit silently assumes that almost everything is 8-pixel aligned */ | ||
145 | static void vt8623fb_iplan_imageblit(struct fb_info *info, const struct fb_image *image) | ||
146 | { | ||
147 | u32 fg = expand_color(image->fg_color); | ||
148 | u32 bg = expand_color(image->bg_color); | ||
149 | const u8 *src1, *src; | ||
150 | u8 __iomem *dst1; | ||
151 | u32 __iomem *dst; | ||
152 | u32 val; | ||
153 | int x, y; | ||
154 | |||
155 | src1 = image->data; | ||
156 | dst1 = info->screen_base + (image->dy * info->fix.line_length) | ||
157 | + ((image->dx / 8) * 4); | ||
158 | |||
159 | for (y = 0; y < image->height; y++) { | ||
160 | src = src1; | ||
161 | dst = (u32 __iomem *) dst1; | ||
162 | for (x = 0; x < image->width; x += 8) { | ||
163 | val = *(src++) * 0x01010101; | ||
164 | val = (val & fg) | (~val & bg); | ||
165 | fb_writel(val, dst++); | ||
166 | } | ||
167 | src1 += image->width / 8; | ||
168 | dst1 += info->fix.line_length; | ||
169 | } | ||
170 | } | ||
171 | |||
172 | /* vt8623fb_iplan_fillrect silently assumes that almost everything is 8-pixel aligned */ | ||
173 | static void vt8623fb_iplan_fillrect(struct fb_info *info, const struct fb_fillrect *rect) | ||
174 | { | ||
175 | u32 fg = expand_color(rect->color); | ||
176 | u8 __iomem *dst1; | ||
177 | u32 __iomem *dst; | ||
178 | int x, y; | ||
179 | |||
180 | dst1 = info->screen_base + (rect->dy * info->fix.line_length) | ||
181 | + ((rect->dx / 8) * 4); | ||
182 | |||
183 | for (y = 0; y < rect->height; y++) { | ||
184 | dst = (u32 __iomem *) dst1; | ||
185 | for (x = 0; x < rect->width; x += 8) { | ||
186 | fb_writel(fg, dst++); | ||
187 | } | ||
188 | dst1 += info->fix.line_length; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | |||
193 | /* image data is MSB-first, fb structure is high-nibble-in-low-byte-first */ | ||
194 | static inline u32 expand_pixel(u32 c) | ||
195 | { | ||
196 | return (((c & 1) << 24) | ((c & 2) << 27) | ((c & 4) << 14) | ((c & 8) << 17) | | ||
197 | ((c & 16) << 4) | ((c & 32) << 7) | ((c & 64) >> 6) | ((c & 128) >> 3)) * 0xF; | ||
198 | } | ||
199 | |||
200 | /* vt8623fb_cfb4_imageblit silently assumes that almost everything is 8-pixel aligned */ | ||
201 | static void vt8623fb_cfb4_imageblit(struct fb_info *info, const struct fb_image *image) | ||
202 | { | ||
203 | u32 fg = image->fg_color * 0x11111111; | ||
204 | u32 bg = image->bg_color * 0x11111111; | ||
205 | const u8 *src1, *src; | ||
206 | u8 __iomem *dst1; | ||
207 | u32 __iomem *dst; | ||
208 | u32 val; | ||
209 | int x, y; | ||
210 | |||
211 | src1 = image->data; | ||
212 | dst1 = info->screen_base + (image->dy * info->fix.line_length) | ||
213 | + ((image->dx / 8) * 4); | ||
214 | |||
215 | for (y = 0; y < image->height; y++) { | ||
216 | src = src1; | ||
217 | dst = (u32 __iomem *) dst1; | ||
218 | for (x = 0; x < image->width; x += 8) { | ||
219 | val = expand_pixel(*(src++)); | ||
220 | val = (val & fg) | (~val & bg); | ||
221 | fb_writel(val, dst++); | ||
222 | } | ||
223 | src1 += image->width / 8; | ||
224 | dst1 += info->fix.line_length; | ||
225 | } | ||
226 | } | ||
227 | |||
228 | static void vt8623fb_imageblit(struct fb_info *info, const struct fb_image *image) | ||
229 | { | ||
230 | if ((info->var.bits_per_pixel == 4) && (image->depth == 1) | ||
231 | && ((image->width % 8) == 0) && ((image->dx % 8) == 0)) { | ||
232 | if (info->fix.type == FB_TYPE_INTERLEAVED_PLANES) | ||
233 | vt8623fb_iplan_imageblit(info, image); | ||
234 | else | ||
235 | vt8623fb_cfb4_imageblit(info, image); | ||
236 | } else | ||
237 | cfb_imageblit(info, image); | ||
238 | } | ||
239 | |||
240 | static void vt8623fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) | ||
241 | { | ||
242 | if ((info->var.bits_per_pixel == 4) | ||
243 | && ((rect->width % 8) == 0) && ((rect->dx % 8) == 0) | ||
244 | && (info->fix.type == FB_TYPE_INTERLEAVED_PLANES)) | ||
245 | vt8623fb_iplan_fillrect(info, rect); | ||
246 | else | ||
247 | cfb_fillrect(info, rect); | ||
248 | } | ||
249 | |||
250 | |||
251 | /* ------------------------------------------------------------------------- */ | ||
252 | |||
253 | |||
254 | static void vt8623_set_pixclock(struct fb_info *info, u32 pixclock) | ||
255 | { | ||
256 | u16 m, n, r; | ||
257 | u8 regval; | ||
258 | int rv; | ||
259 | |||
260 | rv = svga_compute_pll(&vt8623_pll, 1000000000 / pixclock, &m, &n, &r, info->node); | ||
261 | if (rv < 0) { | ||
262 | printk(KERN_ERR "fb%d: cannot set requested pixclock, keeping old value\n", info->node); | ||
263 | return; | ||
264 | } | ||
265 | |||
266 | /* Set VGA misc register */ | ||
267 | regval = vga_r(NULL, VGA_MIS_R); | ||
268 | vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD); | ||
269 | |||
270 | /* Set clock registers */ | ||
271 | vga_wseq(NULL, 0x46, (n | (r << 6))); | ||
272 | vga_wseq(NULL, 0x47, m); | ||
273 | |||
274 | udelay(1000); | ||
275 | |||
276 | /* PLL reset */ | ||
277 | svga_wseq_mask(0x40, 0x02, 0x02); | ||
278 | svga_wseq_mask(0x40, 0x00, 0x02); | ||
279 | } | ||
280 | |||
281 | |||
282 | static int vt8623fb_open(struct fb_info *info, int user) | ||
283 | { | ||
284 | struct vt8623fb_info *par = info->par; | ||
285 | |||
286 | mutex_lock(&(par->open_lock)); | ||
287 | if (par->ref_count == 0) { | ||
288 | memset(&(par->state), 0, sizeof(struct vgastate)); | ||
289 | par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP; | ||
290 | par->state.num_crtc = 0xA2; | ||
291 | par->state.num_seq = 0x50; | ||
292 | save_vga(&(par->state)); | ||
293 | } | ||
294 | |||
295 | par->ref_count++; | ||
296 | mutex_unlock(&(par->open_lock)); | ||
297 | |||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | static int vt8623fb_release(struct fb_info *info, int user) | ||
302 | { | ||
303 | struct vt8623fb_info *par = info->par; | ||
304 | |||
305 | mutex_lock(&(par->open_lock)); | ||
306 | if (par->ref_count == 0) { | ||
307 | mutex_unlock(&(par->open_lock)); | ||
308 | return -EINVAL; | ||
309 | } | ||
310 | |||
311 | if (par->ref_count == 1) | ||
312 | restore_vga(&(par->state)); | ||
313 | |||
314 | par->ref_count--; | ||
315 | mutex_unlock(&(par->open_lock)); | ||
316 | |||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | static int vt8623fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | ||
321 | { | ||
322 | int rv, mem, step; | ||
323 | |||
324 | /* Find appropriate format */ | ||
325 | rv = svga_match_format (vt8623fb_formats, var, NULL); | ||
326 | if (rv < 0) | ||
327 | { | ||
328 | printk(KERN_ERR "fb%d: unsupported mode requested\n", info->node); | ||
329 | return rv; | ||
330 | } | ||
331 | |||
332 | /* Do not allow to have real resoulution larger than virtual */ | ||
333 | if (var->xres > var->xres_virtual) | ||
334 | var->xres_virtual = var->xres; | ||
335 | |||
336 | if (var->yres > var->yres_virtual) | ||
337 | var->yres_virtual = var->yres; | ||
338 | |||
339 | /* Round up xres_virtual to have proper alignment of lines */ | ||
340 | step = vt8623fb_formats[rv].xresstep - 1; | ||
341 | var->xres_virtual = (var->xres_virtual+step) & ~step; | ||
342 | |||
343 | /* Check whether have enough memory */ | ||
344 | mem = ((var->bits_per_pixel * var->xres_virtual) >> 3) * var->yres_virtual; | ||
345 | if (mem > info->screen_size) | ||
346 | { | ||
347 | printk(KERN_ERR "fb%d: not enough framebuffer memory (%d kB requested , %d kB available)\n", info->node, mem >> 10, (unsigned int) (info->screen_size >> 10)); | ||
348 | return -EINVAL; | ||
349 | } | ||
350 | |||
351 | /* Text mode is limited to 256 kB of memory */ | ||
352 | if ((var->bits_per_pixel == 0) && (mem > (256*1024))) | ||
353 | { | ||
354 | printk(KERN_ERR "fb%d: text framebuffer size too large (%d kB requested, 256 kB possible)\n", info->node, mem >> 10); | ||
355 | return -EINVAL; | ||
356 | } | ||
357 | |||
358 | rv = svga_check_timings (&vt8623_timing_regs, var, info->node); | ||
359 | if (rv < 0) | ||
360 | { | ||
361 | printk(KERN_ERR "fb%d: invalid timings requested\n", info->node); | ||
362 | return rv; | ||
363 | } | ||
364 | |||
365 | /* Interlaced mode not supported */ | ||
366 | if (var->vmode & FB_VMODE_INTERLACED) | ||
367 | return -EINVAL; | ||
368 | |||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | |||
373 | static int vt8623fb_set_par(struct fb_info *info) | ||
374 | { | ||
375 | u32 mode, offset_value, fetch_value, screen_size; | ||
376 | u32 bpp = info->var.bits_per_pixel; | ||
377 | |||
378 | if (bpp != 0) { | ||
379 | info->fix.ypanstep = 1; | ||
380 | info->fix.line_length = (info->var.xres_virtual * bpp) / 8; | ||
381 | |||
382 | info->flags &= ~FBINFO_MISC_TILEBLITTING; | ||
383 | info->tileops = NULL; | ||
384 | |||
385 | /* in 4bpp supports 8p wide tiles only, any tiles otherwise */ | ||
386 | info->pixmap.blit_x = (bpp == 4) ? (1 << (8 - 1)) : (~(u32)0); | ||
387 | info->pixmap.blit_y = ~(u32)0; | ||
388 | |||
389 | offset_value = (info->var.xres_virtual * bpp) / 64; | ||
390 | fetch_value = ((info->var.xres * bpp) / 128) + 4; | ||
391 | |||
392 | if (bpp == 4) | ||
393 | fetch_value = (info->var.xres / 8) + 8; /* + 0 is OK */ | ||
394 | |||
395 | screen_size = info->var.yres_virtual * info->fix.line_length; | ||
396 | } else { | ||
397 | info->fix.ypanstep = 16; | ||
398 | info->fix.line_length = 0; | ||
399 | |||
400 | info->flags |= FBINFO_MISC_TILEBLITTING; | ||
401 | info->tileops = &vt8623fb_tile_ops; | ||
402 | |||
403 | /* supports 8x16 tiles only */ | ||
404 | info->pixmap.blit_x = 1 << (8 - 1); | ||
405 | info->pixmap.blit_y = 1 << (16 - 1); | ||
406 | |||
407 | offset_value = info->var.xres_virtual / 16; | ||
408 | fetch_value = (info->var.xres / 8) + 8; | ||
409 | screen_size = (info->var.xres_virtual * info->var.yres_virtual) / 64; | ||
410 | } | ||
411 | |||
412 | info->var.xoffset = 0; | ||
413 | info->var.yoffset = 0; | ||
414 | info->var.activate = FB_ACTIVATE_NOW; | ||
415 | |||
416 | /* Unlock registers */ | ||
417 | svga_wseq_mask(0x10, 0x01, 0x01); | ||
418 | svga_wcrt_mask(0x11, 0x00, 0x80); | ||
419 | svga_wcrt_mask(0x47, 0x00, 0x01); | ||
420 | |||
421 | /* Device, screen and sync off */ | ||
422 | svga_wseq_mask(0x01, 0x20, 0x20); | ||
423 | svga_wcrt_mask(0x36, 0x30, 0x30); | ||
424 | svga_wcrt_mask(0x17, 0x00, 0x80); | ||
425 | |||
426 | /* Set default values */ | ||
427 | svga_set_default_gfx_regs(); | ||
428 | svga_set_default_atc_regs(); | ||
429 | svga_set_default_seq_regs(); | ||
430 | svga_set_default_crt_regs(); | ||
431 | svga_wcrt_multi(vt8623_line_compare_regs, 0xFFFFFFFF); | ||
432 | svga_wcrt_multi(vt8623_start_address_regs, 0); | ||
433 | |||
434 | svga_wcrt_multi(vt8623_offset_regs, offset_value); | ||
435 | svga_wseq_multi(vt8623_fetch_count_regs, fetch_value); | ||
436 | |||
437 | if (info->var.vmode & FB_VMODE_DOUBLE) | ||
438 | svga_wcrt_mask(0x09, 0x80, 0x80); | ||
439 | else | ||
440 | svga_wcrt_mask(0x09, 0x00, 0x80); | ||
441 | |||
442 | svga_wseq_mask(0x1E, 0xF0, 0xF0); // DI/DVP bus | ||
443 | svga_wseq_mask(0x2A, 0x0F, 0x0F); // DI/DVP bus | ||
444 | svga_wseq_mask(0x16, 0x08, 0xBF); // FIFO read treshold | ||
445 | vga_wseq(NULL, 0x17, 0x1F); // FIFO depth | ||
446 | vga_wseq(NULL, 0x18, 0x4E); | ||
447 | svga_wseq_mask(0x1A, 0x08, 0x08); // enable MMIO ? | ||
448 | |||
449 | vga_wcrt(NULL, 0x32, 0x00); | ||
450 | vga_wcrt(NULL, 0x34, 0x00); | ||
451 | vga_wcrt(NULL, 0x6A, 0x80); | ||
452 | vga_wcrt(NULL, 0x6A, 0xC0); | ||
453 | |||
454 | vga_wgfx(NULL, 0x20, 0x00); | ||
455 | vga_wgfx(NULL, 0x21, 0x00); | ||
456 | vga_wgfx(NULL, 0x22, 0x00); | ||
457 | |||
458 | /* Set SR15 according to number of bits per pixel */ | ||
459 | mode = svga_match_format(vt8623fb_formats, &(info->var), &(info->fix)); | ||
460 | switch (mode) { | ||
461 | case 0: | ||
462 | pr_debug("fb%d: text mode\n", info->node); | ||
463 | svga_set_textmode_vga_regs(); | ||
464 | svga_wseq_mask(0x15, 0x00, 0xFE); | ||
465 | svga_wcrt_mask(0x11, 0x60, 0x70); | ||
466 | break; | ||
467 | case 1: | ||
468 | pr_debug("fb%d: 4 bit pseudocolor\n", info->node); | ||
469 | vga_wgfx(NULL, VGA_GFX_MODE, 0x40); | ||
470 | svga_wseq_mask(0x15, 0x20, 0xFE); | ||
471 | svga_wcrt_mask(0x11, 0x00, 0x70); | ||
472 | break; | ||
473 | case 2: | ||
474 | pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node); | ||
475 | svga_wseq_mask(0x15, 0x00, 0xFE); | ||
476 | svga_wcrt_mask(0x11, 0x00, 0x70); | ||
477 | break; | ||
478 | case 3: | ||
479 | pr_debug("fb%d: 8 bit pseudocolor\n", info->node); | ||
480 | svga_wseq_mask(0x15, 0x22, 0xFE); | ||
481 | break; | ||
482 | case 4: | ||
483 | pr_debug("fb%d: 5/6/5 truecolor\n", info->node); | ||
484 | svga_wseq_mask(0x15, 0xB6, 0xFE); | ||
485 | break; | ||
486 | case 5: | ||
487 | pr_debug("fb%d: 8/8/8 truecolor\n", info->node); | ||
488 | svga_wseq_mask(0x15, 0xAE, 0xFE); | ||
489 | break; | ||
490 | default: | ||
491 | printk(KERN_ERR "vt8623fb: unsupported mode - bug\n"); | ||
492 | return (-EINVAL); | ||
493 | } | ||
494 | |||
495 | vt8623_set_pixclock(info, info->var.pixclock); | ||
496 | svga_set_timings(&vt8623_timing_regs, &(info->var), 1, 1, | ||
497 | (info->var.vmode & FB_VMODE_DOUBLE) ? 2 : 1, 1, | ||
498 | 1, info->node); | ||
499 | |||
500 | memset_io(info->screen_base, 0x00, screen_size); | ||
501 | |||
502 | /* Device and screen back on */ | ||
503 | svga_wcrt_mask(0x17, 0x80, 0x80); | ||
504 | svga_wcrt_mask(0x36, 0x00, 0x30); | ||
505 | svga_wseq_mask(0x01, 0x00, 0x20); | ||
506 | |||
507 | return 0; | ||
508 | } | ||
509 | |||
510 | |||
511 | static int vt8623fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, | ||
512 | u_int transp, struct fb_info *fb) | ||
513 | { | ||
514 | switch (fb->var.bits_per_pixel) { | ||
515 | case 0: | ||
516 | case 4: | ||
517 | if (regno >= 16) | ||
518 | return -EINVAL; | ||
519 | |||
520 | outb(0x0F, VGA_PEL_MSK); | ||
521 | outb(regno, VGA_PEL_IW); | ||
522 | outb(red >> 10, VGA_PEL_D); | ||
523 | outb(green >> 10, VGA_PEL_D); | ||
524 | outb(blue >> 10, VGA_PEL_D); | ||
525 | break; | ||
526 | case 8: | ||
527 | if (regno >= 256) | ||
528 | return -EINVAL; | ||
529 | |||
530 | outb(0xFF, VGA_PEL_MSK); | ||
531 | outb(regno, VGA_PEL_IW); | ||
532 | outb(red >> 10, VGA_PEL_D); | ||
533 | outb(green >> 10, VGA_PEL_D); | ||
534 | outb(blue >> 10, VGA_PEL_D); | ||
535 | break; | ||
536 | case 16: | ||
537 | if (regno >= 16) | ||
538 | return 0; | ||
539 | |||
540 | if (fb->var.green.length == 5) | ||
541 | ((u32*)fb->pseudo_palette)[regno] = ((red & 0xF800) >> 1) | | ||
542 | ((green & 0xF800) >> 6) | ((blue & 0xF800) >> 11); | ||
543 | else if (fb->var.green.length == 6) | ||
544 | ((u32*)fb->pseudo_palette)[regno] = (red & 0xF800) | | ||
545 | ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11); | ||
546 | else | ||
547 | return -EINVAL; | ||
548 | break; | ||
549 | case 24: | ||
550 | case 32: | ||
551 | if (regno >= 16) | ||
552 | return 0; | ||
553 | |||
554 | /* ((transp & 0xFF00) << 16) */ | ||
555 | ((u32*)fb->pseudo_palette)[regno] = ((red & 0xFF00) << 8) | | ||
556 | (green & 0xFF00) | ((blue & 0xFF00) >> 8); | ||
557 | break; | ||
558 | default: | ||
559 | return -EINVAL; | ||
560 | } | ||
561 | |||
562 | return 0; | ||
563 | } | ||
564 | |||
565 | |||
566 | static int vt8623fb_blank(int blank_mode, struct fb_info *info) | ||
567 | { | ||
568 | switch (blank_mode) { | ||
569 | case FB_BLANK_UNBLANK: | ||
570 | pr_debug("fb%d: unblank\n", info->node); | ||
571 | svga_wcrt_mask(0x36, 0x00, 0x30); | ||
572 | svga_wseq_mask(0x01, 0x00, 0x20); | ||
573 | break; | ||
574 | case FB_BLANK_NORMAL: | ||
575 | pr_debug("fb%d: blank\n", info->node); | ||
576 | svga_wcrt_mask(0x36, 0x00, 0x30); | ||
577 | svga_wseq_mask(0x01, 0x20, 0x20); | ||
578 | break; | ||
579 | case FB_BLANK_HSYNC_SUSPEND: | ||
580 | pr_debug("fb%d: DPMS standby (hsync off)\n", info->node); | ||
581 | svga_wcrt_mask(0x36, 0x10, 0x30); | ||
582 | svga_wseq_mask(0x01, 0x20, 0x20); | ||
583 | break; | ||
584 | case FB_BLANK_VSYNC_SUSPEND: | ||
585 | pr_debug("fb%d: DPMS suspend (vsync off)\n", info->node); | ||
586 | svga_wcrt_mask(0x36, 0x20, 0x30); | ||
587 | svga_wseq_mask(0x01, 0x20, 0x20); | ||
588 | break; | ||
589 | case FB_BLANK_POWERDOWN: | ||
590 | pr_debug("fb%d: DPMS off (no sync)\n", info->node); | ||
591 | svga_wcrt_mask(0x36, 0x30, 0x30); | ||
592 | svga_wseq_mask(0x01, 0x20, 0x20); | ||
593 | break; | ||
594 | } | ||
595 | |||
596 | return 0; | ||
597 | } | ||
598 | |||
599 | |||
600 | static int vt8623fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) | ||
601 | { | ||
602 | unsigned int offset; | ||
603 | |||
604 | /* Calculate the offset */ | ||
605 | if (var->bits_per_pixel == 0) { | ||
606 | offset = (var->yoffset / 16) * var->xres_virtual + var->xoffset; | ||
607 | offset = offset >> 3; | ||
608 | } else { | ||
609 | offset = (var->yoffset * info->fix.line_length) + | ||
610 | (var->xoffset * var->bits_per_pixel / 8); | ||
611 | offset = offset >> ((var->bits_per_pixel == 4) ? 2 : 1); | ||
612 | } | ||
613 | |||
614 | /* Set the offset */ | ||
615 | svga_wcrt_multi(vt8623_start_address_regs, offset); | ||
616 | |||
617 | return 0; | ||
618 | } | ||
619 | |||
620 | |||
621 | /* ------------------------------------------------------------------------- */ | ||
622 | |||
623 | |||
624 | /* Frame buffer operations */ | ||
625 | |||
626 | static struct fb_ops vt8623fb_ops = { | ||
627 | .owner = THIS_MODULE, | ||
628 | .fb_open = vt8623fb_open, | ||
629 | .fb_release = vt8623fb_release, | ||
630 | .fb_check_var = vt8623fb_check_var, | ||
631 | .fb_set_par = vt8623fb_set_par, | ||
632 | .fb_setcolreg = vt8623fb_setcolreg, | ||
633 | .fb_blank = vt8623fb_blank, | ||
634 | .fb_pan_display = vt8623fb_pan_display, | ||
635 | .fb_fillrect = vt8623fb_fillrect, | ||
636 | .fb_copyarea = cfb_copyarea, | ||
637 | .fb_imageblit = vt8623fb_imageblit, | ||
638 | .fb_get_caps = svga_get_caps, | ||
639 | }; | ||
640 | |||
641 | |||
642 | /* PCI probe */ | ||
643 | |||
644 | static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) | ||
645 | { | ||
646 | struct fb_info *info; | ||
647 | struct vt8623fb_info *par; | ||
648 | unsigned int memsize1, memsize2; | ||
649 | int rc; | ||
650 | |||
651 | /* Ignore secondary VGA device because there is no VGA arbitration */ | ||
652 | if (! svga_primary_device(dev)) { | ||
653 | dev_info(&(dev->dev), "ignoring secondary device\n"); | ||
654 | return -ENODEV; | ||
655 | } | ||
656 | |||
657 | /* Allocate and fill driver data structure */ | ||
658 | info = framebuffer_alloc(sizeof(struct vt8623fb_info), NULL); | ||
659 | if (! info) { | ||
660 | dev_err(&(dev->dev), "cannot allocate memory\n"); | ||
661 | return -ENOMEM; | ||
662 | } | ||
663 | |||
664 | par = info->par; | ||
665 | mutex_init(&par->open_lock); | ||
666 | |||
667 | info->flags = FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN; | ||
668 | info->fbops = &vt8623fb_ops; | ||
669 | |||
670 | /* Prepare PCI device */ | ||
671 | |||
672 | rc = pci_enable_device(dev); | ||
673 | if (rc < 0) { | ||
674 | dev_err(&(dev->dev), "cannot enable PCI device\n"); | ||
675 | goto err_enable_device; | ||
676 | } | ||
677 | |||
678 | rc = pci_request_regions(dev, "vt8623fb"); | ||
679 | if (rc < 0) { | ||
680 | dev_err(&(dev->dev), "cannot reserve framebuffer region\n"); | ||
681 | goto err_request_regions; | ||
682 | } | ||
683 | |||
684 | info->fix.smem_start = pci_resource_start(dev, 0); | ||
685 | info->fix.smem_len = pci_resource_len(dev, 0); | ||
686 | info->fix.mmio_start = pci_resource_start(dev, 1); | ||
687 | info->fix.mmio_len = pci_resource_len(dev, 1); | ||
688 | |||
689 | /* Map physical IO memory address into kernel space */ | ||
690 | info->screen_base = pci_iomap(dev, 0, 0); | ||
691 | if (! info->screen_base) { | ||
692 | rc = -ENOMEM; | ||
693 | dev_err(&(dev->dev), "iomap for framebuffer failed\n"); | ||
694 | goto err_iomap_1; | ||
695 | } | ||
696 | |||
697 | par->mmio_base = pci_iomap(dev, 1, 0); | ||
698 | if (! par->mmio_base) { | ||
699 | rc = -ENOMEM; | ||
700 | dev_err(&(dev->dev), "iomap for MMIO failed\n"); | ||
701 | goto err_iomap_2; | ||
702 | } | ||
703 | |||
704 | /* Find how many physical memory there is on card */ | ||
705 | memsize1 = (vga_rseq(NULL, 0x34) + 1) >> 1; | ||
706 | memsize2 = vga_rseq(NULL, 0x39) << 2; | ||
707 | |||
708 | if ((16 <= memsize1) && (memsize1 <= 64) && (memsize1 == memsize2)) | ||
709 | info->screen_size = memsize1 << 20; | ||
710 | else { | ||
711 | dev_err(&(dev->dev), "memory size detection failed (%x %x), suppose 16 MB\n", memsize1, memsize2); | ||
712 | info->screen_size = 16 << 20; | ||
713 | } | ||
714 | |||
715 | info->fix.smem_len = info->screen_size; | ||
716 | strcpy(info->fix.id, "VIA VT8623"); | ||
717 | info->fix.type = FB_TYPE_PACKED_PIXELS; | ||
718 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; | ||
719 | info->fix.ypanstep = 0; | ||
720 | info->fix.accel = FB_ACCEL_NONE; | ||
721 | info->pseudo_palette = (void*)par->pseudo_palette; | ||
722 | |||
723 | /* Prepare startup mode */ | ||
724 | |||
725 | rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8); | ||
726 | if (! ((rc == 1) || (rc == 2))) { | ||
727 | rc = -EINVAL; | ||
728 | dev_err(&(dev->dev), "mode %s not found\n", mode); | ||
729 | goto err_find_mode; | ||
730 | } | ||
731 | |||
732 | rc = fb_alloc_cmap(&info->cmap, 256, 0); | ||
733 | if (rc < 0) { | ||
734 | dev_err(&(dev->dev), "cannot allocate colormap\n"); | ||
735 | goto err_alloc_cmap; | ||
736 | } | ||
737 | |||
738 | rc = register_framebuffer(info); | ||
739 | if (rc < 0) { | ||
740 | dev_err(&(dev->dev), "cannot register framebugger\n"); | ||
741 | goto err_reg_fb; | ||
742 | } | ||
743 | |||
744 | printk(KERN_INFO "fb%d: %s on %s, %d MB RAM\n", info->node, info->fix.id, | ||
745 | pci_name(dev), info->fix.smem_len >> 20); | ||
746 | |||
747 | /* Record a reference to the driver data */ | ||
748 | pci_set_drvdata(dev, info); | ||
749 | |||
750 | #ifdef CONFIG_MTRR | ||
751 | if (mtrr) { | ||
752 | par->mtrr_reg = -1; | ||
753 | par->mtrr_reg = mtrr_add(info->fix.smem_start, info->fix.smem_len, MTRR_TYPE_WRCOMB, 1); | ||
754 | } | ||
755 | #endif | ||
756 | |||
757 | return 0; | ||
758 | |||
759 | /* Error handling */ | ||
760 | err_reg_fb: | ||
761 | fb_dealloc_cmap(&info->cmap); | ||
762 | err_alloc_cmap: | ||
763 | err_find_mode: | ||
764 | pci_iounmap(dev, par->mmio_base); | ||
765 | err_iomap_2: | ||
766 | pci_iounmap(dev, info->screen_base); | ||
767 | err_iomap_1: | ||
768 | pci_release_regions(dev); | ||
769 | err_request_regions: | ||
770 | /* pci_disable_device(dev); */ | ||
771 | err_enable_device: | ||
772 | framebuffer_release(info); | ||
773 | return rc; | ||
774 | } | ||
775 | |||
776 | /* PCI remove */ | ||
777 | |||
778 | static void __devexit vt8623_pci_remove(struct pci_dev *dev) | ||
779 | { | ||
780 | struct fb_info *info = pci_get_drvdata(dev); | ||
781 | |||
782 | if (info) { | ||
783 | struct vt8623fb_info *par = info->par; | ||
784 | |||
785 | #ifdef CONFIG_MTRR | ||
786 | if (par->mtrr_reg >= 0) { | ||
787 | mtrr_del(par->mtrr_reg, 0, 0); | ||
788 | par->mtrr_reg = -1; | ||
789 | } | ||
790 | #endif | ||
791 | |||
792 | unregister_framebuffer(info); | ||
793 | fb_dealloc_cmap(&info->cmap); | ||
794 | |||
795 | pci_iounmap(dev, info->screen_base); | ||
796 | pci_iounmap(dev, par->mmio_base); | ||
797 | pci_release_regions(dev); | ||
798 | /* pci_disable_device(dev); */ | ||
799 | |||
800 | pci_set_drvdata(dev, NULL); | ||
801 | framebuffer_release(info); | ||
802 | } | ||
803 | } | ||
804 | |||
805 | |||
806 | #ifdef CONFIG_PM | ||
807 | /* PCI suspend */ | ||
808 | |||
809 | static int vt8623_pci_suspend(struct pci_dev* dev, pm_message_t state) | ||
810 | { | ||
811 | struct fb_info *info = pci_get_drvdata(dev); | ||
812 | struct vt8623fb_info *par = info->par; | ||
813 | |||
814 | dev_info(&(dev->dev), "suspend\n"); | ||
815 | |||
816 | acquire_console_sem(); | ||
817 | mutex_lock(&(par->open_lock)); | ||
818 | |||
819 | if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) { | ||
820 | mutex_unlock(&(par->open_lock)); | ||
821 | release_console_sem(); | ||
822 | return 0; | ||
823 | } | ||
824 | |||
825 | fb_set_suspend(info, 1); | ||
826 | |||
827 | pci_save_state(dev); | ||
828 | pci_disable_device(dev); | ||
829 | pci_set_power_state(dev, pci_choose_state(dev, state)); | ||
830 | |||
831 | mutex_unlock(&(par->open_lock)); | ||
832 | release_console_sem(); | ||
833 | |||
834 | return 0; | ||
835 | } | ||
836 | |||
837 | |||
838 | /* PCI resume */ | ||
839 | |||
840 | static int vt8623_pci_resume(struct pci_dev* dev) | ||
841 | { | ||
842 | struct fb_info *info = pci_get_drvdata(dev); | ||
843 | struct vt8623fb_info *par = info->par; | ||
844 | |||
845 | dev_info(&(dev->dev), "resume\n"); | ||
846 | |||
847 | acquire_console_sem(); | ||
848 | mutex_lock(&(par->open_lock)); | ||
849 | |||
850 | if (par->ref_count == 0) { | ||
851 | mutex_unlock(&(par->open_lock)); | ||
852 | release_console_sem(); | ||
853 | return 0; | ||
854 | } | ||
855 | |||
856 | pci_set_power_state(dev, PCI_D0); | ||
857 | pci_restore_state(dev); | ||
858 | |||
859 | if (pci_enable_device(dev)) | ||
860 | goto fail; | ||
861 | |||
862 | pci_set_master(dev); | ||
863 | |||
864 | vt8623fb_set_par(info); | ||
865 | fb_set_suspend(info, 0); | ||
866 | |||
867 | mutex_unlock(&(par->open_lock)); | ||
868 | fail: | ||
869 | release_console_sem(); | ||
870 | |||
871 | return 0; | ||
872 | } | ||
873 | #else | ||
874 | #define vt8623_pci_suspend NULL | ||
875 | #define vt8623_pci_resume NULL | ||
876 | #endif /* CONFIG_PM */ | ||
877 | |||
878 | /* List of boards that we are trying to support */ | ||
879 | |||
880 | static struct pci_device_id vt8623_devices[] __devinitdata = { | ||
881 | {PCI_DEVICE(PCI_VENDOR_ID_VIA, 0x3122)}, | ||
882 | {0, 0, 0, 0, 0, 0, 0} | ||
883 | }; | ||
884 | |||
885 | MODULE_DEVICE_TABLE(pci, vt8623_devices); | ||
886 | |||
887 | static struct pci_driver vt8623fb_pci_driver = { | ||
888 | .name = "vt8623fb", | ||
889 | .id_table = vt8623_devices, | ||
890 | .probe = vt8623_pci_probe, | ||
891 | .remove = __devexit_p(vt8623_pci_remove), | ||
892 | .suspend = vt8623_pci_suspend, | ||
893 | .resume = vt8623_pci_resume, | ||
894 | }; | ||
895 | |||
896 | /* Cleanup */ | ||
897 | |||
898 | static void __exit vt8623fb_cleanup(void) | ||
899 | { | ||
900 | pr_debug("vt8623fb: cleaning up\n"); | ||
901 | pci_unregister_driver(&vt8623fb_pci_driver); | ||
902 | } | ||
903 | |||
904 | /* Driver Initialisation */ | ||
905 | |||
906 | static int __init vt8623fb_init(void) | ||
907 | { | ||
908 | |||
909 | #ifndef MODULE | ||
910 | char *option = NULL; | ||
911 | |||
912 | if (fb_get_options("vt8623fb", &option)) | ||
913 | return -ENODEV; | ||
914 | |||
915 | if (option && *option) | ||
916 | mode = option; | ||
917 | #endif | ||
918 | |||
919 | pr_debug("vt8623fb: initializing\n"); | ||
920 | return pci_register_driver(&vt8623fb_pci_driver); | ||
921 | } | ||
922 | |||
923 | /* ------------------------------------------------------------------------- */ | ||
924 | |||
925 | /* Modularization */ | ||
926 | |||
927 | module_init(vt8623fb_init); | ||
928 | module_exit(vt8623fb_cleanup); | ||
diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c index 5fc86ea20692..003c49a490eb 100644 --- a/drivers/video/w100fb.c +++ b/drivers/video/w100fb.c | |||
@@ -660,7 +660,7 @@ int __init w100fb_probe(struct platform_device *pdev) | |||
660 | err = -ENODEV; | 660 | err = -ENODEV; |
661 | goto out; | 661 | goto out; |
662 | } | 662 | } |
663 | printk(" at 0x%08lx.\n", mem->start+W100_CFG_BASE); | 663 | printk(" at 0x%08lx.\n", (unsigned long) mem->start+W100_CFG_BASE); |
664 | 664 | ||
665 | /* Remap the framebuffer */ | 665 | /* Remap the framebuffer */ |
666 | remapped_fbuf = ioremap_nocache(mem->start+MEM_WINDOW_BASE, MEM_WINDOW_SIZE); | 666 | remapped_fbuf = ioremap_nocache(mem->start+MEM_WINDOW_BASE, MEM_WINDOW_SIZE); |
@@ -753,10 +753,14 @@ int __init w100fb_probe(struct platform_device *pdev) | |||
753 | goto out; | 753 | goto out; |
754 | } | 754 | } |
755 | 755 | ||
756 | device_create_file(&pdev->dev, &dev_attr_fastpllclk); | 756 | err = device_create_file(&pdev->dev, &dev_attr_fastpllclk); |
757 | device_create_file(&pdev->dev, &dev_attr_reg_read); | 757 | err |= device_create_file(&pdev->dev, &dev_attr_reg_read); |
758 | device_create_file(&pdev->dev, &dev_attr_reg_write); | 758 | err |= device_create_file(&pdev->dev, &dev_attr_reg_write); |
759 | device_create_file(&pdev->dev, &dev_attr_flip); | 759 | err |= device_create_file(&pdev->dev, &dev_attr_flip); |
760 | |||
761 | if (err != 0) | ||
762 | printk(KERN_WARNING "fb%d: failed to register attributes (%d)\n", | ||
763 | info->node, err); | ||
760 | 764 | ||
761 | printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); | 765 | printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); |
762 | return 0; | 766 | return 0; |