drm/nouveau: bios parser fixes for eDP boards
authorBen Skeggs <bskeggs@redhat.com>
Mon, 19 Apr 2010 16:28:37 +0000 (02:28 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Wed, 19 May 2010 03:15:15 +0000 (13:15 +1000)
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nouveau_bios.c

index abc382a9918bfe9be71c33cb2cba83ee07a25d08..c11039f90d2e3caaeb7de76047b03cdc4d1c84c2 100644 (file)
@@ -26,6 +26,7 @@
 #define NV_DEBUG_NOTRACE
 #include "nouveau_drv.h"
 #include "nouveau_hw.h"
+#include "nouveau_encoder.h"
 
 /* these defines are made up */
 #define NV_CIO_CRE_44_HEADA 0x0
@@ -1066,6 +1067,126 @@ init_io_flag_condition(struct nvbios *bios, uint16_t offset,
        return 2;
 }
 
+static int
+init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
+{
+       /*
+        * INIT_DP_CONDITION   opcode: 0x3A ('')
+        *
+        * offset      (8 bit): opcode
+        * offset + 1  (8 bit): "sub" opcode
+        * offset + 2  (8 bit): unknown
+        *
+        */
+
+       struct bit_displayport_encoder_table *dpe = NULL;
+       struct dcb_entry *dcb = bios->display.output;
+       struct drm_device *dev = bios->dev;
+       uint8_t cond = bios->data[offset + 1];
+       int dummy;
+
+       BIOSLOG(bios, "0x%04X: subop 0x%02X\n", offset, cond);
+
+       if (!iexec->execute)
+               return 3;
+
+       dpe = nouveau_bios_dp_table(dev, dcb, &dummy);
+       if (!dpe) {
+               NV_ERROR(dev, "0x%04X: INIT_3A: no encoder table!!\n", offset);
+               return -EINVAL;
+       }
+
+       switch (cond) {
+       case 0:
+       {
+               struct dcb_connector_table_entry *ent =
+                       &bios->dcb.connector.entry[dcb->connector];
+
+               if (ent->type != DCB_CONNECTOR_eDP)
+                       iexec->execute = false;
+       }
+               break;
+       case 1:
+       case 2:
+               if (!(dpe->unknown & cond))
+                       iexec->execute = false;
+               break;
+       case 5:
+       {
+               struct nouveau_i2c_chan *auxch;
+               int ret;
+
+               auxch = nouveau_i2c_find(dev, bios->display.output->i2c_index);
+               if (!auxch)
+                       return -ENODEV;
+
+               ret = nouveau_dp_auxch(auxch, 9, 0xd, &cond, 1);
+               if (ret)
+                       return ret;
+
+               if (cond & 1)
+                       iexec->execute = false;
+       }
+               break;
+       default:
+               NV_WARN(dev, "0x%04X: unknown INIT_3A op: %d\n", offset, cond);
+               break;
+       }
+
+       if (iexec->execute)
+               BIOSLOG(bios, "0x%04X: continuing to execute\n", offset);
+       else
+               BIOSLOG(bios, "0x%04X: skipping following commands\n", offset);
+
+       return 3;
+}
+
+static int
+init_op_3b(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
+{
+       /*
+        * INIT_3B   opcode: 0x3B ('')
+        *
+        * offset      (8 bit): opcode
+        * offset + 1  (8 bit): crtc index
+        *
+        */
+
+       uint8_t or = ffs(bios->display.output->or) - 1;
+       uint8_t index = bios->data[offset + 1];
+       uint8_t data;
+
+       if (!iexec->execute)
+               return 2;
+
+       data = bios_idxprt_rd(bios, 0x3d4, index);
+       bios_idxprt_wr(bios, 0x3d4, index, data & ~(1 << or));
+       return 2;
+}
+
+static int
+init_op_3c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
+{
+       /*
+        * INIT_3C   opcode: 0x3C ('')
+        *
+        * offset      (8 bit): opcode
+        * offset + 1  (8 bit): crtc index
+        *
+        */
+
+       uint8_t or = ffs(bios->display.output->or) - 1;
+       uint8_t index = bios->data[offset + 1];
+       uint8_t data;
+
+       if (!iexec->execute)
+               return 2;
+
+       data = bios_idxprt_rd(bios, 0x3d4, index);
+       bios_idxprt_wr(bios, 0x3d4, index, data | (1 << or));
+       return 2;
+}
+
 static int
 init_idx_addr_latched(struct nvbios *bios, uint16_t offset,
                      struct init_exec *iexec)
@@ -2934,6 +3055,9 @@ static struct init_tbl_entry itbl_entry[] = {
        { "INIT_COPY"                         , 0x37, init_copy                       },
        { "INIT_NOT"                          , 0x38, init_not                        },
        { "INIT_IO_FLAG_CONDITION"            , 0x39, init_io_flag_condition          },
+       { "INIT_DP_CONDITION"                 , 0x3A, init_dp_condition               },
+       { "INIT_OP_3B"                        , 0x3B, init_op_3b                      },
+       { "INIT_OP_3C"                        , 0x3C, init_op_3c                      },
        { "INIT_INDEX_ADDRESS_LATCHED"        , 0x49, init_idx_addr_latched           },
        { "INIT_IO_RESTRICT_PLL2"             , 0x4A, init_io_restrict_pll2           },
        { "INIT_PLL2"                         , 0x4B, init_pll2                       },