aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/nvidia
diff options
context:
space:
mode:
authorMichael Hanselmann <linux-kernel@hansmi.ch>2006-06-25 08:47:08 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-25 13:00:59 -0400
commit5474c120aafe78ca54bf272f7a01107c42da2b21 (patch)
treec1b002a27703ce92c816bfb9844752186e33d403 /drivers/video/nvidia
parent17660bdd5c1f1a165273c1a59cb5b87670a81cc4 (diff)
[PATCH] Rewritten backlight infrastructure for portable Apple computers
This patch contains a total rewrite of the backlight infrastructure for portable Apple computers. Backward compatibility is retained. A sysfs interface allows userland to control the brightness with more steps than before. Userland is allowed to upload a brightness curve for different monitors, similar to Mac OS X. [akpm@osdl.org: add needed exports] Signed-off-by: Michael Hanselmann <linux-kernel@hansmi.ch> Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Richard Purdie <rpurdie@rpsys.net> Cc: "Antonino A. Daplas" <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/video/nvidia')
-rw-r--r--drivers/video/nvidia/Makefile3
-rw-r--r--drivers/video/nvidia/nv_backlight.c175
-rw-r--r--drivers/video/nvidia/nv_proto.h10
-rw-r--r--drivers/video/nvidia/nvidia.c95
4 files changed, 201 insertions, 82 deletions
diff --git a/drivers/video/nvidia/Makefile b/drivers/video/nvidia/Makefile
index 690d37e8de5b..ca47432113e0 100644
--- a/drivers/video/nvidia/Makefile
+++ b/drivers/video/nvidia/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_FB_NVIDIA) += nvidiafb.o
7nvidiafb-y := nvidia.o nv_hw.o nv_setup.o \ 7nvidiafb-y := nvidia.o nv_hw.o nv_setup.o \
8 nv_accel.o 8 nv_accel.o
9nvidiafb-$(CONFIG_FB_NVIDIA_I2C) += nv_i2c.o 9nvidiafb-$(CONFIG_FB_NVIDIA_I2C) += nv_i2c.o
10nvidiafb-$(CONFIG_FB_NVIDIA_BACKLIGHT) += nv_backlight.o
10nvidiafb-$(CONFIG_PPC_OF) += nv_of.o 11nvidiafb-$(CONFIG_PPC_OF) += nv_of.o
11 12
12nvidiafb-objs := $(nvidiafb-y) \ No newline at end of file 13nvidiafb-objs := $(nvidiafb-y)
diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c
new file mode 100644
index 000000000000..1c1c10c699c5
--- /dev/null
+++ b/drivers/video/nvidia/nv_backlight.c
@@ -0,0 +1,175 @@
1/*
2 * Backlight code for nVidia based graphic cards
3 *
4 * Copyright 2004 Antonino Daplas <adaplas@pol.net>
5 * Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/backlight.h>
13#include <linux/fb.h>
14#include <linux/pci.h>
15#include "nv_local.h"
16#include "nv_type.h"
17#include "nv_proto.h"
18
19#ifdef CONFIG_PMAC_BACKLIGHT
20#include <asm/backlight.h>
21#include <asm/machdep.h>
22#endif
23
24/* We do not have any information about which values are allowed, thus
25 * we used safe values.
26 */
27#define MIN_LEVEL 0x158
28#define MAX_LEVEL 0x534
29
30static struct backlight_properties nvidia_bl_data;
31
32static int nvidia_bl_get_level_brightness(struct nvidia_par *par,
33 int level)
34{
35 struct fb_info *info = pci_get_drvdata(par->pci_dev);
36 int nlevel;
37
38 /* Get and convert the value */
39 mutex_lock(&info->bl_mutex);
40 nlevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
41 mutex_unlock(&info->bl_mutex);
42
43 if (nlevel < 0)
44 nlevel = 0;
45 else if (nlevel < MIN_LEVEL)
46 nlevel = MIN_LEVEL;
47 else if (nlevel > MAX_LEVEL)
48 nlevel = MAX_LEVEL;
49
50 return nlevel;
51}
52
53static int nvidia_bl_update_status(struct backlight_device *bd)
54{
55 struct nvidia_par *par = class_get_devdata(&bd->class_dev);
56 u32 tmp_pcrt, tmp_pmc, fpcontrol;
57 int level;
58
59 if (!par->FlatPanel)
60 return 0;
61
62 if (bd->props->power != FB_BLANK_UNBLANK ||
63 bd->props->fb_blank != FB_BLANK_UNBLANK)
64 level = 0;
65 else
66 level = bd->props->brightness;
67
68 tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF;
69 tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC;
70 fpcontrol = NV_RD32(par->PRAMDAC, 0x0848) & 0xCFFFFFCC;
71
72 if (level > 0) {
73 tmp_pcrt |= 0x1;
74 tmp_pmc |= (1 << 31); /* backlight bit */
75 tmp_pmc |= nvidia_bl_get_level_brightness(par, level) << 16;
76 fpcontrol |= par->fpSyncs;
77 } else
78 fpcontrol |= 0x20000022;
79
80 NV_WR32(par->PCRTC0, 0x081C, tmp_pcrt);
81 NV_WR32(par->PMC, 0x10F0, tmp_pmc);
82 NV_WR32(par->PRAMDAC, 0x848, fpcontrol);
83
84 return 0;
85}
86
87static int nvidia_bl_get_brightness(struct backlight_device *bd)
88{
89 return bd->props->brightness;
90}
91
92static struct backlight_properties nvidia_bl_data = {
93 .owner = THIS_MODULE,
94 .get_brightness = nvidia_bl_get_brightness,
95 .update_status = nvidia_bl_update_status,
96 .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
97};
98
99void nvidia_bl_init(struct nvidia_par *par)
100{
101 struct fb_info *info = pci_get_drvdata(par->pci_dev);
102 struct backlight_device *bd;
103 char name[12];
104
105 if (!par->FlatPanel)
106 return;
107
108#ifdef CONFIG_PMAC_BACKLIGHT
109 if (!machine_is(powermac) ||
110 !pmac_has_backlight_type("mnca"))
111 return;
112#endif
113
114 snprintf(name, sizeof(name), "nvidiabl%d", info->node);
115
116 bd = backlight_device_register(name, par, &nvidia_bl_data);
117 if (IS_ERR(bd)) {
118 info->bl_dev = NULL;
119 printk("nvidia: Backlight registration failed\n");
120 goto error;
121 }
122
123 mutex_lock(&info->bl_mutex);
124 info->bl_dev = bd;
125 fb_bl_default_curve(info, 0,
126 0x158 * FB_BACKLIGHT_MAX / MAX_LEVEL,
127 0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL);
128 mutex_unlock(&info->bl_mutex);
129
130 up(&bd->sem);
131 bd->props->brightness = nvidia_bl_data.max_brightness;
132 bd->props->power = FB_BLANK_UNBLANK;
133 bd->props->update_status(bd);
134 down(&bd->sem);
135
136#ifdef CONFIG_PMAC_BACKLIGHT
137 mutex_lock(&pmac_backlight_mutex);
138 if (!pmac_backlight)
139 pmac_backlight = bd;
140 mutex_unlock(&pmac_backlight_mutex);
141#endif
142
143 printk("nvidia: Backlight initialized (%s)\n", name);
144
145 return;
146
147error:
148 return;
149}
150
151void nvidia_bl_exit(struct nvidia_par *par)
152{
153 struct fb_info *info = pci_get_drvdata(par->pci_dev);
154
155#ifdef CONFIG_PMAC_BACKLIGHT
156 mutex_lock(&pmac_backlight_mutex);
157#endif
158
159 mutex_lock(&info->bl_mutex);
160 if (info->bl_dev) {
161#ifdef CONFIG_PMAC_BACKLIGHT
162 if (pmac_backlight == info->bl_dev)
163 pmac_backlight = NULL;
164#endif
165
166 backlight_device_unregister(info->bl_dev);
167
168 printk("nvidia: Backlight unloaded\n");
169 }
170 mutex_unlock(&info->bl_mutex);
171
172#ifdef CONFIG_PMAC_BACKLIGHT
173 mutex_unlock(&pmac_backlight_mutex);
174#endif
175}
diff --git a/drivers/video/nvidia/nv_proto.h b/drivers/video/nvidia/nv_proto.h
index b149a690ee0f..6fba656cd56b 100644
--- a/drivers/video/nvidia/nv_proto.h
+++ b/drivers/video/nvidia/nv_proto.h
@@ -63,4 +63,14 @@ extern void nvidiafb_imageblit(struct fb_info *info,
63 const struct fb_image *image); 63 const struct fb_image *image);
64extern int nvidiafb_sync(struct fb_info *info); 64extern int nvidiafb_sync(struct fb_info *info);
65extern u8 byte_rev[256]; 65extern u8 byte_rev[256];
66
67/* in nv_backlight.h */
68#ifdef CONFIG_FB_NVIDIA_BACKLIGHT
69extern void nvidia_bl_init(struct nvidia_par *par);
70extern void nvidia_bl_exit(struct nvidia_par *par);
71#else
72static inline void nvidia_bl_init(struct nvidia_par *par) {}
73static inline void nvidia_bl_exit(struct nvidia_par *par) {}
74#endif
75
66#endif /* __NV_PROTO_H__ */ 76#endif /* __NV_PROTO_H__ */
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index 093ab9977c7c..03a7c1e9ce38 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -22,6 +22,7 @@
22#include <linux/init.h> 22#include <linux/init.h>
23#include <linux/pci.h> 23#include <linux/pci.h>
24#include <linux/console.h> 24#include <linux/console.h>
25#include <linux/backlight.h>
25#ifdef CONFIG_MTRR 26#ifdef CONFIG_MTRR
26#include <asm/mtrr.h> 27#include <asm/mtrr.h>
27#endif 28#endif
@@ -29,10 +30,6 @@
29#include <asm/prom.h> 30#include <asm/prom.h>
30#include <asm/pci-bridge.h> 31#include <asm/pci-bridge.h>
31#endif 32#endif
32#ifdef CONFIG_PMAC_BACKLIGHT
33#include <asm/machdep.h>
34#include <asm/backlight.h>
35#endif
36 33
37#include "nv_local.h" 34#include "nv_local.h"
38#include "nv_type.h" 35#include "nv_type.h"
@@ -470,75 +467,6 @@ static struct fb_var_screeninfo __devinitdata nvidiafb_default_var = {
470 .vmode = FB_VMODE_NONINTERLACED 467 .vmode = FB_VMODE_NONINTERLACED
471}; 468};
472 469
473/*
474 * Backlight control
475 */
476#ifdef CONFIG_PMAC_BACKLIGHT
477
478static int nvidia_backlight_levels[] = {
479 0x158,
480 0x192,
481 0x1c6,
482 0x200,
483 0x234,
484 0x268,
485 0x2a2,
486 0x2d6,
487 0x310,
488 0x344,
489 0x378,
490 0x3b2,
491 0x3e6,
492 0x41a,
493 0x454,
494 0x534,
495};
496
497/* ------------------------------------------------------------------------- *
498 *
499 * Backlight operations
500 *
501 * ------------------------------------------------------------------------- */
502
503static int nvidia_set_backlight_enable(int on, int level, void *data)
504{
505 struct nvidia_par *par = data;
506 u32 tmp_pcrt, tmp_pmc, fpcontrol;
507
508 tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF;
509 tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC;
510 fpcontrol = NV_RD32(par->PRAMDAC, 0x0848) & 0xCFFFFFCC;
511
512 if (on && (level > BACKLIGHT_OFF)) {
513 tmp_pcrt |= 0x1;
514 tmp_pmc |= (1 << 31); // backlight bit
515 tmp_pmc |= nvidia_backlight_levels[level - 1] << 16;
516 }
517
518 if (on)
519 fpcontrol |= par->fpSyncs;
520 else
521 fpcontrol |= 0x20000022;
522
523 NV_WR32(par->PCRTC0, 0x081C, tmp_pcrt);
524 NV_WR32(par->PMC, 0x10F0, tmp_pmc);
525 NV_WR32(par->PRAMDAC, 0x848, fpcontrol);
526
527 return 0;
528}
529
530static int nvidia_set_backlight_level(int level, void *data)
531{
532 return nvidia_set_backlight_enable(1, level, data);
533}
534
535static struct backlight_controller nvidia_backlight_controller = {
536 nvidia_set_backlight_enable,
537 nvidia_set_backlight_level
538};
539
540#endif /* CONFIG_PMAC_BACKLIGHT */
541
542static void nvidiafb_load_cursor_image(struct nvidia_par *par, u8 * data8, 470static void nvidiafb_load_cursor_image(struct nvidia_par *par, u8 * data8,
543 u16 bg, u16 fg, u32 w, u32 h) 471 u16 bg, u16 fg, u32 w, u32 h)
544{ 472{
@@ -1355,10 +1283,15 @@ static int nvidiafb_blank(int blank, struct fb_info *info)
1355 NVWriteSeq(par, 0x01, tmp); 1283 NVWriteSeq(par, 0x01, tmp);
1356 NVWriteCrtc(par, 0x1a, vesa); 1284 NVWriteCrtc(par, 0x1a, vesa);
1357 1285
1358#ifdef CONFIG_PMAC_BACKLIGHT 1286#ifdef CONFIG_FB_NVIDIA_BACKLIGHT
1359 if (par->FlatPanel && machine_is(powermac)) { 1287 mutex_lock(&info->bl_mutex);
1360 set_backlight_enable(!blank); 1288 if (info->bl_dev) {
1289 down(&info->bl_dev->sem);
1290 info->bl_dev->props->power = blank;
1291 info->bl_dev->props->update_status(info->bl_dev);
1292 up(&info->bl_dev->sem);
1361 } 1293 }
1294 mutex_unlock(&info->bl_mutex);
1362#endif 1295#endif
1363 1296
1364 NVTRACE_LEAVE(); 1297 NVTRACE_LEAVE();
@@ -1741,11 +1674,9 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd,
1741 "PCI nVidia %s framebuffer (%dMB @ 0x%lX)\n", 1674 "PCI nVidia %s framebuffer (%dMB @ 0x%lX)\n",
1742 info->fix.id, 1675 info->fix.id,
1743 par->FbMapSize / (1024 * 1024), info->fix.smem_start); 1676 par->FbMapSize / (1024 * 1024), info->fix.smem_start);
1744#ifdef CONFIG_PMAC_BACKLIGHT 1677
1745 if (par->FlatPanel && machine_is(powermac)) 1678 nvidia_bl_init(par);
1746 register_backlight_controller(&nvidia_backlight_controller, 1679
1747 par, "mnca");
1748#endif
1749 NVTRACE_LEAVE(); 1680 NVTRACE_LEAVE();
1750 return 0; 1681 return 0;
1751 1682
@@ -1775,6 +1706,8 @@ static void __exit nvidiafb_remove(struct pci_dev *pd)
1775 1706
1776 NVTRACE_ENTER(); 1707 NVTRACE_ENTER();
1777 1708
1709 nvidia_bl_exit(par);
1710
1778 unregister_framebuffer(info); 1711 unregister_framebuffer(info);
1779#ifdef CONFIG_MTRR 1712#ifdef CONFIG_MTRR
1780 if (par->mtrr.vram_valid) 1713 if (par->mtrr.vram_valid)