aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/aty
diff options
context:
space:
mode:
authorMichael Hanselmann <linux-kernel@hansmi.ch>2006-06-25 08:47:08 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-25 13:00:59 -0400
commit5474c120aafe78ca54bf272f7a01107c42da2b21 (patch)
treec1b002a27703ce92c816bfb9844752186e33d403 /drivers/video/aty
parent17660bdd5c1f1a165273c1a59cb5b87670a81cc4 (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/aty')
-rw-r--r--drivers/video/aty/Makefile1
-rw-r--r--drivers/video/aty/aty128fb.c322
-rw-r--r--drivers/video/aty/atyfb.h1
-rw-r--r--drivers/video/aty/atyfb_base.c178
-rw-r--r--drivers/video/aty/radeon_backlight.c247
-rw-r--r--drivers/video/aty/radeon_base.c140
-rw-r--r--drivers/video/aty/radeonfb.h9
7 files changed, 637 insertions, 261 deletions
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
11radeonfb-y := radeon_base.o radeon_pm.o radeon_monitor.o radeon_accel.o 11radeonfb-y := radeon_base.o radeon_pm.o radeon_monitor.o radeon_accel.o
12radeonfb-$(CONFIG_FB_RADEON_I2C) += radeon_i2c.o 12radeonfb-$(CONFIG_FB_RADEON_I2C) += radeon_i2c.o
13radeonfb-$(CONFIG_FB_RADEON_BACKLIGHT) += radeon_backlight.o
13radeonfb-objs := $(radeonfb-y) 14radeonfb-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
484static int aty128_set_backlight_enable(int on, int level, void* data);
485static int aty128_set_backlight_level(int level, void* data);
486
487static 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)
1258static void aty128_set_lcd_enable(struct aty128fb_par *par, int on) 1249static 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
1705static struct backlight_properties aty128_bl_data;
1706
1707static 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
1735static 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
1788static int aty128_bl_get_brightness(struct backlight_device *bd)
1789{
1790 return bd->props->brightness;
1791}
1792
1793static 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
1800static 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
1848error:
1849 return;
1850}
1851
1852static 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
2142static 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
2155static 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
2202static 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 /* 2123static struct backlight_properties aty_bl_data;
2121 * LCD backlight control
2122 */
2123 2124
2124static int backlight_conv[] = { 2125static 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
2129static int aty_set_backlight_enable(int on, int level, void *data) 2140 return atylevel;
2141}
2142
2143static 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
2147static int aty_set_backlight_level(int level, void *data) 2168static 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
2152static struct backlight_controller aty_backlight_controller = { 2173static 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
2180static 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
2224error:
2225 return;
2226}
2227
2228static 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
2158static void __init aty_calc_mem_refresh(struct atyfb_par *par, int xclk) 2256static 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
22static struct backlight_properties radeon_bl_data;
23
24struct radeon_bl_privdata {
25 struct radeonfb_info *rinfo;
26 uint8_t negative;
27};
28
29static 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
54static 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
131static int radeon_bl_get_brightness(struct backlight_device *bd)
132{
133 return bd->props->brightness;
134}
135
136static 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
143void 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
215error:
216 kfree(pdata);
217 return;
218}
219
220void 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
284static int radeon_set_backlight_enable(int on, int level, void *data);
285static int radeon_set_backlight_level(int level, void *data);
286static 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
294static void radeon_unmap_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev) 276static 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 */
1923static int backlight_conv_m6[] = {
1924 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e,
1925 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
1926};
1927static 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 */
1939static 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
2019static 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_
625extern void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode, 625extern 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
630extern void radeonfb_bl_init(struct radeonfb_info *rinfo);
631extern void radeonfb_bl_exit(struct radeonfb_info *rinfo);
632#else
633static inline void radeonfb_bl_init(struct radeonfb_info *rinfo) {}
634static inline void radeonfb_bl_exit(struct radeonfb_info *rinfo) {}
635#endif
636
628#endif /* __RADEONFB_H__ */ 637#endif /* __RADEONFB_H__ */