2012-08-13 20:43:00

by Matthew Garrett

[permalink] [raw]
Subject: [PATCH 1/2] gmux: Add generic write32 function

Move the special-cased backlight update function to a generic gmux_write32
function.

Signed-off-by: Matthew Garrett <[email protected]>
Cc: Seth Forshee <[email protected]>
---
drivers/gpu/drm/nouveau/nouveau_bios.c | 3 +++
drivers/platform/x86/apple-gmux.c | 23 +++++++++++++----------
2 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index a0a3fe3..818b93c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -6473,6 +6473,9 @@ nouveau_run_vbios_init(struct drm_device *dev)
}
}

+ if (!bios->execute)
+ nouveau_gpio_reset(dev);
+
return ret;
}

diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
index 905fa01..43721c1 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -75,6 +75,18 @@ static inline u32 gmux_read32(struct apple_gmux_data *gmux_data, int port)
return inl(gmux_data->iostart + port);
}

+static inline u32 gmux_write32(struct apple_gmux_data *gmux_data, int port,
+ u32 val)
+{
+ int i;
+ u8 tmpval;
+
+ for (i = 0; i < 4; i++) {
+ tmpval = (val >> (i * 8)) & 0xff;
+ outb(tmpval, port + i);
+ }
+}
+
static int gmux_get_brightness(struct backlight_device *bd)
{
struct apple_gmux_data *gmux_data = bl_get_data(bd);
@@ -90,16 +102,7 @@ static int gmux_update_status(struct backlight_device *bd)
if (bd->props.state & BL_CORE_SUSPENDED)
return 0;

- /*
- * Older gmux versions require writing out lower bytes first then
- * setting the upper byte to 0 to flush the values. Newer versions
- * accept a single u32 write, but the old method also works, so we
- * just use the old method for all gmux versions.
- */
- gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS, brightness);
- gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 1, brightness >> 8);
- gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 2, brightness >> 16);
- gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 3, 0);
+ gmux_write32(gmux_data, GMUX_PORT_BRIGHTNES, brightness);

return 0;
}
--
1.7.11.2


2012-08-13 20:42:43

by Matthew Garrett

[permalink] [raw]
Subject: [PATCH 2/2] apple_gmux: Add support for newer hardware

New gmux devices have a different method for accessing the registers.
Update the driver to cope. Incorporates feedback from Bernhard Froemel.

Signed-off-by: Matthew Garrett <[email protected]>
Cc: Bernhard Froemel <[email protected]>
Cc: Seth Forshee <[email protected]>
---
drivers/platform/x86/apple-gmux.c | 181 ++++++++++++++++++++++++++++++++++----
1 file changed, 166 insertions(+), 15 deletions(-)

diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
index 43721c1..612b6f6 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -18,12 +18,15 @@
#include <linux/pnp.h>
#include <linux/apple_bl.h>
#include <linux/slab.h>
+#include <linux/delay.h>
#include <acpi/video.h>
#include <asm/io.h>

struct apple_gmux_data {
unsigned long iostart;
unsigned long iolen;
+ bool indexed;
+ struct mutex index_lock;

struct backlight_device *bdev;
};
@@ -45,6 +48,9 @@ struct apple_gmux_data {
#define GMUX_PORT_DISCRETE_POWER 0x50
#define GMUX_PORT_MAX_BRIGHTNESS 0x70
#define GMUX_PORT_BRIGHTNESS 0x74
+#define GMUX_PORT_VALUE 0xc2
+#define GMUX_PORT_READ 0xd0
+#define GMUX_PORT_WRITE 0xd4

#define GMUX_MIN_IO_LEN (GMUX_PORT_BRIGHTNESS + 4)

@@ -59,24 +65,24 @@ struct apple_gmux_data {
#define GMUX_BRIGHTNESS_MASK 0x00ffffff
#define GMUX_MAX_BRIGHTNESS GMUX_BRIGHTNESS_MASK

-static inline u8 gmux_read8(struct apple_gmux_data *gmux_data, int port)
+static u8 gmux_pio_read8(struct apple_gmux_data *gmux_data, int port)
{
return inb(gmux_data->iostart + port);
}

-static inline void gmux_write8(struct apple_gmux_data *gmux_data, int port,
+static void gmux_pio_write8(struct apple_gmux_data *gmux_data, int port,
u8 val)
{
outb(val, gmux_data->iostart + port);
}

-static inline u32 gmux_read32(struct apple_gmux_data *gmux_data, int port)
+static u32 gmux_pio_read32(struct apple_gmux_data *gmux_data, int port)
{
return inl(gmux_data->iostart + port);
}

-static inline u32 gmux_write32(struct apple_gmux_data *gmux_data, int port,
- u32 val)
+static void gmux_pio_write32(struct apple_gmux_data *gmux_data, int port,
+ u32 val)
{
int i;
u8 tmpval;
@@ -87,6 +93,144 @@ static inline u32 gmux_write32(struct apple_gmux_data *gmux_data, int port,
}
}

+static int gmux_index_wait_ready(struct apple_gmux_data *gmux_data)
+{
+ int i = 200;
+ u8 gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
+
+ while (i && (gwr & 0x01)) {
+ inb(gmux_data->iostart + GMUX_PORT_READ);
+ gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
+ msleep(100);
+ i--;
+ }
+
+ return !!i;
+}
+
+static int gmux_index_wait_complete(struct apple_gmux_data *gmux_data)
+{
+ int i = 200;
+ u8 gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
+
+ while (i && (gwr & 0x01)) {
+ gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
+ msleep(100);
+ i--;
+ }
+
+ if (gwr & 0x01)
+ inb(gmux_data->iostart + GMUX_PORT_READ);
+
+ return !!i;
+}
+
+static u8 gmux_index_read8(struct apple_gmux_data *gmux_data, int port)
+{
+ u8 val;
+
+ mutex_lock(&gmux_data->index_lock);
+ outb((port & 0xff), gmux_data->iostart + GMUX_PORT_READ);
+ gmux_index_wait_ready(gmux_data);
+ val = inb(gmux_data->iostart + GMUX_PORT_VALUE);
+ mutex_unlock(&gmux_data->index_lock);
+
+ return val;
+}
+
+static void gmux_index_write8(struct apple_gmux_data *gmux_data, int port,
+ u8 val)
+{
+ mutex_lock(&gmux_data->index_lock);
+ outb(val, gmux_data->iostart + GMUX_PORT_VALUE);
+ gmux_index_wait_ready(gmux_data);
+ outb(port & 0xff, gmux_data->iostart + GMUX_PORT_WRITE);
+ gmux_index_wait_complete(gmux_data);
+ mutex_unlock(&gmux_data->index_lock);
+}
+
+static u32 gmux_index_read32(struct apple_gmux_data *gmux_data, int port)
+{
+ u32 val;
+
+ mutex_lock(&gmux_data->index_lock);
+ outb((port & 0xff), gmux_data->iostart + GMUX_PORT_READ);
+ gmux_index_wait_ready(gmux_data);
+ val = inl(gmux_data->iostart + GMUX_PORT_VALUE);
+ mutex_unlock(&gmux_data->index_lock);
+
+ return val;
+}
+
+static void gmux_index_write32(struct apple_gmux_data *gmux_data, int port,
+ u32 val)
+{
+ int i;
+ u8 tmpval;
+
+ mutex_lock(&gmux_data->index_lock);
+
+ for (i = 0; i < 4; i++) {
+ tmpval = (val >> (i * 8)) & 0xff;
+ outb(tmpval, gmux_data->iostart + GMUX_PORT_VALUE + i);
+ }
+
+ gmux_index_wait_ready(gmux_data);
+ outb(port & 0xff, gmux_data->iostart + GMUX_PORT_WRITE);
+ gmux_index_wait_complete(gmux_data);
+ mutex_unlock(&gmux_data->index_lock);
+}
+
+static u8 gmux_read8(struct apple_gmux_data *gmux_data, int port)
+{
+ if (gmux_data->indexed)
+ return gmux_index_read8(gmux_data, port);
+ else
+ return gmux_pio_read8(gmux_data, port);
+}
+
+static void gmux_write8(struct apple_gmux_data *gmux_data, int port, u8 val)
+{
+ if (gmux_data->indexed)
+ gmux_index_write8(gmux_data, port, val);
+ else
+ gmux_pio_write8(gmux_data, port, val);
+}
+
+static u32 gmux_read32(struct apple_gmux_data *gmux_data, int port)
+{
+ if (gmux_data->indexed)
+ return gmux_index_read32(gmux_data, port);
+ else
+ return gmux_pio_read32(gmux_data, port);
+}
+
+static void gmux_write32(struct apple_gmux_data *gmux_data, int port,
+ u32 val)
+{
+ if (gmux_data->indexed)
+ gmux_index_write32(gmux_data, port, val);
+ else
+ gmux_pio_write32(gmux_data, port, val);
+}
+
+static bool gmux_is_indexed(struct apple_gmux_data *gmux_data)
+{
+ u16 val;
+
+ outb(0xaa, gmux_data->iostart + 0xcc);
+ outb(0x55, gmux_data->iostart + 0xcd);
+ outb(0x00, gmux_data->iostart + 0xce);
+
+ val = inb(gmux_data->iostart + 0xcc) |
+ (inb(gmux_data->iostart + 0xcd) << 8);
+
+ if (val == 0x55aa)
+ return true;
+
+ return false;
+}
+
static int gmux_get_brightness(struct backlight_device *bd)
{
struct apple_gmux_data *gmux_data = bl_get_data(bd);
@@ -102,7 +246,7 @@ static int gmux_update_status(struct backlight_device *bd)
if (bd->props.state & BL_CORE_SUSPENDED)
return 0;

- gmux_write32(gmux_data, GMUX_PORT_BRIGHTNES, brightness);
+ gmux_write32(gmux_data, GMUX_PORT_BRIGHTNESS, brightness);

return 0;
}
@@ -150,22 +294,29 @@ static int __devinit gmux_probe(struct pnp_dev *pnp,
}

/*
- * On some machines the gmux is in ACPI even thought the machine
- * doesn't really have a gmux. Check for invalid version information
- * to detect this.
+ * Invalid version information may indicate either that the gmux
+ * device isn't present or that it's a new one that uses indexed
+ * io
*/
+
ver_major = gmux_read8(gmux_data, GMUX_PORT_VERSION_MAJOR);
ver_minor = gmux_read8(gmux_data, GMUX_PORT_VERSION_MINOR);
ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE);
if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) {
- pr_info("gmux device not present\n");
- ret = -ENODEV;
- goto err_release;
+ if (gmux_is_indexed(gmux_data)) {
+ mutex_init(&gmux_data->index_lock);
+ gmux_data->indexed = true;
+ } else {
+ pr_info("gmux device not present\n");
+ ret = -ENODEV;
+ goto err_release;
+ }
+ pr_info("Found indexed gmux\n");
+ } else {
+ pr_info("Found gmux version %d.%d.%d\n", ver_major, ver_minor,
+ ver_release);
}

- pr_info("Found gmux version %d.%d.%d\n", ver_major, ver_minor,
- ver_release);
-
memset(&props, 0, sizeof(props));
props.type = BACKLIGHT_PLATFORM;
props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS);
--
1.7.11.2

2012-08-13 20:50:01

by Seth Forshee

[permalink] [raw]
Subject: Re: [PATCH 1/2] gmux: Add generic write32 function

On Mon, Aug 13, 2012 at 04:20:31PM -0400, Matthew Garrett wrote:
> diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
> index a0a3fe3..818b93c 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_bios.c
> +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
> @@ -6473,6 +6473,9 @@ nouveau_run_vbios_init(struct drm_device *dev)
> }
> }
>
> + if (!bios->execute)
> + nouveau_gpio_reset(dev);
> +
> return ret;
> }

This part doesn't seem to belong.

2012-08-13 20:55:22

by Seth Forshee

[permalink] [raw]
Subject: Re: [PATCH 1/2] gmux: Add generic write32 function

On Mon, Aug 13, 2012 at 04:20:31PM -0400, Matthew Garrett wrote:
> + gmux_write32(gmux_data, GMUX_PORT_BRIGHTNES, brightness);

Also, typo here. Should be GMUX_PORT_BRIGHTNESS.

2012-08-13 21:04:57

by Seth Forshee

[permalink] [raw]
Subject: Re: [PATCH 2/2] apple_gmux: Add support for newer hardware

On Mon, Aug 13, 2012 at 04:20:32PM -0400, Matthew Garrett wrote:
> +static int gmux_index_wait_ready(struct apple_gmux_data *gmux_data)
> +{
> + int i = 200;
> + u8 gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
> +
> + while (i && (gwr & 0x01)) {
> + inb(gmux_data->iostart + GMUX_PORT_READ);
> + gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
> + msleep(100);

Wouldn't it make more sense if the msleep was before reading the port
again? Otherwise there's no substantial dely between the first and
second times we read it.

> +static int gmux_index_wait_complete(struct apple_gmux_data *gmux_data)
> +{
> + int i = 200;
> + u8 gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
> +
> + while (i && (gwr & 0x01)) {
> + gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
> + msleep(100);

Likewise.

2012-08-13 21:33:05

by Matthew Garrett

[permalink] [raw]
Subject: Re: [PATCH 1/2] gmux: Add generic write32 function

On Mon, Aug 13, 2012 at 03:49:46PM -0500, Seth Forshee wrote:

> This part doesn't seem to belong.

Sigh. Yes, sorry.

--
Matthew Garrett | [email protected]

2012-08-13 21:36:11

by Matthew Garrett

[permalink] [raw]
Subject: Re: [PATCH 2/2] apple_gmux: Add support for newer hardware

On Mon, Aug 13, 2012 at 04:04:44PM -0500, Seth Forshee wrote:
> > +
> > + while (i && (gwr & 0x01)) {
> > + inb(gmux_data->iostart + GMUX_PORT_READ);
> > + gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
> > + msleep(100);
>
> Wouldn't it make more sense if the msleep was before reading the port
> again? Otherwise there's no substantial dely between the first and
> second times we read it.

Mm. I'm doing the same as the ACPI implementation - it may be that
reading GMUX_PORT_READ triggers the update of GMUX_PORT_WRITE? Hard to
know without the docs.

--
Matthew Garrett | [email protected]

2012-08-13 22:03:46

by Seth Forshee

[permalink] [raw]
Subject: Re: [PATCH 2/2] apple_gmux: Add support for newer hardware

On Mon, Aug 13, 2012 at 10:36:07PM +0100, Matthew Garrett wrote:
> On Mon, Aug 13, 2012 at 04:04:44PM -0500, Seth Forshee wrote:
> > > +
> > > + while (i && (gwr & 0x01)) {
> > > + inb(gmux_data->iostart + GMUX_PORT_READ);
> > > + gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
> > > + msleep(100);
> >
> > Wouldn't it make more sense if the msleep was before reading the port
> > again? Otherwise there's no substantial dely between the first and
> > second times we read it.
>
> Mm. I'm doing the same as the ACPI implementation - it may be that
> reading GMUX_PORT_READ triggers the update of GMUX_PORT_WRITE? Hard to
> know without the docs.

Indeed. I do find the structure of the loop to be odd, but I suppose the
safest approach is to follow the only known working implementation we
have. In that case ...

Acked-by: Seth Forshee <[email protected]>