diff options
Diffstat (limited to 'drivers/video/aty/aty128fb.c')
-rw-r--r-- | drivers/video/aty/aty128fb.c | 322 |
1 files changed, 225 insertions, 97 deletions
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 |