aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDanny Tholen <moondrake@gmail.com>2009-05-07 00:11:34 +0100
committerStuart Bennett <stuart@freedesktop.org>2009-05-22 15:43:26 +0100
commit85b9f737db0d2a845e4d7e2bbf9ad12ff9e2227c (patch)
tree662b41af45815f84ddc518f065515a89b8c29003
parentf355ad89431c49355e626613e6fc29ef2e183dab (diff)
nouveau: backlight support for ppc laptops
Patch allows the backlight to be manipulated under gnome on apple powerpc based NV30 machines. It works fine on my powerbook, and should also work for older NV17/NV18 machines. Note that older powerpc specific tools (pbbuttonsd) have some problems with this implementation (because the device is not yet there at the start time of the daemon, and the code makes incorrect assumptions about the max brightness values). However, IMHO these things can and should be addressed in the daemon. Some style/warning fixes applied by Stuart Bennett <stuart@freedesktop.org>
-rw-r--r--linux-core/nouveau_backlight.c93
-rw-r--r--shared-core/nouveau_reg.h4
2 files changed, 97 insertions, 0 deletions
diff --git a/linux-core/nouveau_backlight.c b/linux-core/nouveau_backlight.c
index 1b36f3cf..3a68d924 100644
--- a/linux-core/nouveau_backlight.c
+++ b/linux-core/nouveau_backlight.c
@@ -27,6 +27,10 @@
* Authors:
* Matthew Garrett <mjg@redhat.com>
*
+ * PowerPC specific stuff:
+ * Danny Tholen <moondrake@gmail.com>
+ * (mainly based on info from nvidiafb)
+ *
* Register locations derived from NVClock by Roderick Colenbrander
*/
@@ -36,9 +40,54 @@
#include "nouveau_drv.h"
#include "nouveau_drm.h"
#include "nouveau_reg.h"
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23))
+#ifdef CONFIG_PMAC_BACKLIGHT
+static int ppc_get_intensity(struct backlight_device *bd)
+{
+ struct drm_device *dev = bl_get_data(bd);
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ int raw_val = (NV_READ(NV_PBUS_DEBUG_DUALHEAD_CTL) & 0x7fff0000) >> 16;
+ int min_brightness = bd->props.max_brightness / 3;
+ int intensity = raw_val - min_brightness;
+
+ return (intensity < 0 ? 0 : intensity);
+}
+
+static int ppc_set_intensity(struct backlight_device *bd)
+{
+ struct drm_device *dev = bl_get_data(bd);
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ int val = bd->props.brightness;
+ int min_brightness = bd->props.max_brightness / 3;
+ int dh_ctl = NV_READ(NV_PBUS_DEBUG_DUALHEAD_CTL) & 0x0000ffff;
+ int gpio_ext = NV_READ(NV_PCRTC_GPIO_EXT) & ~0x3;
+
+ if (val > 0) {
+ dh_ctl |= (1 << 31); /* backlight bit on */
+ dh_ctl |= (val + min_brightness) << 16;
+ gpio_ext |= 0x1;
+ }
+
+ NV_WRITE(NV_PBUS_DEBUG_DUALHEAD_CTL, dh_ctl);
+ NV_WRITE(NV_PCRTC_GPIO_EXT, gpio_ext);
+
+ return 0;
+}
+
+static struct backlight_ops ppc_bl_ops = {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29))
+ .options = BL_CORE_SUSPENDRESUME,
+#endif
+ .get_brightness = ppc_get_intensity,
+ .update_status = ppc_set_intensity,
+};
+#endif /* CONFIG_PMAC_BACKLIGHT */
+
static int nv40_get_intensity(struct backlight_device *bd)
{
struct drm_device *dev = bl_get_data(bd);
@@ -96,6 +145,45 @@ static struct backlight_ops nv50_bl_ops = {
.update_status = nv50_set_intensity,
};
+#ifdef CONFIG_PMAC_BACKLIGHT
+static int nouveau_ppc_backlight_init(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct backlight_device *bd;
+ int max_brightness;
+
+ if (!machine_is(powermac) ||
+ !pmac_has_backlight_type("mnca"))
+ return -ENODEV;
+
+ /* "nv_bl0", some old powerpc userland tools rely on this */
+ bd = backlight_device_register("nv_bl0", &dev->pdev->dev, dev,
+ &ppc_bl_ops);
+ if (IS_ERR(bd))
+ return PTR_ERR(bd);
+
+ dev_priv->backlight = bd;
+
+ /* the least significant 15 bits of NV_PBUS_DEBUG_DUALHEAD_CTL
+ * set the maximum backlight level, OF sets it to 0x535 on my
+ * powerbook. however, posting the card sets this to 0x7FFF.
+ * Below 25% the blacklight turns off.
+ *
+ * NOTE: pbbuttonsd limits brightness values < 255, and thus
+ * will not work well with this.
+ */
+
+ /* FIXME: do we want to fix this reg to 0x535 for consistency? */
+ max_brightness = NV_READ(NV_PBUS_DEBUG_DUALHEAD_CTL) & 0x0000ffff;
+ /* lose (bottom) 25% of range */
+ bd->props.max_brightness = (max_brightness * 3) / 4;
+ bd->props.brightness = ppc_get_intensity(bd);
+ backlight_update_status(bd);
+
+ return 0;
+}
+#endif
+
static int nouveau_nv40_backlight_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -142,6 +230,11 @@ int nouveau_backlight_init(struct drm_device *dev)
struct drm_nouveau_private *dev_priv = dev->dev_private;
switch (dev_priv->card_type) {
+#ifdef CONFIG_PMAC_BACKLIGHT
+ case NV_17:
+ case NV_30:
+ return nouveau_ppc_backlight_init(dev);
+#endif
case NV_40:
case NV_44:
return nouveau_nv40_backlight_init(dev);
diff --git a/shared-core/nouveau_reg.h b/shared-core/nouveau_reg.h
index eade44e5..695bf5d7 100644
--- a/shared-core/nouveau_reg.h
+++ b/shared-core/nouveau_reg.h
@@ -95,6 +95,9 @@
* the card will hang early on in the X init process.
*/
# define NV_PMC_ENABLE_UNK13 (1<<13)
+
+#define NV_PBUS_DEBUG_DUALHEAD_CTL 0x000010F0
+
#define NV40_PMC_BACKLIGHT 0x000015f0
# define NV40_PMC_BACKLIGHT_MASK 0x001f0000
#define NV40_PMC_1700 0x00001700
@@ -404,6 +407,7 @@
#define NV40_PGRAPH_TSIZE1(i) (0x00406908 + (i*16))
#define NV40_PGRAPH_TSTATUS1(i) (0x0040690C + (i*16))
+#define NV_PCRTC_GPIO_EXT 0x0060081C
/* It's a guess that this works on NV03. Confirmed on NV04, though */
#define NV04_PFIFO_DELAY_0 0x00002040