summaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/Kconfig114
-rw-r--r--drivers/video/Makefile3
-rw-r--r--drivers/video/aty/aty128fb.c114
-rw-r--r--drivers/video/aty/atyfb.h3
-rw-r--r--drivers/video/aty/atyfb_base.c119
-rw-r--r--drivers/video/aty/mach64_ct.c3
-rw-r--r--drivers/video/aty/radeon_backlight.c59
-rw-r--r--drivers/video/aty/radeon_base.c28
-rw-r--r--drivers/video/aty/radeon_monitor.c16
-rw-r--r--drivers/video/aty/radeon_pm.c2
-rw-r--r--drivers/video/aty/radeonfb.h4
-rw-r--r--drivers/video/backlight/Kconfig23
-rw-r--r--drivers/video/backlight/Makefile1
-rw-r--r--drivers/video/backlight/backlight.c123
-rw-r--r--drivers/video/backlight/corgi_bl.c54
-rw-r--r--drivers/video/backlight/hp680_bl.c50
-rw-r--r--drivers/video/backlight/lcd.c83
-rw-r--r--drivers/video/backlight/locomolcd.c17
-rw-r--r--drivers/video/backlight/progear_bl.c153
-rw-r--r--drivers/video/bw2.c18
-rw-r--r--drivers/video/cg14.c5
-rw-r--r--drivers/video/cg3.c28
-rw-r--r--drivers/video/chipsfb.c26
-rw-r--r--drivers/video/console/fbcon.c7
-rw-r--r--drivers/video/controlfb.c16
-rw-r--r--drivers/video/fbsysfs.c14
-rw-r--r--drivers/video/ffb.c84
-rw-r--r--drivers/video/i810/i810_main.c2
-rw-r--r--drivers/video/igafb.c24
-rw-r--r--drivers/video/nvidia/nv_backlight.c97
-rw-r--r--drivers/video/nvidia/nv_proto.h2
-rw-r--r--drivers/video/nvidia/nvidia.c17
-rw-r--r--drivers/video/riva/fbdev.c114
-rw-r--r--drivers/video/s3fb.c9
-rw-r--r--drivers/video/savage/savagefb_driver.c18
-rw-r--r--drivers/video/sm501fb.c1786
-rw-r--r--drivers/video/sstfb.c1
37 files changed, 2497 insertions, 740 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 8874cf2fd27..b1cb72c3780 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -4,20 +4,7 @@
menu "Graphics support"
-config FIRMWARE_EDID
- bool "Enable firmware EDID"
- default y
- ---help---
- This enables access to the EDID transferred from the firmware.
- On the i386, this is from the Video BIOS. Enable this if DDC/I2C
- transfers do not work for your driver and if you are using
- nvidiafb, i810fb or savagefb.
-
- In general, choosing Y for this option is safe. If you
- experience extremely long delays while booting before you get
- something on your display, try setting this to N. Matrox cards in
- combination with certain motherboards and monitors are known to
- suffer from this problem.
+source "drivers/video/backlight/Kconfig"
config FB
tristate "Support for frame buffer devices"
@@ -53,9 +40,27 @@ config FB
(e.g. an accelerated X server) and that are not frame buffer
device-aware may cause unexpected results. If unsure, say N.
+config FIRMWARE_EDID
+ bool "Enable firmware EDID"
+ depends on FB
+ default n
+ ---help---
+ This enables access to the EDID transferred from the firmware.
+ On the i386, this is from the Video BIOS. Enable this if DDC/I2C
+ transfers do not work for your driver and if you are using
+ nvidiafb, i810fb or savagefb.
+
+ In general, choosing Y for this option is safe. If you
+ experience extremely long delays while booting before you get
+ something on your display, try setting this to N. Matrox cards in
+ combination with certain motherboards and monitors are known to
+ suffer from this problem.
+
config FB_DDC
tristate
- depends on FB && I2C && I2C_ALGOBIT
+ depends on FB
+ select I2C_ALGOBIT
+ select I2C
default n
config FB_CFB_FILLRECT
@@ -134,6 +139,9 @@ config FB_TILEBLITTING
This is particularly important to one driver, matroxfb. If
unsure, say N.
+comment "Frame buffer hardware drivers"
+ depends on FB
+
config FB_CIRRUS
tristate "Cirrus Logic support"
depends on FB && (ZORRO || PCI)
@@ -388,7 +396,7 @@ config FB_ATARI
config FB_OF
bool "Open Firmware frame buffer device support"
- depends on (FB = y) && (PPC64 || PPC_OF)
+ depends on (FB = y) && (PPC64 || PPC_OF) && (!PPC_PSERIES || PCI)
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -669,8 +677,7 @@ config FB_S1D13XXX
config FB_NVIDIA
tristate "nVidia Framebuffer Support"
depends on FB && PCI
- select I2C_ALGOBIT if FB_NVIDIA_I2C
- select I2C if FB_NVIDIA_I2C
+ select FB_BACKLIGHT if FB_NVIDIA_BACKLIGHT
select FB_MODE_HELPERS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
@@ -688,6 +695,7 @@ config FB_NVIDIA
config FB_NVIDIA_I2C
bool "Enable DDC Support"
depends on FB_NVIDIA
+ select FB_DDC
help
This enables I2C support for nVidia Chipsets. This is used
only for getting EDID information from the attached display
@@ -699,8 +707,7 @@ config FB_NVIDIA_I2C
config FB_NVIDIA_BACKLIGHT
bool "Support for backlight control"
- depends on FB_NVIDIA && PMAC_BACKLIGHT
- select FB_BACKLIGHT
+ depends on FB_NVIDIA
default y
help
Say Y here if you want to control the backlight of your display.
@@ -708,9 +715,7 @@ config FB_NVIDIA_BACKLIGHT
config FB_RIVA
tristate "nVidia Riva support"
depends on FB && PCI
- select I2C_ALGOBIT if FB_RIVA_I2C
- select I2C if FB_RIVA_I2C
- select FB_DDC if FB_RIVA_I2C
+ select FB_BACKLIGHT if FB_RIVA_BACKLIGHT
select FB_MODE_HELPERS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
@@ -727,6 +732,7 @@ config FB_RIVA
config FB_RIVA_I2C
bool "Enable DDC Support"
depends on FB_RIVA
+ select FB_DDC
help
This enables I2C support for nVidia Chipsets. This is used
only for getting EDID information from the attached display
@@ -747,8 +753,7 @@ config FB_RIVA_DEBUG
config FB_RIVA_BACKLIGHT
bool "Support for backlight control"
- depends on FB_RIVA && PMAC_BACKLIGHT
- select FB_BACKLIGHT
+ depends on FB_RIVA
default y
help
Say Y here if you want to control the backlight of your display.
@@ -798,8 +803,6 @@ config FB_I810_GTF
config FB_I810_I2C
bool "Enable DDC Support"
depends on FB_I810 && FB_I810_GTF
- select I2C
- select I2C_ALGOBIT
select FB_DDC
help
@@ -808,8 +811,6 @@ config FB_INTEL
depends on FB && EXPERIMENTAL && PCI && X86
select AGP
select AGP_INTEL
- select I2C_ALGOBIT if FB_INTEL_I2C
- select I2C if FB_INTEL_I2C
select FB_MODE_HELPERS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
@@ -842,6 +843,7 @@ config FB_INTEL_DEBUG
config FB_INTEL_I2C
bool "DDC/I2C for Intel framebuffer support"
depends on FB_INTEL
+ select FB_DDC
default y
help
Say Y here if you want DDC/I2C support for your on-board Intel graphics.
@@ -920,8 +922,8 @@ config FB_MATROX_G
config FB_MATROX_I2C
tristate "Matrox I2C support"
- depends on FB_MATROX && I2C
- select I2C_ALGOBIT
+ depends on FB_MATROX
+ select FB_DDC
---help---
This drivers creates I2C buses which are needed for accessing the
DDC (I2C) bus present on all Matroxes, an I2C bus which
@@ -989,9 +991,7 @@ config FB_MATROX_MULTIHEAD
config FB_RADEON
tristate "ATI Radeon display support"
depends on FB && PCI
- select I2C_ALGOBIT if FB_RADEON_I2C
- select I2C if FB_RADEON_I2C
- select FB_DDC if FB_RADEON_I2C
+ select FB_BACKLIGHT if FB_RADEON_BACKLIGHT
select FB_MODE_HELPERS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
@@ -1015,14 +1015,14 @@ config FB_RADEON
config FB_RADEON_I2C
bool "DDC/I2C for ATI Radeon support"
depends on FB_RADEON
+ select FB_DDC
default y
help
Say Y here if you want DDC/I2C support for your Radeon board.
config FB_RADEON_BACKLIGHT
bool "Support for backlight control"
- depends on FB_RADEON && PMAC_BACKLIGHT
- select FB_BACKLIGHT
+ depends on FB_RADEON
default y
help
Say Y here if you want to control the backlight of your display.
@@ -1042,6 +1042,7 @@ config FB_ATY128
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select FB_BACKLIGHT if FB_ATY128_BACKLIGHT
select FB_MACMODES if PPC_PMAC
help
This driver supports graphics boards with the ATI Rage128 chips.
@@ -1053,8 +1054,7 @@ config FB_ATY128
config FB_ATY128_BACKLIGHT
bool "Support for backlight control"
- depends on FB_ATY128 && PMAC_BACKLIGHT
- select FB_BACKLIGHT
+ depends on FB_ATY128
default y
help
Say Y here if you want to control the backlight of your display.
@@ -1065,6 +1065,7 @@ config FB_ATY
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select FB_BACKLIGHT if FB_ATY_BACKLIGHT
select FB_MACMODES if PPC
help
This driver supports graphics boards with the ATI Mach64 chips.
@@ -1103,8 +1104,7 @@ config FB_ATY_GX
config FB_ATY_BACKLIGHT
bool "Support for backlight control"
- depends on FB_ATY && PMAC_BACKLIGHT
- select FB_BACKLIGHT
+ depends on FB_ATY
default y
help
Say Y here if you want to control the backlight of your display.
@@ -1123,9 +1123,6 @@ config FB_S3
config FB_SAVAGE
tristate "S3 Savage support"
depends on FB && PCI && EXPERIMENTAL
- select I2C_ALGOBIT if FB_SAVAGE_I2C
- select I2C if FB_SAVAGE_I2C
- select FB_DDC if FB_SAVAGE_I2C
select FB_MODE_HELPERS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
@@ -1142,6 +1139,7 @@ config FB_SAVAGE
config FB_SAVAGE_I2C
bool "Enable DDC2 Support"
depends on FB_SAVAGE
+ select FB_DDC
help
This enables I2C support for S3 Savage Chipsets. This is used
only for getting EDID information from the attached display
@@ -1322,7 +1320,7 @@ config FB_AU1100
config FB_AU1200
bool "Au1200 LCD Driver"
- depends on FB && MIPS && SOC_AU1200
+ depends on (FB = y) && MIPS && SOC_AU1200
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -1472,7 +1470,7 @@ config FB_G364
config FB_68328
bool "Motorola 68328 native frame buffer support"
- depends on FB && (M68328 || M68EZ328 || M68VZ328)
+ depends on (FB = y) && (M68328 || M68EZ328 || M68VZ328)
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -1573,6 +1571,24 @@ config FB_S3C2410_DEBUG
Turn on debugging messages. Note that you can set/unset at run time
through sysfs
+config FB_SM501
+ tristate "Silicon Motion SM501 framebuffer support"
+ depends on FB && MFD_SM501
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ ---help---
+ Frame buffer driver for the CRT and LCD controllers in the Silicon
+ Motion SM501.
+
+ This driver is also available as a module ( = code which can be
+ inserted and removed from the running kernel whenever you want). The
+ module will be called sm501fb. If you want to compile it as a module,
+ say M here and read <file:Documentation/modules.txt>.
+
+ If unsure, say N.
+
+
config FB_PNX4008_DUM
tristate "Display Update Module support on Philips PNX4008 board"
depends on FB && ARCH_PNX4008
@@ -1600,8 +1616,7 @@ config FB_IBM_GXT4500
config FB_PS3
bool "PS3 GPU framebuffer driver"
- depends on FB && PPC_PS3
- select PS3_PS3AV
+ depends on (FB = y) && PS3_PS3AV
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -1639,6 +1654,7 @@ config FB_VIRTUAL
the vfb_enable=1 option.
If unsure, say N.
+
if VT
source "drivers/video/console/Kconfig"
endif
@@ -1647,9 +1663,5 @@ if FB || SGI_NEWPORT_CONSOLE
source "drivers/video/logo/Kconfig"
endif
-if SYSFS
- source "drivers/video/backlight/Kconfig"
-endif
-
endmenu
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 6801edff36d..760305c8a84 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -12,7 +12,7 @@ fb-objs := $(fb-y)
obj-$(CONFIG_VT) += console/
obj-$(CONFIG_LOGO) += logo/
-obj-$(CONFIG_SYSFS) += backlight/
+obj-y += backlight/
obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o
obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o
@@ -98,6 +98,7 @@ obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/
obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/
obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o
obj-$(CONFIG_FB_PS3) += ps3fb.o
+obj-$(CONFIG_FB_SM501) += sm501fb.o
# Platform or fallback drivers go here
obj-$(CONFIG_FB_VESA) += vesafb.o
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index 2e976ffcde0..e86d7e0c982 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -357,6 +357,12 @@ static int default_lcd_on __devinitdata = 1;
static int mtrr = 1;
#endif
+#ifdef CONFIG_PMAC_BACKLIGHT
+static int backlight __devinitdata = 1;
+#else
+static int backlight __devinitdata = 0;
+#endif
+
/* PLL constants */
struct aty128_constants {
u32 ref_clk;
@@ -1652,6 +1658,9 @@ static int __devinit aty128fb_setup(char *options)
} else if (!strncmp(this_opt, "crt:", 4)) {
default_crt_on = simple_strtoul(this_opt+4, NULL, 0);
continue;
+ } else if (!strncmp(this_opt, "backlight:", 10)) {
+ backlight = simple_strtoul(this_opt+10, NULL, 0);
+ continue;
}
#ifdef CONFIG_MTRR
if(!strncmp(this_opt, "nomtrr", 6)) {
@@ -1695,9 +1704,6 @@ static int __devinit aty128fb_setup(char *options)
#ifdef CONFIG_FB_ATY128_BACKLIGHT
#define MAX_LEVEL 0xFF
-static struct backlight_properties aty128_bl_data;
-
-/* Call with fb_info->bl_mutex held */
static int aty128_bl_get_level_brightness(struct aty128fb_par *par,
int level)
{
@@ -1705,6 +1711,7 @@ static int aty128_bl_get_level_brightness(struct aty128fb_par *par,
int atylevel;
/* Get and convert the value */
+ /* No locking of bl_curve since we read a single value */
atylevel = MAX_LEVEL -
(info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL);
@@ -1724,19 +1731,18 @@ static int aty128_bl_get_level_brightness(struct aty128fb_par *par,
/* That one prevents proper CRT output with LCD off */
#undef BACKLIGHT_DAC_OFF
-/* Call with fb_info->bl_mutex held */
-static int __aty128_bl_update_status(struct backlight_device *bd)
+static int aty128_bl_update_status(struct backlight_device *bd)
{
struct aty128fb_par *par = class_get_devdata(&bd->class_dev);
unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
int level;
- if (bd->props->power != FB_BLANK_UNBLANK ||
- bd->props->fb_blank != FB_BLANK_UNBLANK ||
+ if (bd->props.power != FB_BLANK_UNBLANK ||
+ bd->props.fb_blank != FB_BLANK_UNBLANK ||
!par->lcd_on)
level = 0;
else
- level = bd->props->brightness;
+ level = bd->props.brightness;
reg |= LVDS_BL_MOD_EN | LVDS_BLON;
if (level > 0) {
@@ -1778,43 +1784,22 @@ static int __aty128_bl_update_status(struct backlight_device *bd)
return 0;
}
-static int aty128_bl_update_status(struct backlight_device *bd)
-{
- struct aty128fb_par *par = class_get_devdata(&bd->class_dev);
- struct fb_info *info = pci_get_drvdata(par->pdev);
- int ret;
-
- mutex_lock(&info->bl_mutex);
- ret = __aty128_bl_update_status(bd);
- mutex_unlock(&info->bl_mutex);
-
- return ret;
-}
-
static int aty128_bl_get_brightness(struct backlight_device *bd)
{
- return bd->props->brightness;
+ return bd->props.brightness;
}
-static struct backlight_properties aty128_bl_data = {
- .owner = THIS_MODULE,
+static struct backlight_ops aty128_bl_data = {
.get_brightness = aty128_bl_get_brightness,
.update_status = aty128_bl_update_status,
- .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
};
static void aty128_bl_set_power(struct fb_info *info, int power)
{
- mutex_lock(&info->bl_mutex);
-
if (info->bl_dev) {
- down(&info->bl_dev->sem);
- info->bl_dev->props->power = power;
- __aty128_bl_update_status(info->bl_dev);
- up(&info->bl_dev->sem);
+ info->bl_dev->props.power = power;
+ backlight_update_status(info->bl_dev);
}
-
- mutex_unlock(&info->bl_mutex);
}
static void aty128_bl_init(struct aty128fb_par *par)
@@ -1841,25 +1826,15 @@ static void aty128_bl_init(struct aty128fb_par *par)
goto error;
}
- mutex_lock(&info->bl_mutex);
info->bl_dev = bd;
fb_bl_default_curve(info, 0,
63 * FB_BACKLIGHT_MAX / MAX_LEVEL,
219 * FB_BACKLIGHT_MAX / MAX_LEVEL);
- mutex_unlock(&info->bl_mutex);
- down(&bd->sem);
- bd->props->brightness = aty128_bl_data.max_brightness;
- bd->props->power = FB_BLANK_UNBLANK;
- bd->props->update_status(bd);
- up(&bd->sem);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_lock(&pmac_backlight_mutex);
- if (!pmac_backlight)
- pmac_backlight = bd;
- mutex_unlock(&pmac_backlight_mutex);
-#endif
+ bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
+ bd->props.brightness = bd->props.max_brightness;
+ bd->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(bd);
printk("aty128: Backlight initialized (%s)\n", name);
@@ -1869,31 +1844,10 @@ error:
return;
}
-static void aty128_bl_exit(struct aty128fb_par *par)
+static void aty128_bl_exit(struct backlight_device *bd)
{
- struct fb_info *info = pci_get_drvdata(par->pdev);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_lock(&pmac_backlight_mutex);
-#endif
-
- mutex_lock(&info->bl_mutex);
- if (info->bl_dev) {
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (pmac_backlight == info->bl_dev)
- pmac_backlight = NULL;
-#endif
-
- backlight_device_unregister(info->bl_dev);
- info->bl_dev = NULL;
-
- printk("aty128: Backlight unloaded\n");
- }
- mutex_unlock(&info->bl_mutex);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_unlock(&pmac_backlight_mutex);
-#endif
+ backlight_device_unregister(bd);
+ printk("aty128: Backlight unloaded\n");
}
#endif /* CONFIG_FB_ATY128_BACKLIGHT */
@@ -2040,7 +1994,8 @@ static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_i
par->lock_blank = 0;
#ifdef CONFIG_FB_ATY128_BACKLIGHT
- aty128_bl_init(par);
+ if (backlight)
+ aty128_bl_init(par);
#endif
if (register_framebuffer(info) < 0)
@@ -2180,11 +2135,12 @@ static void __devexit aty128_remove(struct pci_dev *pdev)
par = info->par;
+ unregister_framebuffer(info);
+
#ifdef CONFIG_FB_ATY128_BACKLIGHT
- aty128_bl_exit(par);
+ aty128_bl_exit(info->bl_dev);
#endif
- unregister_framebuffer(info);
#ifdef CONFIG_MTRR
if (par->mtrr.vram_valid)
mtrr_del(par->mtrr.vram, info->fix.smem_start,
@@ -2214,11 +2170,6 @@ static int aty128fb_blank(int blank, struct fb_info *fb)
if (par->lock_blank || par->asleep)
return 0;
-#ifdef CONFIG_FB_ATY128_BACKLIGHT
- if (machine_is(powermac) && blank)
- aty128_bl_set_power(fb, FB_BLANK_POWERDOWN);
-#endif
-
if (blank & FB_BLANK_VSYNC_SUSPEND)
state |= 2;
if (blank & FB_BLANK_HSYNC_SUSPEND)
@@ -2233,11 +2184,6 @@ static int aty128fb_blank(int blank, struct fb_info *fb)
aty128_set_lcd_enable(par, par->lcd_on && !blank);
}
-#ifdef CONFIG_FB_ATY128_BACKLIGHT
- if (machine_is(powermac) && !blank)
- aty128_bl_set_power(fb, FB_BLANK_UNBLANK);
-#endif
-
return 0;
}
diff --git a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h
index f72faff33c0..dc62f8e282b 100644
--- a/drivers/video/aty/atyfb.h
+++ b/drivers/video/aty/atyfb.h
@@ -284,7 +284,8 @@ static inline void aty_st_8(int regindex, u8 val, const struct atyfb_par *par)
#endif
}
-#if defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD)
+#if defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || \
+defined (CONFIG_FB_ATY_GENERIC_LCD) || defined (CONFIG_FB_ATY_BACKLIGHT)
extern void aty_st_lcd(int index, u32 val, const struct atyfb_par *par);
extern u32 aty_ld_lcd(int index, const struct atyfb_par *par);
#endif
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index 301612cef35..8514f2a6f06 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -131,7 +131,8 @@
#define PRINTKI(fmt, args...) printk(KERN_INFO "atyfb: " fmt, ## args)
#define PRINTKE(fmt, args...) printk(KERN_ERR "atyfb: " fmt, ## args)
-#if defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD)
+#if defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || \
+defined (CONFIG_FB_ATY_GENERIC_LCD) || defined(CONFIG_FB_ATY_BACKLIGHT)
static const u32 lt_lcd_regs[] = {
CONFIG_PANEL_LG,
LCD_GEN_CNTL_LG,
@@ -308,6 +309,12 @@ static int xclk;
static int comp_sync __devinitdata = -1;
static char *mode;
+#ifdef CONFIG_PMAC_BACKLIGHT
+static int backlight __devinitdata = 1;
+#else
+static int backlight __devinitdata = 0;
+#endif
+
#ifdef CONFIG_PPC
static int default_vmode __devinitdata = VMODE_CHOOSE;
static int default_cmode __devinitdata = CMODE_CHOOSE;
@@ -2114,15 +2121,13 @@ static int atyfb_pci_resume(struct pci_dev *pdev)
#ifdef CONFIG_FB_ATY_BACKLIGHT
#define MAX_LEVEL 0xFF
-static struct backlight_properties aty_bl_data;
-
-/* Call with fb_info->bl_mutex held */
static int aty_bl_get_level_brightness(struct atyfb_par *par, int level)
{
struct fb_info *info = pci_get_drvdata(par->pdev);
int atylevel;
/* Get and convert the value */
+ /* No locking of bl_curve since we read a single value */
atylevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
if (atylevel < 0)
@@ -2133,18 +2138,17 @@ static int aty_bl_get_level_brightness(struct atyfb_par *par, int level)
return atylevel;
}
-/* Call with fb_info->bl_mutex held */
-static int __aty_bl_update_status(struct backlight_device *bd)
+static int aty_bl_update_status(struct backlight_device *bd)
{
struct atyfb_par *par = class_get_devdata(&bd->class_dev);
unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par);
int level;
- if (bd->props->power != FB_BLANK_UNBLANK ||
- bd->props->fb_blank != FB_BLANK_UNBLANK)
+ if (bd->props.power != FB_BLANK_UNBLANK ||
+ bd->props.fb_blank != FB_BLANK_UNBLANK)
level = 0;
else
- level = bd->props->brightness;
+ level = bd->props.brightness;
reg |= (BLMOD_EN | BIASMOD_EN);
if (level > 0) {
@@ -2159,45 +2163,16 @@ static int __aty_bl_update_status(struct backlight_device *bd)
return 0;
}
-static int aty_bl_update_status(struct backlight_device *bd)
-{
- struct atyfb_par *par = class_get_devdata(&bd->class_dev);
- struct fb_info *info = pci_get_drvdata(par->pdev);
- int ret;
-
- mutex_lock(&info->bl_mutex);
- ret = __aty_bl_update_status(bd);
- mutex_unlock(&info->bl_mutex);
-
- return ret;
-}
-
static int aty_bl_get_brightness(struct backlight_device *bd)
{
- return bd->props->brightness;
+ return bd->props.brightness;
}
-static struct backlight_properties aty_bl_data = {
- .owner = THIS_MODULE,
+static struct backlight_ops aty_bl_data = {
.get_brightness = aty_bl_get_brightness,
.update_status = aty_bl_update_status,
- .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
};
-static void aty_bl_set_power(struct fb_info *info, int power)
-{
- mutex_lock(&info->bl_mutex);
-
- if (info->bl_dev) {
- down(&info->bl_dev->sem);
- info->bl_dev->props->power = power;
- __aty_bl_update_status(info->bl_dev);
- up(&info->bl_dev->sem);
- }
-
- mutex_unlock(&info->bl_mutex);
-}
-
static void aty_bl_init(struct atyfb_par *par)
{
struct fb_info *info = pci_get_drvdata(par->pdev);
@@ -2218,25 +2193,15 @@ static void aty_bl_init(struct atyfb_par *par)
goto error;
}
- mutex_lock(&info->bl_mutex);
info->bl_dev = bd;
fb_bl_default_curve(info, 0,
0x3F * FB_BACKLIGHT_MAX / MAX_LEVEL,
0xFF * FB_BACKLIGHT_MAX / MAX_LEVEL);
- mutex_unlock(&info->bl_mutex);
-
- down(&bd->sem);
- bd->props->brightness = aty_bl_data.max_brightness;
- bd->props->power = FB_BLANK_UNBLANK;
- bd->props->update_status(bd);
- up(&bd->sem);
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_lock(&pmac_backlight_mutex);
- if (!pmac_backlight)
- pmac_backlight = bd;
- mutex_unlock(&pmac_backlight_mutex);
-#endif
+ bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
+ bd->props.brightness = bd->props.max_brightness;
+ bd->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(bd);
printk("aty: Backlight initialized (%s)\n", name);
@@ -2246,30 +2211,10 @@ error:
return;
}
-static void aty_bl_exit(struct atyfb_par *par)
+static void aty_bl_exit(struct backlight_device *bd)
{
- struct fb_info *info = pci_get_drvdata(par->pdev);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_lock(&pmac_backlight_mutex);
-#endif
-
- mutex_lock(&info->bl_mutex);
- if (info->bl_dev) {
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (pmac_backlight == info->bl_dev)
- pmac_backlight = NULL;
-#endif
-
- backlight_device_unregister(info->bl_dev);
-
- printk("aty: Backlight unloaded\n");
- }
- mutex_unlock(&info->bl_mutex);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_unlock(&pmac_backlight_mutex);
-#endif
+ backlight_device_unregister(bd);
+ printk("aty: Backlight unloaded\n");
}
#endif /* CONFIG_FB_ATY_BACKLIGHT */
@@ -2637,7 +2582,7 @@ static int __devinit aty_init(struct fb_info *info)
| (USE_F32KHZ | TRISTATE_MEM_EN), par);
} else
#endif
- if (M64_HAS(MOBIL_BUS)) {
+ if (M64_HAS(MOBIL_BUS) && backlight) {
#ifdef CONFIG_FB_ATY_BACKLIGHT
aty_bl_init (par);
#endif
@@ -2814,8 +2759,6 @@ static int atyfb_blank(int blank, struct fb_info *info)
return 0;
#ifdef CONFIG_FB_ATY_BACKLIGHT
- if (machine_is(powermac) && blank > FB_BLANK_NORMAL)
- aty_bl_set_power(info, FB_BLANK_POWERDOWN);
#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
if (par->lcd_table && blank > FB_BLANK_NORMAL &&
(aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
@@ -2846,8 +2789,6 @@ static int atyfb_blank(int blank, struct fb_info *info)
aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par);
#ifdef CONFIG_FB_ATY_BACKLIGHT
- if (machine_is(powermac) && blank <= FB_BLANK_NORMAL)
- aty_bl_set_power(info, FB_BLANK_UNBLANK);
#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
if (par->lcd_table && blank <= FB_BLANK_NORMAL &&
(aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
@@ -2958,7 +2899,7 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
struct fb_info *info, unsigned long addr)
{
struct atyfb_par *par = info->par;
- struct pcidev_cookie *pcp;
+ struct device_node *dp;
char prop[128];
int node, len, i, j, ret;
u32 mem, chip_id;
@@ -3096,8 +3037,8 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
node = 0;
}
- pcp = pdev->sysdata;
- if (node == pcp->prom_node->node) {
+ dp = pci_device_to_OF_node(pdev);
+ if (node == dp->node) {
struct fb_var_screeninfo *var = &default_var;
unsigned int N, P, Q, M, T, R;
u32 v_total, h_total;
@@ -3726,13 +3667,13 @@ static void __devexit atyfb_remove(struct fb_info *info)
aty_set_crtc(par, &saved_crtc);
par->pll_ops->set_pll(info, &saved_pll);
+ unregister_framebuffer(info);
+
#ifdef CONFIG_FB_ATY_BACKLIGHT
if (M64_HAS(MOBIL_BUS))
- aty_bl_exit(par);
+ aty_bl_exit(info->bl_dev);
#endif
- unregister_framebuffer(info);
-
#ifdef CONFIG_MTRR
if (par->mtrr_reg >= 0) {
mtrr_del(par->mtrr_reg, 0, 0);
@@ -3823,6 +3764,8 @@ static int __init atyfb_setup(char *options)
xclk = simple_strtoul(this_opt+5, NULL, 0);
else if (!strncmp(this_opt, "comp_sync:", 10))
comp_sync = simple_strtoul(this_opt+10, NULL, 0);
+ else if (!strncmp(this_opt, "backlight:", 10))
+ backlight = simple_strtoul(this_opt+10, NULL, 0);
#ifdef CONFIG_PPC
else if (!strncmp(this_opt, "vmode:", 6)) {
unsigned int vmode =
diff --git a/drivers/video/aty/mach64_ct.c b/drivers/video/aty/mach64_ct.c
index f3b487b8710..1fdcfdbf669 100644
--- a/drivers/video/aty/mach64_ct.c
+++ b/drivers/video/aty/mach64_ct.c
@@ -598,7 +598,6 @@ static void aty_resume_pll_ct(const struct fb_info *info,
struct atyfb_par *par = info->par;
if (par->mclk_per != par->xclk_per) {
- int i;
/*
* This disables the sclk, crashes the computer as reported:
* aty_st_pll_ct(SPLL_CNTL2, 3, info);
@@ -614,7 +613,7 @@ static void aty_resume_pll_ct(const struct fb_info *info,
* helps for Rage Mobilities that sometimes crash when
* we switch to sclk. (Daniel Mantione, 13-05-2003)
*/
- for (i=0;i<=0x1ffff;i++);
+ udelay(500);
}
aty_st_pll_ct(PLL_REF_DIV, pll->ct.pll_ref_div, par);
diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c
index 3abfd4a380c..0be25fa5540 100644
--- a/drivers/video/aty/radeon_backlight.c
+++ b/drivers/video/aty/radeon_backlight.c
@@ -19,8 +19,6 @@
#define MAX_RADEON_LEVEL 0xFF
-static struct backlight_properties radeon_bl_data;
-
struct radeon_bl_privdata {
struct radeonfb_info *rinfo;
uint8_t negative;
@@ -29,17 +27,13 @@ struct radeon_bl_privdata {
static int radeon_bl_get_level_brightness(struct radeon_bl_privdata *pdata,
int level)
{
- struct fb_info *info = pdata->rinfo->info;
int rlevel;
- mutex_lock(&info->bl_mutex);
-
/* Get and convert the value */
+ /* No locking of bl_curve since we read a single value */
rlevel = pdata->rinfo->info->bl_curve[level] *
FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL;
- mutex_unlock(&info->bl_mutex);
-
if (rlevel < 0)
rlevel = 0;
else if (rlevel > MAX_RADEON_LEVEL)
@@ -65,11 +59,11 @@ static int radeon_bl_update_status(struct backlight_device *bd)
* backlight. This provides some greater power saving and the display
* is useless without backlight anyway.
*/
- if (bd->props->power != FB_BLANK_UNBLANK ||
- bd->props->fb_blank != FB_BLANK_UNBLANK)
+ if (bd->props.power != FB_BLANK_UNBLANK ||
+ bd->props.fb_blank != FB_BLANK_UNBLANK)
level = 0;
else
- level = bd->props->brightness;
+ level = bd->props.brightness;
del_timer_sync(&rinfo->lvds_timer);
radeon_engine_idle();
@@ -130,14 +124,12 @@ static int radeon_bl_update_status(struct backlight_device *bd)
static int radeon_bl_get_brightness(struct backlight_device *bd)
{
- return bd->props->brightness;
+ return bd->props.brightness;
}
-static struct backlight_properties radeon_bl_data = {
- .owner = THIS_MODULE,
+static struct backlight_ops radeon_bl_data = {
.get_brightness = radeon_bl_get_brightness,
.update_status = radeon_bl_update_status,
- .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
};
void radeonfb_bl_init(struct radeonfb_info *rinfo)
@@ -188,25 +180,15 @@ void radeonfb_bl_init(struct radeonfb_info *rinfo)
machine_is_compatible("PowerBook6,5");
#endif
- mutex_lock(&rinfo->info->bl_mutex);
rinfo->info->bl_dev = bd;
fb_bl_default_curve(rinfo->info, 0,
63 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL,
217 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL);
- mutex_unlock(&rinfo->info->bl_mutex);
- down(&bd->sem);
- bd->props->brightness = radeon_bl_data.max_brightness;
- bd->props->power = FB_BLANK_UNBLANK;
- bd->props->update_status(bd);
- up(&bd->sem);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_lock(&pmac_backlight_mutex);
- if (!pmac_backlight)
- pmac_backlight = bd;
- mutex_unlock(&pmac_backlight_mutex);
-#endif
+ bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
+ bd->props.brightness = bd->props.max_brightness;
+ bd->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(bd);
printk("radeonfb: Backlight initialized (%s)\n", name);
@@ -219,29 +201,16 @@ error:
void radeonfb_bl_exit(struct radeonfb_info *rinfo)
{
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_lock(&pmac_backlight_mutex);
-#endif
+ struct backlight_device *bd = rinfo->info->bl_dev;
- mutex_lock(&rinfo->info->bl_mutex);
- if (rinfo->info->bl_dev) {
+ if (bd) {
struct radeon_bl_privdata *pdata;
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (pmac_backlight == rinfo->info->bl_dev)
- pmac_backlight = NULL;
-#endif
-
- pdata = class_get_devdata(&rinfo->info->bl_dev->class_dev);
- backlight_device_unregister(rinfo->info->bl_dev);
+ pdata = class_get_devdata(&bd->class_dev);
+ backlight_device_unregister(bd);
kfree(pdata);
rinfo->info->bl_dev = NULL;
printk("radeonfb: Backlight unloaded\n");
}
- mutex_unlock(&rinfo->info->bl_mutex);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_unlock(&pmac_backlight_mutex);
-#endif
}
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index 0ed577e7cc2..a4b3fd185de 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -268,6 +268,11 @@ static int nomtrr = 0;
#endif
static int force_sleep;
static int ignore_devlist;
+#ifdef CONFIG_PMAC_BACKLIGHT
+static int backlight = 1;
+#else
+static int backlight = 0;
+#endif
/*
* prototypes
@@ -405,7 +410,7 @@ static int __devinit radeon_find_mem_vbios(struct radeonfb_info *rinfo)
}
#endif
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
/*
* Read XTAL (ref clock), SCLK and MCLK from Open Firmware device
* tree. Hopefully, ATI OF driver is kind enough to fill these
@@ -435,7 +440,7 @@ static int __devinit radeon_read_xtal_OF (struct radeonfb_info *rinfo)
return 0;
}
-#endif /* CONFIG_PPC_OF */
+#endif /* CONFIG_PPC_OF || CONFIG_SPARC */
/*
* Read PLL infos from chip registers
@@ -640,7 +645,7 @@ static void __devinit radeon_get_pllinfo(struct radeonfb_info *rinfo)
rinfo->pll.ref_div = INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
/*
* Retrieve PLL infos from Open Firmware first
*/
@@ -648,7 +653,7 @@ static void __devinit radeon_get_pllinfo(struct radeonfb_info *rinfo)
printk(KERN_INFO "radeonfb: Retrieved PLL infos from Open Firmware\n");
goto found;
}
-#endif /* CONFIG_PPC_OF */
+#endif /* CONFIG_PPC_OF || CONFIG_SPARC */
/*
* Check out if we have an X86 which gave us some PLL informations
@@ -1026,8 +1031,7 @@ int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch)
break;
}
- /* let fbcon do a soft blank for us */
- return (blank == FB_BLANK_NORMAL) ? -EINVAL : 0;
+ return 0;
}
static int radeonfb_blank (int blank, struct fb_info *info)
@@ -2227,7 +2231,7 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
rinfo->family == CHIP_FAMILY_RS200)
rinfo->errata |= CHIP_ERRATA_PLL_DELAY;
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
/* On PPC, we obtain the OF device-node pointer to the firmware
* data for this chip
*/
@@ -2236,6 +2240,8 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
printk(KERN_WARNING "radeonfb (%s): Cannot match card to OF node !\n",
pci_name(rinfo->pdev));
+#endif /* CONFIG_PPC_OF || CONFIG_SPARC */
+#ifdef CONFIG_PPC_OF
/* On PPC, the firmware sets up a memory mapping that tends
* to cause lockups when enabling the engine. We reconfigure
* the card internal memory mappings properly
@@ -2349,7 +2355,8 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
MTRR_TYPE_WRCOMB, 1);
#endif
- radeonfb_bl_init(rinfo);
+ if (backlight)
+ radeonfb_bl_init(rinfo);
printk ("radeonfb (%s): %s\n", pci_name(rinfo->pdev), rinfo->name);
@@ -2393,7 +2400,6 @@ static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev)
if (!rinfo)
return;
- radeonfb_bl_exit(rinfo);
radeonfb_pm_exit(rinfo);
if (rinfo->mon1_EDID)
@@ -2420,6 +2426,8 @@ static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev)
unregister_framebuffer(info);
+ radeonfb_bl_exit(rinfo);
+
iounmap(rinfo->mmio_base);
iounmap(rinfo->fb_base);
@@ -2469,6 +2477,8 @@ static int __init radeonfb_setup (char *options)
force_dfp = 1;
} else if (!strncmp(this_opt, "panel_yres:", 11)) {
panel_yres = simple_strtoul((this_opt+11), NULL, 0);
+ } else if (!strncmp(this_opt, "backlight:", 10)) {
+ backlight = simple_strtoul(this_opt+10, NULL, 0);
#ifdef CONFIG_MTRR
} else if (!strncmp(this_opt, "nomtrr", 6)) {
nomtrr = 1;
diff --git a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c
index 38c7dbf8c15..737b5c09dbd 100644
--- a/drivers/video/aty/radeon_monitor.c
+++ b/drivers/video/aty/radeon_monitor.c
@@ -52,7 +52,7 @@ static char *radeon_get_mon_name(int type)
}
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
/*
* Try to find monitor informations & EDID data out of the Open Firmware
* device-tree. This also contains some "hacks" to work around a few machine
@@ -156,7 +156,7 @@ static int __devinit radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_
}
return MT_NONE;
}
-#endif /* CONFIG_PPC_OF */
+#endif /* CONFIG_PPC_OF || CONFIG_SPARC */
static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo)
@@ -495,11 +495,11 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo,
* Old single head cards
*/
if (!rinfo->has_CRTC2) {
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
if (rinfo->mon1_type == MT_NONE)
rinfo->mon1_type = radeon_probe_OF_head(rinfo, 0,
&rinfo->mon1_EDID);
-#endif /* CONFIG_PPC_OF */
+#endif /* CONFIG_PPC_OF || CONFIG_SPARC */
#ifdef CONFIG_FB_RADEON_I2C
if (rinfo->mon1_type == MT_NONE)
rinfo->mon1_type =
@@ -544,11 +544,11 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo,
/*
* Probe primary head (DVI or laptop internal panel)
*/
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
if (rinfo->mon1_type == MT_NONE)
rinfo->mon1_type = radeon_probe_OF_head(rinfo, 0,
&rinfo->mon1_EDID);
-#endif /* CONFIG_PPC_OF */
+#endif /* CONFIG_PPC_OF || CONFIG_SPARC */
#ifdef CONFIG_FB_RADEON_I2C
if (rinfo->mon1_type == MT_NONE)
rinfo->mon1_type = radeon_probe_i2c_connector(rinfo, ddc_dvi,
@@ -572,11 +572,11 @@ void __devinit radeon_probe_screens(struct radeonfb_info *rinfo,
/*
* Probe secondary head (mostly VGA, can be DVI)
*/
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
if (rinfo->mon2_type == MT_NONE)
rinfo->mon2_type = radeon_probe_OF_head(rinfo, 1,
&rinfo->mon2_EDID);
-#endif /* CONFIG_PPC_OF */
+#endif /* CONFIG_PPC_OF || defined(CONFIG_SPARC) */
#ifdef CONFIG_FB_RADEON_I2C
if (rinfo->mon2_type == MT_NONE)
rinfo->mon2_type = radeon_probe_i2c_connector(rinfo, ddc_vga,
diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c
index 9a2b0d69b0a..c411293cefc 100644
--- a/drivers/video/aty/radeon_pm.c
+++ b/drivers/video/aty/radeon_pm.c
@@ -1262,7 +1262,7 @@ static void radeon_pm_full_reset_sdram(struct radeonfb_info *rinfo)
/* This is the code for the Aluminium PowerBooks M10 / iBooks M11 */
if (rinfo->family == CHIP_FAMILY_RV350) {
u32 sdram_mode_reg = rinfo->save_regs[35];
- static u32 default_mrtable[] =
+ static const u32 default_mrtable[] =
{ 0x21320032,
0x21321000, 0xa1321000, 0x21321000, 0xffffffff,
0x21320032, 0xa1320032, 0x21320032, 0xffffffff,
diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h
index d5ff224a625..31900036028 100644
--- a/drivers/video/aty/radeonfb.h
+++ b/drivers/video/aty/radeonfb.h
@@ -16,7 +16,7 @@
#include <asm/io.h>
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
#include <asm/prom.h>
#endif
@@ -292,7 +292,7 @@ struct radeonfb_info {
unsigned long fb_local_base;
struct pci_dev *pdev;
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
struct device_node *of_node;
#endif
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 02f15297a02..47d15b5d985 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -19,11 +19,6 @@ config BACKLIGHT_CLASS_DEVICE
To have support for your specific LCD panel you will have to
select the proper drivers which depend on this option.
-config BACKLIGHT_DEVICE
- bool
- depends on BACKLIGHT_CLASS_DEVICE
- default y
-
config LCD_CLASS_DEVICE
tristate "Lowlevel LCD controls"
depends on BACKLIGHT_LCD_SUPPORT
@@ -37,14 +32,9 @@ config LCD_CLASS_DEVICE
To have support for your specific LCD panel you will have to
select the proper drivers which depend on this option.
-config LCD_DEVICE
- bool
- depends on LCD_CLASS_DEVICE
- default y
-
config BACKLIGHT_CORGI
tristate "Sharp Corgi Backlight Driver (SL Series)"
- depends on BACKLIGHT_DEVICE && PXA_SHARPSL
+ depends on BACKLIGHT_CLASS_DEVICE && PXA_SHARPSL
default y
help
If you have a Sharp Zaurus SL-C7xx, SL-Cxx00 or SL-6000x say y to enable the
@@ -52,7 +42,7 @@ config BACKLIGHT_CORGI
config BACKLIGHT_LOCOMO
tristate "Sharp LOCOMO LCD/Backlight Driver"
- depends on BACKLIGHT_DEVICE && SHARP_LOCOMO
+ depends on BACKLIGHT_CLASS_DEVICE && SHARP_LOCOMO
default y
help
If you have a Sharp Zaurus SL-5500 (Collie) or SL-5600 (Poodle) say y to
@@ -60,9 +50,16 @@ config BACKLIGHT_LOCOMO
config BACKLIGHT_HP680
tristate "HP Jornada 680 Backlight Driver"
- depends on BACKLIGHT_DEVICE && SH_HP6XX
+ depends on BACKLIGHT_CLASS_DEVICE && SH_HP6XX
default y
help
If you have a HP Jornada 680, say y to enable the
backlight driver.
+config BACKLIGHT_PROGEAR
+ tristate "Frontpath ProGear Backlight Driver"
+ depends on BACKLIGHT_CLASS_DEVICE && PCI && X86
+ default n
+ help
+ If you have a Frontpath ProGear say Y to enable the
+ backlight driver.
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 65e5553fc84..0c3ce46f509 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
obj-$(CONFIG_BACKLIGHT_CORGI) += corgi_bl.o
obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o
obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o
+obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index 9601bfe309a..c65e81ff357 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -14,6 +14,9 @@
#include <linux/err.h>
#include <linux/fb.h>
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
#if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \
defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE))
@@ -28,19 +31,18 @@ static int fb_notifier_callback(struct notifier_block *self,
struct fb_event *evdata = data;
/* If we aren't interested in this event, skip it immediately ... */
- if (event != FB_EVENT_BLANK)
+ if (event != FB_EVENT_BLANK && event != FB_EVENT_CONBLANK)
return 0;
bd = container_of(self, struct backlight_device, fb_notif);
- down(&bd->sem);
- if (bd->props)
- if (!bd->props->check_fb ||
- bd->props->check_fb(evdata->info)) {
- bd->props->fb_blank = *(int *)evdata->data;
- if (likely(bd->props && bd->props->update_status))
- bd->props->update_status(bd);
+ mutex_lock(&bd->ops_lock);
+ if (bd->ops)
+ if (!bd->ops->check_fb ||
+ bd->ops->check_fb(evdata->info)) {
+ bd->props.fb_blank = *(int *)evdata->data;
+ backlight_update_status(bd);
}
- up(&bd->sem);
+ mutex_unlock(&bd->ops_lock);
return 0;
}
@@ -69,15 +71,9 @@ static inline void backlight_unregister_fb(struct backlight_device *bd)
static ssize_t backlight_show_power(struct class_device *cdev, char *buf)
{
- int rc = -ENXIO;
struct backlight_device *bd = to_backlight_device(cdev);
- down(&bd->sem);
- if (likely(bd->props))
- rc = sprintf(buf, "%d\n", bd->props->power);
- up(&bd->sem);
-
- return rc;
+ return sprintf(buf, "%d\n", bd->props.power);
}
static ssize_t backlight_store_power(struct class_device *cdev, const char *buf, size_t count)
@@ -93,30 +89,23 @@ static ssize_t backlight_store_power(struct class_device *cdev, const char *buf,
if (size != count)
return -EINVAL;
- down(&bd->sem);
- if (likely(bd->props)) {
+ mutex_lock(&bd->ops_lock);
+ if (bd->ops) {
pr_debug("backlight: set power to %d\n", power);
- bd->props->power = power;
- if (likely(bd->props->update_status))
- bd->props->update_status(bd);
+ bd->props.power = power;
+ backlight_update_status(bd);
rc = count;
}
- up(&bd->sem);
+ mutex_unlock(&bd->ops_lock);
return rc;
}
static ssize_t backlight_show_brightness(struct class_device *cdev, char *buf)
{
- int rc = -ENXIO;
struct backlight_device *bd = to_backlight_device(cdev);
- down(&bd->sem);
- if (likely(bd->props))
- rc = sprintf(buf, "%d\n", bd->props->brightness);
- up(&bd->sem);
-
- return rc;
+ return sprintf(buf, "%d\n", bd->props.brightness);
}
static ssize_t backlight_store_brightness(struct class_device *cdev, const char *buf, size_t count)
@@ -132,35 +121,28 @@ static ssize_t backlight_store_brightness(struct class_device *cdev, const char
if (size != count)
return -EINVAL;
- down(&bd->sem);
- if (likely(bd->props)) {
- if (brightness > bd->props->max_brightness)
+ mutex_lock(&bd->ops_lock);
+ if (bd->ops) {
+ if (brightness > bd->props.max_brightness)
rc = -EINVAL;
else {
pr_debug("backlight: set brightness to %d\n",
brightness);
- bd->props->brightness = brightness;
- if (likely(bd->props->update_status))
- bd->props->update_status(bd);
+ bd->props.brightness = brightness;
+ backlight_update_status(bd);
rc = count;
}
}
- up(&bd->sem);
+ mutex_unlock(&bd->ops_lock);
return rc;
}
static ssize_t backlight_show_max_brightness(struct class_device *cdev, char *buf)
{
- int rc = -ENXIO;
struct backlight_device *bd = to_backlight_device(cdev);
- down(&bd->sem);
- if (likely(bd->props))
- rc = sprintf(buf, "%d\n", bd->props->max_brightness);
- up(&bd->sem);
-
- return rc;
+ return sprintf(buf, "%d\n", bd->props.max_brightness);
}
static ssize_t backlight_show_actual_brightness(struct class_device *cdev,
@@ -169,10 +151,10 @@ static ssize_t backlight_show_actual_brightness(struct class_device *cdev,
int rc = -ENXIO;
struct backlight_device *bd = to_backlight_device(cdev);
- down(&bd->sem);
- if (likely(bd->props && bd->props->get_brightness))
- rc = sprintf(buf, "%d\n", bd->props->get_brightness(bd));
- up(&bd->sem);
+ mutex_lock(&bd->ops_lock);
+ if (bd->ops && bd->ops->get_brightness)
+ rc = sprintf(buf, "%d\n", bd->ops->get_brightness(bd));
+ mutex_unlock(&bd->ops_lock);
return rc;
}
@@ -211,7 +193,7 @@ static const struct class_device_attribute bl_class_device_attributes[] = {
* respective framebuffer device).
* @devdata: an optional pointer to be stored in the class_device. The
* methods may retrieve it by using class_get_devdata(&bd->class_dev).
- * @bp: the backlight properties structure.
+ * @ops: the backlight operations structure.
*
* Creates and registers new backlight class_device. Returns either an
* ERR_PTR() or a pointer to the newly allocated device.
@@ -219,39 +201,42 @@ static const struct class_device_attribute bl_class_device_attributes[] = {
struct backlight_device *backlight_device_register(const char *name,
struct device *dev,
void *devdata,
- struct backlight_properties *bp)
+ struct backlight_ops *ops)
{
int i, rc;
struct backlight_device *new_bd;
pr_debug("backlight_device_alloc: name=%s\n", name);
- new_bd = kmalloc(sizeof(struct backlight_device), GFP_KERNEL);
- if (unlikely(!new_bd))
+ new_bd = kzalloc(sizeof(struct backlight_device), GFP_KERNEL);
+ if (!new_bd)
return ERR_PTR(-ENOMEM);
- init_MUTEX(&new_bd->sem);
- new_bd->props = bp;
- memset(&new_bd->class_dev, 0, sizeof(new_bd->class_dev));
+ mutex_init(&new_bd->update_lock);
+ mutex_init(&new_bd->ops_lock);
+ new_bd->ops = ops;
new_bd->class_dev.class = &backlight_class;
new_bd->class_dev.dev = dev;
strlcpy(new_bd->class_dev.class_id, name, KOBJ_NAME_LEN);
class_set_devdata(&new_bd->class_dev, devdata);
rc = class_device_register(&new_bd->class_dev);
- if (unlikely(rc)) {
-error: kfree(new_bd);
+ if (rc) {
+ kfree(new_bd);
return ERR_PTR(rc);
}
rc = backlight_register_fb(new_bd);
- if (unlikely(rc))
- goto error;
+ if (rc) {
+ class_device_unregister(&new_bd->class_dev);
+ return ERR_PTR(rc);
+ }
+
for (i = 0; i < ARRAY_SIZE(bl_class_device_attributes); i++) {
rc = class_device_create_file(&new_bd->class_dev,
&bl_class_device_attributes[i]);
- if (unlikely(rc)) {
+ if (rc) {
while (--i >= 0)
class_device_remove_file(&new_bd->class_dev,
&bl_class_device_attributes[i]);
@@ -261,6 +246,13 @@ error: kfree(new_bd);
}
}
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+ if (!pmac_backlight)
+ pmac_backlight = new_bd;
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+
return new_bd;
}
EXPORT_SYMBOL(backlight_device_register);
@@ -280,13 +272,20 @@ void backlight_device_unregister(struct backlight_device *bd)
pr_debug("backlight_device_unregister: name=%s\n", bd->class_dev.class_id);
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+ if (pmac_backlight == bd)
+ pmac_backlight = NULL;
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+
for (i = 0; i < ARRAY_SIZE(bl_class_device_attributes); i++)
class_device_remove_file(&bd->class_dev,
&bl_class_device_attributes[i]);
- down(&bd->sem);
- bd->props = NULL;
- up(&bd->sem);
+ mutex_lock(&bd->ops_lock);
+ bd->ops = NULL;
+ mutex_unlock(&bd->ops_lock);
backlight_unregister_fb(bd);
diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c
index fde1d951812..ce00e18a4e5 100644
--- a/drivers/video/backlight/corgi_bl.c
+++ b/drivers/video/backlight/corgi_bl.c
@@ -22,7 +22,6 @@
#include <asm/hardware/sharpsl_pm.h>
static int corgibl_intensity;
-static DEFINE_MUTEX(bl_mutex);
static struct backlight_properties corgibl_data;
static struct backlight_device *corgi_backlight_device;
static struct corgibl_machinfo *bl_machinfo;
@@ -34,20 +33,18 @@ static unsigned long corgibl_flags;
static int corgibl_send_intensity(struct backlight_device *bd)
{
void (*corgi_kick_batt)(void);
- int intensity = bd->props->brightness;
+ int intensity = bd->props.brightness;
- if (bd->props->power != FB_BLANK_UNBLANK)
+ if (bd->props.power != FB_BLANK_UNBLANK)
intensity = 0;
- if (bd->props->fb_blank != FB_BLANK_UNBLANK)
+ if (bd->props.fb_blank != FB_BLANK_UNBLANK)
intensity = 0;
if (corgibl_flags & CORGIBL_SUSPENDED)
intensity = 0;
if (corgibl_flags & CORGIBL_BATTLOW)
intensity &= bl_machinfo->limit_mask;
- mutex_lock(&bl_mutex);
bl_machinfo->set_bl_intensity(intensity);
- mutex_unlock(&bl_mutex);
corgibl_intensity = intensity;
@@ -61,17 +58,21 @@ static int corgibl_send_intensity(struct backlight_device *bd)
}
#ifdef CONFIG_PM
-static int corgibl_suspend(struct platform_device *dev, pm_message_t state)
+static int corgibl_suspend(struct platform_device *pdev, pm_message_t state)
{
+ struct backlight_device *bd = platform_get_drvdata(pdev);
+
corgibl_flags |= CORGIBL_SUSPENDED;
- corgibl_send_intensity(corgi_backlight_device);
+ backlight_update_status(bd);
return 0;
}
-static int corgibl_resume(struct platform_device *dev)
+static int corgibl_resume(struct platform_device *pdev)
{
+ struct backlight_device *bd = platform_get_drvdata(pdev);
+
corgibl_flags &= ~CORGIBL_SUSPENDED;
- corgibl_send_intensity(corgi_backlight_device);
+ backlight_update_status(bd);
return 0;
}
#else
@@ -84,12 +85,6 @@ static int corgibl_get_intensity(struct backlight_device *bd)
return corgibl_intensity;
}
-static int corgibl_set_intensity(struct backlight_device *bd)
-{
- corgibl_send_intensity(corgi_backlight_device);
- return 0;
-}
-
/*
* Called when the battery is low to limit the backlight intensity.
* If limit==0 clear any limit, otherwise limit the intensity
@@ -100,15 +95,14 @@ void corgibl_limit_intensity(int limit)
corgibl_flags |= CORGIBL_BATTLOW;
else
corgibl_flags &= ~CORGIBL_BATTLOW;
- corgibl_send_intensity(corgi_backlight_device);
+ backlight_update_status(corgi_backlight_device);
}
EXPORT_SYMBOL(corgibl_limit_intensity);
-static struct backlight_properties corgibl_data = {
- .owner = THIS_MODULE,
+static struct backlight_ops corgibl_ops = {
.get_brightness = corgibl_get_intensity,
- .update_status = corgibl_set_intensity,
+ .update_status = corgibl_send_intensity,
};
static int corgibl_probe(struct platform_device *pdev)
@@ -116,30 +110,34 @@ static int corgibl_probe(struct platform_device *pdev)
struct corgibl_machinfo *machinfo = pdev->dev.platform_data;
bl_machinfo = machinfo;
- corgibl_data.max_brightness = machinfo->max_intensity;
if (!machinfo->limit_mask)
machinfo->limit_mask = -1;
corgi_backlight_device = backlight_device_register ("corgi-bl",
- &pdev->dev, NULL, &corgibl_data);
+ &pdev->dev, NULL, &corgibl_ops);
if (IS_ERR (corgi_backlight_device))
return PTR_ERR (corgi_backlight_device);
- corgibl_data.power = FB_BLANK_UNBLANK;
- corgibl_data.brightness = machinfo->default_intensity;
- corgibl_send_intensity(corgi_backlight_device);
+ platform_set_drvdata(pdev, corgi_backlight_device);
+
+ corgi_backlight_device->props.max_brightness = machinfo->max_intensity;
+ corgi_backlight_device->props.power = FB_BLANK_UNBLANK;
+ corgi_backlight_device->props.brightness = machinfo->default_intensity;
+ backlight_update_status(corgi_backlight_device);
printk("Corgi Backlight Driver Initialized.\n");
return 0;
}
-static int corgibl_remove(struct platform_device *dev)
+static int corgibl_remove(struct platform_device *pdev)
{
+ struct backlight_device *bd = platform_get_drvdata(pdev);
+
corgibl_data.power = 0;
corgibl_data.brightness = 0;
- corgibl_send_intensity(corgi_backlight_device);
+ backlight_update_status(bd);
- backlight_device_unregister(corgi_backlight_device);
+ backlight_device_unregister(bd);
printk("Corgi Backlight Driver Unloaded\n");
return 0;
diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c
index c07d8207fb5..0899fccbd57 100644
--- a/drivers/video/backlight/hp680_bl.c
+++ b/drivers/video/backlight/hp680_bl.c
@@ -28,17 +28,16 @@
static int hp680bl_suspended;
static int current_intensity = 0;
static DEFINE_SPINLOCK(bl_lock);
-static struct backlight_device *hp680_backlight_device;
static void hp680bl_send_intensity(struct backlight_device *bd)
{
unsigned long flags;
u16 v;
- int intensity = bd->props->brightness;
+ int intensity = bd->props.brightness;
- if (bd->props->power != FB_BLANK_UNBLANK)
+ if (bd->props.power != FB_BLANK_UNBLANK)
intensity = 0;
- if (bd->props->fb_blank != FB_BLANK_UNBLANK)
+ if (bd->props.fb_blank != FB_BLANK_UNBLANK)
intensity = 0;
if (hp680bl_suspended)
intensity = 0;
@@ -66,17 +65,21 @@ static void hp680bl_send_intensity(struct backlight_device *bd)
#ifdef CONFIG_PM
-static int hp680bl_suspend(struct platform_device *dev, pm_message_t state)
+static int hp680bl_suspend(struct platform_device *pdev, pm_message_t state)
{
+ struct backlight_device *bd = platform_get_drvdata(pdev);
+
hp680bl_suspended = 1;
- hp680bl_send_intensity(hp680_backlight_device);
+ hp680bl_send_intensity(bd);
return 0;
}
-static int hp680bl_resume(struct platform_device *dev)
+static int hp680bl_resume(struct platform_device *pdev)
{
+ struct backlight_device *bd = platform_get_drvdata(pdev);
+
hp680bl_suspended = 0;
- hp680bl_send_intensity(hp680_backlight_device);
+ hp680bl_send_intensity(bd);
return 0;
}
#else
@@ -95,33 +98,38 @@ static int hp680bl_get_intensity(struct backlight_device *bd)
return current_intensity;
}
-static struct backlight_properties hp680bl_data = {
- .owner = THIS_MODULE,
- .max_brightness = HP680_MAX_INTENSITY,
+static struct backlight_ops hp680bl_ops = {
.get_brightness = hp680bl_get_intensity,
.update_status = hp680bl_set_intensity,
};
-static int __init hp680bl_probe(struct platform_device *dev)
+static int __init hp680bl_probe(struct platform_device *pdev)
{
- hp680_backlight_device = backlight_device_register ("hp680-bl",
- &dev->dev, NULL, &hp680bl_data);
- if (IS_ERR (hp680_backlight_device))
- return PTR_ERR (hp680_backlight_device);
+ struct backlight_device *bd;
+
+ bd = backlight_device_register ("hp680-bl", &pdev->dev, NULL,
+ &hp680bl_ops);
+ if (IS_ERR(bd))
+ return PTR_ERR(bd);
- hp680_backlight_device->props->brightness = HP680_DEFAULT_INTENSITY;
- hp680bl_send_intensity(hp680_backlight_device);
+ platform_set_drvdata(pdev, bd);
+
+ bd->props.max_brightness = HP680_MAX_INTENSITY;
+ bd->props.brightness = HP680_DEFAULT_INTENSITY;
+ hp680bl_send_intensity(bd);
return 0;
}
-static int hp680bl_remove(struct platform_device *dev)
+static int hp680bl_remove(struct platform_device *pdev)
{
+ struct backlight_device *bd = platform_get_drvdata(pdev);
+
hp680bl_data.brightness = 0;
hp680bl_data.power = 0;
- hp680bl_send_intensity(hp680_backlight_device);
+ hp680bl_send_intensity(bd);
- backlight_device_unregister(hp680_backlight_device);
+ backlight_device_unregister(bd);
return 0;
}
diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c
index f6e041627ed..6ef8f0a7a13 100644
--- a/drivers/video/backlight/lcd.c
+++ b/drivers/video/backlight/lcd.c
@@ -31,11 +31,11 @@ static int fb_notifier_callback(struct notifier_block *self,
return 0;
ld = container_of(self, struct lcd_device, fb_notif);
- down(&ld->sem);
- if (ld->props)
- if (!ld->props->check_fb || ld->props->check_fb(evdata->info))
- ld->props->set_power(ld, *(int *)evdata->data);
- up(&ld->sem);
+ mutex_lock(&ld->ops_lock);
+ if (ld->ops)
+ if (!ld->ops->check_fb || ld->ops->check_fb(evdata->info))
+ ld->ops->set_power(ld, *(int *)evdata->data);
+ mutex_unlock(&ld->ops_lock);
return 0;
}
@@ -66,12 +66,12 @@ static ssize_t lcd_show_power(struct class_device *cdev, char *buf)
int rc;
struct lcd_device *ld = to_lcd_device(cdev);
- down(&ld->sem);
- if (likely(ld->props && ld->props->get_power))
- rc = sprintf(buf, "%d\n", ld->props->get_power(ld));
+ mutex_lock(&ld->ops_lock);
+ if (ld->ops && ld->ops->get_power)
+ rc = sprintf(buf, "%d\n", ld->ops->get_power(ld));
else
rc = -ENXIO;
- up(&ld->sem);
+ mutex_unlock(&ld->ops_lock);
return rc;
}
@@ -89,13 +89,13 @@ static ssize_t lcd_store_power(struct class_device *cdev, const char *buf, size_
if (size != count)
return -EINVAL;
- down(&ld->sem);
- if (likely(ld->props && ld->props->set_power)) {
+ mutex_lock(&ld->ops_lock);
+ if (ld->ops && ld->ops->set_power) {
pr_debug("lcd: set power to %d\n", power);
- ld->props->set_power(ld, power);
+ ld->ops->set_power(ld, power);
rc = count;
}
- up(&ld->sem);
+ mutex_unlock(&ld->ops_lock);
return rc;
}
@@ -105,10 +105,10 @@ static ssize_t lcd_show_contrast(struct class_device *cdev, char *buf)
int rc = -ENXIO;
struct lcd_device *ld = to_lcd_device(cdev);
- down(&ld->sem);
- if (likely(ld->props && ld->props->get_contrast))
- rc = sprintf(buf, "%d\n", ld->props->get_contrast(ld));
- up(&ld->sem);
+ mutex_lock(&ld->ops_lock);
+ if (ld->ops && ld->ops->get_contrast)
+ rc = sprintf(buf, "%d\n", ld->ops->get_contrast(ld));
+ mutex_unlock(&ld->ops_lock);
return rc;
}
@@ -126,28 +126,22 @@ static ssize_t lcd_store_contrast(struct class_device *cdev, const char *buf, si
if (size != count)
return -EINVAL;
- down(&ld->sem);
- if (likely(ld->props && ld->props->set_contrast)) {
+ mutex_lock(&ld->ops_lock);
+ if (ld->ops && ld->ops->set_contrast) {
pr_debug("lcd: set contrast to %d\n", contrast);
- ld->props->set_contrast(ld, contrast);
+ ld->ops->set_contrast(ld, contrast);
rc = count;
}
- up(&ld->sem);
+ mutex_unlock(&ld->ops_lock);
return rc;
}
static ssize_t lcd_show_max_contrast(struct class_device *cdev, char *buf)
{
- int rc = -ENXIO;
struct lcd_device *ld = to_lcd_device(cdev);
- down(&ld->sem);
- if (likely(ld->props))
- rc = sprintf(buf, "%d\n", ld->props->max_contrast);
- up(&ld->sem);
-
- return rc;
+ return sprintf(buf, "%d\n", ld->props.max_contrast);
}
static void lcd_class_release(struct class_device *dev)
@@ -180,45 +174,46 @@ static const struct class_device_attribute lcd_class_device_attributes[] = {
* respective framebuffer device).
* @devdata: an optional pointer to be stored in the class_device. The
* methods may retrieve it by using class_get_devdata(ld->class_dev).
- * @lp: the lcd properties structure.
+ * @ops: the lcd operations structure.
*
* Creates and registers a new lcd class_device. Returns either an ERR_PTR()
* or a pointer to the newly allocated device.
*/
struct lcd_device *lcd_device_register(const char *name, void *devdata,
- struct lcd_properties *lp)
+ struct lcd_ops *ops)
{
int i, rc;
struct lcd_device *new_ld;
pr_debug("lcd_device_register: name=%s\n", name);
- new_ld = kmalloc(sizeof(struct lcd_device), GFP_KERNEL);
- if (unlikely(!new_ld))
+ new_ld = kzalloc(sizeof(struct lcd_device), GFP_KERNEL);
+ if (!new_ld)
return ERR_PTR(-ENOMEM);
- init_MUTEX(&new_ld->sem);
- new_ld->props = lp;
- memset(&new_ld->class_dev, 0, sizeof(new_ld->class_dev));
+ mutex_init(&new_ld->ops_lock);
+ mutex_init(&new_ld->update_lock);
+ new_ld->ops = ops;
new_ld->class_dev.class = &lcd_class;
strlcpy(new_ld->class_dev.class_id, name, KOBJ_NAME_LEN);
class_set_devdata(&new_ld->class_dev, devdata);
rc = class_device_register(&new_ld->class_dev);
- if (unlikely(rc)) {
-error: kfree(new_ld);
+ if (rc) {
+ kfree(new_ld);
return ERR_PTR(rc);
}
rc = lcd_register_fb(new_ld);
-
- if (unlikely(rc))
- goto error;
+ if (rc) {
+ class_device_unregister(&new_ld->class_dev);
+ return ERR_PTR(rc);
+ }
for (i = 0; i < ARRAY_SIZE(lcd_class_device_attributes); i++) {
rc = class_device_create_file(&new_ld->class_dev,
&lcd_class_device_attributes[i]);
- if (unlikely(rc)) {
+ if (rc) {
while (--i >= 0)
class_device_remove_file(&new_ld->class_dev,
&lcd_class_device_attributes[i]);
@@ -251,9 +246,9 @@ void lcd_device_unregister(struct lcd_device *ld)
class_device_remove_file(&ld->class_dev,
&lcd_class_device_attributes[i]);
- down(&ld->sem);
- ld->props = NULL;
- up(&ld->sem);
+ mutex_lock(&ld->ops_lock);
+ ld->ops = NULL;
+ mutex_unlock(&ld->ops_lock);
lcd_unregister_fb(ld);
class_device_unregister(&ld->class_dev);
}
diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c
index fc812d96c31..6b488b8a7ee 100644
--- a/drivers/video/backlight/locomolcd.c
+++ b/drivers/video/backlight/locomolcd.c
@@ -112,11 +112,11 @@ static int current_intensity;
static int locomolcd_set_intensity(struct backlight_device *bd)
{
- int intensity = bd->props->brightness;
+ int intensity = bd->props.brightness;
- if (bd->props->power != FB_BLANK_UNBLANK)
+ if (bd->props.power != FB_BLANK_UNBLANK)
intensity = 0;
- if (bd->props->fb_blank != FB_BLANK_UNBLANK)
+ if (bd->props.fb_blank != FB_BLANK_UNBLANK)
intensity = 0;
if (locomolcd_flags & LOCOMOLCD_SUSPENDED)
intensity = 0;
@@ -141,11 +141,9 @@ static int locomolcd_get_intensity(struct backlight_device *bd)
return current_intensity;
}
-static struct backlight_properties locomobl_data = {
- .owner = THIS_MODULE,
+static struct backlight_ops locomobl_data = {
.get_brightness = locomolcd_get_intensity,
.update_status = locomolcd_set_intensity,
- .max_brightness = 4,
};
#ifdef CONFIG_PM
@@ -190,7 +188,8 @@ static int locomolcd_probe(struct locomo_dev *ldev)
return PTR_ERR (locomolcd_bl_device);
/* Set up frontlight so that screen is readable */
- locomobl_data.brightness = 2;
+ locomolcd_bl_device->props.max_brightness = 4,
+ locomolcd_bl_device->props.brightness = 2;
locomolcd_set_intensity(locomolcd_bl_device);
return 0;
@@ -200,8 +199,8 @@ static int locomolcd_remove(struct locomo_dev *dev)
{
unsigned long flags;
- locomobl_data.brightness = 0;
- locomobl_data.power = 0;
+ locomolcd_bl_device->props.brightness = 0;
+ locomolcd_bl_device->props.power = 0;
locomolcd_set_intensity(locomolcd_bl_device);
backlight_device_unregister(locomolcd_bl_device);
diff --git a/drivers/video/backlight/progear_bl.c b/drivers/video/backlight/progear_bl.c
new file mode 100644
index 00000000000..836ab4df0ef
--- /dev/null
+++ b/drivers/video/backlight/progear_bl.c
@@ -0,0 +1,153 @@
+/*
+ * Backlight Driver for Frontpath ProGear HX1050+
+ *
+ * Copyright (c) 2006 Marcin Juszkiewicz
+ *
+ * Based on Progear LCD driver by M Schacht
+ * <mschacht at alumni dot washington dot edu>
+ *
+ * Based on Sharp's Corgi Backlight Driver
+ * Based on Backlight Driver for HP Jornada 680
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+#include <linux/pci.h>
+#include <asm/uaccess.h>
+
+#define PMU_LPCR 0xB0
+#define SB_MPS1 0x61
+#define HW_LEVEL_MAX 0x77
+#define HW_LEVEL_MIN 0x4f
+
+static struct pci_dev *pmu_dev = NULL;
+static struct pci_dev *sb_dev = NULL;
+
+static int progearbl_set_intensity(struct backlight_device *bd)
+{
+ int intensity = bd->props.brightness;
+
+ if (bd->props.power != FB_BLANK_UNBLANK)
+ intensity = 0;
+ if (bd->props.fb_blank != FB_BLANK_UNBLANK)
+ intensity = 0;
+
+ pci_write_config_byte(pmu_dev, PMU_LPCR, intensity + HW_LEVEL_MIN);
+
+ return 0;
+}
+
+static int progearbl_get_intensity(struct backlight_device *bd)
+{
+ u8 intensity;
+ pci_read_config_byte(pmu_dev, PMU_LPCR, &intensity);
+
+ return intensity - HW_LEVEL_MIN;
+}
+
+static struct backlight_ops progearbl_ops = {
+ .get_brightness = progearbl_get_intensity,
+ .update_status = progearbl_set_intensity,
+};
+
+static int progearbl_probe(struct platform_device *pdev)
+{
+ u8 temp;
+ struct backlight_device *progear_backlight_device;
+
+ pmu_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, NULL);
+ if (!pmu_dev) {
+ printk("ALI M7101 PMU not found.\n");
+ return -ENODEV;
+ }
+
+ sb_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
+ if (!sb_dev) {
+ printk("ALI 1533 SB not found.\n");
+ pci_dev_put(pmu_dev);
+ return -ENODEV;
+ }
+
+ /* Set SB_MPS1 to enable brightness control. */
+ pci_read_config_byte(sb_dev, SB_MPS1, &temp);
+ pci_write_config_byte(sb_dev, SB_MPS1, temp | 0x20);
+
+ progear_backlight_device = backlight_device_register("progear-bl",
+ &pdev->dev, NULL,
+ &progearbl_ops);
+ if (IS_ERR(progear_backlight_device))
+ return PTR_ERR(progear_backlight_device);
+
+ platform_set_drvdata(pdev, progear_backlight_device);
+
+ progear_backlight_device->props.power = FB_BLANK_UNBLANK;
+ progear_backlight_device->props.brightness = HW_LEVEL_MAX - HW_LEVEL_MIN;
+ progear_backlight_device->props.max_brightness = HW_LEVEL_MAX - HW_LEVEL_MIN;
+ progearbl_set_intensity(progear_backlight_device);
+
+ return 0;
+}
+
+static int progearbl_remove(struct platform_device *pdev)
+{
+ struct backlight_device *bd = platform_get_drvdata(pdev);
+ backlight_device_unregister(bd);
+
+ return 0;
+}
+
+static struct platform_driver progearbl_driver = {
+ .probe = progearbl_probe,
+ .remove = progearbl_remove,
+ .driver = {
+ .name = "progear-bl",
+ },
+};
+
+static struct platform_device *progearbl_device;
+
+static int __init progearbl_init(void)
+{
+ int ret = platform_driver_register(&progearbl_driver);
+
+ if (!ret) {
+ progearbl_device = platform_device_alloc("progear-bl", -1);
+ if (!progearbl_device)
+ return -ENOMEM;
+
+ ret = platform_device_add(progearbl_device);
+
+ if (ret) {
+ platform_device_put(progearbl_device);
+ platform_driver_unregister(&progearbl_driver);
+ }
+ }
+
+ return ret;
+}
+
+static void __exit progearbl_exit(void)
+{
+ pci_dev_put(pmu_dev);
+ pci_dev_put(sb_dev);
+
+ platform_device_unregister(progearbl_device);
+ platform_driver_unregister(&progearbl_driver);
+}
+
+module_init(progearbl_init);
+module_exit(progearbl_exit);
+
+MODULE_AUTHOR("Marcin Juszkiewicz <linux@hrw.one.pl>");
+MODULE_DESCRIPTION("ProGear Backlight Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c
index 9bb6257d691..b0b2e40bbd9 100644
--- a/drivers/video/bw2.c
+++ b/drivers/video/bw2.c
@@ -186,8 +186,7 @@ static int bw2_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
* Initialisation
*/
-static void
-bw2_init_fix(struct fb_info *info, int linebytes)
+static void __devinit bw2_init_fix(struct fb_info *info, int linebytes)
{
strlcpy(info->fix.id, "bwtwo", sizeof(info->fix.id));
@@ -199,43 +198,44 @@ bw2_init_fix(struct fb_info *info, int linebytes)
info->fix.accel = FB_ACCEL_SUN_BWTWO;
}
-static u8 bw2regs_1600[] __initdata = {
+static u8 bw2regs_1600[] __devinitdata = {
0x14, 0x8b, 0x15, 0x28, 0x16, 0x03, 0x17, 0x13,
0x18, 0x7b, 0x19, 0x05, 0x1a, 0x34, 0x1b, 0x2e,
0x1c, 0x00, 0x1d, 0x0a, 0x1e, 0xff, 0x1f, 0x01,
0x10, 0x21, 0
};
-static u8 bw2regs_ecl[] __initdata = {
+static u8 bw2regs_ecl[] __devinitdata = {
0x14, 0x65, 0x15, 0x1e, 0x16, 0x04, 0x17, 0x0c,
0x18, 0x5e, 0x19, 0x03, 0x1a, 0xa7, 0x1b, 0x23,
0x1c, 0x00, 0x1d, 0x08, 0x1e, 0xff, 0x1f, 0x01,
0x10, 0x20, 0
};
-static u8 bw2regs_analog[] __initdata = {
+static u8 bw2regs_analog[] __devinitdata = {
0x14, 0xbb, 0x15, 0x2b, 0x16, 0x03, 0x17, 0x13,
0x18, 0xb0, 0x19, 0x03, 0x1a, 0xa6, 0x1b, 0x22,
0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
0x10, 0x20, 0
};
-static u8 bw2regs_76hz[] __initdata = {
+static u8 bw2regs_76hz[] __devinitdata = {
0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f,
0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a,
0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01,
0x10, 0x24, 0
};
-static u8 bw2regs_66hz[] __initdata = {
+static u8 bw2regs_66hz[] __devinitdata = {
0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14,
0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24,
0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
0x10, 0x20, 0
};
-static void bw2_do_default_mode(struct bw2_par *par, struct fb_info *info,
- int *linebytes)
+static void __devinit bw2_do_default_mode(struct bw2_par *par,
+ struct fb_info *info,
+ int *linebytes)
{
u8 status, mon;
u8 *p;
diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c
index ec6a51a5822..b071bb632b9 100644
--- a/drivers/video/cg14.c
+++ b/drivers/video/cg14.c
@@ -354,7 +354,8 @@ static int cg14_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
* Initialisation
*/
-static void cg14_init_fix(struct fb_info *info, int linebytes, struct device_node *dp)
+static void __devinit cg14_init_fix(struct fb_info *info, int linebytes,
+ struct device_node *dp)
{
const char *name = dp->name;
@@ -368,7 +369,7 @@ static void cg14_init_fix(struct fb_info *info, int linebytes, struct device_nod
info->fix.accel = FB_ACCEL_SUN_CG14;
}
-static struct sbus_mmap_map __cg14_mmap_map[CG14_MMAP_ENTRIES] __initdata = {
+static struct sbus_mmap_map __cg14_mmap_map[CG14_MMAP_ENTRIES] __devinitdata = {
{
.voff = CG14_REGS,
.poff = 0x80000000,
diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c
index ada6f7e3a89..f042428a84f 100644
--- a/drivers/video/cg3.c
+++ b/drivers/video/cg3.c
@@ -186,8 +186,7 @@ static int cg3_setcolreg(unsigned regno,
* @blank_mode: the blank mode we want.
* @info: frame buffer structure that represents a single frame buffer
*/
-static int
-cg3_blank(int blank, struct fb_info *info)
+static int cg3_blank(int blank, struct fb_info *info)
{
struct cg3_par *par = (struct cg3_par *) info->par;
struct cg3_regs __iomem *regs = par->regs;
@@ -251,8 +250,8 @@ static int cg3_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
* Initialisation
*/
-static void
-cg3_init_fix(struct fb_info *info, int linebytes, struct device_node *dp)
+static void __devinit cg3_init_fix(struct fb_info *info, int linebytes,
+ struct device_node *dp)
{
strlcpy(info->fix.id, dp->name, sizeof(info->fix.id));
@@ -264,10 +263,10 @@ cg3_init_fix(struct fb_info *info, int linebytes, struct device_node *dp)
info->fix.accel = FB_ACCEL_SUN_CGTHREE;
}
-static void cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo *var,
- struct device_node *dp)
+static void __devinit cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo *var,
+ struct device_node *dp)
{
- char *params;
+ const char *params;
char *p;
int ww, hh;
@@ -287,36 +286,36 @@ static void cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo *var,
}
}
-static u8 cg3regvals_66hz[] __initdata = { /* 1152 x 900, 66 Hz */
+static u8 cg3regvals_66hz[] __devinitdata = { /* 1152 x 900, 66 Hz */
0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14,
0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24,
0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
0x10, 0x20, 0
};
-static u8 cg3regvals_76hz[] __initdata = { /* 1152 x 900, 76 Hz */
+static u8 cg3regvals_76hz[] __devinitdata = { /* 1152 x 900, 76 Hz */
0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f,
0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a,
0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01,
0x10, 0x24, 0
};
-static u8 cg3regvals_rdi[] __initdata = { /* 640 x 480, cgRDI */
+static u8 cg3regvals_rdi[] __devinitdata = { /* 640 x 480, cgRDI */
0x14, 0x70, 0x15, 0x20, 0x16, 0x08, 0x17, 0x10,
0x18, 0x06, 0x19, 0x02, 0x1a, 0x31, 0x1b, 0x51,
0x1c, 0x06, 0x1d, 0x0c, 0x1e, 0xff, 0x1f, 0x01,
0x10, 0x22, 0
};
-static u8 *cg3_regvals[] __initdata = {
+static u8 *cg3_regvals[] __devinitdata = {
cg3regvals_66hz, cg3regvals_76hz, cg3regvals_rdi
};
-static u_char cg3_dacvals[] __initdata = {
+static u_char cg3_dacvals[] __devinitdata = {
4, 0xff, 5, 0x00, 6, 0x70, 7, 0x00, 0
};
-static void cg3_do_default_mode(struct cg3_par *par)
+static void __devinit cg3_do_default_mode(struct cg3_par *par)
{
enum cg3_type type;
u8 *p;
@@ -433,7 +432,8 @@ static int __devinit cg3_init_one(struct of_device *op)
return 0;
}
-static int __devinit cg3_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit cg3_probe(struct of_device *dev,
+ const struct of_device_id *match)
{
struct of_device *op = to_of_device(&dev->dev);
diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c
index 73cb426bf2d..af313bf1a2d 100644
--- a/drivers/video/chipsfb.c
+++ b/drivers/video/chipsfb.c
@@ -145,26 +145,6 @@ static int chipsfb_set_par(struct fb_info *info)
static int chipsfb_blank(int blank, struct fb_info *info)
{
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_lock(&pmac_backlight_mutex);
-
- if (pmac_backlight) {
- /* used to disable backlight only for blank > 1, but it seems
- * useful at blank = 1 too (saves battery, extends backlight
- * life)
- */
- down(&pmac_backlight->sem);
- if (blank)
- pmac_backlight->props->power = FB_BLANK_POWERDOWN;
- else
- pmac_backlight->props->power = FB_BLANK_UNBLANK;
- pmac_backlight->props->update_status(pmac_backlight);
- up(&pmac_backlight->sem);
- }
-
- mutex_unlock(&pmac_backlight_mutex);
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
return 1; /* get fb_blank to set the colormap to all black */
}
@@ -415,10 +395,8 @@ chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
/* turn on the backlight */
mutex_lock(&pmac_backlight_mutex);
if (pmac_backlight) {
- down(&pmac_backlight->sem);
- pmac_backlight->props->power = FB_BLANK_UNBLANK;
- pmac_backlight->props->update_status(pmac_backlight);
- up(&pmac_backlight->sem);
+ pmac_backlight->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(pmac_backlight);
}
mutex_unlock(&pmac_backlight_mutex);
#endif /* CONFIG_PMAC_BACKLIGHT */
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index be3f2c3f132..0429fd2cece 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -2233,6 +2233,8 @@ static int fbcon_switch(struct vc_data *vc)
static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info,
int blank)
{
+ struct fb_event event;
+
if (blank) {
unsigned short charmask = vc->vc_hi_font_mask ?
0x1ff : 0xff;
@@ -2243,6 +2245,11 @@ static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info,
fbcon_clear(vc, 0, 0, vc->vc_rows, vc->vc_cols);
vc->vc_video_erase_char = oldc;
}
+
+
+ event.info = info;
+ event.data = &blank;
+ fb_notifier_call_chain(FB_EVENT_CONBLANK, &event);
}
static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c
index fd60dba294d..8b762739b1e 100644
--- a/drivers/video/controlfb.c
+++ b/drivers/video/controlfb.c
@@ -179,12 +179,14 @@ MODULE_LICENSE("GPL");
int init_module(void)
{
struct device_node *dp;
+ int ret = -ENXIO;
- dp = find_devices("control");
+ dp = of_find_node_by_name(NULL, "control");
if (dp != 0 && !control_of_init(dp))
- return 0;
+ ret = 0;
+ of_node_put(dp);
- return -ENXIO;
+ return ret;
}
void cleanup_module(void)
@@ -589,16 +591,18 @@ static int __init control_init(void)
{
struct device_node *dp;
char *option = NULL;
+ int ret = -ENXIO;
if (fb_get_options("controlfb", &option))
return -ENODEV;
control_setup(option);
- dp = find_devices("control");
+ dp = of_find_node_by_name(NULL, "control");
if (dp != 0 && !control_of_init(dp))
- return 0;
+ ret = 0;
+ of_node_put(dp);
- return -ENXIO;
+ return ret;
}
module_init(control_init);
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
index 818fb09105f..40c80c8190e 100644
--- a/drivers/video/fbsysfs.c
+++ b/drivers/video/fbsysfs.c
@@ -59,7 +59,7 @@ struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
info->device = dev;
#ifdef CONFIG_FB_BACKLIGHT
- mutex_init(&info->bl_mutex);
+ mutex_init(&info->bl_curve_mutex);
#endif
return info;
@@ -445,10 +445,10 @@ static ssize_t store_bl_curve(struct device *device,
/* If there has been an error in the input data, we won't
* reach this loop.
*/
- mutex_lock(&fb_info->bl_mutex);
+ mutex_lock(&fb_info->bl_curve_mutex);
for (i = 0; i < FB_BACKLIGHT_LEVELS; ++i)
fb_info->bl_curve[i] = tmp_curve[i];
- mutex_unlock(&fb_info->bl_mutex);
+ mutex_unlock(&fb_info->bl_curve_mutex);
return count;
}
@@ -466,7 +466,7 @@ static ssize_t show_bl_curve(struct device *device,
if (!fb_info || !fb_info->bl_dev)
return -ENODEV;
- mutex_lock(&fb_info->bl_mutex);
+ mutex_lock(&fb_info->bl_curve_mutex);
for (i = 0; i < FB_BACKLIGHT_LEVELS; i += 8)
len += snprintf(&buf[len], PAGE_SIZE,
"%02x %02x %02x %02x %02x %02x %02x %02x\n",
@@ -478,7 +478,7 @@ static ssize_t show_bl_curve(struct device *device,
fb_info->bl_curve[i + 5],
fb_info->bl_curve[i + 6],
fb_info->bl_curve[i + 7]);
- mutex_unlock(&fb_info->bl_mutex);
+ mutex_unlock(&fb_info->bl_curve_mutex);
return len;
}
@@ -552,6 +552,8 @@ void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max)
{
unsigned int i, flat, count, range = (max - min);
+ mutex_lock(&fb_info->bl_curve_mutex);
+
fb_info->bl_curve[0] = off;
for (flat = 1; flat < (FB_BACKLIGHT_LEVELS / 16); ++flat)
@@ -560,6 +562,8 @@ void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max)
count = FB_BACKLIGHT_LEVELS * 15 / 16;
for (i = 0; i < count; ++i)
fb_info->bl_curve[flat + i] = min + (range * (i + 1) / count);
+
+ mutex_unlock(&fb_info->bl_curve_mutex);
}
EXPORT_SYMBOL_GPL(fb_bl_default_curve);
#endif
diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c
index 15854aec318..1d4e8354b56 100644
--- a/drivers/video/ffb.c
+++ b/drivers/video/ffb.c
@@ -336,14 +336,30 @@ struct ffb_dac {
u32 value2;
};
+#define FFB_DAC_UCTRL 0x1001 /* User Control */
+#define FFB_DAC_UCTRL_MANREV 0x00000f00 /* 4-bit Manufacturing Revision */
+#define FFB_DAC_UCTRL_MANREV_SHIFT 8
+#define FFB_DAC_TGEN 0x6000 /* Timing Generator */
+#define FFB_DAC_TGEN_VIDE 0x00000001 /* Video Enable */
+#define FFB_DAC_DID 0x8000 /* Device Identification */
+#define FFB_DAC_DID_PNUM 0x0ffff000 /* Device Part Number */
+#define FFB_DAC_DID_PNUM_SHIFT 12
+#define FFB_DAC_DID_REV 0xf0000000 /* Device Revision */
+#define FFB_DAC_DID_REV_SHIFT 28
+
+#define FFB_DAC_CUR_CTRL 0x100
+#define FFB_DAC_CUR_CTRL_P0 0x00000001
+#define FFB_DAC_CUR_CTRL_P1 0x00000002
+
struct ffb_par {
spinlock_t lock;
struct ffb_fbc __iomem *fbc;
struct ffb_dac __iomem *dac;
u32 flags;
-#define FFB_FLAG_AFB 0x00000001
-#define FFB_FLAG_BLANKED 0x00000002
+#define FFB_FLAG_AFB 0x00000001 /* AFB m3 or m6 */
+#define FFB_FLAG_BLANKED 0x00000002 /* screen is blanked */
+#define FFB_FLAG_INVCURSOR 0x00000004 /* DAC has inverted cursor logic */
u32 fg_cache __attribute__((aligned (8)));
u32 bg_cache;
@@ -354,7 +370,6 @@ struct ffb_par {
unsigned long physbase;
unsigned long fbsize;
- int dac_rev;
int board_type;
};
@@ -426,11 +441,12 @@ static void ffb_switch_from_graph(struct ffb_par *par)
FFBWait(par);
/* Disable cursor. */
- upa_writel(0x100, &dac->type2);
- if (par->dac_rev <= 2)
+ upa_writel(FFB_DAC_CUR_CTRL, &dac->type2);
+ if (par->flags & FFB_FLAG_INVCURSOR)
upa_writel(0, &dac->value2);
else
- upa_writel(3, &dac->value2);
+ upa_writel((FFB_DAC_CUR_CTRL_P0 |
+ FFB_DAC_CUR_CTRL_P1), &dac->value2);
spin_unlock_irqrestore(&par->lock, flags);
}
@@ -664,18 +680,18 @@ ffb_blank(int blank, struct fb_info *info)
struct ffb_par *par = (struct ffb_par *) info->par;
struct ffb_dac __iomem *dac = par->dac;
unsigned long flags;
- u32 tmp;
+ u32 val;
+ int i;
spin_lock_irqsave(&par->lock, flags);
FFBWait(par);
+ upa_writel(FFB_DAC_TGEN, &dac->type);
+ val = upa_readl(&dac->value);
switch (blank) {
case FB_BLANK_UNBLANK: /* Unblanking */
- upa_writel(0x6000, &dac->type);
- tmp = (upa_readl(&dac->value) | 0x1);
- upa_writel(0x6000, &dac->type);
- upa_writel(tmp, &dac->value);
+ val |= FFB_DAC_TGEN_VIDE;
par->flags &= ~FFB_FLAG_BLANKED;
break;
@@ -683,13 +699,16 @@ ffb_blank(int blank, struct fb_info *info)
case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
case FB_BLANK_POWERDOWN: /* Poweroff */
- upa_writel(0x6000, &dac->type);
- tmp = (upa_readl(&dac->value) & ~0x1);
- upa_writel(0x6000, &dac->type);
- upa_writel(tmp, &dac->value);
+ val &= ~FFB_DAC_TGEN_VIDE;
par->flags |= FFB_FLAG_BLANKED;
break;
}
+ upa_writel(FFB_DAC_TGEN, &dac->type);
+ upa_writel(val, &dac->value);
+ for (i = 0; i < 10; i++) {
+ upa_writel(FFB_DAC_TGEN, &dac->type);
+ upa_readl(&dac->value);
+ }
spin_unlock_irqrestore(&par->lock, flags);
@@ -894,6 +913,7 @@ static int ffb_init_one(struct of_device *op)
struct ffb_dac __iomem *dac;
struct all_info *all;
int err;
+ u32 dac_pnum, dac_rev, dac_mrev;
all = kzalloc(sizeof(*all), GFP_KERNEL);
if (!all)
@@ -948,17 +968,31 @@ static int ffb_init_one(struct of_device *op)
if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0)
upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr);
- ffb_switch_from_graph(&all->par);
-
dac = all->par.dac;
- upa_writel(0x8000, &dac->type);
- all->par.dac_rev = upa_readl(&dac->value) >> 0x1c;
+ upa_writel(FFB_DAC_DID, &dac->type);
+ dac_pnum = upa_readl(&dac->value);
+ dac_rev = (dac_pnum & FFB_DAC_DID_REV) >> FFB_DAC_DID_REV_SHIFT;
+ dac_pnum = (dac_pnum & FFB_DAC_DID_PNUM) >> FFB_DAC_DID_PNUM_SHIFT;
+
+ upa_writel(FFB_DAC_UCTRL, &dac->type);
+ dac_mrev = upa_readl(&dac->value);
+ dac_mrev = (dac_mrev & FFB_DAC_UCTRL_MANREV) >>
+ FFB_DAC_UCTRL_MANREV_SHIFT;
/* Elite3D has different DAC revision numbering, and no DAC revisions
- * have the reversed meaning of cursor enable.
+ * have the reversed meaning of cursor enable. Otherwise, Pacifica 1
+ * ramdacs with manufacturing revision less than 3 have inverted
+ * cursor logic. We identify Pacifica 1 as not Pacifica 2, the
+ * latter having a part number value of 0x236e.
*/
- if (all->par.flags & FFB_FLAG_AFB)
- all->par.dac_rev = 10;
+ if ((all->par.flags & FFB_FLAG_AFB) || dac_pnum == 0x236e) {
+ all->par.flags &= ~FFB_FLAG_INVCURSOR;
+ } else {
+ if (dac_mrev < 3)
+ all->par.flags |= FFB_FLAG_INVCURSOR;
+ }
+
+ ffb_switch_from_graph(&all->par);
/* Unblank it just to be sure. When there are multiple
* FFB/AFB cards in the system, or it is not the OBP
@@ -993,10 +1027,12 @@ static int ffb_init_one(struct of_device *op)
dev_set_drvdata(&op->dev, all);
- printk("%s: %s at %016lx, type %d, DAC revision %d\n",
+ printk("%s: %s at %016lx, type %d, "
+ "DAC pnum[%x] rev[%d] manuf_rev[%d]\n",
dp->full_name,
((all->par.flags & FFB_FLAG_AFB) ? "AFB" : "FFB"),
- all->par.physbase, all->par.board_type, all->par.dac_rev);
+ all->par.physbase, all->par.board_type,
+ dac_pnum, dac_rev, dac_mrev);
return 0;
}
diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c
index ab1b8fe34d6..7e760197cf2 100644
--- a/drivers/video/i810/i810_main.c
+++ b/drivers/video/i810/i810_main.c
@@ -142,7 +142,7 @@ static int hsync2 __devinitdata;
static int vsync1 __devinitdata;
static int vsync2 __devinitdata;
static int xres __devinitdata;
-static int yres __devinitdata;
+static int yres;
static int vyres __devinitdata;
static int sync __devinitdata;
static int extvga __devinitdata;
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
index 90592fb5915..eb1a4812ad1 100644
--- a/drivers/video/igafb.c
+++ b/drivers/video/igafb.c
@@ -44,8 +44,8 @@
#include <asm/io.h>
-#ifdef __sparc__
-#include <asm/pbm.h>
+#ifdef CONFIG_SPARC
+#include <asm/prom.h>
#include <asm/pcic.h>
#endif
@@ -96,7 +96,7 @@ struct fb_var_screeninfo default_var = {
.vmode = FB_VMODE_NONINTERLACED
};
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
struct fb_var_screeninfo default_var_1024x768 __initdata = {
/* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */
.xres = 1024,
@@ -188,7 +188,7 @@ static inline void iga_outb(struct iga_par *par, unsigned char val,
pci_outb(par, val, reg+1);
}
-#endif /* __sparc__ */
+#endif /* CONFIG_SPARC */
/*
* Very important functionality for the JavaEngine1 computer:
@@ -217,7 +217,7 @@ static void iga_blank_border(struct iga_par *par)
iga_outb(par, 0, IGA_EXT_CNTRL, IGA_IDX_OVERSCAN_COLOR + i);
}
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
static int igafb_mmap(struct fb_info *info,
struct vm_area_struct *vma)
{
@@ -271,7 +271,7 @@ static int igafb_mmap(struct fb_info *info,
vma->vm_flags |= VM_IO;
return 0;
}
-#endif /* __sparc__ */
+#endif /* CONFIG_SPARC */
static int igafb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
@@ -323,7 +323,7 @@ static struct fb_ops igafb_ops = {
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
.fb_mmap = igafb_mmap,
#endif
};
@@ -424,7 +424,7 @@ int __init igafb_init(void)
par->frame_buffer_phys = addr & PCI_BASE_ADDRESS_MEM_MASK;
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
/*
* The following is sparc specific and this is why:
*
@@ -477,8 +477,8 @@ int __init igafb_init(void)
* Set default vmode and cmode from PROM properties.
*/
{
- struct pcidev_cookie *cookie = pdev->sysdata;
- int node = cookie->prom_node;
+ struct device_node *dp = pci_device_to_OF_node(pdev);
+ int node = dp->node;
int width = prom_getintdefault(node, "width", 1024);
int height = prom_getintdefault(node, "height", 768);
int depth = prom_getintdefault(node, "depth", 8);
@@ -534,7 +534,7 @@ int __init igafb_init(void)
kfree(info);
}
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
/*
* Add /dev/fb mmap values.
*/
@@ -552,7 +552,7 @@ int __init igafb_init(void)
par->mmap_map[1].size = PAGE_SIZE * 2; /* X wants 2 pages */
par->mmap_map[1].prot_mask = SRMMU_CACHE;
par->mmap_map[1].prot_flag = SRMMU_WRITE;
-#endif /* __sparc__ */
+#endif /* CONFIG_SPARC */
return 0;
}
diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c
index df934bd2189..43f62d8ee41 100644
--- a/drivers/video/nvidia/nv_backlight.c
+++ b/drivers/video/nvidia/nv_backlight.c
@@ -12,15 +12,15 @@
#include <linux/backlight.h>
#include <linux/fb.h>
#include <linux/pci.h>
-#include "nv_local.h"
-#include "nv_type.h"
-#include "nv_proto.h"
#ifdef CONFIG_PMAC_BACKLIGHT
#include <asm/backlight.h>
-#include <asm/machdep.h>
#endif
+#include "nv_local.h"
+#include "nv_type.h"
+#include "nv_proto.h"
+
/* We do not have any information about which values are allowed, thus
* we used safe values.
*/
@@ -28,9 +28,6 @@
#define MAX_LEVEL 0x534
#define LEVEL_STEP ((MAX_LEVEL - MIN_LEVEL) / FB_BACKLIGHT_MAX)
-static struct backlight_properties nvidia_bl_data;
-
-/* Call with fb_info->bl_mutex held */
static int nvidia_bl_get_level_brightness(struct nvidia_par *par,
int level)
{
@@ -38,6 +35,7 @@ static int nvidia_bl_get_level_brightness(struct nvidia_par *par,
int nlevel;
/* Get and convert the value */
+ /* No locking of bl_curve since we read a single value */
nlevel = MIN_LEVEL + info->bl_curve[level] * LEVEL_STEP;
if (nlevel < 0)
@@ -50,8 +48,7 @@ static int nvidia_bl_get_level_brightness(struct nvidia_par *par,
return nlevel;
}
-/* Call with fb_info->bl_mutex held */
-static int __nvidia_bl_update_status(struct backlight_device *bd)
+static int nvidia_bl_update_status(struct backlight_device *bd)
{
struct nvidia_par *par = class_get_devdata(&bd->class_dev);
u32 tmp_pcrt, tmp_pmc, fpcontrol;
@@ -60,11 +57,11 @@ static int __nvidia_bl_update_status(struct backlight_device *bd)
if (!par->FlatPanel)
return 0;
- if (bd->props->power != FB_BLANK_UNBLANK ||
- bd->props->fb_blank != FB_BLANK_UNBLANK)
+ if (bd->props.power != FB_BLANK_UNBLANK ||
+ bd->props.fb_blank != FB_BLANK_UNBLANK)
level = 0;
else
- level = bd->props->brightness;
+ level = bd->props.brightness;
tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF;
tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC;
@@ -85,45 +82,16 @@ static int __nvidia_bl_update_status(struct backlight_device *bd)
return 0;
}
-static int nvidia_bl_update_status(struct backlight_device *bd)
-{
- struct nvidia_par *par = class_get_devdata(&bd->class_dev);
- struct fb_info *info = pci_get_drvdata(par->pci_dev);
- int ret;
-
- mutex_lock(&info->bl_mutex);
- ret = __nvidia_bl_update_status(bd);
- mutex_unlock(&info->bl_mutex);
-
- return ret;
-}
-
static int nvidia_bl_get_brightness(struct backlight_device *bd)
{
- return bd->props->brightness;
+ return bd->props.brightness;
}
-static struct backlight_properties nvidia_bl_data = {
- .owner = THIS_MODULE,
+static struct backlight_ops nvidia_bl_ops = {
.get_brightness = nvidia_bl_get_brightness,
.update_status = nvidia_bl_update_status,
- .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
};
-void nvidia_bl_set_power(struct fb_info *info, int power)
-{
- mutex_lock(&info->bl_mutex);
-
- if (info->bl_dev) {
- down(&info->bl_dev->sem);
- info->bl_dev->props->power = power;
- __nvidia_bl_update_status(info->bl_dev);
- up(&info->bl_dev->sem);
- }
-
- mutex_unlock(&info->bl_mutex);
-}
-
void nvidia_bl_init(struct nvidia_par *par)
{
struct fb_info *info = pci_get_drvdata(par->pci_dev);
@@ -141,32 +109,22 @@ void nvidia_bl_init(struct nvidia_par *par)
snprintf(name, sizeof(name), "nvidiabl%d", info->node);
- bd = backlight_device_register(name, info->dev, par, &nvidia_bl_data);
+ bd = backlight_device_register(name, info->dev, par, &nvidia_bl_ops);
if (IS_ERR(bd)) {
info->bl_dev = NULL;
printk(KERN_WARNING "nvidia: Backlight registration failed\n");
goto error;
}
- mutex_lock(&info->bl_mutex);
info->bl_dev = bd;
fb_bl_default_curve(info, 0,
0x158 * FB_BACKLIGHT_MAX / MAX_LEVEL,
0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL);
- mutex_unlock(&info->bl_mutex);
- down(&bd->sem);
- bd->props->brightness = nvidia_bl_data.max_brightness;
- bd->props->power = FB_BLANK_UNBLANK;
- bd->props->update_status(bd);
- up(&bd->sem);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_lock(&pmac_backlight_mutex);
- if (!pmac_backlight)
- pmac_backlight = bd;
- mutex_unlock(&pmac_backlight_mutex);
-#endif
+ bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
+ bd->props.brightness = bd->props.max_brightness;
+ bd->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(bd);
printk("nvidia: Backlight initialized (%s)\n", name);
@@ -179,25 +137,8 @@ error:
void nvidia_bl_exit(struct nvidia_par *par)
{
struct fb_info *info = pci_get_drvdata(par->pci_dev);
+ struct backlight_device *bd = info->bl_dev;
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_lock(&pmac_backlight_mutex);
-#endif
-
- mutex_lock(&info->bl_mutex);
- if (info->bl_dev) {
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (pmac_backlight == info->bl_dev)
- pmac_backlight = NULL;
-#endif
-
- backlight_device_unregister(info->bl_dev);
-
- printk("nvidia: Backlight unloaded\n");
- }
- mutex_unlock(&info->bl_mutex);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_unlock(&pmac_backlight_mutex);
-#endif
+ backlight_device_unregister(bd);
+ printk("nvidia: Backlight unloaded\n");
}
diff --git a/drivers/video/nvidia/nv_proto.h b/drivers/video/nvidia/nv_proto.h
index 43058d0cf5b..ff5c410355e 100644
--- a/drivers/video/nvidia/nv_proto.h
+++ b/drivers/video/nvidia/nv_proto.h
@@ -67,11 +67,9 @@ extern int nvidiafb_sync(struct fb_info *info);
#ifdef CONFIG_FB_NVIDIA_BACKLIGHT
extern void nvidia_bl_init(struct nvidia_par *par);
extern void nvidia_bl_exit(struct nvidia_par *par);
-extern void nvidia_bl_set_power(struct fb_info *info, int power);
#else
static inline void nvidia_bl_init(struct nvidia_par *par) {}
static inline void nvidia_bl_exit(struct nvidia_par *par) {}
-static inline void nvidia_bl_set_power(struct fb_info *info, int power) {}
#endif
#endif /* __NV_PROTO_H__ */
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index 8e5b484db64..b97ec690126 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -83,6 +83,11 @@ static int bpp __devinitdata = 8;
#ifdef CONFIG_MTRR
static int nomtrr __devinitdata = 0;
#endif
+#ifdef CONFIG_PMAC_BACKLIGHT
+static int backlight __devinitdata = 1;
+#else
+static int backlight __devinitdata = 0;
+#endif
static char *mode_option __devinitdata = NULL;
@@ -938,8 +943,6 @@ static int nvidiafb_blank(int blank, struct fb_info *info)
NVWriteSeq(par, 0x01, tmp);
NVWriteCrtc(par, 0x1a, vesa);
- nvidia_bl_set_power(info, blank);
-
NVTRACE_LEAVE();
return 0;
@@ -1313,7 +1316,10 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd,
nvidia_save_vga(par, &par->SavedReg);
pci_set_drvdata(pd, info);
- nvidia_bl_init(par);
+
+ if (backlight)
+ nvidia_bl_init(par);
+
if (register_framebuffer(info) < 0) {
printk(KERN_ERR PFX "error registering nVidia framebuffer\n");
goto err_out_iounmap_fb;
@@ -1352,9 +1358,10 @@ static void __devexit nvidiafb_remove(struct pci_dev *pd)
NVTRACE_ENTER();
+ unregister_framebuffer(info);
+
nvidia_bl_exit(par);
- unregister_framebuffer(info);
#ifdef CONFIG_MTRR
if (par->mtrr.vram_valid)
mtrr_del(par->mtrr.vram, info->fix.smem_start,
@@ -1409,6 +1416,8 @@ static int __devinit nvidiafb_setup(char *options)
paneltweak = simple_strtoul(this_opt+11, NULL, 0);
} else if (!strncmp(this_opt, "vram:", 5)) {
vram = simple_strtoul(this_opt+5, NULL, 0);
+ } else if (!strncmp(this_opt, "backlight:", 10)) {
+ backlight = simple_strtoul(this_opt+10, NULL, 0);
#ifdef CONFIG_MTRR
} else if (!strncmp(this_opt, "nomtrr", 6)) {
nomtrr = 1;
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index f2e9b742c92..d7ece8d17a2 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -215,6 +215,11 @@ static int noaccel __devinitdata = 0;
#ifdef CONFIG_MTRR
static int nomtrr __devinitdata = 0;
#endif
+#ifdef CONFIG_PMAC_BACKLIGHT
+static int backlight __devinitdata = 1;
+#else
+static int backlight __devinitdata = 0;
+#endif
static char *mode_option __devinitdata = NULL;
static int strictmode = 0;
@@ -280,9 +285,6 @@ static const struct riva_regs reg_template = {
#define MAX_LEVEL 0x534
#define LEVEL_STEP ((MAX_LEVEL - MIN_LEVEL) / FB_BACKLIGHT_MAX)
-static struct backlight_properties riva_bl_data;
-
-/* Call with fb_info->bl_mutex held */
static int riva_bl_get_level_brightness(struct riva_par *par,
int level)
{
@@ -290,6 +292,7 @@ static int riva_bl_get_level_brightness(struct riva_par *par,
int nlevel;
/* Get and convert the value */
+ /* No locking on bl_curve since accessing a single value */
nlevel = MIN_LEVEL + info->bl_curve[level] * LEVEL_STEP;
if (nlevel < 0)
@@ -302,18 +305,17 @@ static int riva_bl_get_level_brightness(struct riva_par *par,
return nlevel;
}
-/* Call with fb_info->bl_mutex held */
-static int __riva_bl_update_status(struct backlight_device *bd)
+static int riva_bl_update_status(struct backlight_device *bd)
{
struct riva_par *par = class_get_devdata(&bd->class_dev);
U032 tmp_pcrt, tmp_pmc;
int level;
- if (bd->props->power != FB_BLANK_UNBLANK ||
- bd->props->fb_blank != FB_BLANK_UNBLANK)
+ if (bd->props.power != FB_BLANK_UNBLANK ||
+ bd->props.fb_blank != FB_BLANK_UNBLANK)
level = 0;
else
- level = bd->props->brightness;
+ level = bd->props.brightness;
tmp_pmc = par->riva.PMC[0x10F0/4] & 0x0000FFFF;
tmp_pcrt = par->riva.PCRTC0[0x081C/4] & 0xFFFFFFFC;
@@ -328,45 +330,16 @@ static int __riva_bl_update_status(struct backlight_device *bd)
return 0;
}
-static int riva_bl_update_status(struct backlight_device *bd)
-{
- struct riva_par *par = class_get_devdata(&bd->class_dev);
- struct fb_info *info = pci_get_drvdata(par->pdev);
- int ret;
-
- mutex_lock(&info->bl_mutex);
- ret = __riva_bl_update_status(bd);
- mutex_unlock(&info->bl_mutex);
-
- return ret;
-}
-
static int riva_bl_get_brightness(struct backlight_device *bd)
{
- return bd->props->brightness;
+ return bd->props.brightness;
}
-static struct backlight_properties riva_bl_data = {
- .owner = THIS_MODULE,
+static struct backlight_ops riva_bl_ops = {
.get_brightness = riva_bl_get_brightness,
.update_status = riva_bl_update_status,
- .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
};
-static void riva_bl_set_power(struct fb_info *info, int power)
-{
- mutex_lock(&info->bl_mutex);
-
- if (info->bl_dev) {
- down(&info->bl_dev->sem);
- info->bl_dev->props->power = power;
- __riva_bl_update_status(info->bl_dev);
- up(&info->bl_dev->sem);
- }
-
- mutex_unlock(&info->bl_mutex);
-}
-
static void riva_bl_init(struct riva_par *par)
{
struct fb_info *info = pci_get_drvdata(par->pdev);
@@ -384,32 +357,22 @@ static void riva_bl_init(struct riva_par *par)
snprintf(name, sizeof(name), "rivabl%d", info->node);
- bd = backlight_device_register(name, info->dev, par, &riva_bl_data);
+ bd = backlight_device_register(name, info->dev, par, &riva_bl_ops);
if (IS_ERR(bd)) {
info->bl_dev = NULL;
printk(KERN_WARNING "riva: Backlight registration failed\n");
goto error;
}
- mutex_lock(&info->bl_mutex);
info->bl_dev = bd;
fb_bl_default_curve(info, 0,
MIN_LEVEL * FB_BACKLIGHT_MAX / MAX_LEVEL,
FB_BACKLIGHT_MAX);
- mutex_unlock(&info->bl_mutex);
- down(&bd->sem);
- bd->props->brightness = riva_bl_data.max_brightness;
- bd->props->power = FB_BLANK_UNBLANK;
- bd->props->update_status(bd);
- up(&bd->sem);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_lock(&pmac_backlight_mutex);
- if (!pmac_backlight)
- pmac_backlight = bd;
- mutex_unlock(&pmac_backlight_mutex);
-#endif
+ bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
+ bd->props.brightness = bd->props.max_brightness;
+ bd->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(bd);
printk("riva: Backlight initialized (%s)\n", name);
@@ -419,35 +382,16 @@ error:
return;
}
-static void riva_bl_exit(struct riva_par *par)
+static void riva_bl_exit(struct fb_info *info)
{
- struct fb_info *info = pci_get_drvdata(par->pdev);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_lock(&pmac_backlight_mutex);
-#endif
-
- mutex_lock(&info->bl_mutex);
- if (info->bl_dev) {
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (pmac_backlight == info->bl_dev)
- pmac_backlight = NULL;
-#endif
-
- backlight_device_unregister(info->bl_dev);
+ struct backlight_device *bd = info->bl_dev;
- printk("riva: Backlight unloaded\n");
- }
- mutex_unlock(&info->bl_mutex);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_unlock(&pmac_backlight_mutex);
-#endif
+ backlight_device_unregister(bd);
+ printk("riva: Backlight unloaded\n");
}
#else
static inline void riva_bl_init(struct riva_par *par) {}
-static inline void riva_bl_exit(struct riva_par *par) {}
-static inline void riva_bl_set_power(struct fb_info *info, int power) {}
+static inline void riva_bl_exit(struct fb_info *info) {}
#endif /* CONFIG_FB_RIVA_BACKLIGHT */
/* ------------------------------------------------------------------------- *
@@ -1348,8 +1292,6 @@ static int rivafb_blank(int blank, struct fb_info *info)
SEQout(par, 0x01, tmp);
CRTCout(par, 0x1a, vesa);
- riva_bl_set_power(info, blank);
-
NVTRACE_LEAVE();
return 0;
@@ -2120,7 +2062,10 @@ static int __devinit rivafb_probe(struct pci_dev *pd,
info->monspecs.modedb = NULL;
pci_set_drvdata(pd, info);
- riva_bl_init(info->par);
+
+ if (backlight)
+ riva_bl_init(info->par);
+
ret = register_framebuffer(info);
if (ret < 0) {
printk(KERN_ERR PFX
@@ -2166,14 +2111,15 @@ static void __exit rivafb_remove(struct pci_dev *pd)
NVTRACE_ENTER();
- riva_bl_exit(par);
-
#ifdef CONFIG_FB_RIVA_I2C
riva_delete_i2c_busses(par);
kfree(par->EDID);
#endif
unregister_framebuffer(info);
+
+ riva_bl_exit(info);
+
#ifdef CONFIG_MTRR
if (par->mtrr.vram_valid)
mtrr_del(par->mtrr.vram, info->fix.smem_start,
@@ -2217,6 +2163,8 @@ static int __init rivafb_setup(char *options)
forceCRTC = -1;
} else if (!strncmp(this_opt, "flatpanel", 9)) {
flatpanel = 1;
+ } else if (!strncmp(this_opt, "backlight:", 10)) {
+ backlight = simple_strtoul(this_opt+10, NULL, 0);
#ifdef CONFIG_MTRR
} else if (!strncmp(this_opt, "nomtrr", 6)) {
nomtrr = 1;
diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c
index 3162c37b144..3091b20124b 100644
--- a/drivers/video/s3fb.c
+++ b/drivers/video/s3fb.c
@@ -1000,11 +1000,12 @@ err_enable_device:
static void __devexit s3_pci_remove(struct pci_dev *dev)
{
struct fb_info *info = pci_get_drvdata(dev);
- struct s3fb_info *par = info->par;
if (info) {
#ifdef CONFIG_MTRR
+ struct s3fb_info *par = info->par;
+
if (par->mtrr_reg >= 0) {
mtrr_del(par->mtrr_reg, 0, 0);
par->mtrr_reg = -1;
@@ -1134,11 +1135,11 @@ static int __init s3fb_setup(char *options)
if (!*opt)
continue;
#ifdef CONFIG_MTRR
- else if (!strcmp(opt, "mtrr:"))
+ else if (!strncmp(opt, "mtrr:", 5))
mtrr = simple_strtoul(opt + 5, NULL, 0);
#endif
- else if (!strcmp(opt, "fasttext:"))
- mtrr = simple_strtoul(opt + 9, NULL, 0);
+ else if (!strncmp(opt, "fasttext:", 9))
+ fasttext = simple_strtoul(opt + 9, NULL, 0);
else
mode = opt;
}
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c
index 4afa30522fd..0166ec2ccf3 100644
--- a/drivers/video/savage/savagefb_driver.c
+++ b/drivers/video/savage/savagefb_driver.c
@@ -384,6 +384,19 @@ SavageSetup2DEngine(struct savagefb_par *par)
BCI_SEND(0);
BCI_SEND(BCI_CMD_SETREG | (1 << 16) | BCI_GBD2);
BCI_SEND(GlobalBitmapDescriptor);
+
+ /*
+ * I don't know why, sending this twice fixes the intial black screen,
+ * prevents X from crashing at least in Toshiba laptops with SavageIX.
+ * --Tony
+ */
+ par->bci_ptr = 0;
+ par->SavageWaitFifo(par, 4);
+
+ BCI_SEND(BCI_CMD_SETREG | (1 << 16) | BCI_GBD1);
+ BCI_SEND(0);
+ BCI_SEND(BCI_CMD_SETREG | (1 << 16) | BCI_GBD2);
+ BCI_SEND(GlobalBitmapDescriptor);
}
static void savagefb_set_clip(struct fb_info *info)
@@ -496,7 +509,7 @@ static int common_calc_clock(long freq, int min_m, int min_n1, int max_n1,
#ifdef SAVAGEFB_DEBUG
/* This function is used to debug, it prints out the contents of s3 regs */
-static void SavagePrintRegs(void)
+static void SavagePrintRegs(struct savagefb_par *par)
{
unsigned char i;
int vgaCRIndex = 0x3d4;
@@ -1525,7 +1538,7 @@ static int savagefb_set_par(struct fb_info *info)
savagefb_set_fix(info);
savagefb_set_clip(info);
- SavagePrintRegs();
+ SavagePrintRegs(par);
return 0;
}
@@ -2155,7 +2168,6 @@ static int __devinit savagefb_probe(struct pci_dev* dev,
int video_len;
DBG("savagefb_probe");
- SavagePrintRegs();
info = framebuffer_alloc(sizeof(struct savagefb_par), &dev->dev);
if (!info)
diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
new file mode 100644
index 00000000000..0a44c44672c
--- /dev/null
+++ b/drivers/video/sm501fb.c
@@ -0,0 +1,1786 @@
+/* linux/drivers/video/sm501fb.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ * Vincent Sanders <vince@simtec.co.uk>
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Framebuffer driver for the Silicon Motion SM501
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/div64.h>
+
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+
+#include <linux/sm501.h>
+#include <linux/sm501-regs.h>
+
+#define NR_PALETTE 256
+
+enum sm501_controller {
+ HEAD_CRT = 0,
+ HEAD_PANEL = 1,
+};
+
+/* SM501 memory adress */
+struct sm501_mem {
+ unsigned long size;
+ unsigned long sm_addr;
+ void __iomem *k_addr;
+};
+
+/* private data that is shared between all frambuffers* */
+struct sm501fb_info {
+ struct device *dev;
+ struct fb_info *fb[2]; /* fb info for both heads */
+ struct resource *fbmem_res; /* framebuffer resource */
+ struct resource *regs_res; /* registers resource */
+ struct sm501_platdata_fb *pdata; /* our platform data */
+
+ int irq;
+ int swap_endian; /* set to swap rgb=>bgr */
+ void __iomem *regs; /* remapped registers */
+ void __iomem *fbmem; /* remapped framebuffer */
+ size_t fbmem_len; /* length of remapped region */
+};
+
+/* per-framebuffer private data */
+struct sm501fb_par {
+ u32 pseudo_palette[16];
+
+ enum sm501_controller head;
+ struct sm501_mem cursor;
+ struct sm501_mem screen;
+ struct fb_ops ops;
+
+ void *store_fb;
+ void *store_cursor;
+ void __iomem *cursor_regs;
+ struct sm501fb_info *info;
+};
+
+/* Helper functions */
+
+static inline int h_total(struct fb_var_screeninfo *var)
+{
+ return var->xres + var->left_margin +
+ var->right_margin + var->hsync_len;
+}
+
+static inline int v_total(struct fb_var_screeninfo *var)
+{
+ return var->yres + var->upper_margin +
+ var->lower_margin + var->vsync_len;
+}
+
+/* sm501fb_sync_regs()
+ *
+ * This call is mainly for PCI bus systems where we need to
+ * ensure that any writes to the bus are completed before the
+ * next phase, or after completing a function.
+*/
+
+static inline void sm501fb_sync_regs(struct sm501fb_info *info)
+{
+ readl(info->regs);
+}
+
+/* sm501_alloc_mem
+ *
+ * This is an attempt to lay out memory for the two framebuffers and
+ * everything else
+ *
+ * |fbmem_res->start fbmem_res->end|
+ * | |
+ * |fb[0].fix.smem_start | |fb[1].fix.smem_start | 2K |
+ * |-> fb[0].fix.smem_len <-| spare |-> fb[1].fix.smem_len <-|-> cursors <-|
+ *
+ * The "spare" space is for the 2d engine data
+ * the fixed is space for the cursors (2x1Kbyte)
+ *
+ * we need to allocate memory for the 2D acceleration engine
+ * command list and the data for the engine to deal with.
+ *
+ * - all allocations must be 128bit aligned
+ * - cursors are 64x64x2 bits (1Kbyte)
+ *
+ */
+
+#define SM501_MEMF_CURSOR (1)
+#define SM501_MEMF_PANEL (2)
+#define SM501_MEMF_CRT (4)
+#define SM501_MEMF_ACCEL (8)
+
+static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
+ unsigned int why, size_t size)
+{
+ unsigned int ptr = 0;
+
+ switch (why) {
+ case SM501_MEMF_CURSOR:
+ ptr = inf->fbmem_len - size;
+ inf->fbmem_len = ptr;
+ break;
+
+ case SM501_MEMF_PANEL:
+ ptr = inf->fbmem_len - size;
+ if (ptr < inf->fb[0]->fix.smem_len)
+ return -ENOMEM;
+
+ break;
+
+ case SM501_MEMF_CRT:
+ ptr = 0;
+ break;
+
+ case SM501_MEMF_ACCEL:
+ ptr = inf->fb[0]->fix.smem_len;
+
+ if ((ptr + size) >
+ (inf->fb[1]->fix.smem_start - inf->fbmem_res->start))
+ return -ENOMEM;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ mem->size = size;
+ mem->sm_addr = ptr;
+ mem->k_addr = inf->fbmem + ptr;
+
+ dev_dbg(inf->dev, "%s: result %08lx, %p - %u, %zd\n",
+ __func__, mem->sm_addr, mem->k_addr, why, size);
+
+ return 0;
+}
+
+/* sm501fb_ps_to_hz
+ *
+ * Converts a period in picoseconds to Hz.
+ *
+ * Note, we try to keep this in Hz to minimise rounding with
+ * the limited PLL settings on the SM501.
+*/
+
+static unsigned long sm501fb_ps_to_hz(unsigned long psvalue)
+{
+ unsigned long long numerator=1000000000000ULL;
+
+ /* 10^12 / picosecond period gives frequency in Hz */
+ do_div(numerator, psvalue);
+ return (unsigned long)numerator;
+}
+
+/* sm501fb_hz_to_ps is identical to the oposite transform */
+
+#define sm501fb_hz_to_ps(x) sm501fb_ps_to_hz(x)
+
+/* sm501fb_setup_gamma
+ *
+ * Programs a linear 1.0 gamma ramp in case the gamma
+ * correction is enabled without programming anything else.
+*/
+
+static void sm501fb_setup_gamma(struct sm501fb_info *fbi,
+ unsigned long palette)
+{
+ unsigned long value = 0;
+ int offset;
+
+ /* set gamma values */
+ for (offset = 0; offset < 256 * 4; offset += 4) {
+ writel(value, fbi->regs + palette + offset);
+ value += 0x010101; /* Advance RGB by 1,1,1.*/
+ }
+}
+
+/* sm501fb_check_var
+ *
+ * check common variables for both panel and crt
+*/
+
+static int sm501fb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct sm501fb_par *par = info->par;
+ struct sm501fb_info *sm = par->info;
+ unsigned long tmp;
+
+ /* check we can fit these values into the registers */
+
+ if (var->hsync_len > 255 || var->vsync_len > 255)
+ return -EINVAL;
+
+ if ((var->xres + var->right_margin) >= 4096)
+ return -EINVAL;
+
+ if ((var->yres + var->lower_margin) > 2048)
+ return -EINVAL;
+
+ /* hard limits of device */
+
+ if (h_total(var) > 4096 || v_total(var) > 2048)
+ return -EINVAL;
+
+ /* check our line length is going to be 128 bit aligned */
+
+ tmp = (var->xres * var->bits_per_pixel) / 8;
+ if ((tmp & 15) != 0)
+ return -EINVAL;
+
+ /* check the virtual size */
+
+ if (var->xres_virtual > 4096 || var->yres_virtual > 2048)
+ return -EINVAL;
+
+ /* can cope with 8,16 or 32bpp */
+
+ if (var->bits_per_pixel <= 8)
+ var->bits_per_pixel = 8;
+ else if (var->bits_per_pixel <= 16)
+ var->bits_per_pixel = 16;
+ else if (var->bits_per_pixel == 24)
+ var->bits_per_pixel = 32;
+
+ /* set r/g/b positions and validate bpp */
+ switch(var->bits_per_pixel) {
+ case 8:
+ var->red.length = var->bits_per_pixel;
+ var->red.offset = 0;
+ var->green.length = var->bits_per_pixel;
+ var->green.offset = 0;
+ var->blue.length = var->bits_per_pixel;
+ var->blue.offset = 0;
+ var->transp.length = 0;
+
+ break;
+
+ case 16:
+ if (sm->pdata->flags & SM501_FBPD_SWAP_FB_ENDIAN) {
+ var->red.offset = 11;
+ var->green.offset = 5;
+ var->blue.offset = 0;
+ } else {
+ var->blue.offset = 11;
+ var->green.offset = 5;
+ var->red.offset = 0;
+ }
+
+ var->red.length = 5;
+ var->green.length = 6;
+ var->blue.length = 5;
+ var->transp.length = 0;
+ break;
+
+ case 32:
+ if (sm->pdata->flags & SM501_FBPD_SWAP_FB_ENDIAN) {
+ var->transp.offset = 0;
+ var->red.offset = 8;
+ var->green.offset = 16;
+ var->blue.offset = 24;
+ } else {
+ var->transp.offset = 24;
+ var->red.offset = 16;
+ var->green.offset = 8;
+ var->blue.offset = 0;
+ }
+
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
+ var->transp.length = 0;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * sm501fb_check_var_crt():
+ *
+ * check the parameters for the CRT head, and either bring them
+ * back into range, or return -EINVAL.
+*/
+
+static int sm501fb_check_var_crt(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ return sm501fb_check_var(var, info);
+}
+
+/* sm501fb_check_var_pnl():
+ *
+ * check the parameters for the CRT head, and either bring them
+ * back into range, or return -EINVAL.
+*/
+
+static int sm501fb_check_var_pnl(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ return sm501fb_check_var(var, info);
+}
+
+/* sm501fb_set_par_common
+ *
+ * set common registers for framebuffers
+*/
+
+static int sm501fb_set_par_common(struct fb_info *info,
+ struct fb_var_screeninfo *var)
+{
+ struct sm501fb_par *par = info->par;
+ struct sm501fb_info *fbi = par->info;
+ unsigned long pixclock; /* pixelclock in Hz */
+ unsigned long sm501pixclock; /* pixelclock the 501 can achive in Hz */
+ unsigned int mem_type;
+ unsigned int clock_type;
+ unsigned int head_addr;
+
+ dev_dbg(fbi->dev, "%s: %dx%d, bpp = %d, virtual %dx%d\n",
+ __func__, var->xres, var->yres, var->bits_per_pixel,
+ var->xres_virtual, var->yres_virtual);
+
+ switch (par->head) {
+ case HEAD_CRT:
+ mem_type = SM501_MEMF_CRT;
+ clock_type = SM501_CLOCK_V2XCLK;
+ head_addr = SM501_DC_CRT_FB_ADDR;
+ break;
+
+ case HEAD_PANEL:
+ mem_type = SM501_MEMF_PANEL;
+ clock_type = SM501_CLOCK_P2XCLK;
+ head_addr = SM501_DC_PANEL_FB_ADDR;
+ break;
+
+ default:
+ mem_type = 0; /* stop compiler warnings */
+ head_addr = 0;
+ clock_type = 0;
+ }
+
+ switch (var->bits_per_pixel) {
+ case 8:
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ break;
+
+ case 16:
+ info->fix.visual = FB_VISUAL_DIRECTCOLOR;
+ break;
+
+ case 32:
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ break;
+ }
+
+ /* allocate fb memory within 501 */
+ info->fix.line_length = (var->xres_virtual * var->bits_per_pixel)/8;
+ info->fix.smem_len = info->fix.line_length * var->yres_virtual;
+
+ dev_dbg(fbi->dev, "%s: line length = %u\n", __func__,
+ info->fix.line_length);
+
+ if (sm501_alloc_mem(fbi, &par->screen, mem_type,
+ info->fix.smem_len)) {
+ dev_err(fbi->dev, "no memory available\n");
+ return -ENOMEM;
+ }
+
+ info->fix.smem_start = fbi->fbmem_res->start + par->screen.sm_addr;
+
+ info->screen_base = fbi->fbmem + par->screen.sm_addr;
+ info->screen_size = info->fix.smem_len;
+
+ /* set start of framebuffer to the screen */
+
+ writel(par->screen.sm_addr | SM501_ADDR_FLIP, fbi->regs + head_addr);
+
+ /* program CRT clock */
+
+ pixclock = sm501fb_ps_to_hz(var->pixclock);
+
+ sm501pixclock = sm501_set_clock(fbi->dev->parent, clock_type,
+ pixclock);
+
+ /* update fb layer with actual clock used */
+ var->pixclock = sm501fb_hz_to_ps(sm501pixclock);
+
+ dev_dbg(fbi->dev, "%s: pixclock(ps) = %u, pixclock(Hz) = %lu, "
+ "sm501pixclock = %lu, error = %ld%%\n",
+ __func__, var->pixclock, pixclock, sm501pixclock,
+ ((pixclock - sm501pixclock)*100)/pixclock);
+
+ return 0;
+}
+
+/* sm501fb_set_par_geometry
+ *
+ * set the geometry registers for specified framebuffer.
+*/
+
+static void sm501fb_set_par_geometry(struct fb_info *info,
+ struct fb_var_screeninfo *var)
+{
+ struct sm501fb_par *par = info->par;
+ struct sm501fb_info *fbi = par->info;
+ void __iomem *base = fbi->regs;
+ unsigned long reg;
+
+ if (par->head == HEAD_CRT)
+ base += SM501_DC_CRT_H_TOT;
+ else
+ base += SM501_DC_PANEL_H_TOT;
+
+ /* set framebuffer width and display width */
+
+ reg = info->fix.line_length;
+ reg |= ((var->xres * var->bits_per_pixel)/8) << 16;
+
+ writel(reg, fbi->regs + (par->head == HEAD_CRT ?
+ SM501_DC_CRT_FB_OFFSET : SM501_DC_PANEL_FB_OFFSET));
+
+ /* program horizontal total */
+
+ reg = (h_total(var) - 1) << 16;
+ reg |= (var->xres - 1);
+
+ writel(reg, base + SM501_OFF_DC_H_TOT);
+
+ /* program horizontal sync */
+
+ reg = var->hsync_len << 16;
+ reg |= var->xres + var->right_margin - 1;
+
+ writel(reg, base + SM501_OFF_DC_H_SYNC);
+
+ /* program vertical total */
+
+ reg = (v_total(var) - 1) << 16;
+ reg |= (var->yres - 1);
+
+ writel(reg, base + SM501_OFF_DC_V_TOT);
+
+ /* program vertical sync */
+ reg = var->vsync_len << 16;
+ reg |= var->yres + var->lower_margin - 1;
+
+ writel(reg, base + SM501_OFF_DC_V_SYNC);
+}
+
+/* sm501fb_pan_crt
+ *
+ * pan the CRT display output within an virtual framebuffer
+*/
+
+static int sm501fb_pan_crt(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct sm501fb_par *par = info->par;
+ struct sm501fb_info *fbi = par->info;
+ unsigned int bytes_pixel = var->bits_per_pixel / 8;
+ unsigned long reg;
+ unsigned long xoffs;
+
+ xoffs = var->xoffset * bytes_pixel;
+
+ reg = readl(fbi->regs + SM501_DC_CRT_CONTROL);
+
+ reg &= ~SM501_DC_CRT_CONTROL_PIXEL_MASK;
+ reg |= ((xoffs & 15) / bytes_pixel) << 4;
+ writel(reg, fbi->regs + SM501_DC_CRT_CONTROL);
+
+ reg = (par->screen.sm_addr + xoffs +
+ var->yoffset * info->fix.line_length);
+ writel(reg | SM501_ADDR_FLIP, fbi->regs + SM501_DC_CRT_FB_ADDR);
+
+ sm501fb_sync_regs(fbi);
+ return 0;
+}
+
+/* sm501fb_pan_pnl
+ *
+ * pan the panel display output within an virtual framebuffer
+*/
+
+static int sm501fb_pan_pnl(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct sm501fb_par *par = info->par;
+ struct sm501fb_info *fbi = par->info;
+ unsigned long reg;
+
+ reg = var->xoffset | (var->xres_virtual << 16);
+ writel(reg, fbi->regs + SM501_DC_PANEL_FB_WIDTH);
+
+ reg = var->yoffset | (var->yres_virtual << 16);
+ writel(reg, fbi->regs + SM501_DC_PANEL_FB_HEIGHT);
+
+ sm501fb_sync_regs(fbi);
+ return 0;
+}
+
+/* sm501fb_set_par_crt
+ *
+ * Set the CRT video mode from the fb_info structure
+*/
+
+static int sm501fb_set_par_crt(struct fb_info *info)
+{
+ struct sm501fb_par *par = info->par;
+ struct sm501fb_info *fbi = par->info;
+ struct fb_var_screeninfo *var = &info->var;
+ unsigned long control; /* control register */
+ int ret;
+
+ /* activate new configuration */
+
+ dev_dbg(fbi->dev, "%s(%p)\n", __func__, info);
+
+ /* enable CRT DAC - note 0 is on!*/
+ sm501_misc_control(fbi->dev->parent, 0, SM501_MISC_DAC_POWER);
+
+ control = readl(fbi->regs + SM501_DC_CRT_CONTROL);
+
+ control &= (SM501_DC_CRT_CONTROL_PIXEL_MASK |
+ SM501_DC_CRT_CONTROL_GAMMA |
+ SM501_DC_CRT_CONTROL_BLANK |
+ SM501_DC_CRT_CONTROL_SEL |
+ SM501_DC_CRT_CONTROL_CP |
+ SM501_DC_CRT_CONTROL_TVP);
+
+ /* set the sync polarities before we check data source */
+
+ if ((var->sync & FB_SYNC_HOR_HIGH_ACT) == 0)
+ control |= SM501_DC_CRT_CONTROL_HSP;
+
+ if ((var->sync & FB_SYNC_VERT_HIGH_ACT) == 0)
+ control |= SM501_DC_CRT_CONTROL_VSP;
+
+ if ((control & SM501_DC_CRT_CONTROL_SEL) == 0) {
+ /* the head is displaying panel data... */
+
+ sm501_alloc_mem(fbi, &par->screen, SM501_MEMF_CRT, 0);
+ goto out_update;
+ }
+
+ ret = sm501fb_set_par_common(info, var);
+ if (ret) {
+ dev_err(fbi->dev, "failed to set common parameters\n");
+ return ret;
+ }
+
+ sm501fb_pan_crt(var, info);
+ sm501fb_set_par_geometry(info, var);
+
+ control |= SM501_FIFO_3; /* fill if >3 free slots */
+
+ switch(var->bits_per_pixel) {
+ case 8:
+ control |= SM501_DC_CRT_CONTROL_8BPP;
+ break;
+
+ case 16:
+ control |= SM501_DC_CRT_CONTROL_16BPP;
+ break;
+
+ case 32:
+ control |= SM501_DC_CRT_CONTROL_32BPP;
+ sm501fb_setup_gamma(fbi, SM501_DC_CRT_PALETTE);
+ break;
+
+ default:
+ BUG();
+ }
+
+ control |= SM501_DC_CRT_CONTROL_SEL; /* CRT displays CRT data */
+ control |= SM501_DC_CRT_CONTROL_TE; /* enable CRT timing */
+ control |= SM501_DC_CRT_CONTROL_ENABLE; /* enable CRT plane */
+
+ out_update:
+ dev_dbg(fbi->dev, "new control is %08lx\n", control);
+
+ writel(control, fbi->regs + SM501_DC_CRT_CONTROL);
+ sm501fb_sync_regs(fbi);
+
+ return 0;
+}
+
+static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
+{
+ unsigned long control;
+ void __iomem *ctrl_reg = fbi->regs + SM501_DC_PANEL_CONTROL;
+
+ control = readl(ctrl_reg);
+
+ if (to && (control & SM501_DC_PANEL_CONTROL_VDD) == 0) {
+ /* enable panel power */
+
+ control |= SM501_DC_PANEL_CONTROL_VDD; /* FPVDDEN */
+ writel(control, ctrl_reg);
+ sm501fb_sync_regs(fbi);
+ mdelay(10);
+
+ control |= SM501_DC_PANEL_CONTROL_DATA; /* DATA */
+ writel(control, ctrl_reg);
+ sm501fb_sync_regs(fbi);
+ mdelay(10);
+
+ control |= SM501_DC_PANEL_CONTROL_BIAS; /* VBIASEN */
+ writel(control, ctrl_reg);
+ sm501fb_sync_regs(fbi);
+ mdelay(10);
+
+ control |= SM501_DC_PANEL_CONTROL_FPEN;
+ writel(control, ctrl_reg);
+
+ } else if (!to && (control & SM501_DC_PANEL_CONTROL_VDD) != 0) {
+ /* disable panel power */
+
+ control &= ~SM501_DC_PANEL_CONTROL_FPEN;
+ writel(control, ctrl_reg);
+ sm501fb_sync_regs(fbi);
+ mdelay(10);
+
+ control &= ~SM501_DC_PANEL_CONTROL_BIAS;
+ writel(control, ctrl_reg);
+ sm501fb_sync_regs(fbi);
+ mdelay(10);
+
+ control &= ~SM501_DC_PANEL_CONTROL_DATA;
+ writel(control, ctrl_reg);
+ sm501fb_sync_regs(fbi);
+ mdelay(10);
+
+ control &= ~SM501_DC_PANEL_CONTROL_VDD;
+ writel(control, ctrl_reg);
+ sm501fb_sync_regs(fbi);
+ mdelay(10);
+ }
+
+ sm501fb_sync_regs(fbi);
+}
+
+/* sm501fb_set_par_pnl
+ *
+ * Set the panel video mode from the fb_info structure
+*/
+
+static int sm501fb_set_par_pnl(struct fb_info *info)
+{
+ struct sm501fb_par *par = info->par;
+ struct sm501fb_info *fbi = par->info;
+ struct fb_var_screeninfo *var = &info->var;
+ unsigned long control;
+ unsigned long reg;
+ int ret;
+
+ dev_dbg(fbi->dev, "%s(%p)\n", __func__, info);
+
+ /* activate this new configuration */
+
+ ret = sm501fb_set_par_common(info, var);
+ if (ret)
+ return ret;
+
+ sm501fb_pan_pnl(var, info);
+ sm501fb_set_par_geometry(info, var);
+
+ /* update control register */
+
+ control = readl(fbi->regs + SM501_DC_PANEL_CONTROL);
+ control &= (SM501_DC_PANEL_CONTROL_GAMMA |
+ SM501_DC_PANEL_CONTROL_VDD |
+ SM501_DC_PANEL_CONTROL_DATA |
+ SM501_DC_PANEL_CONTROL_BIAS |
+ SM501_DC_PANEL_CONTROL_FPEN |
+ SM501_DC_PANEL_CONTROL_CP |
+ SM501_DC_PANEL_CONTROL_CK |
+ SM501_DC_PANEL_CONTROL_HP |
+ SM501_DC_PANEL_CONTROL_VP |
+ SM501_DC_PANEL_CONTROL_HPD |
+ SM501_DC_PANEL_CONTROL_VPD);
+
+ control |= SM501_FIFO_3; /* fill if >3 free slots */
+
+ switch(var->bits_per_pixel) {
+ case 8:
+ control |= SM501_DC_PANEL_CONTROL_8BPP;
+ break;
+
+ case 16:
+ control |= SM501_DC_PANEL_CONTROL_16BPP;
+ break;
+
+ case 32:
+ control |= SM501_DC_PANEL_CONTROL_32BPP;
+ sm501fb_setup_gamma(fbi, SM501_DC_PANEL_PALETTE);
+ break;
+
+ default:
+ BUG();
+ }
+
+ writel(0x0, fbi->regs + SM501_DC_PANEL_PANNING_CONTROL);
+
+ /* panel plane top left and bottom right location */
+
+ writel(0x00, fbi->regs + SM501_DC_PANEL_TL_LOC);
+
+ reg = var->xres - 1;
+ reg |= (var->yres - 1) << 16;
+
+ writel(reg, fbi->regs + SM501_DC_PANEL_BR_LOC);
+
+ /* program panel control register */
+
+ control |= SM501_DC_PANEL_CONTROL_TE; /* enable PANEL timing */
+ control |= SM501_DC_PANEL_CONTROL_EN; /* enable PANEL gfx plane */
+
+ if ((var->sync & FB_SYNC_HOR_HIGH_ACT) == 0)
+ control |= SM501_DC_PANEL_CONTROL_HSP;
+
+ if ((var->sync & FB_SYNC_VERT_HIGH_ACT) == 0)
+ control |= SM501_DC_PANEL_CONTROL_VSP;
+
+ writel(control, fbi->regs + SM501_DC_PANEL_CONTROL);
+ sm501fb_sync_regs(fbi);
+
+ /* power the panel up */
+ sm501fb_panel_power(fbi, 1);
+ return 0;
+}
+
+
+/* chan_to_field
+ *
+ * convert a colour value into a field position
+ *
+ * from pxafb.c
+*/
+
+static inline unsigned int chan_to_field(unsigned int chan,
+ struct fb_bitfield *bf)
+{
+ chan &= 0xffff;
+ chan >>= 16 - bf->length;
+ return chan << bf->offset;
+}
+
+/* sm501fb_setcolreg
+ *
+ * set the colour mapping for modes that support palettised data
+*/
+
+static int sm501fb_setcolreg(unsigned regno,
+ unsigned red, unsigned green, unsigned blue,
+ unsigned transp, struct fb_info *info)
+{
+ struct sm501fb_par *par = info->par;
+ struct sm501fb_info *fbi = par->info;
+ void __iomem *base = fbi->regs;
+ unsigned int val;
+
+ if (par->head == HEAD_CRT)
+ base += SM501_DC_CRT_PALETTE;
+ else
+ base += SM501_DC_PANEL_PALETTE;
+
+ switch (info->fix.visual) {
+ case FB_VISUAL_TRUECOLOR:
+ /* true-colour, use pseuo-palette */
+
+ if (regno < 16) {
+ u32 *pal = par->pseudo_palette;
+
+ val = chan_to_field(red, &info->var.red);
+ val |= chan_to_field(green, &info->var.green);
+ val |= chan_to_field(blue, &info->var.blue);
+
+ pal[regno] = val;
+ }
+ break;
+
+ case FB_VISUAL_PSEUDOCOLOR:
+ if (regno < 256) {
+ val = (red >> 8) << 16;
+ val |= (green >> 8) << 8;
+ val |= blue >> 8;
+
+ writel(val, base + (regno * 4));
+ }
+
+ break;
+
+ default:
+ return 1; /* unknown type */
+ }
+
+ return 0;
+}
+
+/* sm501fb_blank_pnl
+ *
+ * Blank or un-blank the panel interface
+*/
+
+static int sm501fb_blank_pnl(int blank_mode, struct fb_info *info)
+{
+ struct sm501fb_par *par = info->par;
+ struct sm501fb_info *fbi = par->info;
+
+ dev_dbg(fbi->dev, "%s(mode=%d, %p)\n", __func__, blank_mode, info);
+
+ switch (blank_mode) {
+ case FB_BLANK_POWERDOWN:
+ sm501fb_panel_power(fbi, 0);
+ break;
+
+ case FB_BLANK_UNBLANK:
+ sm501fb_panel_power(fbi, 1);
+ break;
+
+ case FB_BLANK_NORMAL:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ default:
+ return 1;
+ }
+
+ return 0;
+}
+
+/* sm501fb_blank_crt
+ *
+ * Blank or un-blank the crt interface
+*/
+
+static int sm501fb_blank_crt(int blank_mode, struct fb_info *info)
+{
+ struct sm501fb_par *par = info->par;
+ struct sm501fb_info *fbi = par->info;
+ unsigned long ctrl;
+
+ dev_dbg(fbi->dev, "%s(mode=%d, %p)\n", __func__, blank_mode, info);
+
+ ctrl = readl(fbi->regs + SM501_DC_CRT_CONTROL);
+
+ switch (blank_mode) {
+ case FB_BLANK_POWERDOWN:
+ ctrl &= ~SM501_DC_CRT_CONTROL_ENABLE;
+ sm501_misc_control(fbi->dev->parent, SM501_MISC_DAC_POWER, 0);
+
+ case FB_BLANK_NORMAL:
+ ctrl |= SM501_DC_CRT_CONTROL_BLANK;
+ break;
+
+ case FB_BLANK_UNBLANK:
+ ctrl &= ~SM501_DC_CRT_CONTROL_BLANK;
+ ctrl |= SM501_DC_CRT_CONTROL_ENABLE;
+ sm501_misc_control(fbi->dev->parent, 0, SM501_MISC_DAC_POWER);
+ break;
+
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ default:
+ return 1;
+
+ }
+
+ writel(ctrl, fbi->regs + SM501_DC_CRT_CONTROL);
+ sm501fb_sync_regs(fbi);
+
+ return 0;
+}
+
+/* sm501fb_cursor
+ *
+ * set or change the hardware cursor parameters
+*/
+
+static int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+ struct sm501fb_par *par = info->par;
+ struct sm501fb_info *fbi = par->info;
+ void __iomem *base = fbi->regs;
+ unsigned long hwc_addr;
+ unsigned long fg, bg;
+
+ dev_dbg(fbi->dev, "%s(%p,%p)\n", __func__, info, cursor);
+
+ if (par->head == HEAD_CRT)
+ base += SM501_DC_CRT_HWC_BASE;
+ else
+ base += SM501_DC_PANEL_HWC_BASE;
+
+ /* check not being asked to exceed capabilities */
+
+ if (cursor->image.width > 64)
+ return -EINVAL;
+
+ if (cursor->image.height > 64)
+ return -EINVAL;
+
+ if (cursor->image.depth > 1)
+ return -EINVAL;
+
+ hwc_addr = readl(base + SM501_OFF_HWC_ADDR);
+
+ if (cursor->enable)
+ writel(hwc_addr | SM501_HWC_EN, base + SM501_OFF_HWC_ADDR);
+ else
+ writel(hwc_addr & ~SM501_HWC_EN, base + SM501_OFF_HWC_ADDR);
+
+ /* set data */
+ if (cursor->set & FB_CUR_SETPOS) {
+ unsigned int x = cursor->image.dx;
+ unsigned int y = cursor->image.dy;
+
+ if (x >= 2048 || y >= 2048 )
+ return -EINVAL;
+
+ dev_dbg(fbi->dev, "set position %d,%d\n", x, y);
+
+ //y += cursor->image.height;
+
+ writel(x | (y << 16), base + SM501_OFF_HWC_LOC);
+ }
+
+ if (cursor->set & FB_CUR_SETCMAP) {
+ unsigned int bg_col = cursor->image.bg_color;
+ unsigned int fg_col = cursor->image.fg_color;
+
+ dev_dbg(fbi->dev, "%s: update cmap (%08x,%08x)\n",
+ __func__, bg_col, fg_col);
+
+ bg = ((info->cmap.red[bg_col] & 0xF8) << 8) |
+ ((info->cmap.green[bg_col] & 0xFC) << 3) |
+ ((info->cmap.blue[bg_col] & 0xF8) >> 3);
+
+ fg = ((info->cmap.red[fg_col] & 0xF8) << 8) |
+ ((info->cmap.green[fg_col] & 0xFC) << 3) |
+ ((info->cmap.blue[fg_col] & 0xF8) >> 3);
+
+ dev_dbg(fbi->dev, "fgcol %08x, bgcol %08x\n", fg, bg);
+
+ writel(bg, base + SM501_OFF_HWC_COLOR_1_2);
+ writel(fg, base + SM501_OFF_HWC_COLOR_3);
+ }
+
+ if (cursor->set & FB_CUR_SETSIZE ||
+ cursor->set & (FB_CUR_SETIMAGE | FB_CUR_SETSHAPE)) {
+ /* SM501 cursor is a two bpp 64x64 bitmap this routine
+ * clears it to transparent then combines the cursor
+ * shape plane with the colour plane to set the
+ * cursor */
+ int x, y;
+ const unsigned char *pcol = cursor->image.data;
+ const unsigned char *pmsk = cursor->mask;
+ void __iomem *dst = par->cursor.k_addr;
+ unsigned char dcol = 0;
+ unsigned char dmsk = 0;
+ unsigned int op;
+
+ dev_dbg(fbi->dev, "%s: setting shape (%d,%d)\n",
+ __func__, cursor->image.width, cursor->image.height);
+
+ for (op = 0; op < (64*64*2)/8; op+=4)
+ writel(0x0, dst + op);
+
+ for (y = 0; y < cursor->image.height; y++) {
+ for (x = 0; x < cursor->image.width; x++) {
+ if ((x % 8) == 0) {
+ dcol = *pcol++;
+ dmsk = *pmsk++;
+ } else {
+ dcol >>= 1;
+ dmsk >>= 1;
+ }
+
+ if (dmsk & 1) {
+ op = (dcol & 1) ? 1 : 3;
+ op <<= ((x % 4) * 2);
+
+ op |= readb(dst + (x / 4));
+ writeb(op, dst + (x / 4));
+ }
+ }
+ dst += (64*2)/8;
+ }
+ }
+
+ sm501fb_sync_regs(fbi); /* ensure cursor data flushed */
+ return 0;
+}
+
+/* sm501fb_crtsrc_show
+ *
+ * device attribute code to show where the crt output is sourced from
+*/
+
+static ssize_t sm501fb_crtsrc_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sm501fb_info *info = dev_get_drvdata(dev);
+ unsigned long ctrl;
+
+ ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
+ ctrl &= SM501_DC_CRT_CONTROL_SEL;
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", ctrl ? "crt" : "panel");
+}
+
+/* sm501fb_crtsrc_show
+ *
+ * device attribute code to set where the crt output is sourced from
+*/
+
+static ssize_t sm501fb_crtsrc_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct sm501fb_info *info = dev_get_drvdata(dev);
+ enum sm501_controller head;
+ unsigned long ctrl;
+
+ if (len < 1)
+ return -EINVAL;
+
+ if (strnicmp(buf, "crt", 3) == 0)
+ head = HEAD_CRT;
+ else if (strnicmp(buf, "panel", 5) == 0)
+ head = HEAD_PANEL;
+ else
+ return -EINVAL;
+
+ dev_info(dev, "setting crt source to head %d\n", head);
+
+ ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
+
+ if (head == HEAD_CRT) {
+ ctrl |= SM501_DC_CRT_CONTROL_SEL;
+ ctrl |= SM501_DC_CRT_CONTROL_ENABLE;
+ ctrl |= SM501_DC_CRT_CONTROL_TE;
+ } else {
+ ctrl &= ~SM501_DC_CRT_CONTROL_SEL;
+ ctrl &= ~SM501_DC_CRT_CONTROL_ENABLE;
+ ctrl &= ~SM501_DC_CRT_CONTROL_TE;
+ }
+
+ writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
+ sm501fb_sync_regs(info);
+
+ return len;
+}
+
+/* Prepare the device_attr for registration with sysfs later */
+static DEVICE_ATTR(crt_src, 0666, sm501fb_crtsrc_show, sm501fb_crtsrc_store);
+
+/* sm501fb_show_regs
+ *
+ * show the primary sm501 registers
+*/
+static int sm501fb_show_regs(struct sm501fb_info *info, char *ptr,
+ unsigned int start, unsigned int len)
+{
+ void __iomem *mem = info->regs;
+ char *buf = ptr;
+ unsigned int reg;
+
+ for (reg = start; reg < (len + start); reg += 4)
+ ptr += sprintf(ptr, "%08x = %08x\n", reg, readl(mem + reg));
+
+ return ptr - buf;
+}
+
+/* sm501fb_debug_show_crt
+ *
+ * show the crt control and cursor registers
+*/
+
+static ssize_t sm501fb_debug_show_crt(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sm501fb_info *info = dev_get_drvdata(dev);
+ char *ptr = buf;
+
+ ptr += sm501fb_show_regs(info, ptr, SM501_DC_CRT_CONTROL, 0x40);
+ ptr += sm501fb_show_regs(info, ptr, SM501_DC_CRT_HWC_BASE, 0x10);
+
+ return ptr - buf;
+}
+
+static DEVICE_ATTR(fbregs_crt, 0444, sm501fb_debug_show_crt, NULL);
+
+/* sm501fb_debug_show_pnl
+ *
+ * show the panel control and cursor registers
+*/
+
+static ssize_t sm501fb_debug_show_pnl(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sm501fb_info *info = dev_get_drvdata(dev);
+ char *ptr = buf;
+
+ ptr += sm501fb_show_regs(info, ptr, 0x0, 0x40);
+ ptr += sm501fb_show_regs(info, ptr, SM501_DC_PANEL_HWC_BASE, 0x10);
+
+ return ptr - buf;
+}
+
+static DEVICE_ATTR(fbregs_pnl, 0444, sm501fb_debug_show_pnl, NULL);
+
+/* framebuffer ops */
+
+static struct fb_ops sm501fb_ops_crt = {
+ .owner = THIS_MODULE,
+ .fb_check_var = sm501fb_check_var_crt,
+ .fb_set_par = sm501fb_set_par_crt,
+ .fb_blank = sm501fb_blank_crt,
+ .fb_setcolreg = sm501fb_setcolreg,
+ .fb_pan_display = sm501fb_pan_crt,
+ .fb_cursor = sm501fb_cursor,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+static struct fb_ops sm501fb_ops_pnl = {
+ .owner = THIS_MODULE,
+ .fb_check_var = sm501fb_check_var_pnl,
+ .fb_set_par = sm501fb_set_par_pnl,
+ .fb_pan_display = sm501fb_pan_pnl,
+ .fb_blank = sm501fb_blank_pnl,
+ .fb_setcolreg = sm501fb_setcolreg,
+ .fb_cursor = sm501fb_cursor,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+/* sm501fb_info_alloc
+ *
+ * creates and initialises an sm501fb_info structure
+*/
+
+static struct sm501fb_info *sm501fb_info_alloc(struct fb_info *fbinfo_crt,
+ struct fb_info *fbinfo_pnl)
+{
+ struct sm501fb_info *info;
+ struct sm501fb_par *par;
+
+ info = kzalloc(sizeof(struct sm501fb_info), GFP_KERNEL);
+ if (info) {
+ /* set the references back */
+
+ par = fbinfo_crt->par;
+ par->info = info;
+ par->head = HEAD_CRT;
+ fbinfo_crt->pseudo_palette = &par->pseudo_palette;
+
+ par = fbinfo_pnl->par;
+ par->info = info;
+ par->head = HEAD_PANEL;
+ fbinfo_pnl->pseudo_palette = &par->pseudo_palette;
+
+ /* store the two fbs into our info */
+ info->fb[HEAD_CRT] = fbinfo_crt;
+ info->fb[HEAD_PANEL] = fbinfo_pnl;
+ }
+
+ return info;
+}
+
+/* sm501_init_cursor
+ *
+ * initialise hw cursor parameters
+*/
+
+static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base)
+{
+ struct sm501fb_par *par = fbi->par;
+ struct sm501fb_info *info = par->info;
+ int ret;
+
+ par->cursor_regs = info->regs + reg_base;
+
+ ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024);
+ if (ret < 0)
+ return ret;
+
+ /* initialise the colour registers */
+
+ writel(par->cursor.sm_addr, par->cursor_regs + SM501_OFF_HWC_ADDR);
+
+ writel(0x00, par->cursor_regs + SM501_OFF_HWC_LOC);
+ writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_1_2);
+ writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_3);
+ sm501fb_sync_regs(info);
+
+ return 0;
+}
+
+/* sm501fb_info_start
+ *
+ * fills the par structure claiming resources and remapping etc.
+*/
+
+static int sm501fb_start(struct sm501fb_info *info,
+ struct platform_device *pdev)
+{
+ struct resource *res;
+ struct device *dev;
+ int ret;
+
+ info->dev = dev = &pdev->dev;
+ platform_set_drvdata(pdev, info);
+
+ info->irq = ret = platform_get_irq(pdev, 0);
+ if (ret < 0) {
+ /* we currently do not use the IRQ */
+ dev_warn(dev, "no irq for device\n");
+ }
+
+ /* allocate, reserve and remap resources for registers */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(dev, "no resource definition for registers\n");
+ ret = -ENOENT;
+ goto err_release;
+ }
+
+ info->regs_res = request_mem_region(res->start,
+ res->end - res->start,
+ pdev->name);
+
+ if (info->regs_res == NULL) {
+ dev_err(dev, "cannot claim registers\n");
+ ret = -ENXIO;
+ goto err_release;
+ }
+
+ info->regs = ioremap(res->start, (res->end - res->start)+1);
+ if (info->regs == NULL) {
+ dev_err(dev, "cannot remap registers\n");
+ ret = -ENXIO;
+ goto err_regs_res;
+ }
+
+ /* allocate, reserve resources for framebuffer */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ if (res == NULL) {
+ dev_err(dev, "no memory resource defined\n");
+ ret = -ENXIO;
+ goto err_regs_map;
+ }
+
+ info->fbmem_res = request_mem_region(res->start,
+ (res->end - res->start)+1,
+ pdev->name);
+ if (info->fbmem_res == NULL) {
+ dev_err(dev, "cannot claim framebuffer\n");
+ ret = -ENXIO;
+ goto err_regs_map;
+ }
+
+ info->fbmem = ioremap(res->start, (res->end - res->start)+1);
+ if (info->fbmem == NULL) {
+ dev_err(dev, "cannot remap framebuffer\n");
+ goto err_mem_res;
+ }
+
+ info->fbmem_len = (res->end - res->start)+1;
+
+ /* enable display controller */
+ sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1);
+
+ /* setup cursors */
+
+ sm501_init_cursor(info->fb[HEAD_CRT], SM501_DC_CRT_HWC_ADDR);
+ sm501_init_cursor(info->fb[HEAD_PANEL], SM501_DC_PANEL_HWC_ADDR);
+
+ return 0; /* everything is setup */
+
+ err_mem_res:
+ release_resource(info->fbmem_res);
+ kfree(info->fbmem_res);
+
+ err_regs_map:
+ iounmap(info->regs);
+
+ err_regs_res:
+ release_resource(info->regs_res);
+ kfree(info->regs_res);
+
+ err_release:
+ return ret;
+}
+
+static void sm501fb_stop(struct sm501fb_info *info)
+{
+ /* disable display controller */
+ sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 0);
+
+ iounmap(info->fbmem);
+ release_resource(info->fbmem_res);
+ kfree(info->fbmem_res);
+
+ iounmap(info->regs);
+ release_resource(info->regs_res);
+ kfree(info->regs_res);
+}
+
+static void sm501fb_info_release(struct sm501fb_info *info)
+{
+ kfree(info);
+}
+
+static int sm501fb_init_fb(struct fb_info *fb,
+ enum sm501_controller head,
+ const char *fbname)
+{
+ struct sm501_platdata_fbsub *pd;
+ struct sm501fb_par *par = fb->par;
+ struct sm501fb_info *info = par->info;
+ unsigned long ctrl;
+ unsigned int enable;
+ int ret;
+
+ switch (head) {
+ case HEAD_CRT:
+ pd = info->pdata->fb_crt;
+ ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
+ enable = (ctrl & SM501_DC_CRT_CONTROL_ENABLE) ? 1 : 0;
+
+ /* ensure we set the correct source register */
+ if (info->pdata->fb_route != SM501_FB_CRT_PANEL) {
+ ctrl |= SM501_DC_CRT_CONTROL_SEL;
+ writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
+ }
+
+ break;
+
+ case HEAD_PANEL:
+ pd = info->pdata->fb_pnl;
+ ctrl = readl(info->regs + SM501_DC_PANEL_CONTROL);
+ enable = (ctrl & SM501_DC_PANEL_CONTROL_EN) ? 1 : 0;
+ break;
+
+ default:
+ pd = NULL; /* stop compiler warnings */
+ ctrl = 0;
+ enable = 0;
+ BUG();
+ }
+
+ dev_info(info->dev, "fb %s %sabled at start\n",
+ fbname, enable ? "en" : "dis");
+
+ /* check to see if our routing allows this */
+
+ if (head == HEAD_CRT && info->pdata->fb_route == SM501_FB_CRT_PANEL) {
+ ctrl &= ~SM501_DC_CRT_CONTROL_SEL;
+ writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
+ enable = 0;
+ }
+
+ strlcpy(fb->fix.id, fbname, sizeof(fb->fix.id));
+
+ memcpy(&par->ops,
+ (head == HEAD_CRT) ? &sm501fb_ops_crt : &sm501fb_ops_pnl,
+ sizeof(struct fb_ops));
+
+ /* update ops dependant on what we've been passed */
+
+ if ((pd->flags & SM501FB_FLAG_USE_HWCURSOR) == 0)
+ par->ops.fb_cursor = NULL;
+
+ fb->fbops = &par->ops;
+ fb->flags = FBINFO_FLAG_DEFAULT |
+ FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
+
+ /* fixed data */
+
+ fb->fix.type = FB_TYPE_PACKED_PIXELS;
+ fb->fix.type_aux = 0;
+ fb->fix.xpanstep = 1;
+ fb->fix.ypanstep = 1;
+ fb->fix.ywrapstep = 0;
+ fb->fix.accel = FB_ACCEL_NONE;
+
+ /* screenmode */
+
+ fb->var.nonstd = 0;
+ fb->var.activate = FB_ACTIVATE_NOW;
+ fb->var.accel_flags = 0;
+ fb->var.vmode = FB_VMODE_NONINTERLACED;
+ fb->var.bits_per_pixel = 16;
+
+ if (enable && (pd->flags & SM501FB_FLAG_USE_INIT_MODE) && 0) {
+ /* TODO read the mode from the current display */
+
+ } else {
+ if (pd->def_mode) {
+ dev_info(info->dev, "using supplied mode\n");
+ fb_videomode_to_var(&fb->var, pd->def_mode);
+
+ fb->var.bits_per_pixel = pd->def_bpp ? pd->def_bpp : 8;
+ fb->var.xres_virtual = fb->var.xres;
+ fb->var.yres_virtual = fb->var.yres;
+ } else {
+ ret = fb_find_mode(&fb->var, fb,
+ NULL, NULL, 0, NULL, 8);
+
+ if (ret == 0 || ret == 4) {
+ dev_err(info->dev,
+ "failed to get initial mode\n");
+ return -EINVAL;
+ }
+ }
+ }
+
+ /* initialise and set the palette */
+ fb_alloc_cmap(&fb->cmap, NR_PALETTE, 0);
+ fb_set_cmap(&fb->cmap, fb);
+
+ ret = (fb->fbops->fb_check_var)(&fb->var, fb);
+ if (ret)
+ dev_err(info->dev, "check_var() failed on initial setup?\n");
+
+ /* ensure we've activated our new configuration */
+ (fb->fbops->fb_set_par)(fb);
+
+ return 0;
+}
+
+/* default platform data if none is supplied (ie, PCI device) */
+
+static struct sm501_platdata_fbsub sm501fb_pdata_crt = {
+ .flags = (SM501FB_FLAG_USE_INIT_MODE |
+ SM501FB_FLAG_USE_HWCURSOR |
+ SM501FB_FLAG_USE_HWACCEL |
+ SM501FB_FLAG_DISABLE_AT_EXIT),
+
+};
+
+static struct sm501_platdata_fbsub sm501fb_pdata_pnl = {
+ .flags = (SM501FB_FLAG_USE_INIT_MODE |
+ SM501FB_FLAG_USE_HWCURSOR |
+ SM501FB_FLAG_USE_HWACCEL |
+ SM501FB_FLAG_DISABLE_AT_EXIT),
+};
+
+static struct sm501_platdata_fb sm501fb_def_pdata = {
+ .fb_route = SM501_FB_OWN,
+ .fb_crt = &sm501fb_pdata_crt,
+ .fb_pnl = &sm501fb_pdata_pnl,
+};
+
+static char driver_name_crt[] = "sm501fb-crt";
+static char driver_name_pnl[] = "sm501fb-panel";
+
+static int __init sm501fb_probe(struct platform_device *pdev)
+{
+ struct sm501fb_info *info;
+ struct device *dev = &pdev->dev;
+ struct fb_info *fbinfo_crt;
+ struct fb_info *fbinfo_pnl;
+ int ret;
+
+ /* allocate our framebuffers */
+
+ fbinfo_crt = framebuffer_alloc(sizeof(struct sm501fb_par), dev);
+ if (fbinfo_crt == NULL) {
+ dev_err(dev, "cannot allocate crt framebuffer\n");
+ return -ENOMEM;
+ }
+
+ fbinfo_pnl = framebuffer_alloc(sizeof(struct sm501fb_par), dev);
+ if (fbinfo_pnl == NULL) {
+ dev_err(dev, "cannot allocate panel framebuffer\n");
+ ret = -ENOMEM;
+ goto fbinfo_crt_alloc_fail;
+ }
+
+ info = sm501fb_info_alloc(fbinfo_crt, fbinfo_pnl);
+ if (info == NULL) {
+ dev_err(dev, "cannot allocate par\n");
+ ret = -ENOMEM;
+ goto sm501fb_alloc_fail;
+ }
+
+ if (dev->parent->platform_data) {
+ struct sm501_platdata *pd = dev->parent->platform_data;
+ info->pdata = pd->fb;
+ }
+
+ if (info->pdata == NULL) {
+ dev_info(dev, "using default configuration data\n");
+ info->pdata = &sm501fb_def_pdata;
+ }
+
+ /* start the framebuffers */
+
+ ret = sm501fb_start(info, pdev);
+ if (ret) {
+ dev_err(dev, "cannot initialise SM501\n");
+ goto sm501fb_start_fail;
+ }
+
+ /* CRT framebuffer setup */
+
+ ret = sm501fb_init_fb(fbinfo_crt, HEAD_CRT, driver_name_crt);
+ if (ret) {
+ dev_err(dev, "cannot initialise CRT fb\n");
+ goto sm501fb_start_fail;
+ }
+
+ /* Panel framebuffer setup */
+
+ ret = sm501fb_init_fb(fbinfo_pnl, HEAD_PANEL, driver_name_pnl);
+ if (ret) {
+ dev_err(dev, "cannot initialise Panel fb\n");
+ goto sm501fb_start_fail;
+ }
+
+ /* register framebuffers */
+
+ ret = register_framebuffer(fbinfo_crt);
+ if (ret < 0) {
+ dev_err(dev, "failed to register CRT fb (%d)\n", ret);
+ goto register_crt_fail;
+ }
+
+ ret = register_framebuffer(fbinfo_pnl);
+ if (ret < 0) {
+ dev_err(dev, "failed to register panel fb (%d)\n", ret);
+ goto register_pnl_fail;
+ }
+
+ dev_info(dev, "fb%d: %s frame buffer device\n",
+ fbinfo_crt->node, fbinfo_crt->fix.id);
+
+ dev_info(dev, "fb%d: %s frame buffer device\n",
+ fbinfo_pnl->node, fbinfo_pnl->fix.id);
+
+ /* create device files */
+
+ ret = device_create_file(dev, &dev_attr_crt_src);
+ if (ret)
+ goto crtsrc_fail;
+
+ ret = device_create_file(dev, &dev_attr_fbregs_pnl);
+ if (ret)
+ goto fbregs_pnl_fail;
+
+ ret = device_create_file(dev, &dev_attr_fbregs_crt);
+ if (ret)
+ goto fbregs_crt_fail;
+
+ /* we registered, return ok */
+ return 0;
+
+ fbregs_crt_fail:
+ device_remove_file(dev, &dev_attr_fbregs_pnl);
+
+ fbregs_pnl_fail:
+ device_remove_file(dev, &dev_attr_crt_src);
+
+ crtsrc_fail:
+ unregister_framebuffer(fbinfo_pnl);
+
+ register_pnl_fail:
+ unregister_framebuffer(fbinfo_crt);
+
+ register_crt_fail:
+ sm501fb_stop(info);
+
+ sm501fb_start_fail:
+ sm501fb_info_release(info);
+
+ sm501fb_alloc_fail:
+ framebuffer_release(fbinfo_pnl);
+
+ fbinfo_crt_alloc_fail:
+ framebuffer_release(fbinfo_crt);
+
+ return ret;
+}
+
+
+/*
+ * Cleanup
+ */
+static int sm501fb_remove(struct platform_device *pdev)
+{
+ struct sm501fb_info *info = platform_get_drvdata(pdev);
+ struct fb_info *fbinfo_crt = info->fb[0];
+ struct fb_info *fbinfo_pnl = info->fb[1];
+
+ device_remove_file(&pdev->dev, &dev_attr_fbregs_crt);
+ device_remove_file(&pdev->dev, &dev_attr_fbregs_pnl);
+ device_remove_file(&pdev->dev, &dev_attr_crt_src);
+
+ unregister_framebuffer(fbinfo_crt);
+ unregister_framebuffer(fbinfo_pnl);
+
+ sm501fb_stop(info);
+ sm501fb_info_release(info);
+
+ framebuffer_release(fbinfo_pnl);
+ framebuffer_release(fbinfo_crt);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int sm501fb_suspend_fb(struct sm501fb_info *info,
+ enum sm501_controller head)
+{
+ struct fb_info *fbi = info->fb[head];
+ struct sm501fb_par *par = fbi->par;
+
+ if (par->screen.size == 0)
+ return 0;
+
+ /* backup copies in case chip is powered down over suspend */
+
+ par->store_fb = vmalloc(par->screen.size);
+ if (par->store_fb == NULL) {
+ dev_err(info->dev, "no memory to store screen\n");
+ return -ENOMEM;
+ }
+
+ par->store_cursor = vmalloc(par->cursor.size);
+ if (par->store_cursor == NULL) {
+ dev_err(info->dev, "no memory to store cursor\n");
+ goto err_nocursor;
+ }
+
+ memcpy_fromio(par->store_fb, par->screen.k_addr, par->screen.size);
+ memcpy_fromio(par->store_cursor, par->cursor.k_addr, par->cursor.size);
+
+ /* blank the relevant interface to ensure unit power minimised */
+ (par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi);
+
+ return 0;
+
+ err_nocursor:
+ vfree(par->store_fb);
+
+ return -ENOMEM;
+
+}
+
+static void sm501fb_resume_fb(struct sm501fb_info *info,
+ enum sm501_controller head)
+{
+ struct fb_info *fbi = info->fb[head];
+ struct sm501fb_par *par = fbi->par;
+
+ if (par->screen.size == 0)
+ return;
+
+ /* re-activate the configuration */
+
+ (par->ops.fb_set_par)(fbi);
+
+ /* restore the data */
+
+ memcpy_toio(par->screen.k_addr, par->store_fb, par->screen.size);
+ memcpy_toio(par->cursor.k_addr, par->store_cursor, par->cursor.size);
+
+ vfree(par->store_fb);
+ vfree(par->store_cursor);
+}
+
+
+/* suspend and resume support */
+
+static int sm501fb_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct sm501fb_info *info = platform_get_drvdata(pdev);
+
+ sm501fb_suspend_fb(info, HEAD_CRT);
+ sm501fb_suspend_fb(info, HEAD_PANEL);
+
+ /* turn off the clocks, in case the device is not powered down */
+ sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 0);
+
+ return 0;
+}
+
+static int sm501fb_resume(struct platform_device *pdev)
+{
+ struct sm501fb_info *info = platform_get_drvdata(pdev);
+
+ sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 1);
+
+ sm501fb_resume_fb(info, HEAD_CRT);
+ sm501fb_resume_fb(info, HEAD_PANEL);
+
+ return 0;
+}
+
+#else
+#define sm501fb_suspend NULL
+#define sm501fb_resume NULL
+#endif
+
+static struct platform_driver sm501fb_driver = {
+ .probe = sm501fb_probe,
+ .remove = sm501fb_remove,
+ .suspend = sm501fb_suspend,
+ .resume = sm501fb_resume,
+ .driver = {
+ .name = "sm501-fb",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __devinit sm501fb_init(void)
+{
+ return platform_driver_register(&sm501fb_driver);
+}
+
+static void __exit sm501fb_cleanup(void)
+{
+ platform_driver_unregister(&sm501fb_driver);
+}
+
+module_init(sm501fb_init);
+module_exit(sm501fb_cleanup);
+
+MODULE_AUTHOR("Ben Dooks, Vincent Sanders");
+MODULE_DESCRIPTION("SM501 Framebuffer driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c
index 59cd1e750f3..62fa5500361 100644
--- a/drivers/video/sstfb.c
+++ b/drivers/video/sstfb.c
@@ -257,6 +257,7 @@ static void __sst_dac_write(u8 __iomem *vbase, u8 reg, u8 val)
r_dprintk("sst_dac_write(%#x, %#x)\n", reg, val);
reg &= 0x07;
__sst_write(vbase, DAC_DATA,(((u32)reg << 8)) | (u32)val);
+ __sst_wait_idle(vbase);
}
/* indexed access to ti/att dacs */