diff options
author | Michael Hanselmann <linux-kernel@hansmi.ch> | 2006-06-25 08:47:08 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-25 13:00:59 -0400 |
commit | 5474c120aafe78ca54bf272f7a01107c42da2b21 (patch) | |
tree | c1b002a27703ce92c816bfb9844752186e33d403 /drivers/video | |
parent | 17660bdd5c1f1a165273c1a59cb5b87670a81cc4 (diff) |
[PATCH] Rewritten backlight infrastructure for portable Apple computers
This patch contains a total rewrite of the backlight infrastructure for
portable Apple computers. Backward compatibility is retained. A sysfs
interface allows userland to control the brightness with more steps than
before. Userland is allowed to upload a brightness curve for different
monitors, similar to Mac OS X.
[akpm@osdl.org: add needed exports]
Signed-off-by: Michael Hanselmann <linux-kernel@hansmi.ch>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Richard Purdie <rpurdie@rpsys.net>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/Kconfig | 56 | ||||
-rw-r--r-- | drivers/video/aty/Makefile | 1 | ||||
-rw-r--r-- | drivers/video/aty/aty128fb.c | 322 | ||||
-rw-r--r-- | drivers/video/aty/atyfb.h | 1 | ||||
-rw-r--r-- | drivers/video/aty/atyfb_base.c | 178 | ||||
-rw-r--r-- | drivers/video/aty/radeon_backlight.c | 247 | ||||
-rw-r--r-- | drivers/video/aty/radeon_base.c | 140 | ||||
-rw-r--r-- | drivers/video/aty/radeonfb.h | 9 | ||||
-rw-r--r-- | drivers/video/chipsfb.c | 30 | ||||
-rw-r--r-- | drivers/video/fbsysfs.c | 88 | ||||
-rw-r--r-- | drivers/video/nvidia/Makefile | 3 | ||||
-rw-r--r-- | drivers/video/nvidia/nv_backlight.c | 175 | ||||
-rw-r--r-- | drivers/video/nvidia/nv_proto.h | 10 | ||||
-rw-r--r-- | drivers/video/nvidia/nvidia.c | 95 | ||||
-rw-r--r-- | drivers/video/riva/fbdev.c | 222 |
15 files changed, 1167 insertions, 410 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 5a2840aeb547..168ede7902bd 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -86,6 +86,11 @@ config FB_FIRMWARE_EDID | |||
86 | combination with certain motherboards and monitors are known to | 86 | combination with certain motherboards and monitors are known to |
87 | suffer from this problem. | 87 | suffer from this problem. |
88 | 88 | ||
89 | config FB_BACKLIGHT | ||
90 | bool | ||
91 | depends on FB | ||
92 | default n | ||
93 | |||
89 | config FB_MODE_HELPERS | 94 | config FB_MODE_HELPERS |
90 | bool "Enable Video Mode Handling Helpers" | 95 | bool "Enable Video Mode Handling Helpers" |
91 | depends on FB | 96 | depends on FB |
@@ -717,6 +722,16 @@ config FB_NVIDIA_I2C | |||
717 | independently validate video mode parameters, you should say Y | 722 | independently validate video mode parameters, you should say Y |
718 | here. | 723 | here. |
719 | 724 | ||
725 | config FB_NVIDIA_BACKLIGHT | ||
726 | bool "Support for backlight control" | ||
727 | depends on FB_NVIDIA && PPC_PMAC | ||
728 | select FB_BACKLIGHT | ||
729 | select BACKLIGHT_LCD_SUPPORT | ||
730 | select BACKLIGHT_CLASS_DEVICE | ||
731 | default y | ||
732 | help | ||
733 | Say Y here if you want to control the backlight of your display. | ||
734 | |||
720 | config FB_RIVA | 735 | config FB_RIVA |
721 | tristate "nVidia Riva support" | 736 | tristate "nVidia Riva support" |
722 | depends on FB && PCI | 737 | depends on FB && PCI |
@@ -755,6 +770,16 @@ config FB_RIVA_DEBUG | |||
755 | of debugging informations to provide to the maintainer when | 770 | of debugging informations to provide to the maintainer when |
756 | something goes wrong. | 771 | something goes wrong. |
757 | 772 | ||
773 | config FB_RIVA_BACKLIGHT | ||
774 | bool "Support for backlight control" | ||
775 | depends on FB_RIVA && PPC_PMAC | ||
776 | select FB_BACKLIGHT | ||
777 | select BACKLIGHT_LCD_SUPPORT | ||
778 | select BACKLIGHT_CLASS_DEVICE | ||
779 | default y | ||
780 | help | ||
781 | Say Y here if you want to control the backlight of your display. | ||
782 | |||
758 | config FB_I810 | 783 | config FB_I810 |
759 | tristate "Intel 810/815 support (EXPERIMENTAL)" | 784 | tristate "Intel 810/815 support (EXPERIMENTAL)" |
760 | depends on FB && EXPERIMENTAL && PCI && X86_32 | 785 | depends on FB && EXPERIMENTAL && PCI && X86_32 |
@@ -993,6 +1018,7 @@ config FB_RADEON | |||
993 | 1018 | ||
994 | There is a product page at | 1019 | There is a product page at |
995 | http://apps.ati.com/ATIcompare/ | 1020 | http://apps.ati.com/ATIcompare/ |
1021 | |||
996 | config FB_RADEON_I2C | 1022 | config FB_RADEON_I2C |
997 | bool "DDC/I2C for ATI Radeon support" | 1023 | bool "DDC/I2C for ATI Radeon support" |
998 | depends on FB_RADEON | 1024 | depends on FB_RADEON |
@@ -1000,6 +1026,16 @@ config FB_RADEON_I2C | |||
1000 | help | 1026 | help |
1001 | Say Y here if you want DDC/I2C support for your Radeon board. | 1027 | Say Y here if you want DDC/I2C support for your Radeon board. |
1002 | 1028 | ||
1029 | config FB_RADEON_BACKLIGHT | ||
1030 | bool "Support for backlight control" | ||
1031 | depends on FB_RADEON && PPC_PMAC | ||
1032 | select FB_BACKLIGHT | ||
1033 | select BACKLIGHT_LCD_SUPPORT | ||
1034 | select BACKLIGHT_CLASS_DEVICE | ||
1035 | default y | ||
1036 | help | ||
1037 | Say Y here if you want to control the backlight of your display. | ||
1038 | |||
1003 | config FB_RADEON_DEBUG | 1039 | config FB_RADEON_DEBUG |
1004 | bool "Lots of debug output from Radeon driver" | 1040 | bool "Lots of debug output from Radeon driver" |
1005 | depends on FB_RADEON | 1041 | depends on FB_RADEON |
@@ -1024,6 +1060,16 @@ config FB_ATY128 | |||
1024 | To compile this driver as a module, choose M here: the | 1060 | To compile this driver as a module, choose M here: the |
1025 | module will be called aty128fb. | 1061 | module will be called aty128fb. |
1026 | 1062 | ||
1063 | config FB_ATY128_BACKLIGHT | ||
1064 | bool "Support for backlight control" | ||
1065 | depends on FB_ATY128 && PPC_PMAC | ||
1066 | select FB_BACKLIGHT | ||
1067 | select BACKLIGHT_LCD_SUPPORT | ||
1068 | select BACKLIGHT_CLASS_DEVICE | ||
1069 | default y | ||
1070 | help | ||
1071 | Say Y here if you want to control the backlight of your display. | ||
1072 | |||
1027 | config FB_ATY | 1073 | config FB_ATY |
1028 | tristate "ATI Mach64 display support" if PCI || ATARI | 1074 | tristate "ATI Mach64 display support" if PCI || ATARI |
1029 | depends on FB && !SPARC32 | 1075 | depends on FB && !SPARC32 |
@@ -1066,6 +1112,16 @@ config FB_ATY_GX | |||
1066 | is at | 1112 | is at |
1067 | <http://support.ati.com/products/pc/mach64/graphics_xpression.html>. | 1113 | <http://support.ati.com/products/pc/mach64/graphics_xpression.html>. |
1068 | 1114 | ||
1115 | config FB_ATY_BACKLIGHT | ||
1116 | bool "Support for backlight control" | ||
1117 | depends on FB_ATY && PPC_PMAC | ||
1118 | select FB_BACKLIGHT | ||
1119 | select BACKLIGHT_LCD_SUPPORT | ||
1120 | select BACKLIGHT_CLASS_DEVICE | ||
1121 | default y | ||
1122 | help | ||
1123 | Say Y here if you want to control the backlight of your display. | ||
1124 | |||
1069 | config FB_S3TRIO | 1125 | config FB_S3TRIO |
1070 | bool "S3 Trio display support" | 1126 | bool "S3 Trio display support" |
1071 | depends on (FB = y) && PPC && BROKEN | 1127 | depends on (FB = y) && PPC && BROKEN |
diff --git a/drivers/video/aty/Makefile b/drivers/video/aty/Makefile index 18521397a6e3..a6cc0e9ec790 100644 --- a/drivers/video/aty/Makefile +++ b/drivers/video/aty/Makefile | |||
@@ -10,5 +10,6 @@ atyfb-objs := $(atyfb-y) | |||
10 | 10 | ||
11 | radeonfb-y := radeon_base.o radeon_pm.o radeon_monitor.o radeon_accel.o | 11 | radeonfb-y := radeon_base.o radeon_pm.o radeon_monitor.o radeon_accel.o |
12 | radeonfb-$(CONFIG_FB_RADEON_I2C) += radeon_i2c.o | 12 | radeonfb-$(CONFIG_FB_RADEON_I2C) += radeon_i2c.o |
13 | radeonfb-$(CONFIG_FB_RADEON_BACKLIGHT) += radeon_backlight.o | ||
13 | radeonfb-objs := $(radeonfb-y) | 14 | radeonfb-objs := $(radeonfb-y) |
14 | 15 | ||
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index f7bbff4ddc6a..db878fd55fb2 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c | |||
@@ -64,6 +64,7 @@ | |||
64 | #include <linux/pci.h> | 64 | #include <linux/pci.h> |
65 | #include <linux/ioport.h> | 65 | #include <linux/ioport.h> |
66 | #include <linux/console.h> | 66 | #include <linux/console.h> |
67 | #include <linux/backlight.h> | ||
67 | #include <asm/io.h> | 68 | #include <asm/io.h> |
68 | 69 | ||
69 | #ifdef CONFIG_PPC_PMAC | 70 | #ifdef CONFIG_PPC_PMAC |
@@ -480,16 +481,6 @@ static struct fb_ops aty128fb_ops = { | |||
480 | .fb_imageblit = cfb_imageblit, | 481 | .fb_imageblit = cfb_imageblit, |
481 | }; | 482 | }; |
482 | 483 | ||
483 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
484 | static int aty128_set_backlight_enable(int on, int level, void* data); | ||
485 | static int aty128_set_backlight_level(int level, void* data); | ||
486 | |||
487 | static struct backlight_controller aty128_backlight_controller = { | ||
488 | aty128_set_backlight_enable, | ||
489 | aty128_set_backlight_level | ||
490 | }; | ||
491 | #endif /* CONFIG_PMAC_BACKLIGHT */ | ||
492 | |||
493 | /* | 484 | /* |
494 | * Functions to read from/write to the mmio registers | 485 | * Functions to read from/write to the mmio registers |
495 | * - endian conversions may possibly be avoided by | 486 | * - endian conversions may possibly be avoided by |
@@ -1258,19 +1249,35 @@ static void aty128_set_crt_enable(struct aty128fb_par *par, int on) | |||
1258 | static void aty128_set_lcd_enable(struct aty128fb_par *par, int on) | 1249 | static void aty128_set_lcd_enable(struct aty128fb_par *par, int on) |
1259 | { | 1250 | { |
1260 | u32 reg; | 1251 | u32 reg; |
1252 | #ifdef CONFIG_FB_ATY128_BACKLIGHT | ||
1253 | struct fb_info *info = pci_get_drvdata(par->pdev); | ||
1254 | #endif | ||
1261 | 1255 | ||
1262 | if (on) { | 1256 | if (on) { |
1263 | reg = aty_ld_le32(LVDS_GEN_CNTL); | 1257 | reg = aty_ld_le32(LVDS_GEN_CNTL); |
1264 | reg |= LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION; | 1258 | reg |= LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION; |
1265 | reg &= ~LVDS_DISPLAY_DIS; | 1259 | reg &= ~LVDS_DISPLAY_DIS; |
1266 | aty_st_le32(LVDS_GEN_CNTL, reg); | 1260 | aty_st_le32(LVDS_GEN_CNTL, reg); |
1267 | #ifdef CONFIG_PMAC_BACKLIGHT | 1261 | #ifdef CONFIG_FB_ATY128_BACKLIGHT |
1268 | aty128_set_backlight_enable(get_backlight_enable(), | 1262 | mutex_lock(&info->bl_mutex); |
1269 | get_backlight_level(), par); | 1263 | if (info->bl_dev) { |
1264 | down(&info->bl_dev->sem); | ||
1265 | info->bl_dev->props->update_status(info->bl_dev); | ||
1266 | up(&info->bl_dev->sem); | ||
1267 | } | ||
1268 | mutex_unlock(&info->bl_mutex); | ||
1270 | #endif | 1269 | #endif |
1271 | } else { | 1270 | } else { |
1272 | #ifdef CONFIG_PMAC_BACKLIGHT | 1271 | #ifdef CONFIG_FB_ATY128_BACKLIGHT |
1273 | aty128_set_backlight_enable(0, 0, par); | 1272 | mutex_lock(&info->bl_mutex); |
1273 | if (info->bl_dev) { | ||
1274 | down(&info->bl_dev->sem); | ||
1275 | info->bl_dev->props->brightness = 0; | ||
1276 | info->bl_dev->props->power = FB_BLANK_POWERDOWN; | ||
1277 | info->bl_dev->props->update_status(info->bl_dev); | ||
1278 | up(&info->bl_dev->sem); | ||
1279 | } | ||
1280 | mutex_unlock(&info->bl_mutex); | ||
1274 | #endif | 1281 | #endif |
1275 | reg = aty_ld_le32(LVDS_GEN_CNTL); | 1282 | reg = aty_ld_le32(LVDS_GEN_CNTL); |
1276 | reg |= LVDS_DISPLAY_DIS; | 1283 | reg |= LVDS_DISPLAY_DIS; |
@@ -1691,6 +1698,184 @@ static int __init aty128fb_setup(char *options) | |||
1691 | } | 1698 | } |
1692 | #endif /* MODULE */ | 1699 | #endif /* MODULE */ |
1693 | 1700 | ||
1701 | /* Backlight */ | ||
1702 | #ifdef CONFIG_FB_ATY128_BACKLIGHT | ||
1703 | #define MAX_LEVEL 0xFF | ||
1704 | |||
1705 | static struct backlight_properties aty128_bl_data; | ||
1706 | |||
1707 | static int aty128_bl_get_level_brightness(struct aty128fb_par *par, | ||
1708 | int level) | ||
1709 | { | ||
1710 | struct fb_info *info = pci_get_drvdata(par->pdev); | ||
1711 | int atylevel; | ||
1712 | |||
1713 | /* Get and convert the value */ | ||
1714 | mutex_lock(&info->bl_mutex); | ||
1715 | atylevel = MAX_LEVEL - | ||
1716 | (info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL); | ||
1717 | mutex_unlock(&info->bl_mutex); | ||
1718 | |||
1719 | if (atylevel < 0) | ||
1720 | atylevel = 0; | ||
1721 | else if (atylevel > MAX_LEVEL) | ||
1722 | atylevel = MAX_LEVEL; | ||
1723 | |||
1724 | return atylevel; | ||
1725 | } | ||
1726 | |||
1727 | /* We turn off the LCD completely instead of just dimming the backlight. | ||
1728 | * This provides greater power saving and the display is useless without | ||
1729 | * backlight anyway | ||
1730 | */ | ||
1731 | #define BACKLIGHT_LVDS_OFF | ||
1732 | /* That one prevents proper CRT output with LCD off */ | ||
1733 | #undef BACKLIGHT_DAC_OFF | ||
1734 | |||
1735 | static int aty128_bl_update_status(struct backlight_device *bd) | ||
1736 | { | ||
1737 | struct aty128fb_par *par = class_get_devdata(&bd->class_dev); | ||
1738 | unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL); | ||
1739 | int level; | ||
1740 | |||
1741 | if (bd->props->power != FB_BLANK_UNBLANK || | ||
1742 | bd->props->fb_blank != FB_BLANK_UNBLANK || | ||
1743 | !par->lcd_on) | ||
1744 | level = 0; | ||
1745 | else | ||
1746 | level = bd->props->brightness; | ||
1747 | |||
1748 | reg |= LVDS_BL_MOD_EN | LVDS_BLON; | ||
1749 | if (level > 0) { | ||
1750 | reg |= LVDS_DIGION; | ||
1751 | if (!(reg & LVDS_ON)) { | ||
1752 | reg &= ~LVDS_BLON; | ||
1753 | aty_st_le32(LVDS_GEN_CNTL, reg); | ||
1754 | aty_ld_le32(LVDS_GEN_CNTL); | ||
1755 | mdelay(10); | ||
1756 | reg |= LVDS_BLON; | ||
1757 | aty_st_le32(LVDS_GEN_CNTL, reg); | ||
1758 | } | ||
1759 | reg &= ~LVDS_BL_MOD_LEVEL_MASK; | ||
1760 | reg |= (aty128_bl_get_level_brightness(par, level) << LVDS_BL_MOD_LEVEL_SHIFT); | ||
1761 | #ifdef BACKLIGHT_LVDS_OFF | ||
1762 | reg |= LVDS_ON | LVDS_EN; | ||
1763 | reg &= ~LVDS_DISPLAY_DIS; | ||
1764 | #endif | ||
1765 | aty_st_le32(LVDS_GEN_CNTL, reg); | ||
1766 | #ifdef BACKLIGHT_DAC_OFF | ||
1767 | aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & (~DAC_PDWN)); | ||
1768 | #endif | ||
1769 | } else { | ||
1770 | reg &= ~LVDS_BL_MOD_LEVEL_MASK; | ||
1771 | reg |= (aty128_bl_get_level_brightness(par, 0) << LVDS_BL_MOD_LEVEL_SHIFT); | ||
1772 | #ifdef BACKLIGHT_LVDS_OFF | ||
1773 | reg |= LVDS_DISPLAY_DIS; | ||
1774 | aty_st_le32(LVDS_GEN_CNTL, reg); | ||
1775 | aty_ld_le32(LVDS_GEN_CNTL); | ||
1776 | udelay(10); | ||
1777 | reg &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION); | ||
1778 | #endif | ||
1779 | aty_st_le32(LVDS_GEN_CNTL, reg); | ||
1780 | #ifdef BACKLIGHT_DAC_OFF | ||
1781 | aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PDWN); | ||
1782 | #endif | ||
1783 | } | ||
1784 | |||
1785 | return 0; | ||
1786 | } | ||
1787 | |||
1788 | static int aty128_bl_get_brightness(struct backlight_device *bd) | ||
1789 | { | ||
1790 | return bd->props->brightness; | ||
1791 | } | ||
1792 | |||
1793 | static struct backlight_properties aty128_bl_data = { | ||
1794 | .owner = THIS_MODULE, | ||
1795 | .get_brightness = aty128_bl_get_brightness, | ||
1796 | .update_status = aty128_bl_update_status, | ||
1797 | .max_brightness = (FB_BACKLIGHT_LEVELS - 1), | ||
1798 | }; | ||
1799 | |||
1800 | static void aty128_bl_init(struct aty128fb_par *par) | ||
1801 | { | ||
1802 | struct fb_info *info = pci_get_drvdata(par->pdev); | ||
1803 | struct backlight_device *bd; | ||
1804 | char name[12]; | ||
1805 | |||
1806 | /* Could be extended to Rage128Pro LVDS output too */ | ||
1807 | if (par->chip_gen != rage_M3) | ||
1808 | return; | ||
1809 | |||
1810 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
1811 | if (!pmac_has_backlight_type("ati")) | ||
1812 | return; | ||
1813 | #endif | ||
1814 | |||
1815 | snprintf(name, sizeof(name), "aty128bl%d", info->node); | ||
1816 | |||
1817 | bd = backlight_device_register(name, par, &aty128_bl_data); | ||
1818 | if (IS_ERR(bd)) { | ||
1819 | info->bl_dev = NULL; | ||
1820 | printk("aty128: Backlight registration failed\n"); | ||
1821 | goto error; | ||
1822 | } | ||
1823 | |||
1824 | mutex_lock(&info->bl_mutex); | ||
1825 | info->bl_dev = bd; | ||
1826 | fb_bl_default_curve(info, 0, | ||
1827 | 63 * FB_BACKLIGHT_MAX / MAX_LEVEL, | ||
1828 | 219 * FB_BACKLIGHT_MAX / MAX_LEVEL); | ||
1829 | mutex_unlock(&info->bl_mutex); | ||
1830 | |||
1831 | up(&bd->sem); | ||
1832 | bd->props->brightness = aty128_bl_data.max_brightness; | ||
1833 | bd->props->power = FB_BLANK_UNBLANK; | ||
1834 | bd->props->update_status(bd); | ||
1835 | down(&bd->sem); | ||
1836 | |||
1837 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
1838 | mutex_lock(&pmac_backlight_mutex); | ||
1839 | if (!pmac_backlight) | ||
1840 | pmac_backlight = bd; | ||
1841 | mutex_unlock(&pmac_backlight_mutex); | ||
1842 | #endif | ||
1843 | |||
1844 | printk("aty128: Backlight initialized (%s)\n", name); | ||
1845 | |||
1846 | return; | ||
1847 | |||
1848 | error: | ||
1849 | return; | ||
1850 | } | ||
1851 | |||
1852 | static void aty128_bl_exit(struct aty128fb_par *par) | ||
1853 | { | ||
1854 | struct fb_info *info = pci_get_drvdata(par->pdev); | ||
1855 | |||
1856 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
1857 | mutex_lock(&pmac_backlight_mutex); | ||
1858 | #endif | ||
1859 | |||
1860 | mutex_lock(&info->bl_mutex); | ||
1861 | if (info->bl_dev) { | ||
1862 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
1863 | if (pmac_backlight == info->bl_dev) | ||
1864 | pmac_backlight = NULL; | ||
1865 | #endif | ||
1866 | |||
1867 | backlight_device_unregister(info->bl_dev); | ||
1868 | info->bl_dev = NULL; | ||
1869 | |||
1870 | printk("aty128: Backlight unloaded\n"); | ||
1871 | } | ||
1872 | mutex_unlock(&info->bl_mutex); | ||
1873 | |||
1874 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
1875 | mutex_unlock(&pmac_backlight_mutex); | ||
1876 | #endif | ||
1877 | } | ||
1878 | #endif /* CONFIG_FB_ATY128_BACKLIGHT */ | ||
1694 | 1879 | ||
1695 | /* | 1880 | /* |
1696 | * Initialisation | 1881 | * Initialisation |
@@ -1835,17 +2020,15 @@ static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id * | |||
1835 | if (register_framebuffer(info) < 0) | 2020 | if (register_framebuffer(info) < 0) |
1836 | return 0; | 2021 | return 0; |
1837 | 2022 | ||
1838 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
1839 | /* Could be extended to Rage128Pro LVDS output too */ | ||
1840 | if (par->chip_gen == rage_M3) | ||
1841 | register_backlight_controller(&aty128_backlight_controller, par, "ati"); | ||
1842 | #endif /* CONFIG_PMAC_BACKLIGHT */ | ||
1843 | |||
1844 | par->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM); | 2023 | par->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM); |
1845 | par->pdev = pdev; | 2024 | par->pdev = pdev; |
1846 | par->asleep = 0; | 2025 | par->asleep = 0; |
1847 | par->lock_blank = 0; | 2026 | par->lock_blank = 0; |
1848 | 2027 | ||
2028 | #ifdef CONFIG_FB_ATY128_BACKLIGHT | ||
2029 | aty128_bl_init(par); | ||
2030 | #endif | ||
2031 | |||
1849 | printk(KERN_INFO "fb%d: %s frame buffer device on %s\n", | 2032 | printk(KERN_INFO "fb%d: %s frame buffer device on %s\n", |
1850 | info->node, info->fix.id, video_card); | 2033 | info->node, info->fix.id, video_card); |
1851 | 2034 | ||
@@ -1981,6 +2164,10 @@ static void __devexit aty128_remove(struct pci_dev *pdev) | |||
1981 | 2164 | ||
1982 | par = info->par; | 2165 | par = info->par; |
1983 | 2166 | ||
2167 | #ifdef CONFIG_FB_ATY128_BACKLIGHT | ||
2168 | aty128_bl_exit(par); | ||
2169 | #endif | ||
2170 | |||
1984 | unregister_framebuffer(info); | 2171 | unregister_framebuffer(info); |
1985 | #ifdef CONFIG_MTRR | 2172 | #ifdef CONFIG_MTRR |
1986 | if (par->mtrr.vram_valid) | 2173 | if (par->mtrr.vram_valid) |
@@ -2011,10 +2198,14 @@ static int aty128fb_blank(int blank, struct fb_info *fb) | |||
2011 | if (par->lock_blank || par->asleep) | 2198 | if (par->lock_blank || par->asleep) |
2012 | return 0; | 2199 | return 0; |
2013 | 2200 | ||
2014 | #ifdef CONFIG_PMAC_BACKLIGHT | 2201 | #ifdef CONFIG_FB_ATY128_BACKLIGHT |
2015 | if (machine_is(powermac) && blank) | 2202 | if (machine_is(powermac) && blank) { |
2016 | set_backlight_enable(0); | 2203 | down(&fb->bl_dev->sem); |
2017 | #endif /* CONFIG_PMAC_BACKLIGHT */ | 2204 | fb->bl_dev->props->power = FB_BLANK_POWERDOWN; |
2205 | fb->bl_dev->props->update_status(fb->bl_dev); | ||
2206 | up(&fb->bl_dev->sem); | ||
2207 | } | ||
2208 | #endif | ||
2018 | 2209 | ||
2019 | if (blank & FB_BLANK_VSYNC_SUSPEND) | 2210 | if (blank & FB_BLANK_VSYNC_SUSPEND) |
2020 | state |= 2; | 2211 | state |= 2; |
@@ -2029,10 +2220,14 @@ static int aty128fb_blank(int blank, struct fb_info *fb) | |||
2029 | aty128_set_crt_enable(par, par->crt_on && !blank); | 2220 | aty128_set_crt_enable(par, par->crt_on && !blank); |
2030 | aty128_set_lcd_enable(par, par->lcd_on && !blank); | 2221 | aty128_set_lcd_enable(par, par->lcd_on && !blank); |
2031 | } | 2222 | } |
2032 | #ifdef CONFIG_PMAC_BACKLIGHT | 2223 | #ifdef CONFIG_FB_ATY128_BACKLIGHT |
2033 | if (machine_is(powermac) && !blank) | 2224 | if (machine_is(powermac) && !blank) { |
2034 | set_backlight_enable(1); | 2225 | down(&fb->bl_dev->sem); |
2035 | #endif /* CONFIG_PMAC_BACKLIGHT */ | 2226 | fb->bl_dev->props->power = FB_BLANK_UNBLANK; |
2227 | fb->bl_dev->props->update_status(fb->bl_dev); | ||
2228 | up(&fb->bl_dev->sem); | ||
2229 | } | ||
2230 | #endif | ||
2036 | return 0; | 2231 | return 0; |
2037 | } | 2232 | } |
2038 | 2233 | ||
@@ -2138,73 +2333,6 @@ static int aty128fb_ioctl(struct fb_info *info, u_int cmd, u_long arg) | |||
2138 | return -EINVAL; | 2333 | return -EINVAL; |
2139 | } | 2334 | } |
2140 | 2335 | ||
2141 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
2142 | static int backlight_conv[] = { | ||
2143 | 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e, | ||
2144 | 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24 | ||
2145 | }; | ||
2146 | |||
2147 | /* We turn off the LCD completely instead of just dimming the backlight. | ||
2148 | * This provides greater power saving and the display is useless without | ||
2149 | * backlight anyway | ||
2150 | */ | ||
2151 | #define BACKLIGHT_LVDS_OFF | ||
2152 | /* That one prevents proper CRT output with LCD off */ | ||
2153 | #undef BACKLIGHT_DAC_OFF | ||
2154 | |||
2155 | static int aty128_set_backlight_enable(int on, int level, void *data) | ||
2156 | { | ||
2157 | struct aty128fb_par *par = data; | ||
2158 | unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL); | ||
2159 | |||
2160 | if (!par->lcd_on) | ||
2161 | on = 0; | ||
2162 | reg |= LVDS_BL_MOD_EN | LVDS_BLON; | ||
2163 | if (on && level > BACKLIGHT_OFF) { | ||
2164 | reg |= LVDS_DIGION; | ||
2165 | if (!(reg & LVDS_ON)) { | ||
2166 | reg &= ~LVDS_BLON; | ||
2167 | aty_st_le32(LVDS_GEN_CNTL, reg); | ||
2168 | (void)aty_ld_le32(LVDS_GEN_CNTL); | ||
2169 | mdelay(10); | ||
2170 | reg |= LVDS_BLON; | ||
2171 | aty_st_le32(LVDS_GEN_CNTL, reg); | ||
2172 | } | ||
2173 | reg &= ~LVDS_BL_MOD_LEVEL_MASK; | ||
2174 | reg |= (backlight_conv[level] << LVDS_BL_MOD_LEVEL_SHIFT); | ||
2175 | #ifdef BACKLIGHT_LVDS_OFF | ||
2176 | reg |= LVDS_ON | LVDS_EN; | ||
2177 | reg &= ~LVDS_DISPLAY_DIS; | ||
2178 | #endif | ||
2179 | aty_st_le32(LVDS_GEN_CNTL, reg); | ||
2180 | #ifdef BACKLIGHT_DAC_OFF | ||
2181 | aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & (~DAC_PDWN)); | ||
2182 | #endif | ||
2183 | } else { | ||
2184 | reg &= ~LVDS_BL_MOD_LEVEL_MASK; | ||
2185 | reg |= (backlight_conv[0] << LVDS_BL_MOD_LEVEL_SHIFT); | ||
2186 | #ifdef BACKLIGHT_LVDS_OFF | ||
2187 | reg |= LVDS_DISPLAY_DIS; | ||
2188 | aty_st_le32(LVDS_GEN_CNTL, reg); | ||
2189 | (void)aty_ld_le32(LVDS_GEN_CNTL); | ||
2190 | udelay(10); | ||
2191 | reg &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION); | ||
2192 | #endif | ||
2193 | aty_st_le32(LVDS_GEN_CNTL, reg); | ||
2194 | #ifdef BACKLIGHT_DAC_OFF | ||
2195 | aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PDWN); | ||
2196 | #endif | ||
2197 | } | ||
2198 | |||
2199 | return 0; | ||
2200 | } | ||
2201 | |||
2202 | static int aty128_set_backlight_level(int level, void* data) | ||
2203 | { | ||
2204 | return aty128_set_backlight_enable(1, level, data); | ||
2205 | } | ||
2206 | #endif /* CONFIG_PMAC_BACKLIGHT */ | ||
2207 | |||
2208 | #if 0 | 2336 | #if 0 |
2209 | /* | 2337 | /* |
2210 | * Accelerated functions | 2338 | * Accelerated functions |
diff --git a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h index e9b7a64c1ac4..43d2cb58af87 100644 --- a/drivers/video/aty/atyfb.h +++ b/drivers/video/aty/atyfb.h | |||
@@ -151,6 +151,7 @@ struct atyfb_par { | |||
151 | int lock_blank; | 151 | int lock_blank; |
152 | unsigned long res_start; | 152 | unsigned long res_start; |
153 | unsigned long res_size; | 153 | unsigned long res_size; |
154 | struct pci_dev *pdev; | ||
154 | #ifdef __sparc__ | 155 | #ifdef __sparc__ |
155 | struct pci_mmap_map *mmap_map; | 156 | struct pci_mmap_map *mmap_map; |
156 | u8 mmaped; | 157 | u8 mmaped; |
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index c054bb28b1c4..c5185f7cf4ba 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c | |||
@@ -66,6 +66,7 @@ | |||
66 | #include <linux/interrupt.h> | 66 | #include <linux/interrupt.h> |
67 | #include <linux/spinlock.h> | 67 | #include <linux/spinlock.h> |
68 | #include <linux/wait.h> | 68 | #include <linux/wait.h> |
69 | #include <linux/backlight.h> | ||
69 | 70 | ||
70 | #include <asm/io.h> | 71 | #include <asm/io.h> |
71 | #include <asm/uaccess.h> | 72 | #include <asm/uaccess.h> |
@@ -2115,45 +2116,142 @@ static int atyfb_pci_resume(struct pci_dev *pdev) | |||
2115 | 2116 | ||
2116 | #endif /* defined(CONFIG_PM) && defined(CONFIG_PCI) */ | 2117 | #endif /* defined(CONFIG_PM) && defined(CONFIG_PCI) */ |
2117 | 2118 | ||
2118 | #ifdef CONFIG_PMAC_BACKLIGHT | 2119 | /* Backlight */ |
2120 | #ifdef CONFIG_FB_ATY_BACKLIGHT | ||
2121 | #define MAX_LEVEL 0xFF | ||
2119 | 2122 | ||
2120 | /* | 2123 | static struct backlight_properties aty_bl_data; |
2121 | * LCD backlight control | ||
2122 | */ | ||
2123 | 2124 | ||
2124 | static int backlight_conv[] = { | 2125 | static int aty_bl_get_level_brightness(struct atyfb_par *par, int level) |
2125 | 0x00, 0x3f, 0x4c, 0x59, 0x66, 0x73, 0x80, 0x8d, | 2126 | { |
2126 | 0x9a, 0xa7, 0xb4, 0xc1, 0xcf, 0xdc, 0xe9, 0xff | 2127 | struct fb_info *info = pci_get_drvdata(par->pdev); |
2127 | }; | 2128 | int atylevel; |
2129 | |||
2130 | /* Get and convert the value */ | ||
2131 | mutex_lock(&info->bl_mutex); | ||
2132 | atylevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL; | ||
2133 | mutex_unlock(&info->bl_mutex); | ||
2134 | |||
2135 | if (atylevel < 0) | ||
2136 | atylevel = 0; | ||
2137 | else if (atylevel > MAX_LEVEL) | ||
2138 | atylevel = MAX_LEVEL; | ||
2128 | 2139 | ||
2129 | static int aty_set_backlight_enable(int on, int level, void *data) | 2140 | return atylevel; |
2141 | } | ||
2142 | |||
2143 | static int aty_bl_update_status(struct backlight_device *bd) | ||
2130 | { | 2144 | { |
2131 | struct fb_info *info = (struct fb_info *) data; | 2145 | struct atyfb_par *par = class_get_devdata(&bd->class_dev); |
2132 | struct atyfb_par *par = (struct atyfb_par *) info->par; | ||
2133 | unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par); | 2146 | unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par); |
2147 | int level; | ||
2148 | |||
2149 | if (bd->props->power != FB_BLANK_UNBLANK || | ||
2150 | bd->props->fb_blank != FB_BLANK_UNBLANK) | ||
2151 | level = 0; | ||
2152 | else | ||
2153 | level = bd->props->brightness; | ||
2134 | 2154 | ||
2135 | reg |= (BLMOD_EN | BIASMOD_EN); | 2155 | reg |= (BLMOD_EN | BIASMOD_EN); |
2136 | if (on && level > BACKLIGHT_OFF) { | 2156 | if (level > 0) { |
2137 | reg &= ~BIAS_MOD_LEVEL_MASK; | 2157 | reg &= ~BIAS_MOD_LEVEL_MASK; |
2138 | reg |= (backlight_conv[level] << BIAS_MOD_LEVEL_SHIFT); | 2158 | reg |= (aty_bl_get_level_brightness(par, level) << BIAS_MOD_LEVEL_SHIFT); |
2139 | } else { | 2159 | } else { |
2140 | reg &= ~BIAS_MOD_LEVEL_MASK; | 2160 | reg &= ~BIAS_MOD_LEVEL_MASK; |
2141 | reg |= (backlight_conv[0] << BIAS_MOD_LEVEL_SHIFT); | 2161 | reg |= (aty_bl_get_level_brightness(par, 0) << BIAS_MOD_LEVEL_SHIFT); |
2142 | } | 2162 | } |
2143 | aty_st_lcd(LCD_MISC_CNTL, reg, par); | 2163 | aty_st_lcd(LCD_MISC_CNTL, reg, par); |
2164 | |||
2144 | return 0; | 2165 | return 0; |
2145 | } | 2166 | } |
2146 | 2167 | ||
2147 | static int aty_set_backlight_level(int level, void *data) | 2168 | static int aty_bl_get_brightness(struct backlight_device *bd) |
2148 | { | 2169 | { |
2149 | return aty_set_backlight_enable(1, level, data); | 2170 | return bd->props->brightness; |
2150 | } | 2171 | } |
2151 | 2172 | ||
2152 | static struct backlight_controller aty_backlight_controller = { | 2173 | static struct backlight_properties aty_bl_data = { |
2153 | aty_set_backlight_enable, | 2174 | .owner = THIS_MODULE, |
2154 | aty_set_backlight_level | 2175 | .get_brightness = aty_bl_get_brightness, |
2176 | .update_status = aty_bl_update_status, | ||
2177 | .max_brightness = (FB_BACKLIGHT_LEVELS - 1), | ||
2155 | }; | 2178 | }; |
2156 | #endif /* CONFIG_PMAC_BACKLIGHT */ | 2179 | |
2180 | static void aty_bl_init(struct atyfb_par *par) | ||
2181 | { | ||
2182 | struct fb_info *info = pci_get_drvdata(par->pdev); | ||
2183 | struct backlight_device *bd; | ||
2184 | char name[12]; | ||
2185 | |||
2186 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
2187 | if (!pmac_has_backlight_type("ati")) | ||
2188 | return; | ||
2189 | #endif | ||
2190 | |||
2191 | snprintf(name, sizeof(name), "atybl%d", info->node); | ||
2192 | |||
2193 | bd = backlight_device_register(name, par, &aty_bl_data); | ||
2194 | if (IS_ERR(bd)) { | ||
2195 | info->bl_dev = NULL; | ||
2196 | printk("aty: Backlight registration failed\n"); | ||
2197 | goto error; | ||
2198 | } | ||
2199 | |||
2200 | mutex_lock(&info->bl_mutex); | ||
2201 | info->bl_dev = bd; | ||
2202 | fb_bl_default_curve(info, 0, | ||
2203 | 0x3F * FB_BACKLIGHT_MAX / MAX_LEVEL, | ||
2204 | 0xFF * FB_BACKLIGHT_MAX / MAX_LEVEL); | ||
2205 | mutex_unlock(&info->bl_mutex); | ||
2206 | |||
2207 | up(&bd->sem); | ||
2208 | bd->props->brightness = aty_bl_data.max_brightness; | ||
2209 | bd->props->power = FB_BLANK_UNBLANK; | ||
2210 | bd->props->update_status(bd); | ||
2211 | down(&bd->sem); | ||
2212 | |||
2213 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
2214 | mutex_lock(&pmac_backlight_mutex); | ||
2215 | if (!pmac_backlight) | ||
2216 | pmac_backlight = bd; | ||
2217 | mutex_unlock(&pmac_backlight_mutex); | ||
2218 | #endif | ||
2219 | |||
2220 | printk("aty: Backlight initialized (%s)\n", name); | ||
2221 | |||
2222 | return; | ||
2223 | |||
2224 | error: | ||
2225 | return; | ||
2226 | } | ||
2227 | |||
2228 | static void aty_bl_exit(struct atyfb_par *par) | ||
2229 | { | ||
2230 | struct fb_info *info = pci_get_drvdata(par->pdev); | ||
2231 | |||
2232 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
2233 | mutex_lock(&pmac_backlight_mutex); | ||
2234 | #endif | ||
2235 | |||
2236 | mutex_lock(&info->bl_mutex); | ||
2237 | if (info->bl_dev) { | ||
2238 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
2239 | if (pmac_backlight == info->bl_dev) | ||
2240 | pmac_backlight = NULL; | ||
2241 | #endif | ||
2242 | |||
2243 | backlight_device_unregister(info->bl_dev); | ||
2244 | |||
2245 | printk("aty: Backlight unloaded\n"); | ||
2246 | } | ||
2247 | mutex_unlock(&info->bl_mutex); | ||
2248 | |||
2249 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
2250 | mutex_unlock(&pmac_backlight_mutex); | ||
2251 | #endif | ||
2252 | } | ||
2253 | |||
2254 | #endif /* CONFIG_FB_ATY_BACKLIGHT */ | ||
2157 | 2255 | ||
2158 | static void __init aty_calc_mem_refresh(struct atyfb_par *par, int xclk) | 2256 | static void __init aty_calc_mem_refresh(struct atyfb_par *par, int xclk) |
2159 | { | 2257 | { |
@@ -2513,9 +2611,13 @@ static int __init aty_init(struct fb_info *info, const char *name) | |||
2513 | /* these bits let the 101 powerbook wake up from sleep -- paulus */ | 2611 | /* these bits let the 101 powerbook wake up from sleep -- paulus */ |
2514 | aty_st_lcd(POWER_MANAGEMENT, aty_ld_lcd(POWER_MANAGEMENT, par) | 2612 | aty_st_lcd(POWER_MANAGEMENT, aty_ld_lcd(POWER_MANAGEMENT, par) |
2515 | | (USE_F32KHZ | TRISTATE_MEM_EN), par); | 2613 | | (USE_F32KHZ | TRISTATE_MEM_EN), par); |
2516 | } else if (M64_HAS(MOBIL_BUS)) | 2614 | } else |
2517 | register_backlight_controller(&aty_backlight_controller, info, "ati"); | 2615 | #endif |
2518 | #endif /* CONFIG_PMAC_BACKLIGHT */ | 2616 | if (M64_HAS(MOBIL_BUS)) { |
2617 | #ifdef CONFIG_FB_ATY_BACKLIGHT | ||
2618 | aty_bl_init (par); | ||
2619 | #endif | ||
2620 | } | ||
2519 | 2621 | ||
2520 | memset(&var, 0, sizeof(var)); | 2622 | memset(&var, 0, sizeof(var)); |
2521 | #ifdef CONFIG_PPC | 2623 | #ifdef CONFIG_PPC |
@@ -2674,8 +2776,16 @@ static int atyfb_blank(int blank, struct fb_info *info) | |||
2674 | return 0; | 2776 | return 0; |
2675 | 2777 | ||
2676 | #ifdef CONFIG_PMAC_BACKLIGHT | 2778 | #ifdef CONFIG_PMAC_BACKLIGHT |
2677 | if (machine_is(powermac) && blank > FB_BLANK_NORMAL) | 2779 | if (machine_is(powermac) && blank > FB_BLANK_NORMAL) { |
2678 | set_backlight_enable(0); | 2780 | mutex_lock(&info->bl_mutex); |
2781 | if (info->bl_dev) { | ||
2782 | down(&info->bl_dev->sem); | ||
2783 | info->bl_dev->props->power = FB_BLANK_POWERDOWN; | ||
2784 | info->bl_dev->props->update_status(info->bl_dev); | ||
2785 | up(&info->bl_dev->sem); | ||
2786 | } | ||
2787 | mutex_unlock(&info->bl_mutex); | ||
2788 | } | ||
2679 | #elif defined(CONFIG_FB_ATY_GENERIC_LCD) | 2789 | #elif defined(CONFIG_FB_ATY_GENERIC_LCD) |
2680 | if (par->lcd_table && blank > FB_BLANK_NORMAL && | 2790 | if (par->lcd_table && blank > FB_BLANK_NORMAL && |
2681 | (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) { | 2791 | (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) { |
@@ -2706,8 +2816,16 @@ static int atyfb_blank(int blank, struct fb_info *info) | |||
2706 | aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par); | 2816 | aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par); |
2707 | 2817 | ||
2708 | #ifdef CONFIG_PMAC_BACKLIGHT | 2818 | #ifdef CONFIG_PMAC_BACKLIGHT |
2709 | if (machine_is(powermac) && blank <= FB_BLANK_NORMAL) | 2819 | if (machine_is(powermac) && blank <= FB_BLANK_NORMAL) { |
2710 | set_backlight_enable(1); | 2820 | mutex_lock(&info->bl_mutex); |
2821 | if (info->bl_dev) { | ||
2822 | down(&info->bl_dev->sem); | ||
2823 | info->bl_dev->props->power = FB_BLANK_UNBLANK; | ||
2824 | info->bl_dev->props->update_status(info->bl_dev); | ||
2825 | up(&info->bl_dev->sem); | ||
2826 | } | ||
2827 | mutex_unlock(&info->bl_mutex); | ||
2828 | } | ||
2711 | #elif defined(CONFIG_FB_ATY_GENERIC_LCD) | 2829 | #elif defined(CONFIG_FB_ATY_GENERIC_LCD) |
2712 | if (par->lcd_table && blank <= FB_BLANK_NORMAL && | 2830 | if (par->lcd_table && blank <= FB_BLANK_NORMAL && |
2713 | (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) { | 2831 | (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) { |
@@ -3440,6 +3558,7 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi | |||
3440 | par->res_start = res_start; | 3558 | par->res_start = res_start; |
3441 | par->res_size = res_size; | 3559 | par->res_size = res_size; |
3442 | par->irq = pdev->irq; | 3560 | par->irq = pdev->irq; |
3561 | par->pdev = pdev; | ||
3443 | 3562 | ||
3444 | /* Setup "info" structure */ | 3563 | /* Setup "info" structure */ |
3445 | #ifdef __sparc__ | 3564 | #ifdef __sparc__ |
@@ -3571,6 +3690,11 @@ static void __devexit atyfb_remove(struct fb_info *info) | |||
3571 | aty_set_crtc(par, &saved_crtc); | 3690 | aty_set_crtc(par, &saved_crtc); |
3572 | par->pll_ops->set_pll(info, &saved_pll); | 3691 | par->pll_ops->set_pll(info, &saved_pll); |
3573 | 3692 | ||
3693 | #ifdef CONFIG_FB_ATY_BACKLIGHT | ||
3694 | if (M64_HAS(MOBIL_BUS)) | ||
3695 | aty_bl_exit(par); | ||
3696 | #endif | ||
3697 | |||
3574 | unregister_framebuffer(info); | 3698 | unregister_framebuffer(info); |
3575 | 3699 | ||
3576 | #ifdef CONFIG_MTRR | 3700 | #ifdef CONFIG_MTRR |
diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c new file mode 100644 index 000000000000..7de66b855d4e --- /dev/null +++ b/drivers/video/aty/radeon_backlight.c | |||
@@ -0,0 +1,247 @@ | |||
1 | /* | ||
2 | * Backlight code for ATI Radeon based graphic cards | ||
3 | * | ||
4 | * Copyright (c) 2000 Ani Joshi <ajoshi@kernel.crashing.org> | ||
5 | * Copyright (c) 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org> | ||
6 | * Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include "radeonfb.h" | ||
14 | #include <linux/backlight.h> | ||
15 | |||
16 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
17 | #include <asm/backlight.h> | ||
18 | #endif | ||
19 | |||
20 | #define MAX_RADEON_LEVEL 0xFF | ||
21 | |||
22 | static struct backlight_properties radeon_bl_data; | ||
23 | |||
24 | struct radeon_bl_privdata { | ||
25 | struct radeonfb_info *rinfo; | ||
26 | uint8_t negative; | ||
27 | }; | ||
28 | |||
29 | static int radeon_bl_get_level_brightness(struct radeon_bl_privdata *pdata, | ||
30 | int level) | ||
31 | { | ||
32 | struct fb_info *info = pdata->rinfo->info; | ||
33 | int rlevel; | ||
34 | |||
35 | mutex_lock(&info->bl_mutex); | ||
36 | |||
37 | /* Get and convert the value */ | ||
38 | rlevel = pdata->rinfo->info->bl_curve[level] * | ||
39 | FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL; | ||
40 | |||
41 | mutex_unlock(&info->bl_mutex); | ||
42 | |||
43 | if (pdata->negative) | ||
44 | rlevel = MAX_RADEON_LEVEL - rlevel; | ||
45 | |||
46 | if (rlevel < 0) | ||
47 | rlevel = 0; | ||
48 | else if (rlevel > MAX_RADEON_LEVEL) | ||
49 | rlevel = MAX_RADEON_LEVEL; | ||
50 | |||
51 | return rlevel; | ||
52 | } | ||
53 | |||
54 | static int radeon_bl_update_status(struct backlight_device *bd) | ||
55 | { | ||
56 | struct radeon_bl_privdata *pdata = class_get_devdata(&bd->class_dev); | ||
57 | struct radeonfb_info *rinfo = pdata->rinfo; | ||
58 | u32 lvds_gen_cntl, tmpPixclksCntl; | ||
59 | int level; | ||
60 | |||
61 | if (rinfo->mon1_type != MT_LCD) | ||
62 | return 0; | ||
63 | |||
64 | /* We turn off the LCD completely instead of just dimming the | ||
65 | * backlight. This provides some greater power saving and the display | ||
66 | * is useless without backlight anyway. | ||
67 | */ | ||
68 | if (bd->props->power != FB_BLANK_UNBLANK || | ||
69 | bd->props->fb_blank != FB_BLANK_UNBLANK) | ||
70 | level = 0; | ||
71 | else | ||
72 | level = bd->props->brightness; | ||
73 | |||
74 | del_timer_sync(&rinfo->lvds_timer); | ||
75 | radeon_engine_idle(); | ||
76 | |||
77 | lvds_gen_cntl = INREG(LVDS_GEN_CNTL); | ||
78 | if (level > 0) { | ||
79 | lvds_gen_cntl &= ~LVDS_DISPLAY_DIS; | ||
80 | if (!(lvds_gen_cntl & LVDS_BLON) || !(lvds_gen_cntl & LVDS_ON)) { | ||
81 | lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON); | ||
82 | lvds_gen_cntl |= LVDS_BLON | LVDS_EN; | ||
83 | OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); | ||
84 | lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK; | ||
85 | lvds_gen_cntl |= | ||
86 | (radeon_bl_get_level_brightness(pdata, level) << | ||
87 | LVDS_BL_MOD_LEVEL_SHIFT); | ||
88 | lvds_gen_cntl |= LVDS_ON; | ||
89 | lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN); | ||
90 | rinfo->pending_lvds_gen_cntl = lvds_gen_cntl; | ||
91 | mod_timer(&rinfo->lvds_timer, | ||
92 | jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay)); | ||
93 | } else { | ||
94 | lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK; | ||
95 | lvds_gen_cntl |= | ||
96 | (radeon_bl_get_level_brightness(pdata, level) << | ||
97 | LVDS_BL_MOD_LEVEL_SHIFT); | ||
98 | OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); | ||
99 | } | ||
100 | rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK; | ||
101 | rinfo->init_state.lvds_gen_cntl |= rinfo->pending_lvds_gen_cntl | ||
102 | & LVDS_STATE_MASK; | ||
103 | } else { | ||
104 | /* Asic bug, when turning off LVDS_ON, we have to make sure | ||
105 | RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off | ||
106 | */ | ||
107 | tmpPixclksCntl = INPLL(PIXCLKS_CNTL); | ||
108 | if (rinfo->is_mobility || rinfo->is_IGP) | ||
109 | OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb); | ||
110 | lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN); | ||
111 | lvds_gen_cntl |= (radeon_bl_get_level_brightness(pdata, 0) << | ||
112 | LVDS_BL_MOD_LEVEL_SHIFT); | ||
113 | lvds_gen_cntl |= LVDS_DISPLAY_DIS; | ||
114 | OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); | ||
115 | udelay(100); | ||
116 | lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN); | ||
117 | OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); | ||
118 | lvds_gen_cntl &= ~(LVDS_DIGON); | ||
119 | rinfo->pending_lvds_gen_cntl = lvds_gen_cntl; | ||
120 | mod_timer(&rinfo->lvds_timer, | ||
121 | jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay)); | ||
122 | if (rinfo->is_mobility || rinfo->is_IGP) | ||
123 | OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl); | ||
124 | } | ||
125 | rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK; | ||
126 | rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK); | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int radeon_bl_get_brightness(struct backlight_device *bd) | ||
132 | { | ||
133 | return bd->props->brightness; | ||
134 | } | ||
135 | |||
136 | static struct backlight_properties radeon_bl_data = { | ||
137 | .owner = THIS_MODULE, | ||
138 | .get_brightness = radeon_bl_get_brightness, | ||
139 | .update_status = radeon_bl_update_status, | ||
140 | .max_brightness = (FB_BACKLIGHT_LEVELS - 1), | ||
141 | }; | ||
142 | |||
143 | void radeonfb_bl_init(struct radeonfb_info *rinfo) | ||
144 | { | ||
145 | struct backlight_device *bd; | ||
146 | struct radeon_bl_privdata *pdata; | ||
147 | char name[12]; | ||
148 | |||
149 | if (rinfo->mon1_type != MT_LCD) | ||
150 | return; | ||
151 | |||
152 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
153 | if (!pmac_has_backlight_type("ati") && | ||
154 | !pmac_has_backlight_type("mnca")) | ||
155 | return; | ||
156 | #endif | ||
157 | |||
158 | pdata = kmalloc(sizeof(struct radeon_bl_privdata), GFP_KERNEL); | ||
159 | if (!pdata) { | ||
160 | printk("radeonfb: Memory allocation failed\n"); | ||
161 | goto error; | ||
162 | } | ||
163 | |||
164 | snprintf(name, sizeof(name), "radeonbl%d", rinfo->info->node); | ||
165 | |||
166 | bd = backlight_device_register(name, pdata, &radeon_bl_data); | ||
167 | if (IS_ERR(bd)) { | ||
168 | rinfo->info->bl_dev = NULL; | ||
169 | printk("radeonfb: Backlight registration failed\n"); | ||
170 | goto error; | ||
171 | } | ||
172 | |||
173 | pdata->rinfo = rinfo; | ||
174 | |||
175 | /* Pardon me for that hack... maybe some day we can figure out in what | ||
176 | * direction backlight should work on a given panel? | ||
177 | */ | ||
178 | pdata->negative = | ||
179 | (rinfo->family != CHIP_FAMILY_RV200 && | ||
180 | rinfo->family != CHIP_FAMILY_RV250 && | ||
181 | rinfo->family != CHIP_FAMILY_RV280 && | ||
182 | rinfo->family != CHIP_FAMILY_RV350); | ||
183 | |||
184 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
185 | pdata->negative = pdata->negative || | ||
186 | machine_is_compatible("PowerBook4,3") || | ||
187 | machine_is_compatible("PowerBook6,3") || | ||
188 | machine_is_compatible("PowerBook6,5"); | ||
189 | #endif | ||
190 | |||
191 | mutex_lock(&rinfo->info->bl_mutex); | ||
192 | rinfo->info->bl_dev = bd; | ||
193 | fb_bl_default_curve(rinfo->info, 0, | ||
194 | 63 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL, | ||
195 | 217 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL); | ||
196 | mutex_unlock(&rinfo->info->bl_mutex); | ||
197 | |||
198 | up(&bd->sem); | ||
199 | bd->props->brightness = radeon_bl_data.max_brightness; | ||
200 | bd->props->power = FB_BLANK_UNBLANK; | ||
201 | bd->props->update_status(bd); | ||
202 | down(&bd->sem); | ||
203 | |||
204 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
205 | mutex_lock(&pmac_backlight_mutex); | ||
206 | if (!pmac_backlight) | ||
207 | pmac_backlight = bd; | ||
208 | mutex_unlock(&pmac_backlight_mutex); | ||
209 | #endif | ||
210 | |||
211 | printk("radeonfb: Backlight initialized (%s)\n", name); | ||
212 | |||
213 | return; | ||
214 | |||
215 | error: | ||
216 | kfree(pdata); | ||
217 | return; | ||
218 | } | ||
219 | |||
220 | void radeonfb_bl_exit(struct radeonfb_info *rinfo) | ||
221 | { | ||
222 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
223 | mutex_lock(&pmac_backlight_mutex); | ||
224 | #endif | ||
225 | |||
226 | mutex_lock(&rinfo->info->bl_mutex); | ||
227 | if (rinfo->info->bl_dev) { | ||
228 | struct radeon_bl_privdata *pdata; | ||
229 | |||
230 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
231 | if (pmac_backlight == rinfo->info->bl_dev) | ||
232 | pmac_backlight = NULL; | ||
233 | #endif | ||
234 | |||
235 | pdata = class_get_devdata(&rinfo->info->bl_dev->class_dev); | ||
236 | backlight_device_unregister(rinfo->info->bl_dev); | ||
237 | kfree(pdata); | ||
238 | rinfo->info->bl_dev = NULL; | ||
239 | |||
240 | printk("radeonfb: Backlight unloaded\n"); | ||
241 | } | ||
242 | mutex_unlock(&rinfo->info->bl_mutex); | ||
243 | |||
244 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
245 | mutex_unlock(&pmac_backlight_mutex); | ||
246 | #endif | ||
247 | } | ||
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index 387a18a47ac2..c5ecbb02e01d 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c | |||
@@ -78,10 +78,6 @@ | |||
78 | #include <asm/pci-bridge.h> | 78 | #include <asm/pci-bridge.h> |
79 | #include "../macmodes.h" | 79 | #include "../macmodes.h" |
80 | 80 | ||
81 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
82 | #include <asm/backlight.h> | ||
83 | #endif | ||
84 | |||
85 | #ifdef CONFIG_BOOTX_TEXT | 81 | #ifdef CONFIG_BOOTX_TEXT |
86 | #include <asm/btext.h> | 82 | #include <asm/btext.h> |
87 | #endif | 83 | #endif |
@@ -277,20 +273,6 @@ static int nomtrr = 0; | |||
277 | * prototypes | 273 | * prototypes |
278 | */ | 274 | */ |
279 | 275 | ||
280 | |||
281 | #ifdef CONFIG_PPC_OF | ||
282 | |||
283 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
284 | static int radeon_set_backlight_enable(int on, int level, void *data); | ||
285 | static int radeon_set_backlight_level(int level, void *data); | ||
286 | static struct backlight_controller radeon_backlight_controller = { | ||
287 | radeon_set_backlight_enable, | ||
288 | radeon_set_backlight_level | ||
289 | }; | ||
290 | #endif /* CONFIG_PMAC_BACKLIGHT */ | ||
291 | |||
292 | #endif /* CONFIG_PPC_OF */ | ||
293 | |||
294 | static void radeon_unmap_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev) | 276 | static void radeon_unmap_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev) |
295 | { | 277 | { |
296 | if (!rinfo->bios_seg) | 278 | if (!rinfo->bios_seg) |
@@ -1913,116 +1895,6 @@ static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo) | |||
1913 | return 0; | 1895 | return 0; |
1914 | } | 1896 | } |
1915 | 1897 | ||
1916 | |||
1917 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
1918 | |||
1919 | /* TODO: Dbl check these tables, we don't go up to full ON backlight | ||
1920 | * in these, possibly because we noticed MacOS doesn't, but I'd prefer | ||
1921 | * having some more official numbers from ATI | ||
1922 | */ | ||
1923 | static int backlight_conv_m6[] = { | ||
1924 | 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e, | ||
1925 | 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24 | ||
1926 | }; | ||
1927 | static int backlight_conv_m7[] = { | ||
1928 | 0x00, 0x3f, 0x4a, 0x55, 0x60, 0x6b, 0x76, 0x81, | ||
1929 | 0x8c, 0x97, 0xa2, 0xad, 0xb8, 0xc3, 0xce, 0xd9 | ||
1930 | }; | ||
1931 | |||
1932 | #define BACKLIGHT_LVDS_OFF | ||
1933 | #undef BACKLIGHT_DAC_OFF | ||
1934 | |||
1935 | /* We turn off the LCD completely instead of just dimming the backlight. | ||
1936 | * This provides some greater power saving and the display is useless | ||
1937 | * without backlight anyway. | ||
1938 | */ | ||
1939 | static int radeon_set_backlight_enable(int on, int level, void *data) | ||
1940 | { | ||
1941 | struct radeonfb_info *rinfo = (struct radeonfb_info *)data; | ||
1942 | u32 lvds_gen_cntl, tmpPixclksCntl; | ||
1943 | int* conv_table; | ||
1944 | |||
1945 | if (rinfo->mon1_type != MT_LCD) | ||
1946 | return 0; | ||
1947 | |||
1948 | /* Pardon me for that hack... maybe some day we can figure | ||
1949 | * out in what direction backlight should work on a given | ||
1950 | * panel ? | ||
1951 | */ | ||
1952 | if ((rinfo->family == CHIP_FAMILY_RV200 || | ||
1953 | rinfo->family == CHIP_FAMILY_RV250 || | ||
1954 | rinfo->family == CHIP_FAMILY_RV280 || | ||
1955 | rinfo->family == CHIP_FAMILY_RV350) && | ||
1956 | !machine_is_compatible("PowerBook4,3") && | ||
1957 | !machine_is_compatible("PowerBook6,3") && | ||
1958 | !machine_is_compatible("PowerBook6,5")) | ||
1959 | conv_table = backlight_conv_m7; | ||
1960 | else | ||
1961 | conv_table = backlight_conv_m6; | ||
1962 | |||
1963 | del_timer_sync(&rinfo->lvds_timer); | ||
1964 | radeon_engine_idle(); | ||
1965 | |||
1966 | lvds_gen_cntl = INREG(LVDS_GEN_CNTL); | ||
1967 | if (on && (level > BACKLIGHT_OFF)) { | ||
1968 | lvds_gen_cntl &= ~LVDS_DISPLAY_DIS; | ||
1969 | if (!(lvds_gen_cntl & LVDS_BLON) || !(lvds_gen_cntl & LVDS_ON)) { | ||
1970 | lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON); | ||
1971 | lvds_gen_cntl |= LVDS_BLON | LVDS_EN; | ||
1972 | OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); | ||
1973 | lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK; | ||
1974 | lvds_gen_cntl |= (conv_table[level] << | ||
1975 | LVDS_BL_MOD_LEVEL_SHIFT); | ||
1976 | lvds_gen_cntl |= LVDS_ON; | ||
1977 | lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN); | ||
1978 | rinfo->pending_lvds_gen_cntl = lvds_gen_cntl; | ||
1979 | mod_timer(&rinfo->lvds_timer, | ||
1980 | jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay)); | ||
1981 | } else { | ||
1982 | lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK; | ||
1983 | lvds_gen_cntl |= (conv_table[level] << | ||
1984 | LVDS_BL_MOD_LEVEL_SHIFT); | ||
1985 | OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); | ||
1986 | } | ||
1987 | rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK; | ||
1988 | rinfo->init_state.lvds_gen_cntl |= rinfo->pending_lvds_gen_cntl | ||
1989 | & LVDS_STATE_MASK; | ||
1990 | } else { | ||
1991 | /* Asic bug, when turning off LVDS_ON, we have to make sure | ||
1992 | RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off | ||
1993 | */ | ||
1994 | tmpPixclksCntl = INPLL(PIXCLKS_CNTL); | ||
1995 | if (rinfo->is_mobility || rinfo->is_IGP) | ||
1996 | OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb); | ||
1997 | lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN); | ||
1998 | lvds_gen_cntl |= (conv_table[0] << | ||
1999 | LVDS_BL_MOD_LEVEL_SHIFT); | ||
2000 | lvds_gen_cntl |= LVDS_DISPLAY_DIS; | ||
2001 | OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); | ||
2002 | udelay(100); | ||
2003 | lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN); | ||
2004 | OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); | ||
2005 | lvds_gen_cntl &= ~(LVDS_DIGON); | ||
2006 | rinfo->pending_lvds_gen_cntl = lvds_gen_cntl; | ||
2007 | mod_timer(&rinfo->lvds_timer, | ||
2008 | jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay)); | ||
2009 | if (rinfo->is_mobility || rinfo->is_IGP) | ||
2010 | OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl); | ||
2011 | } | ||
2012 | rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK; | ||
2013 | rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK); | ||
2014 | |||
2015 | return 0; | ||
2016 | } | ||
2017 | |||
2018 | |||
2019 | static int radeon_set_backlight_level(int level, void *data) | ||
2020 | { | ||
2021 | return radeon_set_backlight_enable(1, level, data); | ||
2022 | } | ||
2023 | #endif /* CONFIG_PMAC_BACKLIGHT */ | ||
2024 | |||
2025 | |||
2026 | /* | 1898 | /* |
2027 | * This reconfigure the card's internal memory map. In theory, we'd like | 1899 | * This reconfigure the card's internal memory map. In theory, we'd like |
2028 | * to setup the card's memory at the same address as it's PCI bus address, | 1900 | * to setup the card's memory at the same address as it's PCI bus address, |
@@ -2477,14 +2349,7 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev, | |||
2477 | MTRR_TYPE_WRCOMB, 1); | 2349 | MTRR_TYPE_WRCOMB, 1); |
2478 | #endif | 2350 | #endif |
2479 | 2351 | ||
2480 | #ifdef CONFIG_PMAC_BACKLIGHT | 2352 | radeonfb_bl_init(rinfo); |
2481 | if (rinfo->mon1_type == MT_LCD) { | ||
2482 | register_backlight_controller(&radeon_backlight_controller, | ||
2483 | rinfo, "ati"); | ||
2484 | register_backlight_controller(&radeon_backlight_controller, | ||
2485 | rinfo, "mnca"); | ||
2486 | } | ||
2487 | #endif | ||
2488 | 2353 | ||
2489 | printk ("radeonfb (%s): %s\n", pci_name(rinfo->pdev), rinfo->name); | 2354 | printk ("radeonfb (%s): %s\n", pci_name(rinfo->pdev), rinfo->name); |
2490 | 2355 | ||
@@ -2528,7 +2393,8 @@ static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev) | |||
2528 | 2393 | ||
2529 | if (!rinfo) | 2394 | if (!rinfo) |
2530 | return; | 2395 | return; |
2531 | 2396 | ||
2397 | radeonfb_bl_exit(rinfo); | ||
2532 | radeonfb_pm_exit(rinfo); | 2398 | radeonfb_pm_exit(rinfo); |
2533 | 2399 | ||
2534 | if (rinfo->mon1_EDID) | 2400 | if (rinfo->mon1_EDID) |
diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h index 217e00ab4a2d..1645943b1123 100644 --- a/drivers/video/aty/radeonfb.h +++ b/drivers/video/aty/radeonfb.h | |||
@@ -625,4 +625,13 @@ extern int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_ | |||
625 | extern void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode, | 625 | extern void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode, |
626 | int reg_only); | 626 | int reg_only); |
627 | 627 | ||
628 | /* Backlight functions */ | ||
629 | #ifdef CONFIG_FB_RADEON_BACKLIGHT | ||
630 | extern void radeonfb_bl_init(struct radeonfb_info *rinfo); | ||
631 | extern void radeonfb_bl_exit(struct radeonfb_info *rinfo); | ||
632 | #else | ||
633 | static inline void radeonfb_bl_init(struct radeonfb_info *rinfo) {} | ||
634 | static inline void radeonfb_bl_exit(struct radeonfb_info *rinfo) {} | ||
635 | #endif | ||
636 | |||
628 | #endif /* __RADEONFB_H__ */ | 637 | #endif /* __RADEONFB_H__ */ |
diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c index 72ff6bf75e5e..d76bbfac92cc 100644 --- a/drivers/video/chipsfb.c +++ b/drivers/video/chipsfb.c | |||
@@ -148,9 +148,24 @@ static int chipsfb_set_par(struct fb_info *info) | |||
148 | static int chipsfb_blank(int blank, struct fb_info *info) | 148 | static int chipsfb_blank(int blank, struct fb_info *info) |
149 | { | 149 | { |
150 | #ifdef CONFIG_PMAC_BACKLIGHT | 150 | #ifdef CONFIG_PMAC_BACKLIGHT |
151 | // used to disable backlight only for blank > 1, but it seems | 151 | mutex_lock(&pmac_backlight_mutex); |
152 | // useful at blank = 1 too (saves battery, extends backlight life) | 152 | |
153 | set_backlight_enable(!blank); | 153 | if (pmac_backlight) { |
154 | down(&pmac_backlight->sem); | ||
155 | |||
156 | /* used to disable backlight only for blank > 1, but it seems | ||
157 | * useful at blank = 1 too (saves battery, extends backlight | ||
158 | * life) | ||
159 | */ | ||
160 | if (blank) | ||
161 | pmac_backlight->props->power = FB_BLANK_POWERDOWN; | ||
162 | else | ||
163 | pmac_backlight->props->power = FB_BLANK_UNBLANK; | ||
164 | pmac_backlight->props->update_status(pmac_backlight); | ||
165 | up(&pmac_backlight->sem); | ||
166 | } | ||
167 | |||
168 | mutex_unlock(&pmac_backlight_mutex); | ||
154 | #endif /* CONFIG_PMAC_BACKLIGHT */ | 169 | #endif /* CONFIG_PMAC_BACKLIGHT */ |
155 | 170 | ||
156 | return 1; /* get fb_blank to set the colormap to all black */ | 171 | return 1; /* get fb_blank to set the colormap to all black */ |
@@ -401,7 +416,14 @@ chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) | |||
401 | 416 | ||
402 | #ifdef CONFIG_PMAC_BACKLIGHT | 417 | #ifdef CONFIG_PMAC_BACKLIGHT |
403 | /* turn on the backlight */ | 418 | /* turn on the backlight */ |
404 | set_backlight_enable(1); | 419 | mutex_lock(&pmac_backlight_mutex); |
420 | if (pmac_backlight) { | ||
421 | down(&pmac_backlight->sem); | ||
422 | pmac_backlight->props->power = FB_BLANK_UNBLANK; | ||
423 | pmac_backlight->props->update_status(pmac_backlight); | ||
424 | up(&pmac_backlight->sem); | ||
425 | } | ||
426 | mutex_unlock(&pmac_backlight_mutex); | ||
405 | #endif /* CONFIG_PMAC_BACKLIGHT */ | 427 | #endif /* CONFIG_PMAC_BACKLIGHT */ |
406 | 428 | ||
407 | #ifdef CONFIG_PPC | 429 | #ifdef CONFIG_PPC |
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c index 34e07399756b..3ceb8c1b392e 100644 --- a/drivers/video/fbsysfs.c +++ b/drivers/video/fbsysfs.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
19 | #include <linux/fb.h> | 19 | #include <linux/fb.h> |
20 | #include <linux/console.h> | 20 | #include <linux/console.h> |
21 | #include <linux/module.h> | ||
21 | 22 | ||
22 | /** | 23 | /** |
23 | * framebuffer_alloc - creates a new frame buffer info structure | 24 | * framebuffer_alloc - creates a new frame buffer info structure |
@@ -55,6 +56,10 @@ struct fb_info *framebuffer_alloc(size_t size, struct device *dev) | |||
55 | 56 | ||
56 | info->device = dev; | 57 | info->device = dev; |
57 | 58 | ||
59 | #ifdef CONFIG_FB_BACKLIGHT | ||
60 | mutex_init(&info->bl_mutex); | ||
61 | #endif | ||
62 | |||
58 | return info; | 63 | return info; |
59 | #undef PADDING | 64 | #undef PADDING |
60 | #undef BYTES_PER_LONG | 65 | #undef BYTES_PER_LONG |
@@ -414,6 +419,65 @@ static ssize_t show_fbstate(struct class_device *class_device, char *buf) | |||
414 | return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->state); | 419 | return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->state); |
415 | } | 420 | } |
416 | 421 | ||
422 | #ifdef CONFIG_FB_BACKLIGHT | ||
423 | static ssize_t store_bl_curve(struct class_device *class_device, | ||
424 | const char *buf, size_t count) | ||
425 | { | ||
426 | struct fb_info *fb_info = class_get_devdata(class_device); | ||
427 | u8 tmp_curve[FB_BACKLIGHT_LEVELS]; | ||
428 | unsigned int i; | ||
429 | |||
430 | if (count != (FB_BACKLIGHT_LEVELS / 8 * 24)) | ||
431 | return -EINVAL; | ||
432 | |||
433 | for (i = 0; i < (FB_BACKLIGHT_LEVELS / 8); ++i) | ||
434 | if (sscanf(&buf[i * 24], | ||
435 | "%2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx\n", | ||
436 | &tmp_curve[i * 8 + 0], | ||
437 | &tmp_curve[i * 8 + 1], | ||
438 | &tmp_curve[i * 8 + 2], | ||
439 | &tmp_curve[i * 8 + 3], | ||
440 | &tmp_curve[i * 8 + 4], | ||
441 | &tmp_curve[i * 8 + 5], | ||
442 | &tmp_curve[i * 8 + 6], | ||
443 | &tmp_curve[i * 8 + 7]) != 8) | ||
444 | return -EINVAL; | ||
445 | |||
446 | /* If there has been an error in the input data, we won't | ||
447 | * reach this loop. | ||
448 | */ | ||
449 | mutex_lock(&fb_info->bl_mutex); | ||
450 | for (i = 0; i < FB_BACKLIGHT_LEVELS; ++i) | ||
451 | fb_info->bl_curve[i] = tmp_curve[i]; | ||
452 | mutex_unlock(&fb_info->bl_mutex); | ||
453 | |||
454 | return count; | ||
455 | } | ||
456 | |||
457 | static ssize_t show_bl_curve(struct class_device *class_device, char *buf) | ||
458 | { | ||
459 | struct fb_info *fb_info = class_get_devdata(class_device); | ||
460 | ssize_t len = 0; | ||
461 | unsigned int i; | ||
462 | |||
463 | mutex_lock(&fb_info->bl_mutex); | ||
464 | for (i = 0; i < FB_BACKLIGHT_LEVELS; i += 8) | ||
465 | len += snprintf(&buf[len], PAGE_SIZE, | ||
466 | "%02x %02x %02x %02x %02x %02x %02x %02x\n", | ||
467 | fb_info->bl_curve[i + 0], | ||
468 | fb_info->bl_curve[i + 1], | ||
469 | fb_info->bl_curve[i + 2], | ||
470 | fb_info->bl_curve[i + 3], | ||
471 | fb_info->bl_curve[i + 4], | ||
472 | fb_info->bl_curve[i + 5], | ||
473 | fb_info->bl_curve[i + 6], | ||
474 | fb_info->bl_curve[i + 7]); | ||
475 | mutex_unlock(&fb_info->bl_mutex); | ||
476 | |||
477 | return len; | ||
478 | } | ||
479 | #endif | ||
480 | |||
417 | /* When cmap is added back in it should be a binary attribute | 481 | /* When cmap is added back in it should be a binary attribute |
418 | * not a text one. Consideration should also be given to converting | 482 | * not a text one. Consideration should also be given to converting |
419 | * fbdev to use configfs instead of sysfs */ | 483 | * fbdev to use configfs instead of sysfs */ |
@@ -432,6 +496,9 @@ static struct class_device_attribute class_device_attrs[] = { | |||
432 | __ATTR(con_rotate, S_IRUGO|S_IWUSR, show_con_rotate, store_con_rotate), | 496 | __ATTR(con_rotate, S_IRUGO|S_IWUSR, show_con_rotate, store_con_rotate), |
433 | __ATTR(con_rotate_all, S_IWUSR, NULL, store_con_rotate_all), | 497 | __ATTR(con_rotate_all, S_IWUSR, NULL, store_con_rotate_all), |
434 | __ATTR(state, S_IRUGO|S_IWUSR, show_fbstate, store_fbstate), | 498 | __ATTR(state, S_IRUGO|S_IWUSR, show_fbstate, store_fbstate), |
499 | #ifdef CONFIG_FB_BACKLIGHT | ||
500 | __ATTR(bl_curve, S_IRUGO|S_IWUSR, show_bl_curve, store_bl_curve), | ||
501 | #endif | ||
435 | }; | 502 | }; |
436 | 503 | ||
437 | int fb_init_class_device(struct fb_info *fb_info) | 504 | int fb_init_class_device(struct fb_info *fb_info) |
@@ -454,4 +521,25 @@ void fb_cleanup_class_device(struct fb_info *fb_info) | |||
454 | &class_device_attrs[i]); | 521 | &class_device_attrs[i]); |
455 | } | 522 | } |
456 | 523 | ||
524 | #ifdef CONFIG_FB_BACKLIGHT | ||
525 | /* This function generates a linear backlight curve | ||
526 | * | ||
527 | * 0: off | ||
528 | * 1-7: min | ||
529 | * 8-127: linear from min to max | ||
530 | */ | ||
531 | void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max) | ||
532 | { | ||
533 | unsigned int i, flat, count, range = (max - min); | ||
534 | |||
535 | fb_info->bl_curve[0] = off; | ||
457 | 536 | ||
537 | for (flat = 1; flat < (FB_BACKLIGHT_LEVELS / 16); ++flat) | ||
538 | fb_info->bl_curve[flat] = min; | ||
539 | |||
540 | count = FB_BACKLIGHT_LEVELS * 15 / 16; | ||
541 | for (i = 0; i < count; ++i) | ||
542 | fb_info->bl_curve[flat + i] = min + (range * (i + 1) / count); | ||
543 | } | ||
544 | EXPORT_SYMBOL_GPL(fb_bl_default_curve); | ||
545 | #endif | ||
diff --git a/drivers/video/nvidia/Makefile b/drivers/video/nvidia/Makefile index 690d37e8de5b..ca47432113e0 100644 --- a/drivers/video/nvidia/Makefile +++ b/drivers/video/nvidia/Makefile | |||
@@ -7,6 +7,7 @@ obj-$(CONFIG_FB_NVIDIA) += nvidiafb.o | |||
7 | nvidiafb-y := nvidia.o nv_hw.o nv_setup.o \ | 7 | nvidiafb-y := nvidia.o nv_hw.o nv_setup.o \ |
8 | nv_accel.o | 8 | nv_accel.o |
9 | nvidiafb-$(CONFIG_FB_NVIDIA_I2C) += nv_i2c.o | 9 | nvidiafb-$(CONFIG_FB_NVIDIA_I2C) += nv_i2c.o |
10 | nvidiafb-$(CONFIG_FB_NVIDIA_BACKLIGHT) += nv_backlight.o | ||
10 | nvidiafb-$(CONFIG_PPC_OF) += nv_of.o | 11 | nvidiafb-$(CONFIG_PPC_OF) += nv_of.o |
11 | 12 | ||
12 | nvidiafb-objs := $(nvidiafb-y) \ No newline at end of file | 13 | nvidiafb-objs := $(nvidiafb-y) |
diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c new file mode 100644 index 000000000000..1c1c10c699c5 --- /dev/null +++ b/drivers/video/nvidia/nv_backlight.c | |||
@@ -0,0 +1,175 @@ | |||
1 | /* | ||
2 | * Backlight code for nVidia based graphic cards | ||
3 | * | ||
4 | * Copyright 2004 Antonino Daplas <adaplas@pol.net> | ||
5 | * Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/backlight.h> | ||
13 | #include <linux/fb.h> | ||
14 | #include <linux/pci.h> | ||
15 | #include "nv_local.h" | ||
16 | #include "nv_type.h" | ||
17 | #include "nv_proto.h" | ||
18 | |||
19 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
20 | #include <asm/backlight.h> | ||
21 | #include <asm/machdep.h> | ||
22 | #endif | ||
23 | |||
24 | /* We do not have any information about which values are allowed, thus | ||
25 | * we used safe values. | ||
26 | */ | ||
27 | #define MIN_LEVEL 0x158 | ||
28 | #define MAX_LEVEL 0x534 | ||
29 | |||
30 | static struct backlight_properties nvidia_bl_data; | ||
31 | |||
32 | static int nvidia_bl_get_level_brightness(struct nvidia_par *par, | ||
33 | int level) | ||
34 | { | ||
35 | struct fb_info *info = pci_get_drvdata(par->pci_dev); | ||
36 | int nlevel; | ||
37 | |||
38 | /* Get and convert the value */ | ||
39 | mutex_lock(&info->bl_mutex); | ||
40 | nlevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL; | ||
41 | mutex_unlock(&info->bl_mutex); | ||
42 | |||
43 | if (nlevel < 0) | ||
44 | nlevel = 0; | ||
45 | else if (nlevel < MIN_LEVEL) | ||
46 | nlevel = MIN_LEVEL; | ||
47 | else if (nlevel > MAX_LEVEL) | ||
48 | nlevel = MAX_LEVEL; | ||
49 | |||
50 | return nlevel; | ||
51 | } | ||
52 | |||
53 | static int nvidia_bl_update_status(struct backlight_device *bd) | ||
54 | { | ||
55 | struct nvidia_par *par = class_get_devdata(&bd->class_dev); | ||
56 | u32 tmp_pcrt, tmp_pmc, fpcontrol; | ||
57 | int level; | ||
58 | |||
59 | if (!par->FlatPanel) | ||
60 | return 0; | ||
61 | |||
62 | if (bd->props->power != FB_BLANK_UNBLANK || | ||
63 | bd->props->fb_blank != FB_BLANK_UNBLANK) | ||
64 | level = 0; | ||
65 | else | ||
66 | level = bd->props->brightness; | ||
67 | |||
68 | tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF; | ||
69 | tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC; | ||
70 | fpcontrol = NV_RD32(par->PRAMDAC, 0x0848) & 0xCFFFFFCC; | ||
71 | |||
72 | if (level > 0) { | ||
73 | tmp_pcrt |= 0x1; | ||
74 | tmp_pmc |= (1 << 31); /* backlight bit */ | ||
75 | tmp_pmc |= nvidia_bl_get_level_brightness(par, level) << 16; | ||
76 | fpcontrol |= par->fpSyncs; | ||
77 | } else | ||
78 | fpcontrol |= 0x20000022; | ||
79 | |||
80 | NV_WR32(par->PCRTC0, 0x081C, tmp_pcrt); | ||
81 | NV_WR32(par->PMC, 0x10F0, tmp_pmc); | ||
82 | NV_WR32(par->PRAMDAC, 0x848, fpcontrol); | ||
83 | |||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static int nvidia_bl_get_brightness(struct backlight_device *bd) | ||
88 | { | ||
89 | return bd->props->brightness; | ||
90 | } | ||
91 | |||
92 | static struct backlight_properties nvidia_bl_data = { | ||
93 | .owner = THIS_MODULE, | ||
94 | .get_brightness = nvidia_bl_get_brightness, | ||
95 | .update_status = nvidia_bl_update_status, | ||
96 | .max_brightness = (FB_BACKLIGHT_LEVELS - 1), | ||
97 | }; | ||
98 | |||
99 | void nvidia_bl_init(struct nvidia_par *par) | ||
100 | { | ||
101 | struct fb_info *info = pci_get_drvdata(par->pci_dev); | ||
102 | struct backlight_device *bd; | ||
103 | char name[12]; | ||
104 | |||
105 | if (!par->FlatPanel) | ||
106 | return; | ||
107 | |||
108 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
109 | if (!machine_is(powermac) || | ||
110 | !pmac_has_backlight_type("mnca")) | ||
111 | return; | ||
112 | #endif | ||
113 | |||
114 | snprintf(name, sizeof(name), "nvidiabl%d", info->node); | ||
115 | |||
116 | bd = backlight_device_register(name, par, &nvidia_bl_data); | ||
117 | if (IS_ERR(bd)) { | ||
118 | info->bl_dev = NULL; | ||
119 | printk("nvidia: Backlight registration failed\n"); | ||
120 | goto error; | ||
121 | } | ||
122 | |||
123 | mutex_lock(&info->bl_mutex); | ||
124 | info->bl_dev = bd; | ||
125 | fb_bl_default_curve(info, 0, | ||
126 | 0x158 * FB_BACKLIGHT_MAX / MAX_LEVEL, | ||
127 | 0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL); | ||
128 | mutex_unlock(&info->bl_mutex); | ||
129 | |||
130 | up(&bd->sem); | ||
131 | bd->props->brightness = nvidia_bl_data.max_brightness; | ||
132 | bd->props->power = FB_BLANK_UNBLANK; | ||
133 | bd->props->update_status(bd); | ||
134 | down(&bd->sem); | ||
135 | |||
136 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
137 | mutex_lock(&pmac_backlight_mutex); | ||
138 | if (!pmac_backlight) | ||
139 | pmac_backlight = bd; | ||
140 | mutex_unlock(&pmac_backlight_mutex); | ||
141 | #endif | ||
142 | |||
143 | printk("nvidia: Backlight initialized (%s)\n", name); | ||
144 | |||
145 | return; | ||
146 | |||
147 | error: | ||
148 | return; | ||
149 | } | ||
150 | |||
151 | void nvidia_bl_exit(struct nvidia_par *par) | ||
152 | { | ||
153 | struct fb_info *info = pci_get_drvdata(par->pci_dev); | ||
154 | |||
155 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
156 | mutex_lock(&pmac_backlight_mutex); | ||
157 | #endif | ||
158 | |||
159 | mutex_lock(&info->bl_mutex); | ||
160 | if (info->bl_dev) { | ||
161 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
162 | if (pmac_backlight == info->bl_dev) | ||
163 | pmac_backlight = NULL; | ||
164 | #endif | ||
165 | |||
166 | backlight_device_unregister(info->bl_dev); | ||
167 | |||
168 | printk("nvidia: Backlight unloaded\n"); | ||
169 | } | ||
170 | mutex_unlock(&info->bl_mutex); | ||
171 | |||
172 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
173 | mutex_unlock(&pmac_backlight_mutex); | ||
174 | #endif | ||
175 | } | ||
diff --git a/drivers/video/nvidia/nv_proto.h b/drivers/video/nvidia/nv_proto.h index b149a690ee0f..6fba656cd56b 100644 --- a/drivers/video/nvidia/nv_proto.h +++ b/drivers/video/nvidia/nv_proto.h | |||
@@ -63,4 +63,14 @@ extern void nvidiafb_imageblit(struct fb_info *info, | |||
63 | const struct fb_image *image); | 63 | const struct fb_image *image); |
64 | extern int nvidiafb_sync(struct fb_info *info); | 64 | extern int nvidiafb_sync(struct fb_info *info); |
65 | extern u8 byte_rev[256]; | 65 | extern u8 byte_rev[256]; |
66 | |||
67 | /* in nv_backlight.h */ | ||
68 | #ifdef CONFIG_FB_NVIDIA_BACKLIGHT | ||
69 | extern void nvidia_bl_init(struct nvidia_par *par); | ||
70 | extern void nvidia_bl_exit(struct nvidia_par *par); | ||
71 | #else | ||
72 | static inline void nvidia_bl_init(struct nvidia_par *par) {} | ||
73 | static inline void nvidia_bl_exit(struct nvidia_par *par) {} | ||
74 | #endif | ||
75 | |||
66 | #endif /* __NV_PROTO_H__ */ | 76 | #endif /* __NV_PROTO_H__ */ |
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index 093ab9977c7c..03a7c1e9ce38 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
24 | #include <linux/console.h> | 24 | #include <linux/console.h> |
25 | #include <linux/backlight.h> | ||
25 | #ifdef CONFIG_MTRR | 26 | #ifdef CONFIG_MTRR |
26 | #include <asm/mtrr.h> | 27 | #include <asm/mtrr.h> |
27 | #endif | 28 | #endif |
@@ -29,10 +30,6 @@ | |||
29 | #include <asm/prom.h> | 30 | #include <asm/prom.h> |
30 | #include <asm/pci-bridge.h> | 31 | #include <asm/pci-bridge.h> |
31 | #endif | 32 | #endif |
32 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
33 | #include <asm/machdep.h> | ||
34 | #include <asm/backlight.h> | ||
35 | #endif | ||
36 | 33 | ||
37 | #include "nv_local.h" | 34 | #include "nv_local.h" |
38 | #include "nv_type.h" | 35 | #include "nv_type.h" |
@@ -470,75 +467,6 @@ static struct fb_var_screeninfo __devinitdata nvidiafb_default_var = { | |||
470 | .vmode = FB_VMODE_NONINTERLACED | 467 | .vmode = FB_VMODE_NONINTERLACED |
471 | }; | 468 | }; |
472 | 469 | ||
473 | /* | ||
474 | * Backlight control | ||
475 | */ | ||
476 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
477 | |||
478 | static int nvidia_backlight_levels[] = { | ||
479 | 0x158, | ||
480 | 0x192, | ||
481 | 0x1c6, | ||
482 | 0x200, | ||
483 | 0x234, | ||
484 | 0x268, | ||
485 | 0x2a2, | ||
486 | 0x2d6, | ||
487 | 0x310, | ||
488 | 0x344, | ||
489 | 0x378, | ||
490 | 0x3b2, | ||
491 | 0x3e6, | ||
492 | 0x41a, | ||
493 | 0x454, | ||
494 | 0x534, | ||
495 | }; | ||
496 | |||
497 | /* ------------------------------------------------------------------------- * | ||
498 | * | ||
499 | * Backlight operations | ||
500 | * | ||
501 | * ------------------------------------------------------------------------- */ | ||
502 | |||
503 | static int nvidia_set_backlight_enable(int on, int level, void *data) | ||
504 | { | ||
505 | struct nvidia_par *par = data; | ||
506 | u32 tmp_pcrt, tmp_pmc, fpcontrol; | ||
507 | |||
508 | tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF; | ||
509 | tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC; | ||
510 | fpcontrol = NV_RD32(par->PRAMDAC, 0x0848) & 0xCFFFFFCC; | ||
511 | |||
512 | if (on && (level > BACKLIGHT_OFF)) { | ||
513 | tmp_pcrt |= 0x1; | ||
514 | tmp_pmc |= (1 << 31); // backlight bit | ||
515 | tmp_pmc |= nvidia_backlight_levels[level - 1] << 16; | ||
516 | } | ||
517 | |||
518 | if (on) | ||
519 | fpcontrol |= par->fpSyncs; | ||
520 | else | ||
521 | fpcontrol |= 0x20000022; | ||
522 | |||
523 | NV_WR32(par->PCRTC0, 0x081C, tmp_pcrt); | ||
524 | NV_WR32(par->PMC, 0x10F0, tmp_pmc); | ||
525 | NV_WR32(par->PRAMDAC, 0x848, fpcontrol); | ||
526 | |||
527 | return 0; | ||
528 | } | ||
529 | |||
530 | static int nvidia_set_backlight_level(int level, void *data) | ||
531 | { | ||
532 | return nvidia_set_backlight_enable(1, level, data); | ||
533 | } | ||
534 | |||
535 | static struct backlight_controller nvidia_backlight_controller = { | ||
536 | nvidia_set_backlight_enable, | ||
537 | nvidia_set_backlight_level | ||
538 | }; | ||
539 | |||
540 | #endif /* CONFIG_PMAC_BACKLIGHT */ | ||
541 | |||
542 | static void nvidiafb_load_cursor_image(struct nvidia_par *par, u8 * data8, | 470 | static void nvidiafb_load_cursor_image(struct nvidia_par *par, u8 * data8, |
543 | u16 bg, u16 fg, u32 w, u32 h) | 471 | u16 bg, u16 fg, u32 w, u32 h) |
544 | { | 472 | { |
@@ -1355,10 +1283,15 @@ static int nvidiafb_blank(int blank, struct fb_info *info) | |||
1355 | NVWriteSeq(par, 0x01, tmp); | 1283 | NVWriteSeq(par, 0x01, tmp); |
1356 | NVWriteCrtc(par, 0x1a, vesa); | 1284 | NVWriteCrtc(par, 0x1a, vesa); |
1357 | 1285 | ||
1358 | #ifdef CONFIG_PMAC_BACKLIGHT | 1286 | #ifdef CONFIG_FB_NVIDIA_BACKLIGHT |
1359 | if (par->FlatPanel && machine_is(powermac)) { | 1287 | mutex_lock(&info->bl_mutex); |
1360 | set_backlight_enable(!blank); | 1288 | if (info->bl_dev) { |
1289 | down(&info->bl_dev->sem); | ||
1290 | info->bl_dev->props->power = blank; | ||
1291 | info->bl_dev->props->update_status(info->bl_dev); | ||
1292 | up(&info->bl_dev->sem); | ||
1361 | } | 1293 | } |
1294 | mutex_unlock(&info->bl_mutex); | ||
1362 | #endif | 1295 | #endif |
1363 | 1296 | ||
1364 | NVTRACE_LEAVE(); | 1297 | NVTRACE_LEAVE(); |
@@ -1741,11 +1674,9 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd, | |||
1741 | "PCI nVidia %s framebuffer (%dMB @ 0x%lX)\n", | 1674 | "PCI nVidia %s framebuffer (%dMB @ 0x%lX)\n", |
1742 | info->fix.id, | 1675 | info->fix.id, |
1743 | par->FbMapSize / (1024 * 1024), info->fix.smem_start); | 1676 | par->FbMapSize / (1024 * 1024), info->fix.smem_start); |
1744 | #ifdef CONFIG_PMAC_BACKLIGHT | 1677 | |
1745 | if (par->FlatPanel && machine_is(powermac)) | 1678 | nvidia_bl_init(par); |
1746 | register_backlight_controller(&nvidia_backlight_controller, | 1679 | |
1747 | par, "mnca"); | ||
1748 | #endif | ||
1749 | NVTRACE_LEAVE(); | 1680 | NVTRACE_LEAVE(); |
1750 | return 0; | 1681 | return 0; |
1751 | 1682 | ||
@@ -1775,6 +1706,8 @@ static void __exit nvidiafb_remove(struct pci_dev *pd) | |||
1775 | 1706 | ||
1776 | NVTRACE_ENTER(); | 1707 | NVTRACE_ENTER(); |
1777 | 1708 | ||
1709 | nvidia_bl_exit(par); | ||
1710 | |||
1778 | unregister_framebuffer(info); | 1711 | unregister_framebuffer(info); |
1779 | #ifdef CONFIG_MTRR | 1712 | #ifdef CONFIG_MTRR |
1780 | if (par->mtrr.vram_valid) | 1713 | if (par->mtrr.vram_valid) |
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index 3e9308f0f165..d4384ab1df65 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/fb.h> | 41 | #include <linux/fb.h> |
42 | #include <linux/init.h> | 42 | #include <linux/init.h> |
43 | #include <linux/pci.h> | 43 | #include <linux/pci.h> |
44 | #include <linux/backlight.h> | ||
44 | #ifdef CONFIG_MTRR | 45 | #ifdef CONFIG_MTRR |
45 | #include <asm/mtrr.h> | 46 | #include <asm/mtrr.h> |
46 | #endif | 47 | #endif |
@@ -272,34 +273,154 @@ static const struct riva_regs reg_template = { | |||
272 | /* | 273 | /* |
273 | * Backlight control | 274 | * Backlight control |
274 | */ | 275 | */ |
275 | #ifdef CONFIG_PMAC_BACKLIGHT | 276 | #ifdef CONFIG_FB_RIVA_BACKLIGHT |
277 | /* We do not have any information about which values are allowed, thus | ||
278 | * we used safe values. | ||
279 | */ | ||
280 | #define MIN_LEVEL 0x158 | ||
281 | #define MAX_LEVEL 0x534 | ||
276 | 282 | ||
277 | static int riva_backlight_levels[] = { | 283 | static struct backlight_properties riva_bl_data; |
278 | 0x158, | 284 | |
279 | 0x192, | 285 | static int riva_bl_get_level_brightness(struct riva_par *par, |
280 | 0x1c6, | 286 | int level) |
281 | 0x200, | 287 | { |
282 | 0x234, | 288 | struct fb_info *info = pci_get_drvdata(par->pdev); |
283 | 0x268, | 289 | int nlevel; |
284 | 0x2a2, | 290 | |
285 | 0x2d6, | 291 | /* Get and convert the value */ |
286 | 0x310, | 292 | mutex_lock(&info->bl_mutex); |
287 | 0x344, | 293 | nlevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL; |
288 | 0x378, | 294 | mutex_unlock(&info->bl_mutex); |
289 | 0x3b2, | 295 | |
290 | 0x3e6, | 296 | if (nlevel < 0) |
291 | 0x41a, | 297 | nlevel = 0; |
292 | 0x454, | 298 | else if (nlevel < MIN_LEVEL) |
293 | 0x534, | 299 | nlevel = MIN_LEVEL; |
294 | }; | 300 | else if (nlevel > MAX_LEVEL) |
301 | nlevel = MAX_LEVEL; | ||
302 | |||
303 | return nlevel; | ||
304 | } | ||
305 | |||
306 | static int riva_bl_update_status(struct backlight_device *bd) | ||
307 | { | ||
308 | struct riva_par *par = class_get_devdata(&bd->class_dev); | ||
309 | U032 tmp_pcrt, tmp_pmc; | ||
310 | int level; | ||
311 | |||
312 | if (bd->props->power != FB_BLANK_UNBLANK || | ||
313 | bd->props->fb_blank != FB_BLANK_UNBLANK) | ||
314 | level = 0; | ||
315 | else | ||
316 | level = bd->props->brightness; | ||
317 | |||
318 | tmp_pmc = par->riva.PMC[0x10F0/4] & 0x0000FFFF; | ||
319 | tmp_pcrt = par->riva.PCRTC0[0x081C/4] & 0xFFFFFFFC; | ||
320 | if(level > 0) { | ||
321 | tmp_pcrt |= 0x1; | ||
322 | tmp_pmc |= (1 << 31); /* backlight bit */ | ||
323 | tmp_pmc |= riva_bl_get_level_brightness(par, level) << 16; /* level */ | ||
324 | } | ||
325 | par->riva.PCRTC0[0x081C/4] = tmp_pcrt; | ||
326 | par->riva.PMC[0x10F0/4] = tmp_pmc; | ||
327 | |||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | static int riva_bl_get_brightness(struct backlight_device *bd) | ||
332 | { | ||
333 | return bd->props->brightness; | ||
334 | } | ||
295 | 335 | ||
296 | static int riva_set_backlight_enable(int on, int level, void *data); | 336 | static struct backlight_properties riva_bl_data = { |
297 | static int riva_set_backlight_level(int level, void *data); | 337 | .owner = THIS_MODULE, |
298 | static struct backlight_controller riva_backlight_controller = { | 338 | .get_brightness = riva_bl_get_brightness, |
299 | riva_set_backlight_enable, | 339 | .update_status = riva_bl_update_status, |
300 | riva_set_backlight_level | 340 | .max_brightness = (FB_BACKLIGHT_LEVELS - 1), |
301 | }; | 341 | }; |
302 | #endif /* CONFIG_PMAC_BACKLIGHT */ | 342 | |
343 | static void riva_bl_init(struct riva_par *par) | ||
344 | { | ||
345 | struct fb_info *info = pci_get_drvdata(par->pdev); | ||
346 | struct backlight_device *bd; | ||
347 | char name[12]; | ||
348 | |||
349 | if (!par->FlatPanel) | ||
350 | return; | ||
351 | |||
352 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
353 | if (!machine_is(powermac) || | ||
354 | !pmac_has_backlight_type("mnca")) | ||
355 | return; | ||
356 | #endif | ||
357 | |||
358 | snprintf(name, sizeof(name), "rivabl%d", info->node); | ||
359 | |||
360 | bd = backlight_device_register(name, par, &riva_bl_data); | ||
361 | if (IS_ERR(bd)) { | ||
362 | info->bl_dev = NULL; | ||
363 | printk("riva: Backlight registration failed\n"); | ||
364 | goto error; | ||
365 | } | ||
366 | |||
367 | mutex_lock(&info->bl_mutex); | ||
368 | info->bl_dev = bd; | ||
369 | fb_bl_default_curve(info, 0, | ||
370 | 0x158 * FB_BACKLIGHT_MAX / MAX_LEVEL, | ||
371 | 0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL); | ||
372 | mutex_unlock(&info->bl_mutex); | ||
373 | |||
374 | up(&bd->sem); | ||
375 | bd->props->brightness = riva_bl_data.max_brightness; | ||
376 | bd->props->power = FB_BLANK_UNBLANK; | ||
377 | bd->props->update_status(bd); | ||
378 | down(&bd->sem); | ||
379 | |||
380 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
381 | mutex_lock(&pmac_backlight_mutex); | ||
382 | if (!pmac_backlight) | ||
383 | pmac_backlight = bd; | ||
384 | mutex_unlock(&pmac_backlight_mutex); | ||
385 | #endif | ||
386 | |||
387 | printk("riva: Backlight initialized (%s)\n", name); | ||
388 | |||
389 | return; | ||
390 | |||
391 | error: | ||
392 | return; | ||
393 | } | ||
394 | |||
395 | static void riva_bl_exit(struct riva_par *par) | ||
396 | { | ||
397 | struct fb_info *info = pci_get_drvdata(par->pdev); | ||
398 | |||
399 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
400 | mutex_lock(&pmac_backlight_mutex); | ||
401 | #endif | ||
402 | |||
403 | mutex_lock(&info->bl_mutex); | ||
404 | if (info->bl_dev) { | ||
405 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
406 | if (pmac_backlight == info->bl_dev) | ||
407 | pmac_backlight = NULL; | ||
408 | #endif | ||
409 | |||
410 | backlight_device_unregister(info->bl_dev); | ||
411 | |||
412 | printk("riva: Backlight unloaded\n"); | ||
413 | } | ||
414 | mutex_unlock(&info->bl_mutex); | ||
415 | |||
416 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
417 | mutex_unlock(&pmac_backlight_mutex); | ||
418 | #endif | ||
419 | } | ||
420 | #else | ||
421 | static inline void riva_bl_init(struct riva_par *par) {} | ||
422 | static inline void riva_bl_exit(struct riva_par *par) {} | ||
423 | #endif /* CONFIG_FB_RIVA_BACKLIGHT */ | ||
303 | 424 | ||
304 | /* ------------------------------------------------------------------------- * | 425 | /* ------------------------------------------------------------------------- * |
305 | * | 426 | * |
@@ -973,36 +1094,6 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var) | |||
973 | 1094 | ||
974 | /* ------------------------------------------------------------------------- * | 1095 | /* ------------------------------------------------------------------------- * |
975 | * | 1096 | * |
976 | * Backlight operations | ||
977 | * | ||
978 | * ------------------------------------------------------------------------- */ | ||
979 | |||
980 | #ifdef CONFIG_PMAC_BACKLIGHT | ||
981 | static int riva_set_backlight_enable(int on, int level, void *data) | ||
982 | { | ||
983 | struct riva_par *par = data; | ||
984 | U032 tmp_pcrt, tmp_pmc; | ||
985 | |||
986 | tmp_pmc = par->riva.PMC[0x10F0/4] & 0x0000FFFF; | ||
987 | tmp_pcrt = par->riva.PCRTC0[0x081C/4] & 0xFFFFFFFC; | ||
988 | if(on && (level > BACKLIGHT_OFF)) { | ||
989 | tmp_pcrt |= 0x1; | ||
990 | tmp_pmc |= (1 << 31); // backlight bit | ||
991 | tmp_pmc |= riva_backlight_levels[level-1] << 16; // level | ||
992 | } | ||
993 | par->riva.PCRTC0[0x081C/4] = tmp_pcrt; | ||
994 | par->riva.PMC[0x10F0/4] = tmp_pmc; | ||
995 | return 0; | ||
996 | } | ||
997 | |||
998 | static int riva_set_backlight_level(int level, void *data) | ||
999 | { | ||
1000 | return riva_set_backlight_enable(1, level, data); | ||
1001 | } | ||
1002 | #endif /* CONFIG_PMAC_BACKLIGHT */ | ||
1003 | |||
1004 | /* ------------------------------------------------------------------------- * | ||
1005 | * | ||
1006 | * framebuffer operations | 1097 | * framebuffer operations |
1007 | * | 1098 | * |
1008 | * ------------------------------------------------------------------------- */ | 1099 | * ------------------------------------------------------------------------- */ |
@@ -1247,10 +1338,15 @@ static int rivafb_blank(int blank, struct fb_info *info) | |||
1247 | SEQout(par, 0x01, tmp); | 1338 | SEQout(par, 0x01, tmp); |
1248 | CRTCout(par, 0x1a, vesa); | 1339 | CRTCout(par, 0x1a, vesa); |
1249 | 1340 | ||
1250 | #ifdef CONFIG_PMAC_BACKLIGHT | 1341 | #ifdef CONFIG_FB_RIVA_BACKLIGHT |
1251 | if ( par->FlatPanel && machine_is(powermac)) { | 1342 | mutex_lock(&info->bl_mutex); |
1252 | set_backlight_enable(!blank); | 1343 | if (info->bl_dev) { |
1344 | down(&info->bl_dev->sem); | ||
1345 | info->bl_dev->props->power = blank; | ||
1346 | info->bl_dev->props->update_status(info->bl_dev); | ||
1347 | up(&info->bl_dev->sem); | ||
1253 | } | 1348 | } |
1349 | mutex_unlock(&info->bl_mutex); | ||
1254 | #endif | 1350 | #endif |
1255 | 1351 | ||
1256 | NVTRACE_LEAVE(); | 1352 | NVTRACE_LEAVE(); |
@@ -2037,11 +2133,9 @@ static int __devinit rivafb_probe(struct pci_dev *pd, | |||
2037 | RIVAFB_VERSION, | 2133 | RIVAFB_VERSION, |
2038 | info->fix.smem_len / (1024 * 1024), | 2134 | info->fix.smem_len / (1024 * 1024), |
2039 | info->fix.smem_start); | 2135 | info->fix.smem_start); |
2040 | #ifdef CONFIG_PMAC_BACKLIGHT | 2136 | |
2041 | if (default_par->FlatPanel && machine_is(powermac)) | 2137 | riva_bl_init(info->par); |
2042 | register_backlight_controller(&riva_backlight_controller, | 2138 | |
2043 | default_par, "mnca"); | ||
2044 | #endif | ||
2045 | NVTRACE_LEAVE(); | 2139 | NVTRACE_LEAVE(); |
2046 | return 0; | 2140 | return 0; |
2047 | 2141 | ||
@@ -2074,6 +2168,8 @@ static void __exit rivafb_remove(struct pci_dev *pd) | |||
2074 | 2168 | ||
2075 | NVTRACE_ENTER(); | 2169 | NVTRACE_ENTER(); |
2076 | 2170 | ||
2171 | riva_bl_exit(par); | ||
2172 | |||
2077 | #ifdef CONFIG_FB_RIVA_I2C | 2173 | #ifdef CONFIG_FB_RIVA_I2C |
2078 | riva_delete_i2c_busses(par); | 2174 | riva_delete_i2c_busses(par); |
2079 | kfree(par->EDID); | 2175 | kfree(par->EDID); |