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>
This commit is contained in:
Danny Tholen 2009-05-07 00:11:34 +01:00 committed by Stuart Bennett
parent f355ad8943
commit 85b9f737db
2 changed files with 97 additions and 0 deletions

View file

@ -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);

View file

@ -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