drm/nouveau/bios: fix INIT_GPIO for new chipsets
authorBen Skeggs <bskeggs@redhat.com>
Sun, 3 Jul 2011 03:40:01 +0000 (13:40 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Tue, 20 Sep 2011 06:05:40 +0000 (16:05 +1000)
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nouveau_bios.c

index 30e723c81069c9e73330db07871a96b6c9efcf72..f0a77b7ce60e952aa7a7b4df4cf1430af2de6507 100644 (file)
@@ -3221,6 +3221,49 @@ init_8d(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        return 1;
 }
 
+static void
+init_gpio_unknv50(struct nvbios *bios, struct dcb_gpio_entry *gpio)
+{
+       const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c };
+       u32 r, s, v;
+
+       /* Not a clue, needs de-magicing */
+       r = nv50_gpio_ctl[gpio->line >> 4];
+       s = (gpio->line & 0x0f);
+       v = bios_rd32(bios, r) & ~(0x00010001 << s);
+       switch ((gpio->entry & 0x06000000) >> 25) {
+       case 1:
+               v |= (0x00000001 << s);
+               break;
+       case 2:
+               v |= (0x00010000 << s);
+               break;
+       default:
+               break;
+       }
+
+       bios_wr32(bios, r, v);
+}
+
+static void
+init_gpio_unknvd0(struct nvbios *bios, struct dcb_gpio_entry *gpio)
+{
+       u32 v, i;
+
+       v  = bios_rd32(bios, 0x00d610 + (gpio->line * 4));
+       v &= 0xffffff00;
+       v |= (gpio->entry & 0x00ff0000) >> 16;
+       bios_wr32(bios, 0x00d610 + (gpio->line * 4), v);
+
+       i = (gpio->entry & 0x1f000000) >> 24;
+       if (i) {
+               v  = bios_rd32(bios, 0x00d640 + ((i - 1) * 4));
+               v &= 0xffffff00;
+               v |= gpio->line;
+               bios_wr32(bios, 0x00d640 + ((i - 1) * 4), v);
+       }
+}
+
 static int
 init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
@@ -3235,7 +3278,6 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 
        struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
        struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
-       const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c };
        int i;
 
        if (dev_priv->card_type < NV_50) {
@@ -3248,33 +3290,20 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 
        for (i = 0; i < bios->dcb.gpio.entries; i++) {
                struct dcb_gpio_entry *gpio = &bios->dcb.gpio.entry[i];
-               uint32_t r, s, v;
 
                BIOSLOG(bios, "0x%04X: Entry: 0x%08X\n", offset, gpio->entry);
 
                BIOSLOG(bios, "0x%04X: set gpio 0x%02x, state %d\n",
                        offset, gpio->tag, gpio->state_default);
-               if (bios->execute)
-                       pgpio->set(bios->dev, gpio->tag, gpio->state_default);
 
-               /* The NVIDIA binary driver doesn't appear to actually do
-                * any of this, my VBIOS does however.
-                */
-               /* Not a clue, needs de-magicing */
-               r = nv50_gpio_ctl[gpio->line >> 4];
-               s = (gpio->line & 0x0f);
-               v = bios_rd32(bios, r) & ~(0x00010001 << s);
-               switch ((gpio->entry & 0x06000000) >> 25) {
-               case 1:
-                       v |= (0x00000001 << s);
-                       break;
-               case 2:
-                       v |= (0x00010000 << s);
-                       break;
-               default:
-                       break;
-               }
-               bios_wr32(bios, r, v);
+               if (!bios->execute)
+                       continue;
+
+               pgpio->set(bios->dev, gpio->tag, gpio->state_default);
+               if (dev_priv->card_type < NV_D0)
+                       init_gpio_unknv50(bios, gpio);
+               else
+                       init_gpio_unknvd0(bios, gpio);
        }
 
        return 1;