aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/68328fb.c2
-rw-r--r--drivers/video/Kconfig269
-rw-r--r--drivers/video/Makefile4
-rw-r--r--drivers/video/amba-clcd.c3
-rw-r--r--drivers/video/arkfb.c1201
-rw-r--r--drivers/video/atmel_lcdfb.c801
-rw-r--r--drivers/video/aty/ati_ids.h1
-rw-r--r--drivers/video/aty/atyfb_base.c26
-rw-r--r--drivers/video/aty/radeon_base.c12
-rw-r--r--drivers/video/aty/radeonfb.h2
-rw-r--r--drivers/video/au1200fb.c3
-rw-r--r--drivers/video/backlight/backlight.c2
-rw-r--r--drivers/video/backlight/cr_bllcd.c2
-rw-r--r--drivers/video/backlight/lcd.c2
-rw-r--r--drivers/video/chipsfb.c6
-rw-r--r--drivers/video/clps711xfb.c3
-rw-r--r--drivers/video/console/Kconfig25
-rw-r--r--drivers/video/console/Makefile2
-rw-r--r--drivers/video/console/fbcon.c366
-rw-r--r--drivers/video/console/fbcon.h1
-rw-r--r--drivers/video/console/softcursor.c2
-rw-r--r--drivers/video/console/sticore.c50
-rw-r--r--drivers/video/console/vgacon.c15
-rw-r--r--drivers/video/controlfb.c2
-rw-r--r--drivers/video/cyber2000fb.c3
-rw-r--r--drivers/video/cyblafb.c21
-rw-r--r--drivers/video/epson1355fb.c21
-rw-r--r--drivers/video/fbmem.c295
-rw-r--r--drivers/video/ffb.c4
-rw-r--r--drivers/video/fm2fb.c16
-rw-r--r--drivers/video/gbefb.c41
-rw-r--r--drivers/video/i810/i810.h2
-rw-r--r--drivers/video/i810/i810_main.c2
-rw-r--r--drivers/video/igafb.c4
-rw-r--r--drivers/video/imxfb.c24
-rw-r--r--drivers/video/intelfb/intelfb.h2
-rw-r--r--drivers/video/kyro/STG4000InitDevice.c5
-rw-r--r--drivers/video/logo/Kconfig5
-rw-r--r--drivers/video/logo/Makefile2
-rw-r--r--drivers/video/logo/logo.c7
-rw-r--r--drivers/video/logo/logo_spe_clut224.ppm283
-rw-r--r--drivers/video/macfb.c93
-rw-r--r--drivers/video/macmodes.c5
-rw-r--r--drivers/video/macmodes.h8
-rw-r--r--drivers/video/matrox/matroxfb_Ti3026.c2
-rw-r--r--drivers/video/matrox/matroxfb_accel.c13
-rw-r--r--drivers/video/matrox/matroxfb_base.c10
-rw-r--r--drivers/video/matrox/matroxfb_base.h2
-rw-r--r--drivers/video/matrox/matroxfb_crtc2.c6
-rw-r--r--drivers/video/matrox/matroxfb_crtc2.h4
-rw-r--r--drivers/video/matrox/matroxfb_maven.c9
-rw-r--r--drivers/video/matrox/matroxfb_misc.c2
-rw-r--r--drivers/video/neofb.c30
-rw-r--r--drivers/video/nvidia/nv_hw.c57
-rw-r--r--drivers/video/nvidia/nv_setup.c12
-rw-r--r--drivers/video/nvidia/nv_type.h1
-rw-r--r--drivers/video/nvidia/nvidia.c9
-rw-r--r--drivers/video/offb.c2
-rw-r--r--drivers/video/omap/Kconfig58
-rw-r--r--drivers/video/omap/Makefile29
-rw-r--r--drivers/video/omap/blizzard.c1568
-rw-r--r--drivers/video/omap/dispc.c1502
-rw-r--r--drivers/video/omap/dispc.h43
-rw-r--r--drivers/video/omap/hwa742.c1077
-rw-r--r--drivers/video/omap/lcd_h3.c141
-rw-r--r--drivers/video/omap/lcd_h4.c117
-rw-r--r--drivers/video/omap/lcd_inn1510.c124
-rw-r--r--drivers/video/omap/lcd_inn1610.c150
-rw-r--r--drivers/video/omap/lcd_osk.c144
-rw-r--r--drivers/video/omap/lcd_palmte.c123
-rw-r--r--drivers/video/omap/lcd_palmtt.c127
-rw-r--r--drivers/video/omap/lcd_palmz71.c123
-rw-r--r--drivers/video/omap/lcd_sx1.c334
-rw-r--r--drivers/video/omap/lcdc.c893
-rw-r--r--drivers/video/omap/lcdc.h7
-rw-r--r--drivers/video/omap/omapfb_main.c1941
-rw-r--r--drivers/video/omap/rfbi.c588
-rw-r--r--drivers/video/omap/sossi.c686
-rw-r--r--drivers/video/platinumfb.c2
-rw-r--r--drivers/video/pm2fb.c257
-rw-r--r--drivers/video/pm3fb.c4152
-rw-r--r--drivers/video/ps3fb.c301
-rw-r--r--drivers/video/pvr2fb.c111
-rw-r--r--drivers/video/q40fb.c2
-rw-r--r--drivers/video/riva/fbdev.c2
-rw-r--r--drivers/video/riva/riva_hw.c7
-rw-r--r--drivers/video/riva/rivafb-i2c.c2
-rw-r--r--drivers/video/s3fb.c19
-rw-r--r--drivers/video/savage/savagefb_driver.c3
-rw-r--r--drivers/video/sgivwfb.c2
-rw-r--r--drivers/video/sis/sis.h2
-rw-r--r--drivers/video/sis/sis_main.c8
-rw-r--r--drivers/video/skeletonfb.c33
-rw-r--r--drivers/video/sstfb.c2
-rw-r--r--drivers/video/sunxvr2500.c17
-rw-r--r--drivers/video/sunxvr500.c6
-rw-r--r--drivers/video/svgalib.c17
-rw-r--r--drivers/video/tgafb.c5
-rw-r--r--drivers/video/tridentfb.c30
-rw-r--r--drivers/video/tx3912fb.c2
-rw-r--r--drivers/video/valkyriefb.c3
-rw-r--r--drivers/video/vt8623fb.c928
-rw-r--r--drivers/video/w100fb.c14
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;
60static u_long videomemorysize; 60static u_long videomemorysize;
61 61
62static struct fb_info fb_info; 62static struct fb_info fb_info;
63static u32 mc68x328fb_pseudo_palette[17]; 63static u32 mc68x328fb_pseudo_palette[16];
64 64
65static struct fb_var_screeninfo mc68x328fb_default __initdata = { 65static 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
5menu "Graphics support" 5menu "Graphics support"
6 depends on HAS_IOMEM
6 7
7source "drivers/video/backlight/Kconfig" 8source "drivers/video/backlight/Kconfig"
8source "drivers/video/display/Kconfig" 9source "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
714config 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
723config 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
733config 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
743config 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
753config 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
763config 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
773config 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
786config 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
713config FB_PVR2 799config 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
734config FB_EPSON1355 820config 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
843config 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
852config 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
859config 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
757config FB_NVIDIA 869config 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
901config 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
789config FB_NVIDIA_BACKLIGHT 910config 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
827config FB_RIVA_DEBUG 948config 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
1176config FB_ATY_CT 1297config 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
1479config 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
1358config FB_CYBLA 1493config 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
1546config 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
1411config FB_PM3 1560config 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
1435source "drivers/video/geode/Kconfig" 1587source "drivers/video/geode/Kconfig"
1436 1588
1437config 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
1446config 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
1456config 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
1466config 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
1476config 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
1486config 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
1499config 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
1512config FB_PCI
1513 bool "PCI framebuffers"
1514 depends on (FB = y) && PCI && SPARC
1515
1516config 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
1526config FB_HIT 1589config 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
1746config FB_PS3 1809config 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
1755config FB_PS3_DEFAULT_SIZE_M 1820config 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
1841if ARCH_OMAP
1842 source "drivers/video/omap/Kconfig"
1843endif
1844
1776config FB_VIRTUAL 1845config 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
54obj-$(CONFIG_FB_CT65550) += chipsfb.o 54obj-$(CONFIG_FB_CT65550) += chipsfb.o
55obj-$(CONFIG_FB_IMSTT) += imsttfb.o 55obj-$(CONFIG_FB_IMSTT) += imsttfb.o
56obj-$(CONFIG_FB_FM2) += fm2fb.o 56obj-$(CONFIG_FB_FM2) += fm2fb.o
57obj-$(CONFIG_FB_VT8623) += vt8623fb.o
57obj-$(CONFIG_FB_CYBLA) += cyblafb.o 58obj-$(CONFIG_FB_CYBLA) += cyblafb.o
58obj-$(CONFIG_FB_TRIDENT) += tridentfb.o 59obj-$(CONFIG_FB_TRIDENT) += tridentfb.o
59obj-$(CONFIG_FB_LE80578) += vermilion/ 60obj-$(CONFIG_FB_LE80578) += vermilion/
60obj-$(CONFIG_FB_S3) += s3fb.o 61obj-$(CONFIG_FB_S3) += s3fb.o
62obj-$(CONFIG_FB_ARK) += arkfb.o
61obj-$(CONFIG_FB_STI) += stifb.o 63obj-$(CONFIG_FB_STI) += stifb.o
62obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o 64obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o
63obj-$(CONFIG_FB_CG6) += cg6.o sbuslib.o 65obj-$(CONFIG_FB_CG6) += cg6.o sbuslib.o
@@ -85,6 +87,7 @@ obj-$(CONFIG_FB_G364) += g364fb.o
85obj-$(CONFIG_FB_SA1100) += sa1100fb.o 87obj-$(CONFIG_FB_SA1100) += sa1100fb.o
86obj-$(CONFIG_FB_HIT) += hitfb.o 88obj-$(CONFIG_FB_HIT) += hitfb.o
87obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o 89obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o
90obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o
88obj-$(CONFIG_FB_PVR2) += pvr2fb.o 91obj-$(CONFIG_FB_PVR2) += pvr2fb.o
89obj-$(CONFIG_FB_VOODOO1) += sstfb.o 92obj-$(CONFIG_FB_VOODOO1) += sstfb.o
90obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o 93obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o
@@ -110,6 +113,7 @@ obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o
110obj-$(CONFIG_FB_PS3) += ps3fb.o 113obj-$(CONFIG_FB_PS3) += ps3fb.o
111obj-$(CONFIG_FB_SM501) += sm501fb.o 114obj-$(CONFIG_FB_SM501) += sm501fb.o
112obj-$(CONFIG_FB_XILINX) += xilinxfb.o 115obj-$(CONFIG_FB_XILINX) += xilinxfb.o
116obj-$(CONFIG_FB_OMAP) += omap/
113 117
114# Platform or fallback drivers go here 118# Platform or fallback drivers go here
115obj-$(CONFIG_FB_VESA) += vesafb.o 119obj-$(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
34struct 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
49static 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
72static const struct vga_regset ark_h_total_regs[] = {{0x00, 0, 7}, {0x41, 7, 7}, VGA_REGSET_END};
73static const struct vga_regset ark_h_display_regs[] = {{0x01, 0, 7}, {0x41, 6, 6}, VGA_REGSET_END};
74static const struct vga_regset ark_h_blank_start_regs[] = {{0x02, 0, 7}, {0x41, 5, 5}, VGA_REGSET_END};
75static const struct vga_regset ark_h_blank_end_regs[] = {{0x03, 0, 4}, {0x05, 7, 7 }, VGA_REGSET_END};
76static const struct vga_regset ark_h_sync_start_regs[] = {{0x04, 0, 7}, {0x41, 4, 4}, VGA_REGSET_END};
77static const struct vga_regset ark_h_sync_end_regs[] = {{0x05, 0, 4}, VGA_REGSET_END};
78
79static const struct vga_regset ark_v_total_regs[] = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x40, 7, 7}, VGA_REGSET_END};
80static const struct vga_regset ark_v_display_regs[] = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x40, 6, 6}, VGA_REGSET_END};
81static 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};
83static const struct vga_regset ark_v_blank_end_regs[] = {{0x16, 0, 7}, VGA_REGSET_END};
84static const struct vga_regset ark_v_sync_start_regs[] = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x40, 4, 4}, VGA_REGSET_END};
85static const struct vga_regset ark_v_sync_end_regs[] = {{0x11, 0, 3}, VGA_REGSET_END};
86
87static const struct vga_regset ark_line_compare_regs[] = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, VGA_REGSET_END};
88static const struct vga_regset ark_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x40, 0, 2}, VGA_REGSET_END};
89static const struct vga_regset ark_offset_regs[] = {{0x13, 0, 7}, {0x41, 3, 3}, VGA_REGSET_END};
90
91static 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
104static char *mode = "640x480-8@60";
105
106#ifdef CONFIG_MTRR
107static int mtrr = 1;
108#endif
109
110MODULE_AUTHOR("(c) 2007 Ondrej Zajicek <santiago@crfreenet.org>");
111MODULE_LICENSE("GPL");
112MODULE_DESCRIPTION("fbdev driver for ARK 2000PV");
113
114module_param(mode, charp, 0444);
115MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)");
116
117#ifdef CONFIG_MTRR
118module_param(mtrr, int, 0444);
119MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)");
120#endif
121
122static int threshold = 4;
123
124module_param(threshold, int, 0644);
125MODULE_PARM_DESC(threshold, "FIFO threshold");
126
127
128/* ------------------------------------------------------------------------- */
129
130
131static 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
160static 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 */
174static 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 */
180static 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 */
209static 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 */
231static 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 */
238static 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
266static 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
278static 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
292enum
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
307struct 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
315typedef void (*dac_read_regs_t)(void *data, u8 *code, int count);
316typedef void (*dac_write_regs_t)(void *data, u8 *code, int count);
317
318struct 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
327static 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
334static 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
339static 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
345static 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
350static inline int dac_set_mode(struct dac_info *info, int mode)
351{
352 return info->dacops->dac_set_mode(info, mode);
353}
354
355static 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
360static 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
371struct 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 */
380static 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
386static 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
404static 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) */
408static 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
414static 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
432static void ics5342_release(struct dac_info *info)
433{
434 ics5342_set_mode(info, DAC_PSEUDO8_8);
435 kfree(info);
436}
437
438static 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
445static 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
464static unsigned short dac_regs[4] = {0x3c8, 0x3c9, 0x3c6, 0x3c7};
465
466static 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
481static 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
497static 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
516static 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
537static 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
560static 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
608static 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
796static 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
857static 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
884static 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
910static 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 */
930static 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 */
1037err_reg_fb:
1038 fb_dealloc_cmap(&info->cmap);
1039err_alloc_cmap:
1040err_find_mode:
1041 pci_iounmap(dev, info->screen_base);
1042err_iomap:
1043 dac_release(par->dac);
1044err_dac:
1045 pci_release_regions(dev);
1046err_request_regions:
1047/* pci_disable_device(dev); */
1048err_enable_device:
1049 framebuffer_release(info);
1050 return rc;
1051}
1052
1053/* PCI remove */
1054
1055static 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
1086static 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
1117static 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));
1145fail:
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
1156static struct pci_device_id ark_devices[] __devinitdata = {
1157 {PCI_DEVICE(0xEDD8, 0xA099)},
1158 {0, 0, 0, 0, 0, 0, 0}
1159};
1160
1161
1162MODULE_DEVICE_TABLE(pci, ark_devices);
1163
1164static 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
1175static 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
1183static 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
1200module_init(arkfb_init);
1201module_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
42static 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
53static 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
73static 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
82static 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
106static 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
124static 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 */
136static 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 */
177static 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 */
255static 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
390static 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 */
422static 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
478static 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
488static 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
499static 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
510static 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
532static 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
539static 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
547static 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
715free_cmap:
716 fb_dealloc_cmap(&info->cmap);
717unregister_irqs:
718 free_irq(sinfo->irq_base, info);
719unmap_mmio:
720 iounmap(sinfo->mmio);
721release_mem:
722 release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
723free_fb:
724 if (map)
725 iounmap(info->screen_base);
726 else
727 atmel_lcdfb_free_video_memory(sinfo);
728
729release_intmem:
730 if (map)
731 release_mem_region(info->fix.smem_start, info->fix.smem_len);
732stop_clk:
733 atmel_lcdfb_stop_clock(sinfo);
734 clk_put(sinfo->lcdc_clk);
735put_bus_clk:
736 if (sinfo->bus_clk)
737 clk_put(sinfo->bus_clk);
738free_info:
739 framebuffer_release(info);
740out:
741 dev_dbg(dev, "%s FAILED\n", __func__);
742 return ret;
743}
744
745static 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
778static 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
786static int __init atmel_lcdfb_init(void)
787{
788 return platform_driver_probe(&atmel_lcdfb_driver, atmel_lcdfb_probe);
789}
790
791static void __exit atmel_lcdfb_exit(void)
792{
793 platform_driver_unregister(&atmel_lcdfb_driver);
794}
795
796module_init(atmel_lcdfb_init);
797module_exit(atmel_lcdfb_exit);
798
799MODULE_DESCRIPTION("AT91/AT32 LCD Controller framebuffer driver");
800MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@rfo.atmel.com>");
801MODULE_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
544static u32 pseudo_palette[17]; 544static u32 pseudo_palette[16];
545 545
546#ifdef CONFIG_FB_ATY_GX 546#ifdef CONFIG_FB_ATY_GX
547static char *aty_gx_ram[8] __devinitdata = { 547static 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
2105static ssize_t radeon_show_edid1(struct kobject *kobj, char *buf, loff_t off, size_t count) 2107static 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
2116static ssize_t radeon_show_edid2(struct kobject *kobj, char *buf, loff_t off, size_t count) 2120static 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
2126static struct bin_attribute edid1_attr = { 2132static 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 = {
2136static struct bin_attribute edid2_attr = { 2141static 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
295static struct fb_fix_screeninfo chipsfb_fix __initdata = { 295static 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
312static struct fb_var_screeninfo chipsfb_var __initdata = { 312static 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
333static void __init init_chips(struct fb_info *p, unsigned long addr) 333static 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
7config VGA_CONSOLE 7config 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
29config VGACON_SOFT_SCROLLBACK 22config 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
121config 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
128config FRAMEBUFFER_CONSOLE_ROTATION 137config 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
47quiet_cmd_conmakehash = CNMKHSH $@ 47quiet_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;
125static int last_fb_vc = MAX_NR_CONSOLES - 1; 126static int last_fb_vc = MAX_NR_CONSOLES - 1;
126static int fbcon_is_default = 1; 127static int fbcon_is_default = 1;
127static int fbcon_has_exited; 128static int fbcon_has_exited;
129static int primary_device = -1;
130static int map_override;
128 131
129/* font data */ 132/* font data */
130static char fontname[40]; 133static 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
154static int vbl_cursor_cnt; 157static int vbl_cursor_cnt;
158static 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);
188static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx, 192static 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);
190static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, 194static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
191 struct vc_data *vc); 195 int unit);
192static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *var,
193 int unit);
194static void fbcon_redraw_move(struct vc_data *vc, struct display *p, 196static 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);
196static void fbcon_modechanged(struct fb_info *info); 198static void fbcon_modechanged(struct fb_info *info);
197static void fbcon_set_all_vcs(struct fb_info *info); 199static void fbcon_set_all_vcs(struct fb_info *info);
198static void fbcon_start(void); 200static void fbcon_start(void);
199static void fbcon_exit(void); 201static void fbcon_exit(void);
200static struct class_device *fbcon_class_device; 202static 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;
1368static int scrollback_max = 0; 1381static int scrollback_max = 0;
1369static int scrollback_current = 0; 1382static int scrollback_current = 0;
1370 1383
1371/*
1372 * If no vc is existent yet, just set struct display
1373 */
1374static 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
1389static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, 1384static 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
1713static 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
1707static void fbcon_redraw(struct vc_data *vc, struct display *p, 1763static 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
2940static int fbcon_fb_unregistered(int idx) 3006#ifdef CONFIG_VT_HW_CONSOLE_BINDING
3007static 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
3016static inline int fbcon_unbind(void)
3017{
3018 return -EINVAL;
3019}
3020#endif /* CONFIG_VT_HW_CONSOLE_BINDING */
3021
3022static 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
3045static 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
2973static int fbcon_fb_registered(int idx) 3082#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
3083static 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
3106static inline void fbcon_select_primary(struct fb_info *info)
3107{
3108 return;
3109}
3110#endif /* CONFIG_FRAMEBUFFER_DETECT_PRIMARY */
3111
3112static 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
3182static ssize_t store_rotate(struct class_device *class_device, 3320static 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
3206static ssize_t store_rotate_all(struct class_device *class_device, 3345static 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
3230static ssize_t show_rotate(struct class_device *class_device, char *buf) 3370static 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
3251static struct class_device_attribute class_device_attrs[] = { 3392static 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;
3415err:
3416 release_console_sem();
3417 return snprintf(buf, PAGE_SIZE, "%d\n", blink);
3418}
3419
3420static 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
3452err:
3453 release_console_sem();
3454 return count;
3455}
3456
3457static 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
3256static int fbcon_init_class_device(void) 3464static 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
3382static void __exit fbcon_deinit_class_device(void) 3587static 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
177extern void fbcon_set_bitops(struct fbcon_ops *ops); 177extern void fbcon_set_bitops(struct fbcon_ops *ops);
178extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor); 178extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor);
179extern 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
243void __init 243void __devinit
244sti_rom_copy(unsigned long base, unsigned long count, void *dest) 244sti_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)
269static char default_sti_path[21] __read_mostly; 269static char default_sti_path[21] __read_mostly;
270 270
271#ifndef MODULE 271#ifndef MODULE
272static int __init sti_setup(char *str) 272static 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
291static char __initdata *font_name[MAX_STI_ROMS] = { "VGA8x16", }; 291static char __devinitdata *font_name[MAX_STI_ROMS] = { "VGA8x16", };
292static int __initdata font_index[MAX_STI_ROMS], 292static 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
296static int __init sti_font_setup(char *str) 296static 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
349static void __init 349static void __devinit
350sti_dump_globcfg(struct sti_glob_cfg *glob_cfg, unsigned int sti_mem_request) 350sti_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
389static void __init 389static void __devinit
390sti_dump_outptr(struct sti_struct *sti) 390sti_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
403static int __init 403static int __devinit
404sti_init_glob_cfg(struct sti_struct *sti, 404sti_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
485struct sti_cooked_font * __init 485struct sti_cooked_font * __devinit
486sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name) 486sti_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
541struct sti_cooked_font * __init 541struct sti_cooked_font * __devinit
542sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name) 542sti_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
548struct sti_cooked_font * __init 548struct sti_cooked_font * __devinit
549sti_select_font(struct sti_cooked_rom *rom, 549sti_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
575static void __init 575static void __devinit
576sti_dump_rom(struct sti_rom *rom) 576sti_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
593static int __init 593static int __devinit
594sti_cook_fonts(struct sti_cooked_rom *cooked_rom, 594sti_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
628static int __init 628static int __devinit
629sti_search_font(struct sti_cooked_rom *rom, int height, int width) 629sti_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
645static void * __init 645static void * __devinit
646sti_bmode_font_raw(struct sti_cooked_font *f) 646sti_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
663static void __init 663static void __devinit
664sti_bmode_rom_copy(unsigned long base, unsigned long count, void *dest) 664sti_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
678static struct sti_rom * __init 678static struct sti_rom * __devinit
679sti_get_bmode_rom (unsigned long address) 679sti_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
714struct sti_rom * __init 714struct sti_rom * __devinit
715sti_get_wmode_rom (unsigned long address) 715sti_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
730int __init 730int __devinit
731sti_read_rom(int wordmode, struct sti_struct *sti, unsigned long address) 731sti_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
786static struct sti_struct * __init 786static struct sti_struct * __devinit
787sti_try_rom_generic(unsigned long address, unsigned long hpa, struct pci_dev *pd) 787sti_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
901static void __init sticore_check_for_default_sti(struct sti_struct *sti, char *path) 901static 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 */
912static int __init sticore_pa_init(struct parisc_device *dev) 912static 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
1016static int sticore_initialized __read_mostly; 1016static int sticore_initialized __read_mostly;
1017 1017
1018static void __init sti_init_roms(void) 1018static 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
190static 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 */
194static 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
94struct fb_info_control { 94struct 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
64struct epson1355_par { 64struct 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
72static inline u8 epson1355_read_reg(int index)
73{
74 return ctrl_inb(par.reg_addr + index);
75}
76
77static 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
407static 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
479static struct logo_data_extra {
480 const struct linux_logo *logo;
481 unsigned int n;
482} fb_logo_ex[FB_LOGO_EX_NUM_MAX];
483static unsigned int fb_logo_ex_num;
484
485void 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
495static 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
515static 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
528static inline int fb_prepare_extra_logos(struct fb_info *info,
529 unsigned int height,
530 unsigned int yres)
531{
532 return height;
533}
534
535static 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
414int fb_prepare_logo(struct fb_info *info, int rotate) 543int 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
480int fb_show_logo(struct fb_info *info, int rotate) 610int 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
547int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; } 621int 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
1158static int 1232static int
1159fb_mmap(struct file *file, struct vm_area_struct * vma) 1233fb_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
1254static int 1285static 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
1389int 1427int
1390unregister_framebuffer(struct fb_info *fb_info) 1428unregister_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; 1457done:
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)
903struct all_info { 903struct 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
909static int ffb_init_one(struct of_device *op) 909static 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)
195static int fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 195static 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
87static int ypan, ywrap; 87static int ypan, ywrap;
88 88
89static uint32_t pseudo_palette[256]; 89static uint32_t pseudo_palette[16];
90 90
91static char *mode_option __initdata = NULL; 91static 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 */
1723static void __devinit i810_init_monspecs(struct fb_info *info) 1723static 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
11if LOGO 11if LOGO
12 12
13config FB_LOGO_EXTRA
14 bool
15 depends on FB=y
16 default y if SPU_BASE
17
13config LOGO_LINUX_MONO 18config 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
14obj-$(CONFIG_LOGO_SUPERH_CLUT224) += logo_superh_clut224.o 14obj-$(CONFIG_LOGO_SUPERH_CLUT224) += logo_superh_clut224.o
15obj-$(CONFIG_LOGO_M32R_CLUT224) += logo_m32r_clut224.o 15obj-$(CONFIG_LOGO_M32R_CLUT224) += logo_m32r_clut224.o
16 16
17obj-$(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;
34extern const struct linux_logo logo_superh_clut224; 34extern const struct linux_logo logo_superh_clut224;
35extern const struct linux_logo logo_m32r_clut224; 35extern const struct linux_logo logo_m32r_clut224;
36 36
37 37/* logo's are marked __initdata. Use __init_refok to tell
38const struct linux_logo *fb_find_logo(int depth) 38 * modpost that it is intended that this function uses data
39 * marked __initdata.
40 */
41const 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 @@
1P3
240 40
3255
40 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
50 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
60 0 0 0 0 0 0 0 0 0 0 0 2 2 2 6 6 6
715 15 15 21 21 21 19 19 19 14 14 14 6 6 6 2 2 2
80 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
90 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
100 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
120 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
130 0 0 0 0 0 0 0 0 2 2 2 21 21 21 55 55 55
1456 56 56 54 54 54 53 53 53 60 60 60 56 56 56 25 25 25
156 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
160 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
170 0 0 0 0 0 0 0 0 0 0 0
180 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
190 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
200 0 0 0 0 0 2 2 2 27 27 27 62 62 62 17 17 19
212 2 6 2 2 6 2 2 6 2 2 6 16 16 18 57 57 57
2245 45 45 8 8 8 0 0 0 0 0 0 0 0 0 0 0 0
230 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
240 0 0 0 0 0 0 0 0 0 0 0
250 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
260 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
270 0 0 0 0 0 16 16 16 62 62 62 8 8 10 2 2 6
282 2 6 2 2 6 2 2 6 12 12 14 67 67 67 16 16 17
2945 45 45 41 41 41 4 4 4 0 0 0 0 0 0 0 0 0
300 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
310 0 0 0 0 0 0 0 0 0 0 0
320 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
330 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
340 0 0 2 2 2 35 35 35 40 40 40 2 2 6 2 2 6
352 2 6 2 2 6 2 2 6 15 15 17 70 70 70 27 27 27
363 3 6 62 62 62 20 20 20 0 0 0 0 0 0 0 0 0
370 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
380 0 0 0 0 0 0 0 0 0 0 0
390 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
400 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
410 0 0 4 4 4 58 58 58 12 12 14 2 2 6 2 2 6
422 2 6 2 2 6 2 2 6 4 4 7 4 4 7 2 2 6
432 2 6 34 34 36 40 40 40 3 3 3 0 0 0 0 0 0
440 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
450 0 0 0 0 0 0 0 0 0 0 0
460 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
470 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
480 0 0 7 7 7 64 64 64 2 2 6 5 5 5 17 17 17
493 3 6 2 2 6 2 2 6 15 15 15 21 21 21 7 7 10
502 2 6 8 8 10 62 62 62 6 6 6 0 0 0 0 0 0
510 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
520 0 0 0 0 0 0 0 0 0 0 0
530 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
540 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
550 0 0 7 7 7 66 66 66 5 5 8 122 122 122 122 122 122
569 9 11 3 3 6 104 96 81 179 179 179 122 122 122 13 13 13
572 2 6 2 2 6 67 67 67 10 10 10 0 0 0 0 0 0
580 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
590 0 0 0 0 0 0 0 0 0 0 0
600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
610 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
620 0 0 7 7 7 65 65 65 41 41 43 152 149 142 192 191 189
6348 48 49 23 23 24 228 210 210 86 86 86 192 191 189 59 59 61
642 2 6 2 2 6 64 64 64 14 14 14 0 0 0 0 0 0
650 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
660 0 0 0 0 0 0 0 0 0 0 0
670 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
680 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
690 0 0 7 7 7 66 66 66 59 59 59 59 59 61 86 86 86
7099 84 50 78 66 28 152 149 142 5 5 8 122 122 122 104 96 81
712 2 6 2 2 6 67 67 67 14 14 14 0 0 0 0 0 0
720 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
730 0 0 0 0 0 0 0 0 0 0 0
740 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
750 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
760 0 0 5 5 5 63 63 63 24 24 24 152 149 142 175 122 13
77238 184 12 220 170 13 226 181 52 112 86 32 194 165 151 46 46 47
782 2 6 2 2 6 65 65 65 17 17 17 0 0 0 0 0 0
790 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
800 0 0 0 0 0 0 0 0 0 0 0
810 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
820 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
830 0 0 5 5 5 59 59 59 21 21 21 175 122 13 231 174 11
84240 192 13 237 183 61 240 192 13 240 192 13 234 179 16 81 64 9
852 2 6 2 2 6 63 63 63 25 25 25 0 0 0 0 0 0
860 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
870 0 0 0 0 0 0 0 0 0 0 0
880 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
890 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
900 0 0 5 5 5 54 54 54 51 48 39 189 138 9 238 184 12
91240 192 13 240 192 13 240 192 13 215 161 11 207 152 19 81 64 9
9216 16 18 5 5 8 40 40 40 44 44 44 4 4 4 0 0 0
930 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
940 0 0 0 0 0 0 0 0 0 0 0
950 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
960 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
970 0 0 5 5 5 59 59 59 27 27 27 126 107 64 187 136 12
98220 170 13 201 147 20 189 138 9 198 154 46 199 182 125 70 70 70
9927 27 27 104 96 81 12 12 14 70 70 70 16 16 16 0 0 0
1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1010 0 0 0 0 0 0 0 0 0 0 0
1020 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1030 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1040 0 0 17 17 17 70 70 70 12 12 12 168 168 168 174 135 135
105175 122 13 175 122 13 178 151 83 192 191 189 233 233 233 179 179 179
1063 3 6 29 29 31 3 3 6 41 41 41 44 44 44 5 5 5
1070 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1080 0 0 0 0 0 0 0 0 0 0 0
1090 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1100 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1118 8 8 53 53 53 44 44 44 59 59 59 238 238 238 192 191 189
112192 191 189 192 191 189 221 205 205 240 240 240 253 253 253 253 253 253
11370 70 70 2 2 6 2 2 6 5 5 8 67 67 67 22 22 22
1142 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1150 0 0 0 0 0 0 0 0 0 0 0
1160 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1170 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5
11838 38 38 56 56 56 7 7 9 221 205 205 253 253 253 233 233 233
119221 205 205 233 233 233 251 251 251 253 253 253 253 253 253 253 253 253
120192 191 189 2 2 6 2 2 6 2 2 6 25 25 25 64 64 64
12115 15 15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1220 0 0 0 0 0 0 0 0 0 0 0
1230 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1240 0 0 0 0 0 0 0 0 0 0 0 2 2 2 27 27 27
12566 66 66 7 7 9 86 86 86 252 252 252 253 253 253 253 253 253
126252 252 252 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
127244 244 244 19 19 21 2 2 6 2 2 6 2 2 6 38 38 38
12854 54 54 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0
1290 0 0 0 0 0 0 0 0 0 0 0
1300 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1310 0 0 0 0 0 0 0 0 0 0 0 14 14 14 62 62 62
13210 10 12 3 3 6 122 122 122 235 235 235 251 251 251 248 248 248
133235 235 235 248 248 248 252 252 252 246 246 246 233 233 233 237 228 228
134223 207 207 70 70 70 2 2 6 2 2 6 2 2 6 2 2 6
13546 46 47 38 38 38 4 4 4 0 0 0 0 0 0 0 0 0
1360 0 0 0 0 0 0 0 0 0 0 0
1370 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1380 0 0 0 0 0 0 0 0 2 2 2 33 33 33 44 44 44
1394 4 7 9 9 11 168 168 168 240 240 240 252 252 252 252 252 252
140246 246 246 253 253 253 253 253 253 251 251 251 245 241 241 233 233 233
141221 205 205 192 191 189 29 29 31 27 27 27 9 9 12 2 2 6
1423 3 6 65 65 65 15 15 15 0 0 0 0 0 0 0 0 0
1430 0 0 0 0 0 0 0 0 0 0 0
1440 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1450 0 0 0 0 0 0 0 0 6 6 6 59 59 59 19 19 21
14624 24 24 86 86 86 249 249 249 253 253 253 253 253 253 253 253 253
147253 253 253 228 210 210 241 230 230 253 253 253 253 253 253 253 253 253
148251 251 251 228 210 210 152 149 142 5 5 8 27 27 27 4 4 7
1492 2 6 46 46 47 34 34 34 2 2 2 0 0 0 0 0 0
1500 0 0 0 0 0 0 0 0 0 0 0
1510 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1520 0 0 0 0 0 0 0 0 16 16 16 67 67 67 19 19 21
15312 12 14 223 207 207 254 20 20 254 20 20 253 127 127 242 223 223
154254 20 20 253 127 127 254 48 48 242 223 223 254 86 86 254 20 20
155254 20 20 253 137 137 233 233 233 32 32 32 35 35 35 23 23 24
1562 2 6 15 15 15 60 60 60 6 6 6 0 0 0 0 0 0
1570 0 0 0 0 0 0 0 0 0 0 0
1580 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1590 0 0 0 0 0 4 4 4 38 38 38 48 48 49 22 22 22
16086 86 86 253 253 253 254 20 20 241 230 230 227 216 186 253 137 137
161253 137 137 253 253 253 253 137 137 253 137 137 254 48 48 253 253 253
162253 253 253 253 253 253 253 253 253 62 62 62 2 2 6 23 23 24
1632 2 6 2 2 6 62 62 62 17 17 17 0 0 0 0 0 0
1640 0 0 0 0 0 0 0 0 0 0 0
1650 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1660 0 0 0 0 0 14 14 14 70 70 70 14 14 14 16 16 18
167179 179 179 253 253 253 227 216 186 254 48 48 240 219 160 253 127 127
168254 20 20 253 137 137 254 86 86 231 203 141 254 20 20 254 20 20
169253 137 137 253 253 253 253 253 253 104 96 81 2 2 6 23 23 24
1702 2 6 2 2 6 46 46 47 27 27 27 0 0 0 0 0 0
1710 0 0 0 0 0 0 0 0 0 0 0
1720 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1730 0 0 4 4 4 39 39 39 42 42 43 19 19 21 13 13 13
174228 210 210 242 223 223 253 253 253 242 223 223 253 127 127 253 127 127
175253 127 127 253 127 127 253 137 137 253 253 253 254 48 48 253 253 253
176228 210 210 253 253 253 253 253 253 122 122 122 2 2 6 19 19 19
1772 2 6 2 2 6 39 39 39 38 38 38 3 3 3 0 0 0
1780 0 0 0 0 0 0 0 0 0 0 0
1790 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1800 0 0 8 8 8 60 60 60 3 3 6 33 33 33 38 38 38
181253 137 137 254 86 86 253 137 137 254 86 86 253 137 137 209 197 168
182253 127 127 253 253 253 253 253 253 253 253 253 253 127 127 254 86 86
183254 86 86 253 137 137 253 253 253 122 122 122 2 2 6 17 17 17
1842 2 6 2 2 6 34 34 36 42 42 43 3 3 3 0 0 0
1850 0 0 0 0 0 0 0 0 0 0 0
1860 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1870 0 0 13 13 13 59 59 59 2 2 6 9 9 12 56 56 56
188252 252 252 240 219 160 253 137 137 240 219 160 253 253 253 237 228 228
189254 86 86 253 253 253 253 253 253 253 253 253 253 253 253 242 223 223
190227 216 186 249 249 249 253 253 253 122 122 122 16 16 17 17 17 17
19112 12 14 3 3 6 39 39 39 38 38 38 3 3 3 0 0 0
1920 0 0 0 0 0 0 0 0 0 0 0
1930 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2
1945 5 5 22 22 22 104 96 81 187 136 12 207 152 19 51 48 39
195221 205 205 253 253 253 253 253 253 253 253 253 253 253 253 240 240 240
196250 247 243 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
197253 253 253 250 247 243 240 219 160 99 84 50 5 5 8 2 2 6
1987 7 9 46 46 47 58 58 58 35 35 35 3 3 3 0 0 0
1990 0 0 0 0 0 0 0 0 0 0 0
2000 0 0 0 0 0 0 0 0 0 0 0 8 8 8 33 33 33
20158 58 58 86 86 86 170 136 53 239 182 13 246 190 14 220 170 13
20244 38 29 179 179 179 253 253 253 253 253 253 253 253 253 240 240 240
203253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
204253 253 253 240 219 160 240 192 13 112 86 32 2 2 6 2 2 6
2053 3 6 41 33 20 220 170 13 53 53 53 4 4 4 0 0 0
2060 0 0 0 0 0 0 0 0 0 0 0
2070 0 0 0 0 0 0 0 0 2 2 2 32 32 32 150 116 44
208215 161 11 215 161 11 228 170 11 245 188 14 246 190 14 246 190 14
209187 136 12 9 9 11 122 122 122 251 251 251 253 253 253 253 253 253
210253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
211248 248 248 211 196 135 239 182 13 175 122 13 6 5 6 2 2 6
21216 14 12 187 136 12 238 184 12 84 78 65 10 10 10 0 0 0
2130 0 0 0 0 0 0 0 0 0 0 0
2140 0 0 0 0 0 0 0 0 4 4 4 53 53 53 207 152 19
215242 185 13 245 188 14 246 190 14 246 190 14 246 190 14 246 190 14
216240 192 13 81 64 9 2 2 6 86 86 86 244 244 244 253 253 253
217253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
218233 233 233 199 182 125 231 174 11 207 152 19 175 122 13 175 122 13
219201 147 20 239 182 13 244 187 14 150 116 44 35 35 35 6 6 6
2200 0 0 0 0 0 0 0 0 0 0 0
2210 0 0 0 0 0 0 0 0 5 5 5 53 53 53 201 147 20
222242 185 13 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
223246 190 14 220 170 13 13 11 10 2 2 6 152 149 142 253 253 253
224253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
225235 235 235 199 182 125 228 170 11 234 177 12 226 168 11 226 168 11
226234 177 12 246 190 14 246 190 14 234 179 16 126 107 64 36 36 36
2276 6 6 0 0 0 0 0 0 0 0 0
2280 0 0 0 0 0 0 0 0 3 3 3 48 48 49 189 142 35
229242 185 13 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
230246 190 14 246 190 14 140 112 39 36 36 36 192 191 189 253 253 253
231253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
232192 191 189 112 86 32 226 168 11 244 187 14 244 187 14 244 187 14
233245 188 14 246 190 14 246 190 14 246 190 14 242 185 13 150 116 44
23427 27 27 2 2 2 0 0 0 0 0 0
2350 0 0 0 0 0 0 0 0 6 6 6 58 58 58 189 142 35
236239 182 13 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
237246 190 14 246 190 14 239 188 14 209 197 168 253 253 253 253 253 253
238253 253 253 253 253 253 253 253 253 253 253 253 252 252 252 168 168 168
23916 16 18 97 67 8 228 170 11 245 188 14 246 190 14 246 190 14
240246 190 14 246 190 14 246 190 14 246 190 14 244 187 14 198 154 46
24135 35 35 3 3 3 0 0 0 0 0 0
2420 0 0 0 0 0 0 0 0 13 13 13 84 78 65 215 161 11
243244 187 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
244246 190 14 246 190 14 238 184 12 187 136 12 168 168 168 244 244 244
245253 253 253 252 252 252 240 240 240 179 179 179 67 67 67 2 2 6
2462 2 6 97 67 8 228 170 11 246 190 14 246 190 14 246 190 14
247246 190 14 246 190 14 245 188 14 234 177 12 189 142 35 86 77 61
24816 16 16 0 0 0 0 0 0 0 0 0
2490 0 0 0 0 0 0 0 0 13 13 13 103 92 56 207 152 19
250228 170 11 234 177 12 239 182 13 242 186 14 245 188 14 246 190 14
251246 190 14 246 190 14 239 182 13 189 138 9 41 33 20 10 10 12
25230 30 31 23 23 24 5 5 8 2 2 6 2 2 6 2 2 6
2534 4 6 112 86 32 215 161 11 245 188 14 246 190 14 245 188 14
254239 182 13 228 170 11 189 142 35 104 96 81 48 48 49 17 17 17
2552 2 2 0 0 0 0 0 0 0 0 0
2560 0 0 0 0 0 0 0 0 5 5 5 39 39 39 103 92 56
257141 109 44 175 122 13 187 136 12 189 138 9 207 152 19 228 170 11
258239 182 13 239 182 13 215 161 11 175 122 13 41 33 20 2 2 6
25915 15 17 20 20 22 20 20 22 20 20 22 20 20 22 8 8 10
2604 4 6 97 67 8 189 138 9 231 174 11 239 182 13 226 168 11
261189 138 9 126 107 64 59 59 59 21 21 21 5 5 5 0 0 0
2620 0 0 0 0 0 0 0 0 0 0 0
2630 0 0 0 0 0 0 0 0 0 0 0 5 5 5 17 17 17
26434 34 34 57 57 57 84 78 65 103 92 56 125 101 41 140 112 39
265175 122 13 175 122 13 175 122 13 97 67 8 72 67 58 84 78 65
26660 60 60 56 56 56 56 56 56 56 56 56 57 57 57 65 65 65
26786 86 86 95 73 34 175 122 13 187 136 12 187 136 12 175 122 13
268103 92 56 41 41 41 10 10 10 0 0 0 0 0 0 0 0 0
2690 0 0 0 0 0 0 0 0 0 0 0
2700 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2712 2 2 4 4 4 12 12 12 24 24 24 40 40 40 70 70 70
27286 77 61 95 73 34 88 72 41 72 67 58 36 36 36 10 10 10
2735 5 5 5 5 5 5 5 5 4 4 4 5 5 5 6 6 6
27422 22 22 61 61 59 88 72 41 112 86 32 112 86 32 84 78 65
27532 32 32 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0
2760 0 0 0 0 0 0 0 0 0 0 0
2770 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2780 0 0 0 0 0 0 0 0 0 0 0 3 3 3 10 10 10
27921 21 21 33 33 33 31 31 31 16 16 16 2 2 2 0 0 0
2800 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2812 2 2 12 12 12 30 30 31 40 40 40 32 32 32 16 16 16
2822 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2830 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
172static struct fb_info fb_info; 172static struct fb_info fb_info;
173static u32 pseudo_palette[17]; 173static u32 pseudo_palette[16];
174static int inverse = 0; 174static int inverse = 0;
175static int vidtest = 0; 175static 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
584static struct fb_ops macfb_ops = { 591static 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
372int __devinit mac_find_mode(struct fb_var_screeninfo *var, 372int 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,
55extern int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode, 55extern int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode,
56 int *cmode); 56 int *cmode);
57extern int mac_map_monitor_sense(int sense); 57extern int mac_map_monitor_sense(int sense);
58extern int __devinit mac_find_mode(struct fb_var_screeninfo *var, 58extern 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
97static inline void matrox_cfb8_pal(u_int32_t* pal) { 96static 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
106static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area); 104static 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
1995static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dummy) { 1999static 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
166static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info) {
167 /* no acceleration for secondary head... */
168 m2info->cmap[16] = 0xFFFFFFFF;
169}
170
171static void matroxfb_dh_pan_var(struct matroxfb_dh_fb_info* m2info, 166static 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
9struct matroxfb_dh_fb_info { 7struct 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
939void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) 945void 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)
166static int NVIsConnected(struct nvidia_par *par, int output) 166static 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
91struct riva_regs { 92struct 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 @@
1config 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
10config 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
18config 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
29config 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
39config 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
46config 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
53config 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
5obj-$(CONFIG_FB_OMAP) += omapfb.o
6
7objs-yy := omapfb_main.o
8
9objs-y$(CONFIG_ARCH_OMAP1) += lcdc.o
10objs-y$(CONFIG_ARCH_OMAP2) += dispc.o
11
12objs-$(CONFIG_ARCH_OMAP1)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += sossi.o
13objs-$(CONFIG_ARCH_OMAP2)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += rfbi.o
14
15objs-y$(CONFIG_FB_OMAP_LCDC_HWA742) += hwa742.o
16objs-y$(CONFIG_FB_OMAP_LCDC_BLIZZARD) += blizzard.o
17
18objs-y$(CONFIG_MACH_OMAP_H4) += lcd_h4.o
19objs-y$(CONFIG_MACH_OMAP_H3) += lcd_h3.o
20objs-y$(CONFIG_MACH_OMAP_PALMTE) += lcd_palmte.o
21objs-y$(CONFIG_MACH_OMAP_PALMTT) += lcd_palmtt.o
22objs-y$(CONFIG_MACH_OMAP_PALMZ71) += lcd_palmz71.o
23objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1610.o
24objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1510.o
25objs-y$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o
26objs-y$(CONFIG_MACH_SX1) += lcd_sx1.o
27
28omapfb-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
89struct blizzard_reg_list {
90 int start;
91 int end;
92};
93
94/* These need to be saved / restored separately from the rest. */
95static 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
106static 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
117static u8 blizzard_reg_cache[0x5a / 2];
118
119struct 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
129struct 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
143struct 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
153struct 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
197struct lcd_ctrl blizzard_ctrl;
198
199static u8 blizzard_read_reg(u8 reg)
200{
201 u8 data;
202
203 blizzard.extif->set_bits_per_cycle(8);
204 blizzard.extif->write_command(&reg, 1);
205 blizzard.extif->read_data(&data, 1);
206
207 return data;
208}
209
210static void blizzard_write_reg(u8 reg, u8 val)
211{
212 blizzard.extif->set_bits_per_cycle(8);
213 blizzard.extif->write_command(&reg, 1);
214 blizzard.extif->write_data(&val, 1);
215}
216
217static 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
235static 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 */
243static 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. */
258static 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
272static void disable_overlay(void)
273{
274 blizzard_write_reg(BLIZZARD_DATA_SOURCE_SELECT,
275 BLIZZARD_SRC_DISABLE_OVERLAY);
276}
277
278static 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
324static 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
352static 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
363static inline void set_extif_timings(const struct extif_timings *t);
364
365static 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
389static 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
403static 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
434static 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
449static 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
467static 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. */
517static 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
668static 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
696static 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
719static 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
773static 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
780static 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
797int 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}
822EXPORT_SYMBOL(blizzard_update_window_async);
823
824static 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
831static 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
883static 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
911static 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
921static int sync_handler(struct blizzard_request *req)
922{
923 complete(req->par.sync);
924 return REQ_COMPLETE;
925}
926
927static 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 = &comp;
939
940 list_add(&req->entry, &req_list);
941 submit_req_list(&req_list);
942
943 wait_for_completion(&comp);
944}
945
946
947static 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
954static 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
998static enum omapfb_update_mode blizzard_get_update_mode(void)
999{
1000 return blizzard.update_mode;
1001}
1002
1003static inline void set_extif_timings(const struct extif_timings *t)
1004{
1005 blizzard.extif->set_timings(t);
1006}
1007
1008static 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
1014static 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
1064static 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
1118static 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;
1145err:
1146 dev_err(blizzard.fbdev->dev, "can't setup timings\n");
1147 return -1;
1148}
1149
1150static 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
1177static 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
1282static 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
1295static 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
1306static 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
1317static 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
1323static void blizzard_restore_pll_regs(void)
1324{
1325 _restore_regs(blizzard_pll_regs, ARRAY_SIZE(blizzard_pll_regs));
1326}
1327
1328static void blizzard_restore_gen_regs(void)
1329{
1330 _restore_regs(blizzard_gen_regs, ARRAY_SIZE(blizzard_gen_regs));
1331}
1332
1333static 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
1374static 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
1412static 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;
1533err3:
1534 if (blizzard.power_down != NULL)
1535 blizzard.power_down(fbdev->dev);
1536 blizzard.extif->cleanup();
1537err2:
1538 blizzard.int_ctrl->cleanup();
1539err1:
1540 return r;
1541}
1542
1543static 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
1552struct 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
151struct resmap {
152 unsigned long start;
153 unsigned page_cnt;
154 unsigned long *map;
155};
156
157static 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
186static void enable_lcd_clocks(int enable);
187
188static void inline dispc_write_reg(int idx, u32 val)
189{
190 __raw_writel(val, dispc.base + idx);
191}
192
193static 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 */
200static 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
219static 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
247static 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
254void 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}
262EXPORT_SYMBOL(omap_dispc_set_lcd_size);
263
264void 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}
272EXPORT_SYMBOL(omap_dispc_set_digit_size);
273
274static 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
300void 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}
306EXPORT_SYMBOL(omap_dispc_enable_lcd_out);
307
308void 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}
314EXPORT_SYMBOL(omap_dispc_enable_digit_out);
315
316static 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
441static 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
461static 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
472static 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
483static 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
503static 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
580static 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
595static 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
640static int omap_dispc_get_color_key(struct omapfb_color_key *ck)
641{
642 *ck = dispc.color_key;
643 return 0;
644}
645
646static void load_palette(void)
647{
648}
649
650static 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
681static 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
697static enum omapfb_update_mode omap_dispc_get_update_mode(void)
698{
699 return dispc.update_mode;
700}
701
702static 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
737static 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
763static 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
771static 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
811int 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}
826EXPORT_SYMBOL(omap_dispc_request_irq);
827
828void 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}
836EXPORT_SYMBOL(omap_dispc_enable_irqs);
837
838void 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}
846EXPORT_SYMBOL(omap_dispc_disable_irqs);
847
848void 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}
856EXPORT_SYMBOL(omap_dispc_free_irq);
857
858static 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
880static 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
904static 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
911static 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
919static 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
927static 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
935static 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
949static 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
962static 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
970static 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
999static 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
1006static 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
1013static struct vm_operations_struct mmap_user_ops = {
1014 .open = mmap_user_open,
1015 .close = mmap_user_close,
1016};
1017
1018static 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
1052static void unmap_kern(struct omapfb_mem_region *region)
1053{
1054 vunmap(region->vaddr);
1055}
1056
1057static 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
1069static 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
1075static int alloc_fbmem(struct omapfb_mem_region *region)
1076{
1077 region->vaddr = dma_alloc_writecombine(dispc.fbdev->dev,
1078 region->size, &region->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
1088static 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
1094static 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
1110static void cleanup_resmap(struct resmap *res_map)
1111{
1112 kfree(res_map);
1113}
1114
1115static 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
1124static 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
1129static 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
1135static 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
1141static 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
1160static 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
1178static 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 */
1210static 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
1246static 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;
1311fail:
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
1319static 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
1339static 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;
1458fail3:
1459 free_palette_ram();
1460fail2:
1461 free_irq(INT_24XX_DSS_IRQ, fbdev);
1462fail1:
1463 enable_lcd_clocks(0);
1464 enable_interface_clocks(0);
1465 put_dss_clocks();
1466
1467 return r;
1468}
1469
1470static 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
1485const 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
35extern void omap_dispc_set_lcd_size(int width, int height);
36
37extern void omap_dispc_enable_lcd_out(int enable);
38extern void omap_dispc_enable_digit_out(int enable);
39
40extern int omap_dispc_request_irq(void (*callback)(void *data), void *data);
41extern 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
84struct update_param {
85 int x, y, width, height;
86 int color_mode;
87 int flags;
88};
89
90struct 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
104struct {
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
140struct lcd_ctrl hwa742_ctrl;
141
142static u8 hwa742_read_reg(u8 reg)
143{
144 u8 data;
145
146 hwa742.extif->set_bits_per_cycle(8);
147 hwa742.extif->write_command(&reg, 1);
148 hwa742.extif->read_data(&data, 1);
149
150 return data;
151}
152
153static void hwa742_write_reg(u8 reg, u8 data)
154{
155 hwa742.extif->set_bits_per_cycle(8);
156 hwa742.extif->write_command(&reg, 1);
157 hwa742.extif->write_data(&data, 1);
158}
159
160static 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
184static 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
203static 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
231static 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
242static 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
266static 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
280static 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
311static 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
326static 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
343static 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
413static 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
431static 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
473static 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
480static 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
494int 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
524out:
525 return r;
526}
527EXPORT_SYMBOL(hwa742_update_window_async);
528
529static 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
541static 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
551static int sync_handler(struct hwa742_request *req)
552{
553 complete(req->par.sync);
554 return REQ_COMPLETE;
555}
556
557static 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 = &comp;
569
570 list_add(&req->entry, &req_list);
571 submit_req_list(&req_list);
572
573 wait_for_completion(&comp);
574}
575
576static 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
584static 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
627static enum omapfb_update_mode hwa742_get_update_mode(void)
628{
629 return hwa742.update_mode;
630}
631
632static 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
638static 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
684static 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
735static 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
760err:
761 dev_err(hwa742.fbdev->dev, "can't setup timings\n");
762 return -1;
763}
764
765static 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
791static 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
901static 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
912static 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
922static 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
938static 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;
1042err4:
1043 if (hwa742.power_down != NULL)
1044 hwa742.power_down(fbdev->dev);
1045err3:
1046 hwa742.extif->cleanup();
1047err2:
1048 hwa742.int_ctrl->cleanup();
1049err1:
1050 return r;
1051}
1052
1053static 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
1062struct 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
33static int h3_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
34{
35 return 0;
36}
37
38static void h3_panel_cleanup(struct lcd_panel *panel)
39{
40}
41
42static 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
56static 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
68static unsigned long h3_panel_get_caps(struct lcd_panel *panel)
69{
70 return 0;
71}
72
73struct 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
97static int h3_panel_probe(struct platform_device *pdev)
98{
99 omapfb_register_panel(&h3_panel);
100 return 0;
101}
102
103static int h3_panel_remove(struct platform_device *pdev)
104{
105 return 0;
106}
107
108static int h3_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
109{
110 return 0;
111}
112
113static int h3_panel_resume(struct platform_device *pdev)
114{
115 return 0;
116}
117
118struct 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
129static int h3_panel_drv_init(void)
130{
131 return platform_driver_register(&h3_panel_driver);
132}
133
134static void h3_panel_drv_cleanup(void)
135{
136 platform_driver_unregister(&h3_panel_driver);
137}
138
139module_init(h3_panel_drv_init);
140module_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
27static int h4_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
28{
29 return 0;
30}
31
32static void h4_panel_cleanup(struct lcd_panel *panel)
33{
34}
35
36static int h4_panel_enable(struct lcd_panel *panel)
37{
38 return 0;
39}
40
41static void h4_panel_disable(struct lcd_panel *panel)
42{
43}
44
45static unsigned long h4_panel_get_caps(struct lcd_panel *panel)
46{
47 return 0;
48}
49
50struct 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
73static int h4_panel_probe(struct platform_device *pdev)
74{
75 omapfb_register_panel(&h4_panel);
76 return 0;
77}
78
79static int h4_panel_remove(struct platform_device *pdev)
80{
81 return 0;
82}
83
84static int h4_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
85{
86 return 0;
87}
88
89static int h4_panel_resume(struct platform_device *pdev)
90{
91 return 0;
92}
93
94struct 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
105static int h4_panel_drv_init(void)
106{
107 return platform_driver_register(&h4_panel_driver);
108}
109
110static void h4_panel_drv_cleanup(void)
111{
112 platform_driver_unregister(&h4_panel_driver);
113}
114
115module_init(h4_panel_drv_init);
116module_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
29static int innovator1510_panel_init(struct lcd_panel *panel,
30 struct omapfb_device *fbdev)
31{
32 return 0;
33}
34
35static void innovator1510_panel_cleanup(struct lcd_panel *panel)
36{
37}
38
39static int innovator1510_panel_enable(struct lcd_panel *panel)
40{
41 fpga_write(0x7, OMAP1510_FPGA_LCD_PANEL_CONTROL);
42 return 0;
43}
44
45static void innovator1510_panel_disable(struct lcd_panel *panel)
46{
47 fpga_write(0x0, OMAP1510_FPGA_LCD_PANEL_CONTROL);
48}
49
50static unsigned long innovator1510_panel_get_caps(struct lcd_panel *panel)
51{
52 return 0;
53}
54
55struct 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
79static int innovator1510_panel_probe(struct platform_device *pdev)
80{
81 omapfb_register_panel(&innovator1510_panel);
82 return 0;
83}
84
85static int innovator1510_panel_remove(struct platform_device *pdev)
86{
87 return 0;
88}
89
90static int innovator1510_panel_suspend(struct platform_device *pdev,
91 pm_message_t mesg)
92{
93 return 0;
94}
95
96static int innovator1510_panel_resume(struct platform_device *pdev)
97{
98 return 0;
99}
100
101struct 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
112static int innovator1510_panel_drv_init(void)
113{
114 return platform_driver_register(&innovator1510_panel_driver);
115}
116
117static void innovator1510_panel_drv_cleanup(void)
118{
119 platform_driver_unregister(&innovator1510_panel_driver);
120}
121
122module_init(innovator1510_panel_drv_init);
123module_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
32static 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);
51exit:
52 return r;
53}
54
55static void innovator1610_panel_cleanup(struct lcd_panel *panel)
56{
57 omap_free_gpio(15);
58 omap_free_gpio(14);
59}
60
61static 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
69static 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
76static unsigned long innovator1610_panel_get_caps(struct lcd_panel *panel)
77{
78 return 0;
79}
80
81struct 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
105static int innovator1610_panel_probe(struct platform_device *pdev)
106{
107 omapfb_register_panel(&innovator1610_panel);
108 return 0;
109}
110
111static int innovator1610_panel_remove(struct platform_device *pdev)
112{
113 return 0;
114}
115
116static int innovator1610_panel_suspend(struct platform_device *pdev,
117 pm_message_t mesg)
118{
119 return 0;
120}
121
122static int innovator1610_panel_resume(struct platform_device *pdev)
123{
124 return 0;
125}
126
127struct 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
138static int innovator1610_panel_drv_init(void)
139{
140 return platform_driver_register(&innovator1610_panel_driver);
141}
142
143static void innovator1610_panel_drv_cleanup(void)
144{
145 platform_driver_unregister(&innovator1610_panel_driver);
146}
147
148module_init(innovator1610_panel_drv_init);
149module_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
30static int osk_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
31{
32 return 0;
33}
34
35static void osk_panel_cleanup(struct lcd_panel *panel)
36{
37}
38
39static 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
59static 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
71static unsigned long osk_panel_get_caps(struct lcd_panel *panel)
72{
73 return 0;
74}
75
76struct 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
100static int osk_panel_probe(struct platform_device *pdev)
101{
102 omapfb_register_panel(&osk_panel);
103 return 0;
104}
105
106static int osk_panel_remove(struct platform_device *pdev)
107{
108 return 0;
109}
110
111static int osk_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
112{
113 return 0;
114}
115
116static int osk_panel_resume(struct platform_device *pdev)
117{
118 return 0;
119}
120
121struct 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
132static int osk_panel_drv_init(void)
133{
134 return platform_driver_register(&osk_panel_driver);
135}
136
137static void osk_panel_drv_cleanup(void)
138{
139 platform_driver_unregister(&osk_panel_driver);
140}
141
142module_init(osk_panel_drv_init);
143module_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
29static int palmte_panel_init(struct lcd_panel *panel,
30 struct omapfb_device *fbdev)
31{
32 return 0;
33}
34
35static void palmte_panel_cleanup(struct lcd_panel *panel)
36{
37}
38
39static int palmte_panel_enable(struct lcd_panel *panel)
40{
41 return 0;
42}
43
44static void palmte_panel_disable(struct lcd_panel *panel)
45{
46}
47
48static unsigned long palmte_panel_get_caps(struct lcd_panel *panel)
49{
50 return 0;
51}
52
53struct 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
79static int palmte_panel_probe(struct platform_device *pdev)
80{
81 omapfb_register_panel(&palmte_panel);
82 return 0;
83}
84
85static int palmte_panel_remove(struct platform_device *pdev)
86{
87 return 0;
88}
89
90static int palmte_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
91{
92 return 0;
93}
94
95static int palmte_panel_resume(struct platform_device *pdev)
96{
97 return 0;
98}
99
100struct 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
111static int palmte_panel_drv_init(void)
112{
113 return platform_driver_register(&palmte_panel_driver);
114}
115
116static void palmte_panel_drv_cleanup(void)
117{
118 platform_driver_unregister(&palmte_panel_driver);
119}
120
121module_init(palmte_panel_drv_init);
122module_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/*
23GPIO11 - backlight
24GPIO12 - screen blanking
25GPIO13 - 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
35static int palmtt_panel_init(struct lcd_panel *panel,
36 struct omapfb_device *fbdev)
37{
38 return 0;
39}
40
41static void palmtt_panel_cleanup(struct lcd_panel *panel)
42{
43}
44
45static int palmtt_panel_enable(struct lcd_panel *panel)
46{
47 return 0;
48}
49
50static void palmtt_panel_disable(struct lcd_panel *panel)
51{
52}
53
54static unsigned long palmtt_panel_get_caps(struct lcd_panel *panel)
55{
56 return OMAPFB_CAPS_SET_BACKLIGHT;
57}
58
59struct 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
84static int palmtt_panel_probe(struct platform_device *pdev)
85{
86 omapfb_register_panel(&palmtt_panel);
87 return 0;
88}
89
90static int palmtt_panel_remove(struct platform_device *pdev)
91{
92 return 0;
93}
94
95static int palmtt_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
96{
97 return 0;
98}
99
100static int palmtt_panel_resume(struct platform_device *pdev)
101{
102 return 0;
103}
104
105struct 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
116static int palmtt_panel_drv_init(void)
117{
118 return platform_driver_register(&palmtt_panel_driver);
119}
120
121static void palmtt_panel_drv_cleanup(void)
122{
123 platform_driver_unregister(&palmtt_panel_driver);
124}
125
126module_init(palmtt_panel_drv_init);
127module_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
29static int palmz71_panel_init(struct lcd_panel *panel,
30 struct omapfb_device *fbdev)
31{
32 return 0;
33}
34
35static void palmz71_panel_cleanup(struct lcd_panel *panel)
36{
37
38}
39
40static int palmz71_panel_enable(struct lcd_panel *panel)
41{
42 return 0;
43}
44
45static void palmz71_panel_disable(struct lcd_panel *panel)
46{
47}
48
49static unsigned long palmz71_panel_get_caps(struct lcd_panel *panel)
50{
51 return OMAPFB_CAPS_SET_BACKLIGHT;
52}
53
54struct 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
79static int palmz71_panel_probe(struct platform_device *pdev)
80{
81 omapfb_register_panel(&palmz71_panel);
82 return 0;
83}
84
85static int palmz71_panel_remove(struct platform_device *pdev)
86{
87 return 0;
88}
89
90static int palmz71_panel_suspend(struct platform_device *pdev,
91 pm_message_t mesg)
92{
93 return 0;
94}
95
96static int palmz71_panel_resume(struct platform_device *pdev)
97{
98 return 0;
99}
100
101struct 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
112static int palmz71_panel_drv_init(void)
113{
114 return platform_driver_register(&palmz71_panel_driver);
115}
116
117static void palmz71_panel_drv_cleanup(void)
118{
119 platform_driver_unregister(&palmz71_panel_driver);
120}
121
122module_init(palmz71_panel_drv_init);
123module_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
51const unsigned char INIT_1[12] = {
52 0x1C, 0x02, 0x88, 0x00, 0x1E, 0xE0, 0x00, 0xDC, 0x00, 0x02, 0x00
53};
54
55const 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
74const unsigned char INIT_3[15] = {
75 0x14, 0x26, 0x33, 0x3D, 0x45, 0x4D, 0x53, 0x59,
76 0x5E, 0x63, 0x67, 0x6D, 0x71, 0x78, 0xFF
77};
78
79static 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
101static void init_system(void)
102{
103 omap_mcbsp_request(OMAP_MCBSP3);
104 omap_mcbsp_stop(OMAP_MCBSP3);
105}
106
107static 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
131static 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
221static int sx1_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
222{
223 return 0;
224}
225
226static void sx1_panel_cleanup(struct lcd_panel *panel)
227{
228}
229
230static 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
248static 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
261static unsigned long sx1_panel_get_caps(struct lcd_panel *panel)
262{
263 return 0;
264}
265
266struct 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
291static int sx1_panel_probe(struct platform_device *pdev)
292{
293 omapfb_register_panel(&sx1_panel);
294 return 0;
295}
296
297static int sx1_panel_remove(struct platform_device *pdev)
298{
299 return 0;
300}
301
302static int sx1_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
303{
304 return 0;
305}
306
307static int sx1_panel_resume(struct platform_device *pdev)
308{
309 return 0;
310}
311
312struct 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
323static int sx1_panel_drv_init(void)
324{
325 return platform_driver_register(&sx1_panel_driver);
326}
327
328static void sx1_panel_drv_cleanup(void)
329{
330 platform_driver_unregister(&sx1_panel_driver);
331}
332
333module_init(sx1_panel_drv_init);
334module_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
73enum lcdc_load_mode {
74 OMAP_LCDC_LOAD_PALETTE,
75 OMAP_LCDC_LOAD_FRAME,
76 OMAP_LCDC_LOAD_PALETTE_AND_FRAME
77};
78
79static 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
110static void inline enable_irqs(int mask)
111{
112 lcdc.irq_mask |= mask;
113}
114
115static void inline disable_irqs(int mask)
116{
117 lcdc.irq_mask &= ~mask;
118}
119
120static 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
141static 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
152static 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
168static 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
177static 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 */
203static 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
269static 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 */
319static 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
406static 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 */
422static 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 */
452static 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
478static 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
497static 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 */
562static 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
594static 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 */
600static 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
608static 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
620static void omap_lcdc_get_caps(int plane, struct omapfb_caps *caps)
621{
622 return;
623}
624
625int 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}
637EXPORT_SYMBOL(omap_lcdc_set_dma_callback);
638
639void omap_lcdc_free_dma_callback(void)
640{
641 lcdc.dma_callback = NULL;
642}
643EXPORT_SYMBOL(omap_lcdc_free_dma_callback);
644
645static void lcdc_dma_handler(u16 status, void *data)
646{
647 if (lcdc.dma_callback)
648 lcdc.dma_callback(lcdc.dma_callback_data);
649}
650
651static 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
682static void unmap_kern(void)
683{
684 vunmap(lcdc.vram_virt);
685}
686
687static 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
700static 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
706static 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
735static void free_fbmem(void)
736{
737 dma_free_writecombine(lcdc.fbdev->dev, lcdc.vram_size,
738 lcdc.vram_virt, lcdc.vram_phys);
739}
740
741static 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
774static void cleanup_fbmem(void)
775{
776 if (lcdc.fbmem_allocated)
777 free_fbmem();
778 else
779 unmap_kern();
780}
781
782static 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;
854fail5:
855 if (!ext_mode)
856 free_palette_ram();
857fail4:
858 omap_free_lcd_dma();
859fail3:
860 free_irq(OMAP_LCDC_IRQ, lcdc.fbdev);
861fail2:
862 clk_disable(lcdc.lcd_ck);
863fail1:
864 clk_put(lcdc.lcd_ck);
865fail0:
866 return r;
867}
868
869static 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
880const 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
4int omap_lcdc_set_dma_callback(void (*callback)(void *data), void *data);
5void 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
36static unsigned int def_accel;
37static unsigned long def_vram[OMAPFB_PLANE_NUM];
38static int def_vram_cnt;
39static unsigned long def_vxres;
40static unsigned long def_vyres;
41static unsigned int def_rotate;
42static unsigned int def_mirror;
43
44#ifdef CONFIG_FB_OMAP_MANUAL_UPDATE
45static int manual_update = 1;
46#else
47static int manual_update;
48#endif
49
50static struct platform_device *fbdev_pdev;
51static struct lcd_panel *fbdev_panel;
52static struct omapfb_device *omapfb_dev;
53
54struct caps_table_struct {
55 unsigned long flag;
56 const char *name;
57};
58
59static 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
70static 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 */
87extern struct lcd_ctrl omap1_int_ctrl;
88extern struct lcd_ctrl omap2_int_ctrl;
89extern struct lcd_ctrl hwa742_ctrl;
90extern struct lcd_ctrl blizzard_ctrl;
91
92static 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
109extern struct lcd_ctrl_extif omap1_ext_if;
110#else
111extern struct lcd_ctrl_extif omap2_ext_if;
112#endif
113#endif
114
115static void omapfb_rqueue_lock(struct omapfb_device *fbdev)
116{
117 mutex_lock(&fbdev->rqueue_mutex);
118}
119
120static 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. */
131static 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 */
145static 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
194static void ctrl_cleanup(struct omapfb_device *fbdev)
195{
196 fbdev->ctrl->cleanup();
197}
198
199/* Must be called with fbdev->rqueue_mutex held. */
200static 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 */
232static int omapfb_open(struct fb_info *info, int user)
233{
234 return 0;
235}
236
237static 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. */
241static 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 */
251static 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
299static 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
305static 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
329static int omapfb_update_full_screen(struct fb_info *fbi);
330
331static 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
370static 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 */
385static 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
420static 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 */
471static 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. */
594static 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 */
618static 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. */
646static 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 */
669static 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 */
688static 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
702int 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}
734EXPORT_SYMBOL(omapfb_update_window_async);
735
736static 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
749static 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
777static 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 }
812out:
813 omapfb_rqueue_unlock(fbdev);
814 return r;
815}
816
817static 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
825static 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 }
893out:
894 omapfb_rqueue_unlock(fbdev);
895
896 return r;
897}
898
899static 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
913static 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
928static 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
943static struct blocking_notifier_head omapfb_client_list[OMAPFB_PLANE_NUM];
944static int notifier_inited;
945
946static 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
954int 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}
983EXPORT_SYMBOL(omapfb_register_client);
984
985int 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}
990EXPORT_SYMBOL(omapfb_unregister_client);
991
992void 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}
1004EXPORT_SYMBOL(omapfb_notify_clients);
1005
1006static 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
1018static 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
1029static 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 */
1038void 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}
1054EXPORT_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 */
1060static 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
1209static 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 */
1226static 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 */
1249static 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
1269static 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
1312static DEVICE_ATTR(caps_num, 0444, omapfb_show_caps_num, NULL);
1313static DEVICE_ATTR(caps_text, 0444, omapfb_show_caps_text, NULL);
1314
1315/* panel sysfs entries */
1316static 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
1324static 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
1339static 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
1359static 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
1373static struct device_attribute dev_attr_panel_name =
1374 __ATTR(name, 0444, omapfb_show_panel_name, NULL);
1375static DEVICE_ATTR(backlight_level, 0664,
1376 omapfb_show_bklight_level, omapfb_store_bklight_level);
1377static DEVICE_ATTR(backlight_max, 0444, omapfb_show_bklight_max, NULL);
1378
1379static 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
1386static struct attribute_group panel_attr_grp = {
1387 .name = "panel",
1388 .attrs = panel_attrs,
1389};
1390
1391/* ctrl sysfs entries */
1392static 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
1400static struct device_attribute dev_attr_ctrl_name =
1401 __ATTR(name, 0444, omapfb_show_ctrl_name, NULL);
1402
1403static struct attribute *ctrl_attrs[] = {
1404 &dev_attr_ctrl_name.attr,
1405 NULL,
1406};
1407
1408static struct attribute_group ctrl_attr_grp = {
1409 .name = "ctrl",
1410 .attrs = ctrl_attrs,
1411};
1412
1413static 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;
1430fail3:
1431 sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp);
1432fail2:
1433 device_remove_file(fbdev->dev, &dev_attr_caps_text);
1434fail1:
1435 device_remove_file(fbdev->dev, &dev_attr_caps_num);
1436fail0:
1437 dev_err(fbdev->dev, "unable to register sysfs interface\n");
1438 return r;
1439}
1440
1441static 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 */
1457static 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 */
1489static void fbinfo_cleanup(struct omapfb_device *fbdev, struct fb_info *fbi)
1490{
1491 fb_dealloc_cmap(&fbi->cmap);
1492}
1493
1494static 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
1506static 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 */
1543static 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
1574static 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
1608static 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 */
1634static 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
1775cleanup:
1776 omapfb_free_resources(fbdev, init_state);
1777
1778 return r;
1779}
1780
1781static 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
1792void 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 */
1802static 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 */
1816static 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 */
1826static 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
1834static 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 */
1848static 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 */
1905static 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
1923static void __exit omapfb_cleanup(void)
1924{
1925 platform_driver_unregister(&omapfb_driver);
1926}
1927
1928module_param_named(accel, def_accel, uint, 0664);
1929module_param_array_named(vram, def_vram, ulong, &def_vram_cnt, 0664);
1930module_param_named(vxres, def_vxres, long, 0664);
1931module_param_named(vyres, def_vyres, long, 0664);
1932module_param_named(rotate, def_rotate, uint, 0664);
1933module_param_named(mirror, def_mirror, uint, 0664);
1934module_param_named(manual_update, manual_update, bool, 0664);
1935
1936module_init(omapfb_init);
1937module_exit(omapfb_cleanup);
1938
1939MODULE_DESCRIPTION("TI OMAP framebuffer driver");
1940MODULE_AUTHOR("Imre Deak <imre.deak@nokia.com>");
1941MODULE_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
61static 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
74static inline void rfbi_write_reg(int idx, u32 val)
75{
76 __raw_writel(val, rfbi.base + idx);
77}
78
79static inline u32 rfbi_read_reg(int idx)
80{
81 return __raw_readl(rfbi.base + idx);
82}
83
84static 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
100static void rfbi_put_clocks(void)
101{
102 clk_put(rfbi.dss1_fck);
103 clk_put(rfbi.dss_ick);
104}
105
106static 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
119static 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
145static void rfbi_print_timings(void) {}
146#endif
147
148static 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
167static 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
173static 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
187static 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
234static int rfbi_get_max_tx_rate(void)
235{
236 return rfbi.l4_khz * 1000;
237}
238#endif
239
240
241static 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
329static 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
375static 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
399static 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
416static 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
437static 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
454static 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
478static 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
487static void rfbi_dma_callback(void *data)
488{
489 _stop_transfer();
490 rfbi.lcdc_callback(rfbi.lcdc_callback_data);
491}
492
493static 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
515static 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
565static void rfbi_cleanup(void)
566{
567 omap_dispc_free_irq();
568 rfbi_put_clocks();
569}
570
571const 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
57static 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
82static inline u32 sossi_read_reg(int reg)
83{
84 return readl(sossi.base + reg);
85}
86
87static inline u16 sossi_read_reg16(int reg)
88{
89 return readw(sossi.base + reg);
90}
91
92static inline u8 sossi_read_reg8(int reg)
93{
94 return readb(sossi.base + reg);
95}
96
97static inline void sossi_write_reg(int reg, u32 value)
98{
99 writel(value, sossi.base + reg);
100}
101
102static inline void sossi_write_reg16(int reg, u16 value)
103{
104 writew(value, sossi.base + reg);
105}
106
107static inline void sossi_write_reg8(int reg, u8 value)
108{
109 writeb(value, sossi.base + reg);
110}
111
112static void sossi_set_bits(int reg, u32 bits)
113{
114 sossi_write_reg(reg, sossi_read_reg(reg) | bits);
115}
116
117static 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
124static 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
130static 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
181static 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
220static 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
238static 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
248static 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
264static 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
273static 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
281static 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
289static 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
295static 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
314static 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
324static 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
348static 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
361static 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
367static 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
393static 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
437static 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
457static 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
472static 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
487static 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
521static 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
529static 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
557static 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
570static 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
658err:
659 clk_disable(sossi.fck);
660 clk_put(sossi.fck);
661 return r;
662}
663
664static void sossi_cleanup(void)
665{
666 omap_lcdc_free_dma_callback();
667 clk_put(sossi.fck);
668}
669
670struct 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 */
63static char *mode __devinitdata = NULL; 63static 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 */
97static struct fb_fix_screeninfo pm2fb_fix __devinitdata = { 97static 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 */
110static struct fb_var_screeninfo pm2fb_var __devinitdata = { 110static 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
190static inline void pm2v_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) 191static 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
200static inline void WAIT_FIFO(struct pm2fb_par* p, u32 a) 202static 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
207static 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))
222static const struct { 213static 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)
366static void reset_config(struct pm2fb_par* p) 357static 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 */
885static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, 868static 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 */
987static int pm2fb_pan_display(struct fb_var_screeninfo *var, 970static 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 */
1020static int pm2fb_blank(int blank_mode, struct fb_info *info) 1003static 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
1036static 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 */
1056static void pm2fb_block_op(struct pm2fb_par* par, int copy, 1055static 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
1082static void pm2fb_fillrect (struct fb_info *info, 1080static 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,
1126static void pm2fb_copyarea(struct fb_info *info, 1123static 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
1406static struct pci_driver pm2fb_driver = { 1403static 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
1413MODULE_DEVICE_TABLE(pci, pm2fb_id_table); 1410MODULE_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 */
93static const char permedia3_name[16] = "Permedia3";
94
95/* the fb_par struct, mandatory */
96struct 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)
120struct 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};
128typedef 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 */
133struct 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*/
166static 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
540static struct pm3fb_info fb_info[PM3_MAX_BOARD]; 43#ifdef PM3FB_MASTER_DEBUG
541static struct pm3fb_par current_par[PM3_MAX_BOARD]; 44#define DPRINTK(a,b...) printk(KERN_DEBUG "pm3fb: %s: " a, __FUNCTION__ , ## b)
542static int current_par_valid[PM3_MAX_BOARD]; 45#else
543/* to allow explicit filtering of board */ 46#define DPRINTK(a,b...)
544short bus[PM3_MAX_BOARD];
545short slot[PM3_MAX_BOARD];
546short func[PM3_MAX_BOARD];
547short disable[PM3_MAX_BOARD];
548short noaccel[PM3_MAX_BOARD];
549char fontn[PM3_MAX_BOARD][PM3_FONTNAME_SIZE];
550short depth[PM3_MAX_BOARD];
551short flatpanel[PM3_MAX_BOARD];
552static struct display disp[PM3_MAX_BOARD];
553static char g_options[PM3_OPTIONS_SIZE] __initdata = "pm3fb,dummy";
554short printtimings = 0;
555short forcesize[PM3_MAX_BOARD];
556
557/* ********************* */
558/* ***** prototype ***** */
559/* ********************* */
560/* card-specific */
561static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info);
562/* permedia3-specific */
563static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info);
564static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info);
565static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info);
566static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info,
567 unsigned long r);
568static 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 */ );
574static void pm3fb_clear_memory(struct pm3fb_info *l_fb_info, u32 cc);
575static void pm3fb_clear_colormap(struct pm3fb_info *l_fb_info, unsigned char r, unsigned char g, unsigned char b);
576static void pm3fb_common_init(struct pm3fb_info *l_fb_info);
577static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info,
578 unsigned long depth, int v);
579static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info,
580 unsigned long depth, int v);
581static void pm3fb_mapIO(struct pm3fb_info *l_fb_info);
582static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info);
583#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2)
584static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info);
585#endif 47#endif
586static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info);
587static void pm3fb_write_mode(struct pm3fb_info *l_fb_info);
588static void pm3fb_read_mode(struct pm3fb_info *l_fb_info,
589 struct pm3fb_par *curpar);
590static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info);
591/* accelerated permedia3-specific */
592#ifdef PM3FB_USE_ACCEL
593static void pm3fb_wait_pm3(struct pm3fb_info *l_fb_info);
594static void pm3fb_init_engine(struct pm3fb_info *l_fb_info);
595#ifdef FBCON_HAS_CFB32
596static void pm3fb_cfb32_clear(struct vc_data *conp,
597 struct display *p,
598 int sy, int sx, int height, int width);
599static 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
603static void pm3fb_cfb16_clear(struct vc_data *conp,
604 struct display *p,
605 int sy, int sx, int height, int width);
606static 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
610static void pm3fb_cfb8_clear(struct vc_data *conp,
611 struct display *p,
612 int sy, int sx, int height, int width);
613static 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)
617static void pm3fb_cfbX_bmove(struct display *p,
618 int sy, int sx,
619 int dy, int dx, int height, int width);
620static void pm3fb_cfbX_putc(struct vc_data *conp, struct display *p,
621 int c, int yy, int xx);
622static void pm3fb_cfbX_putcs(struct vc_data *conp, struct display *p,
623 const unsigned short *s, int count, int yy,
624 int xx);
625static 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 */
629static void pm3fb_mode_setup(char *mode, unsigned long board_num);
630static void pm3fb_pciid_setup(char *pciid, unsigned long board_num);
631static char *pm3fb_boardnum_setup(char *options, unsigned long *bn);
632static void pm3fb_real_setup(char *options);
633/* fbdev */
634static int pm3fb_encode_fix(struct fb_fix_screeninfo *fix,
635 const void *par, struct fb_info_gen *info);
636static int pm3fb_decode_var(const struct fb_var_screeninfo *var,
637 void *par, struct fb_info_gen *info);
638static void pm3fb_encode_depth(struct fb_var_screeninfo *var, long d);
639static int pm3fb_encode_var(struct fb_var_screeninfo *var,
640 const void *par, struct fb_info_gen *info);
641static void pm3fb_get_par(void *par, struct fb_info_gen *info);
642static void pm3fb_set_par(const void *par, struct fb_info_gen *info);
643static void pm3fb_set_color(struct pm3fb_info *l_fb_info,
644 unsigned char regno, unsigned char r,
645 unsigned char g, unsigned char b);
646static int pm3fb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
647 unsigned *blue, unsigned *transp,
648 struct fb_info *info);
649static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
650 unsigned blue, unsigned transp,
651 struct fb_info *info);
652static int pm3fb_blank(int blank_mode, struct fb_info_gen *info);
653static void pm3fb_set_disp(const void *par, struct display *disp,
654 struct fb_info_gen *info);
655static void pm3fb_detect(void);
656static int pm3fb_pan_display(const struct fb_var_screeninfo *var,
657 struct fb_info_gen *info);
658static int pm3fb_ioctl(struct fb_info *info, u_int cmd, u_long arg);
659
660
661/* the struct that hold them together */
662struct 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
668static 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
683static struct display_switch pm3fb_cfb32 = { 51 */
684 fbcon_cfb32_setup, pm3fb_cfbX_bmove, pm3fb_cfb32_clear, 52static 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
692static 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
701static 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/* ****************************** */
714struct pm3fb_card_timings {
715 unsigned long memsize; /* 0 for last value (i.e. default) */
716 struct pm3fb_timings memt;
717};
718 53
719static 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 */
61struct 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
724static 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 */
73static 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
729static 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
734static struct { 87static 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/* ********************************** */ 92static 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);
765static 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/* *************************************** */ 97static inline void PM3_WAIT(struct pm3_par *par, u32 n)
777/* ***** permedia3-specific function ***** */
778/* *************************************** */
779static 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
799static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info) 102static 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
825static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info) 112static 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
857static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info, 126static 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 */
868static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock, /* In kHz units */ 137static 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
165static 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
906static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info, 174static 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
925static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info, 188/* acceleration */
926 unsigned long depth, int v) 189static 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
944static 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
959static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info) 205static 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);
970static 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) */ 360static void pm3fb_fillrect (struct fb_info *info,
1021static 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 */
1049static void pm3fb_write_mode(struct pm3fb_info *l_fb_info) 421static 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
1256static 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
1372static 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
1499static 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
1511static 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 */
1523static 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 615static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1586static 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
1599static 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
1759static 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
1839static 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
1906static 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
1958static 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
2048static 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
2091static 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)
2160static 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
2216static 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
2325static 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
2440static 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
2493static 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
2523static 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
2555static 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
2566static 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
2578static 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
2590static 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
2612static void pm3fb_real_setup(char *options) 706static 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
2698static 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
2732static 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
2912static 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
2968static 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
3027static 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
3045static 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
3061static 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);
3073static 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
3098static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green, 766static 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
3161static int pm3fb_blank(int blank_mode, struct fb_info_gen *info) 839static 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; 853static 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
3217static 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 /*
3288static 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; 903static 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, 924static 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
3416static 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
3435static int pm3fb_ioctl(struct fb_info *info, u_int cmd, u_long arg) 1006static 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
3493int __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
3507int __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);
3528MODULE_AUTHOR("Romain Dolbeau"); 1123 err_exit_mmio:
3529MODULE_DESCRIPTION("Permedia3 framebuffer device driver"); 1124 iounmap(par->v_regs);
3530static char *mode[PM3_MAX_BOARD]; 1125 release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);
3531module_param_array(mode, charp, NULL, 0); 1126 err_exit_neither:
3532MODULE_PARM_DESC(mode,"video mode"); 1127 framebuffer_release(info);
3533module_param_array(disable, short, NULL, 0); 1128 return retval;
3534MODULE_PARM_DESC(disable,"disable board"); 1129}
3535static short off[PM3_MAX_BOARD];
3536module_param_array(off, short, NULL, 0);
3537MODULE_PARM_DESC(off,"disable board");
3538static char *pciid[PM3_MAX_BOARD];
3539module_param_array(pciid, charp, NULL, 0);
3540MODULE_PARM_DESC(pciid,"board PCI Id");
3541module_param_array(noaccel, short, NULL, 0);
3542MODULE_PARM_DESC(noaccel,"disable accel");
3543static char *font[PM3_MAX_BOARD];
3544module_param_array(font, charp, NULL, 0);
3545MODULE_PARM_DESC(font,"choose font");
3546module_param(depth, short, NULL, 0);
3547MODULE_PARM_DESC(depth,"boot-time depth");
3548module_param(printtimings, short, NULL, 0);
3549MODULE_PARM_DESC(printtimings, "print the memory timings of the card(s)");
3550module_param(forcesize, short, NULL, 0);
3551MODULE_PARM_DESC(forcesize, "force specified memory size");
3552/*
3553MODULE_SUPPORTED_DEVICE("Permedia3 PCI boards")
3554MODULE_GENERIC_TABLE(gtype,name)
3555MODULE_DEVICE_TABLE(type,name)
3556*/
3557 1130
3558void pm3fb_build_options(void) 1131 /*
1132 * Cleanup
1133 */
1134static 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
3601int init_module(void) 1155static 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 */
1162static 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(); 1169MODULE_DEVICE_TABLE(pci, pm3fb_id_table);
3608 1170
3609 return 0; 1171static 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
3612void cleanup_module(void) 1180static 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
1185module_init(pm3fb_init);
1186module_exit(pm3fb_exit);
1187
1188MODULE_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
127struct ps3fb_priv { 129struct 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
176static const struct fb_videomode ps3fb_modedb[] = { 177static 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
300static int ps3fb_mode; 301static int ps3fb_mode;
301module_param(ps3fb_mode, bool, 0); 302module_param(ps3fb_mode, int, 0);
302
303static char *mode_option __initdata;
304 303
304static char *mode_option __devinitdata;
305 305
306static int ps3fb_get_res_table(u32 xres, u32 yres) 306static int ps3fb_get_res_table(u32 xres, u32 yres)
307{ 307{
@@ -681,15 +681,15 @@ int ps3fb_wait_for_vsync(u32 crtc)
681 681
682EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync); 682EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync);
683 683
684void ps3fb_flip_ctl(int on) 684void 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
692EXPORT_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
813static int ps3fbd(void *arg) 813static 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
855static 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
879static void ps3fb_platform_release(struct device *device) 856static 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
884static 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)
951static struct fb_ops ps3fb_ops = { 923static 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
966static struct fb_fix_screeninfo ps3fb_fix __initdata = { 940static 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
973static int __init ps3fb_probe(struct platform_device *dev) 947static 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
975static 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:
1082err_framebuffer_release: 1110err_framebuffer_release:
1083 framebuffer_release(info); 1111 framebuffer_release(info);
1084err_free_irq: 1112err_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);
1087err_iounmap_dinfo: 1115err_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
1097static void ps3fb_shutdown(struct platform_device *dev) 1125static 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
1106void 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
1132EXPORT_SYMBOL_GPL(ps3fb_cleanup);
1133
1134static 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
1147static struct platform_driver ps3fb_driver = { 1167static 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,
1154static struct platform_device ps3fb_device = {
1155 .name = "ps3fb",
1156 .id = 0,
1157 .dev = { .release = ps3fb_platform_release }
1158}; 1174};
1159 1175
1160int ps3fb_set_sync(void) 1176static 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
1190EXPORT_SYMBOL_GPL(ps3fb_set_sync);
1191
1192static 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(); 1205static int __init ps3fb_init(void)
1240 1206{
1241 return error; 1207 if (!ps3fb_videomemory.address || ps3fb_setup())
1208 return -ENXIO;
1242 1209
1243err: 1210 return ps3_system_bus_driver_register(&ps3fb_driver);
1244 return -ENXIO;
1245} 1211}
1246 1212
1247module_init(ps3fb_init);
1248
1249#ifdef MODULE
1250static void __exit ps3fb_exit(void) 1213static 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
1220module_init(ps3fb_init);
1256module_exit(ps3fb_exit); 1221module_exit(ps3fb_exit);
1257 1222
1258MODULE_LICENSE("GPL"); 1223MODULE_LICENSE("GPL");
1259#endif /* MODULE */ 1224MODULE_DESCRIPTION("PS3 GPU Frame Buffer Driver");
1225MODULE_AUTHOR("Sony Computer Entertainment Inc.");
1226MODULE_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 };
115enum { PAL_ARGB1555, PAL_RGB565, PAL_ARGB4444, PAL_ARGB8888 }; 115enum { PAL_ARGB1555, PAL_RGB565, PAL_ARGB4444, PAL_ARGB8888 };
116 116
117struct pvr2_params { unsigned int val; char *name; }; 117struct pvr2_params { unsigned int val; char *name; };
118static struct pvr2_params cables[] __initdata = { 118static 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
122static struct pvr2_params outputs[] __initdata = { 122static 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
148static struct fb_info *fb_info; 148static struct fb_info *fb_info;
149 149
150static struct fb_fix_screeninfo pvr2_fix __initdata = { 150static 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
159static struct fb_var_screeninfo pvr2_var __initdata = { 159static 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;
195static unsigned int pvr2dma = ONCHIP_NR_DMA_CHANNELS; 195static unsigned int pvr2dma = ONCHIP_NR_DMA_CHANNELS;
196#endif 196#endif
197 197
198/* Interface used by the world */
199
200int pvr2fb_setup(char*);
201
202static int pvr2fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, unsigned int blue, 198static 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);
204static int pvr2fb_blank(int blank, struct fb_info *info); 200static 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
235static struct fb_videomode pvr2_modedb[] __initdata = { 231static 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
264static int defmode = DEFMODE_NTSC; 260static int defmode = DEFMODE_NTSC;
265static char *mode_option __initdata = NULL; 261static char *mode_option __devinitdata = NULL;
266 262
267static inline void pvr2fb_set_pal_type(unsigned int type) 263static 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)
657static int pvr2_init_cable(void) 654static 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(&current->mm->mmap_sem); 688 down_read(&current->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 */
768static int __init pvr2fb_common_init(void) 765static 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
906static void pvr2fb_dc_exit(void) 903static 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
990static void pvr2fb_pci_exit(void) 987static 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
996static int __init pvr2_get_param(const struct pvr2_params *p, const char *s, 993static 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
1024int __init pvr2fb_setup(char *options) 1021static 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
1074int __init pvr2fb_init(void) 1071static 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);
1139MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>"); 1135MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>");
1140MODULE_DESCRIPTION("Framebuffer driver for NEC PowerVR 2 based graphics boards"); 1136MODULE_DESCRIPTION("Framebuffer driver for NEC PowerVR 2 based graphics boards");
1141MODULE_LICENSE("GPL"); 1137MODULE_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
2149static int __init rivafb_setup(char *options) 2149static 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
801static 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, &reg16); 5800 pci_read_config_word(pdev, PCI_COMMAND, &reg16);
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;
132static struct xxx_par __initdata current_par; 132static struct xxx_par __initdata current_par;
133 133
134int xxxfb_init(void); 134int xxxfb_init(void);
135int 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 */
986int __init xxxfb_setup(char *options)
987{
988 /* Parse user speficied options (`video=xxxfb:') */
989}
990#endif /* MODULE */
991
978static int __init xxxfb_init(void) 992static 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 */
1018int __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
34static int __devinit s3d_get_props(struct s3d_info *sp) 34static 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
56static int __devinit e3d_get_props(struct e3d_info *ep) 56static 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
352void 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}
366EXPORT_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
35struct 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
48static 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
66static const struct svga_pll vt8623_pll = {2, 127, 2, 7, 0, 3,
67 60000, 300000, 14318};
68
69/* CRT timing register sets */
70
71static struct vga_regset vt8623_h_total_regs[] = {{0x00, 0, 7}, {0x36, 3, 3}, VGA_REGSET_END};
72static struct vga_regset vt8623_h_display_regs[] = {{0x01, 0, 7}, VGA_REGSET_END};
73static struct vga_regset vt8623_h_blank_start_regs[] = {{0x02, 0, 7}, VGA_REGSET_END};
74static struct vga_regset vt8623_h_blank_end_regs[] = {{0x03, 0, 4}, {0x05, 7, 7}, {0x33, 5, 5}, VGA_REGSET_END};
75static struct vga_regset vt8623_h_sync_start_regs[] = {{0x04, 0, 7}, {0x33, 4, 4}, VGA_REGSET_END};
76static struct vga_regset vt8623_h_sync_end_regs[] = {{0x05, 0, 4}, VGA_REGSET_END};
77
78static struct vga_regset vt8623_v_total_regs[] = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x35, 0, 0}, VGA_REGSET_END};
79static struct vga_regset vt8623_v_display_regs[] = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x35, 2, 2}, VGA_REGSET_END};
80static struct vga_regset vt8623_v_blank_start_regs[] = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x35, 3, 3}, VGA_REGSET_END};
81static struct vga_regset vt8623_v_blank_end_regs[] = {{0x16, 0, 7}, VGA_REGSET_END};
82static struct vga_regset vt8623_v_sync_start_regs[] = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x35, 1, 1}, VGA_REGSET_END};
83static struct vga_regset vt8623_v_sync_end_regs[] = {{0x11, 0, 3}, VGA_REGSET_END};
84
85static struct vga_regset vt8623_offset_regs[] = {{0x13, 0, 7}, {0x35, 5, 7}, VGA_REGSET_END};
86static 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};
87static struct vga_regset vt8623_fetch_count_regs[] = {{0x1C, 0, 7}, {0x1D, 0, 1}, VGA_REGSET_END};
88static struct vga_regset vt8623_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x34, 0, 7}, {0x48, 0, 1}, VGA_REGSET_END};
89
90static 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
103static char *mode = "640x480-8@60";
104
105#ifdef CONFIG_MTRR
106static int mtrr = 1;
107#endif
108
109MODULE_AUTHOR("(c) 2006 Ondrej Zajicek <santiago@crfreenet.org>");
110MODULE_LICENSE("GPL");
111MODULE_DESCRIPTION("fbdev driver for integrated graphics core in VIA VT8623 [CLE266]");
112
113module_param(mode, charp, 0644);
114MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)");
115
116#ifdef CONFIG_MTRR
117module_param(mtrr, int, 0444);
118MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)");
119#endif
120
121
122/* ------------------------------------------------------------------------- */
123
124
125static 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 */
139static 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 */
145static 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 */
173static 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 */
194static 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 */
201static 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
228static 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
240static 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
254static 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
282static 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
301static 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
320static 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
373static 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
511static 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
566static 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
600static 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
626static 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
644static 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 */
760err_reg_fb:
761 fb_dealloc_cmap(&info->cmap);
762err_alloc_cmap:
763err_find_mode:
764 pci_iounmap(dev, par->mmio_base);
765err_iomap_2:
766 pci_iounmap(dev, info->screen_base);
767err_iomap_1:
768 pci_release_regions(dev);
769err_request_regions:
770/* pci_disable_device(dev); */
771err_enable_device:
772 framebuffer_release(info);
773 return rc;
774}
775
776/* PCI remove */
777
778static 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
809static 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
840static 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));
868fail:
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
880static 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
885MODULE_DEVICE_TABLE(pci, vt8623_devices);
886
887static 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
898static 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
906static 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
927module_init(vt8623fb_init);
928module_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;