drm/nouveau/i2c: port to subdev interfaces
authorBen Skeggs <bskeggs@redhat.com>
Tue, 10 Jul 2012 04:36:38 +0000 (14:36 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Wed, 3 Oct 2012 03:12:46 +0000 (13:12 +1000)
v2/v3: Ben Skeggs <bskeggs@redhat.com>
- fix typo in default bus selection
- fix accidental loss of destructor

v4: Dmitry Eremin-Solenikov <dmitry_eremin@mentor.com>
- fix typo causing incorrect default i2c port settings when no BMP data

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
29 files changed:
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/core/engine/disp/vga.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/include/subdev/bios/i2c.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/include/subdev/i2c.h
drivers/gpu/drm/nouveau/core/include/subdev/vga.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/device/nv04.c
drivers/gpu/drm/nouveau/core/subdev/device/nv10.c
drivers/gpu/drm/nouveau/core/subdev/device/nv20.c
drivers/gpu/drm/nouveau/core/subdev/device/nv30.c
drivers/gpu/drm/nouveau/core/subdev/device/nv40.c
drivers/gpu/drm/nouveau/core/subdev/device/nv50.c
drivers/gpu/drm/nouveau/core/subdev/device/nvc0.c
drivers/gpu/drm/nouveau/core/subdev/device/nve0.c
drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_bios.c
drivers/gpu/drm/nouveau/nouveau_bios.h
drivers/gpu/drm/nouveau/nouveau_compat.c
drivers/gpu/drm/nouveau/nouveau_compat.h
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_connector.h
drivers/gpu/drm/nouveau/nouveau_dp.c
drivers/gpu/drm/nouveau/nouveau_encoder.h
drivers/gpu/drm/nouveau/nouveau_mxm.c
drivers/gpu/drm/nouveau/nouveau_temp.c
drivers/gpu/drm/nouveau/nv04_dfp.c
drivers/gpu/drm/nouveau/nv04_tv.c

index 414b2e8..40ce4e1 100644 (file)
@@ -22,6 +22,7 @@ nouveau-y += core/subdev/bios/base.o
 nouveau-y += core/subdev/bios/bit.o
 nouveau-y += core/subdev/bios/dcb.o
 nouveau-y += core/subdev/bios/gpio.o
+nouveau-y += core/subdev/bios/i2c.o
 nouveau-y += core/subdev/device/base.o
 nouveau-y += core/subdev/device/nv04.o
 nouveau-y += core/subdev/device/nv10.o
@@ -45,6 +46,8 @@ nouveau-y += core/subdev/gpio/nv10.o
 nouveau-y += core/subdev/gpio/nv50.o
 nouveau-y += core/subdev/gpio/nvd0.o
 nouveau-y += core/subdev/i2c/base.o
+nouveau-y += core/subdev/i2c/aux.o
+nouveau-y += core/subdev/i2c/bit.o
 nouveau-y += core/subdev/instmem/nv04.o
 nouveau-y += core/subdev/instmem/nv50.o
 nouveau-y += core/subdev/instmem/nvc0.o
@@ -61,6 +64,7 @@ nouveau-y += core/engine/copy/nva3.o
 nouveau-y += core/engine/copy/nvc0.o
 nouveau-y += core/engine/crypt/nv84.o
 nouveau-y += core/engine/crypt/nv98.o
+nouveau-y += core/engine/disp/vga.o
 nouveau-y += core/engine/fifo/nv04.o
 nouveau-y += core/engine/fifo/nv10.o
 nouveau-y += core/engine/fifo/nv17.o
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/vga.c b/drivers/gpu/drm/nouveau/core/engine/disp/vga.c
new file mode 100644 (file)
index 0000000..cec2110
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <core/subdev.h>
+#include <core/device.h>
+
+u8
+nv_rdport(void *obj, int head, u16 port)
+{
+       struct nouveau_device *device = nv_device(obj);
+
+       if (device->card_type >= NV_50)
+               return nv_rd08(obj, 0x601000 + port);
+
+       if (port == 0x03c0 || port == 0x03c1 || /* AR */
+           port == 0x03c2 || port == 0x03da || /* INP0 */
+           port == 0x03d4 || port == 0x03d5)   /* CR */
+               return nv_rd08(obj, 0x601000 + (head * 0x2000) + port);
+
+       if (port == 0x03c2 || port == 0x03cc || /* MISC */
+           port == 0x03c4 || port == 0x03c5 || /* SR */
+           port == 0x03ce || port == 0x03cf) { /* GR */
+               if (device->card_type < NV_40)
+                       head = 0; /* CR44 selects head */
+               return nv_rd08(obj, 0x0c0000 + (head * 0x2000) + port);
+       }
+
+       nv_error(obj, "unknown vga port 0x%04x\n", port);
+       return 0x00;
+}
+
+void
+nv_wrport(void *obj, int head, u16 port, u8 data)
+{
+       struct nouveau_device *device = nv_device(obj);
+
+       if (device->card_type >= NV_50)
+               nv_wr08(obj, 0x601000 + port, data);
+       else
+       if (port == 0x03c0 || port == 0x03c1 || /* AR */
+           port == 0x03c2 || port == 0x03da || /* INP0 */
+           port == 0x03d4 || port == 0x03d5)   /* CR */
+               nv_wr08(obj, 0x601000 + (head * 0x2000) + port, data);
+       else
+       if (port == 0x03c2 || port == 0x03cc || /* MISC */
+           port == 0x03c4 || port == 0x03c5 || /* SR */
+           port == 0x03ce || port == 0x03cf) { /* GR */
+               if (device->card_type < NV_40)
+                       head = 0; /* CR44 selects head */
+               nv_wr08(obj, 0x0c0000 + (head * 0x2000) + port, data);
+       } else
+               nv_error(obj, "unknown vga port 0x%04x\n", port);
+}
+
+u8
+nv_rdvgas(void *obj, int head, u8 index)
+{
+       nv_wrport(obj, head, 0x03c4, index);
+       return nv_rdport(obj, head, 0x03c5);
+}
+
+void
+nv_wrvgas(void *obj, int head, u8 index, u8 value)
+{
+       nv_wrport(obj, head, 0x03c4, index);
+       nv_wrport(obj, head, 0x03c5, value);
+}
+
+u8
+nv_rdvgag(void *obj, int head, u8 index)
+{
+       nv_wrport(obj, head, 0x03ce, index);
+       return nv_rdport(obj, head, 0x03cf);
+}
+
+void
+nv_wrvgag(void *obj, int head, u8 index, u8 value)
+{
+       nv_wrport(obj, head, 0x03ce, index);
+       nv_wrport(obj, head, 0x03cf, value);
+}
+
+u8
+nv_rdvgac(void *obj, int head, u8 index)
+{
+       nv_wrport(obj, head, 0x03d4, index);
+       return nv_rdport(obj, head, 0x03d5);
+}
+
+void
+nv_wrvgac(void *obj, int head, u8 index, u8 value)
+{
+       nv_wrport(obj, head, 0x03d4, index);
+       nv_wrport(obj, head, 0x03d5, value);
+}
+
+u8
+nv_rdvgai(void *obj, int head, u16 port, u8 index)
+{
+       if (port == 0x03c4) return nv_rdvgas(obj, head, index);
+       if (port == 0x03ce) return nv_rdvgag(obj, head, index);
+       if (port == 0x03d4) return nv_rdvgac(obj, head, index);
+       nv_error(obj, "unknown indexed vga port 0x%04x\n", port);
+       return 0x00;
+}
+
+void
+nv_wrvgai(void *obj, int head, u16 port, u8 index, u8 value)
+{
+       if      (port == 0x03c4) nv_wrvgas(obj, head, index, value);
+       else if (port == 0x03ce) nv_wrvgag(obj, head, index, value);
+       else if (port == 0x03d4) nv_wrvgac(obj, head, index, value);
+       else nv_error(obj, "unknown indexed vga port 0x%04x\n", port);
+}
+
+bool
+nv_lockvgac(void *obj, bool lock)
+{
+       bool locked = !nv_rdvgac(obj, 0, 0x1f);
+       u8 data = lock ? 0x99 : 0x57;
+       nv_wrvgac(obj, 0, 0x1f, data);
+       if (nv_device(obj)->chipset == 0x11) {
+               if (!(nv_rd32(obj, 0x001084) & 0x10000000))
+                       nv_wrvgac(obj, 1, 0x1f, data);
+       }
+       return locked;
+}
+
+/* CR44 takes values 0 (head A), 3 (head B) and 4 (heads tied)
+ * it affects only the 8 bit vga io regs, which we access using mmio at
+ * 0xc{0,2}3c*, 0x60{1,3}3*, and 0x68{1,3}3d*
+ * in general, the set value of cr44 does not matter: reg access works as
+ * expected and values can be set for the appropriate head by using a 0x2000
+ * offset as required
+ * however:
+ * a) pre nv40, the head B range of PRMVIO regs at 0xc23c* was not exposed and
+ *    cr44 must be set to 0 or 3 for accessing values on the correct head
+ *    through the common 0xc03c* addresses
+ * b) in tied mode (4) head B is programmed to the values set on head A, and
+ *    access using the head B addresses can have strange results, ergo we leave
+ *    tied mode in init once we know to what cr44 should be restored on exit
+ *
+ * the owner parameter is slightly abused:
+ * 0 and 1 are treated as head values and so the set value is (owner * 3)
+ * other values are treated as literal values to set
+ */
+u8
+nv_rdvgaowner(void *obj)
+{
+       if (nv_device(obj)->card_type < NV_50) {
+               if (nv_device(obj)->chipset == 0x11) {
+                       u32 tied = nv_rd32(obj, 0x001084) & 0x10000000;
+                       if (tied == 0) {
+                               u8 slA = nv_rdvgac(obj, 0, 0x28) & 0x80;
+                               u8 tvA = nv_rdvgac(obj, 0, 0x33) & 0x01;
+                               u8 slB = nv_rdvgac(obj, 1, 0x28) & 0x80;
+                               u8 tvB = nv_rdvgac(obj, 1, 0x33) & 0x01;
+                               if (slA && !tvA) return 0x00;
+                               if (slB && !tvB) return 0x03;
+                               if (slA) return 0x00;
+                               if (slB) return 0x03;
+                               return 0x00;
+                       }
+                       return 0x04;
+               }
+
+               return nv_rdvgac(obj, 0, 0x44);
+       }
+
+       nv_error(obj, "rdvgaowner after nv4x\n");
+       return 0x00;
+}
+
+void
+nv_wrvgaowner(void *obj, u8 select)
+{
+       if (nv_device(obj)->card_type < NV_50) {
+               u8 owner = (select == 1) ? 3 : select;
+               if (nv_device(obj)->chipset == 0x11) {
+                       /* workaround hw lockup bug */
+                       nv_rdvgac(obj, 0, 0x1f);
+                       nv_rdvgac(obj, 1, 0x1f);
+               }
+
+               nv_wrvgac(obj, 0, 0x44, owner);
+
+               if (nv_device(obj)->chipset == 0x11) {
+                       nv_wrvgac(obj, 0, 0x2e, owner);
+                       nv_wrvgac(obj, 0, 0x2e, owner);
+               }
+       } else
+               nv_error(obj, "wrvgaowner after nv4x\n");
+}
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/i2c.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/i2c.h
new file mode 100644 (file)
index 0000000..5079bed
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef __NVBIOS_I2C_H__
+#define __NVBIOS_I2C_H__
+
+struct nouveau_bios;
+
+enum dcb_i2c_type {
+       DCB_I2C_NV04_BIT = 0,
+       DCB_I2C_NV4E_BIT = 4,
+       DCB_I2C_NVIO_BIT = 5,
+       DCB_I2C_NVIO_AUX = 6,
+       DCB_I2C_UNUSED = 0xff
+};
+
+struct dcb_i2c_entry {
+       enum dcb_i2c_type type;
+       u8 drive;
+       u8 sense;
+       u32 data;
+};
+
+u16 dcb_i2c_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 dcb_i2c_entry(struct nouveau_bios *, u8 index, u8 *ver, u8 *len);
+int dcb_i2c_parse(struct nouveau_bios *, u8 index, struct dcb_i2c_entry *);
+
+#endif
index 1d08389..b93ab01 100644 (file)
@@ -1,39 +1,18 @@
-/*
- * Copyright 2009 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
 #ifndef __NOUVEAU_I2C_H__
 #define __NOUVEAU_I2C_H__
 
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-#include "drm_dp_helper.h"
+#include <core/subdev.h>
+#include <core/device.h>
+
+#include <subdev/bios.h>
+#include <subdev/bios/i2c.h>
 
 #define NV_I2C_PORT(n)    (0x00 + (n))
-#define NV_I2C_PORT_NUM    0x10
 #define NV_I2C_DEFAULT(n) (0x80 + (n))
 
-struct nouveau_i2c_chan {
+struct nouveau_i2c_port {
        struct i2c_adapter adapter;
-       struct drm_device *dev;
+       struct nouveau_i2c *i2c;
        struct i2c_algo_bit_data bit;
        struct list_head head;
        u8  index;
@@ -44,16 +23,38 @@ struct nouveau_i2c_chan {
        u32 state;
 };
 
-int  nouveau_i2c_init(struct drm_device *);
-void nouveau_i2c_fini(struct drm_device *);
-struct nouveau_i2c_chan *nouveau_i2c_find(struct drm_device *, u8 index);
-bool nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr);
-int nouveau_i2c_identify(struct drm_device *dev, const char *what,
-                        struct i2c_board_info *info,
-                        bool (*match)(struct nouveau_i2c_chan *,
-                                      struct i2c_board_info *),
-                        int index);
+struct nouveau_i2c {
+       struct nouveau_subdev base;
+
+       struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index);
+       int (*identify)(struct nouveau_i2c *, int index,
+                       const char *what, struct i2c_board_info *,
+                       bool (*match)(struct nouveau_i2c_port *,
+                                     struct i2c_board_info *));
+       struct list_head ports;
+};
+
+static inline struct nouveau_i2c *
+nouveau_i2c(void *obj)
+{
+       return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_I2C];
+}
+
+extern struct nouveau_oclass nouveau_i2c_oclass;
+
+void nouveau_i2c_drive_scl(void *, int);
+void nouveau_i2c_drive_sda(void *, int);
+int  nouveau_i2c_sense_scl(void *);
+int  nouveau_i2c_sense_sda(void *);
+
+int  nv_rdi2cr(struct nouveau_i2c_port *, u8 addr, u8 reg);
+int  nv_wri2cr(struct nouveau_i2c_port *, u8 addr, u8 reg, u8 val);
+bool nv_probe_i2c(struct nouveau_i2c_port *, u8 addr);
+
+int nv_rdaux(struct nouveau_i2c_port *, u32 addr, u8 *data, u8 size);
+int nv_wraux(struct nouveau_i2c_port *, u32 addr, u8 *data, u8 size);
 
-extern const struct i2c_algorithm nouveau_dp_i2c_algo;
+extern const struct i2c_algorithm nouveau_i2c_bit_algo;
+extern const struct i2c_algorithm nouveau_i2c_aux_algo;
 
-#endif /* __NOUVEAU_I2C_H__ */
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/vga.h b/drivers/gpu/drm/nouveau/core/include/subdev/vga.h
new file mode 100644 (file)
index 0000000..d81df1a
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef __NOUVEAU_VGA_H__
+#define __NOUVEAU_VGA_H__
+
+/* access to various legacy io ports */
+u8   nv_rdport(void *obj, int head, u16 port);
+void nv_wrport(void *obj, int head, u16 port, u8 value);
+
+/* VGA Sequencer */
+u8   nv_rdvgas(void *obj, int head, u8 index);
+void nv_wrvgas(void *obj, int head, u8 index, u8 value);
+
+/* VGA Graphics */
+u8   nv_rdvgag(void *obj, int head, u8 index);
+void nv_wrvgag(void *obj, int head, u8 index, u8 value);
+
+/* VGA CRTC */
+u8   nv_rdvgac(void *obj, int head, u8 index);
+void nv_wrvgac(void *obj, int head, u8 index, u8 value);
+
+/* VGA indexed port access dispatcher */
+u8   nv_rdvgai(void *obj, int head, u16 port, u8 index);
+void nv_wrvgai(void *obj, int head, u16 port, u8 index, u8 value);
+
+bool nv_lockvgac(void *obj, bool lock);
+u8   nv_rdvgaowner(void *obj);
+void nv_wrvgaowner(void *obj, u8);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c b/drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c
new file mode 100644 (file)
index 0000000..ad577db
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+
+#include "subdev/bios.h"
+#include "subdev/bios/dcb.h"
+#include "subdev/bios/i2c.h"
+
+u16
+dcb_i2c_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+       u16 i2c = 0x0000;
+       u16 dcb = dcb_table(bios, ver, hdr, cnt, len);
+       if (dcb) {
+               if (*ver >= 0x15)
+                       i2c = nv_ro16(bios, dcb + 2);
+               if (*ver >= 0x30)
+                       i2c = nv_ro16(bios, dcb + 4);
+       }
+
+       if (i2c && *ver >= 0x30) {
+               *ver = nv_ro08(bios, i2c + 0);
+               *hdr = nv_ro08(bios, i2c + 1);
+               *cnt = nv_ro08(bios, i2c + 2);
+               *len = nv_ro08(bios, i2c + 3);
+       } else {
+               *ver = *ver; /* use DCB version */
+               *hdr = 0;
+               *cnt = 16;
+               *len = 4;
+       }
+
+       return i2c;
+}
+
+u16
+dcb_i2c_entry(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len)
+{
+       u8  hdr, cnt;
+       u16 i2c = dcb_i2c_table(bios, ver, &hdr, &cnt, len);
+       if (i2c && idx < cnt)
+               return i2c + hdr + (idx * *len);
+       return 0x0000;
+}
+
+int
+dcb_i2c_parse(struct nouveau_bios *bios, u8 idx, struct dcb_i2c_entry *info)
+{
+       u8  ver, len;
+       u16 ent = dcb_i2c_entry(bios, idx, &ver, &len);
+       if (ent) {
+               info->data = nv_ro32(bios, ent + 0);
+               info->type = nv_ro08(bios, ent + 3);
+               if (ver < 0x30) {
+                       info->type &= 0x07;
+                       if (info->type == 0x07)
+                               info->type = 0xff;
+               }
+
+               switch (info->type) {
+               case DCB_I2C_NV04_BIT:
+                       info->drive = nv_ro08(bios, ent + 0);
+                       info->sense = nv_ro08(bios, ent + 1);
+                       return 0;
+               case DCB_I2C_NV4E_BIT:
+                       info->drive = nv_ro08(bios, ent + 1);
+                       return 0;
+               case DCB_I2C_NVIO_BIT:
+               case DCB_I2C_NVIO_AUX:
+                       info->drive = nv_ro08(bios, ent + 0);
+                       return 0;
+               case DCB_I2C_UNUSED:
+                       return 0;
+               default:
+                       nv_warn(bios, "unknown i2c type %d\n", info->type);
+                       info->type = DCB_I2C_UNUSED;
+                       return 0;
+               }
+       }
+
+       if (bios->bmp_offset && idx < 2) {
+               /* BMP (from v4.0 has i2c info in the structure, it's in a
+                * fixed location on earlier VBIOS
+                */
+               if (nv_ro08(bios, bios->bmp_offset + 5) < 4)
+                       ent = 0x0048;
+               else
+                       ent = 0x0036 + bios->bmp_offset;
+
+               if (idx == 0) {
+                       info->drive = nv_ro08(bios, ent + 4);
+                       if (!info->drive) info->drive = 0x3f;
+                       info->sense = nv_ro08(bios, ent + 5);
+                       if (!info->sense) info->sense = 0x3e;
+               } else
+               if (idx == 1) {
+                       info->drive = nv_ro08(bios, ent + 6);
+                       if (!info->drive) info->drive = 0x37;
+                       info->sense = nv_ro08(bios, ent + 7);
+                       if (!info->sense) info->sense = 0x36;
+               }
+
+               info->type = DCB_I2C_NV04_BIT;
+               return 0;
+       }
+
+       return -ENOENT;
+}
index d54daa3..e0ebbe1 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <subdev/device.h>
 #include <subdev/bios.h>
+#include <subdev/i2c.h>
 
 int
 nv04_identify(struct nouveau_device *device)
@@ -31,9 +32,11 @@ nv04_identify(struct nouveau_device *device)
        switch (device->chipset) {
        case 0x04:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x05:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        default:
                nv_fatal(device, "unknown RIVA chipset\n");
index c0c40cd..19b1de6 100644 (file)
@@ -25,6 +25,7 @@
 #include <subdev/device.h>
 #include <subdev/bios.h>
 #include <subdev/gpio.h>
+#include <subdev/i2c.h>
 
 int
 nv10_identify(struct nouveau_device *device)
@@ -33,34 +34,42 @@ nv10_identify(struct nouveau_device *device)
        case 0x10:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x15:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x16:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x1a:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x11:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x17:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x1f:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x18:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        default:
                nv_fatal(device, "unknown Celsius chipset\n");
index 1215e3f..8f73527 100644 (file)
@@ -25,6 +25,7 @@
 #include <subdev/device.h>
 #include <subdev/bios.h>
 #include <subdev/gpio.h>
+#include <subdev/i2c.h>
 
 int
 nv20_identify(struct nouveau_device *device)
@@ -33,18 +34,22 @@ nv20_identify(struct nouveau_device *device)
        case 0x20:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x25:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x28:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x2a:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        default:
                nv_fatal(device, "unknown Kelvin chipset\n");
index 43eb94e..eefc345 100644 (file)
@@ -25,6 +25,7 @@
 #include <subdev/device.h>
 #include <subdev/bios.h>
 #include <subdev/gpio.h>
+#include <subdev/i2c.h>
 
 int
 nv30_identify(struct nouveau_device *device)
@@ -33,22 +34,27 @@ nv30_identify(struct nouveau_device *device)
        case 0x30:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x35:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x31:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x36:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x34:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        default:
                nv_fatal(device, "unknown Rankine chipset\n");
index 7c10a3c..63047c5 100644 (file)
@@ -25,6 +25,7 @@
 #include <subdev/device.h>
 #include <subdev/bios.h>
 #include <subdev/gpio.h>
+#include <subdev/i2c.h>
 
 int
 nv40_identify(struct nouveau_device *device)
@@ -33,66 +34,82 @@ nv40_identify(struct nouveau_device *device)
        case 0x40:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x41:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x42:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x43:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x45:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x47:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x49:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x4b:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x44:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x46:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x4a:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x4c:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x4e:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x63:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x67:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x68:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        default:
                nv_fatal(device, "unknown Curie chipset\n");
index 581dcf1..9f4f6ef 100644 (file)
@@ -25,6 +25,7 @@
 #include <subdev/device.h>
 #include <subdev/bios.h>
 #include <subdev/gpio.h>
+#include <subdev/i2c.h>
 
 int
 nv50_identify(struct nouveau_device *device)
@@ -33,58 +34,72 @@ nv50_identify(struct nouveau_device *device)
        case 0x50:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x84:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x86:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x92:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x94:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x96:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0x98:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0xa0:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0xaa:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0xac:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0xa3:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0xa5:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0xa8:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0xaf:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        default:
                nv_fatal(device, "unknown Tesla chipset\n");
index df31111..f941024 100644 (file)
@@ -25,6 +25,7 @@
 #include <subdev/device.h>
 #include <subdev/bios.h>
 #include <subdev/gpio.h>
+#include <subdev/i2c.h>
 
 int
 nvc0_identify(struct nouveau_device *device)
@@ -33,34 +34,42 @@ nvc0_identify(struct nouveau_device *device)
        case 0xc0:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0xc4:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0xc3:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0xce:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0xcf:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0xc1:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0xc8:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv50_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0xd9:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nvd0_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        default:
                nv_fatal(device, "unknown Fermi chipset\n");
index d321cb4..21763cf 100644 (file)
@@ -25,6 +25,7 @@
 #include <subdev/device.h>
 #include <subdev/bios.h>
 #include <subdev/gpio.h>
+#include <subdev/i2c.h>
 
 int
 nve0_identify(struct nouveau_device *device)
@@ -33,10 +34,12 @@ nve0_identify(struct nouveau_device *device)
        case 0xe4:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nvd0_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        case 0xe7:
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nvd0_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
                break;
        default:
                nv_fatal(device, "unknown Kepler chipset\n");
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c
new file mode 100644 (file)
index 0000000..fe1ebf1
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2009 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/i2c.h>
+
+/******************************************************************************
+ * aux channel util functions
+ *****************************************************************************/
+#define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args)
+#define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args)
+
+static void
+auxch_fini(struct nouveau_i2c *aux, int ch)
+{
+       nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000);
+}
+
+static int
+auxch_init(struct nouveau_i2c *aux, int ch)
+{
+       const u32 unksel = 1; /* nfi which to use, or if it matters.. */
+       const u32 ureq = unksel ? 0x00100000 : 0x00200000;
+       const u32 urep = unksel ? 0x01000000 : 0x02000000;
+       u32 ctrl, timeout;
+
+       /* wait up to 1ms for any previous transaction to be done... */
+       timeout = 1000;
+       do {
+               ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
+               udelay(1);
+               if (!timeout--) {
+                       AUX_ERR("begin idle timeout 0x%08x", ctrl);
+                       return -EBUSY;
+               }
+       } while (ctrl & 0x03010000);
+
+       /* set some magic, and wait up to 1ms for it to appear */
+       nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq);
+       timeout = 1000;
+       do {
+               ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
+               udelay(1);
+               if (!timeout--) {
+                       AUX_ERR("magic wait 0x%08x\n", ctrl);
+                       auxch_fini(aux, ch);
+                       return -EBUSY;
+               }
+       } while ((ctrl & 0x03000000) != urep);
+
+       return 0;
+}
+
+static int
+auxch_tx(struct nouveau_i2c *aux, int ch, u8 type, u32 addr, u8 *data, u8 size)
+{
+       u32 ctrl, stat, timeout, retries;
+       u32 xbuf[4] = {};
+       int ret, i;
+
+       AUX_DBG("%d: 0x%08x %d\n", type, addr, size);
+
+       ret = auxch_init(aux, ch);
+       if (ret)
+               goto out;
+
+       stat = nv_rd32(aux, 0x00e4e8 + (ch * 0x50));
+       if (!(stat & 0x10000000)) {
+               AUX_DBG("sink not detected\n");
+               ret = -ENXIO;
+               goto out;
+       }
+
+       if (!(type & 1)) {
+               memcpy(xbuf, data, size);
+               for (i = 0; i < 16; i += 4) {
+                       AUX_DBG("wr 0x%08x\n", xbuf[i / 4]);
+                       nv_wr32(aux, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]);
+               }
+       }
+
+       ctrl  = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
+       ctrl &= ~0x0001f0ff;
+       ctrl |= type << 12;
+       ctrl |= size - 1;
+       nv_wr32(aux, 0x00e4e0 + (ch * 0x50), addr);
+
+       /* retry transaction a number of times on failure... */
+       ret = -EREMOTEIO;
+       for (retries = 0; retries < 32; retries++) {
+               /* reset, and delay a while if this is a retry */
+               nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl);
+               nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl);
+               if (retries)
+                       udelay(400);
+
+               /* transaction request, wait up to 1ms for it to complete */
+               nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl);
+
+               timeout = 1000;
+               do {
+                       ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
+                       udelay(1);
+                       if (!timeout--) {
+                               AUX_ERR("tx req timeout 0x%08x\n", ctrl);
+                               goto out;
+                       }
+               } while (ctrl & 0x00010000);
+
+               /* read status, and check if transaction completed ok */
+               stat = nv_mask(aux, 0x00e4e8 + (ch * 0x50), 0, 0);
+               if (!(stat & 0x000f0f00)) {
+                       ret = 0;
+                       break;
+               }
+
+               AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat);
+       }
+
+       if (type & 1) {
+               for (i = 0; i < 16; i += 4) {
+                       xbuf[i / 4] = nv_rd32(aux, 0x00e4d0 + (ch * 0x50) + i);
+                       AUX_DBG("rd 0x%08x\n", xbuf[i / 4]);
+               }
+               memcpy(data, xbuf, size);
+       }
+
+out:
+       auxch_fini(aux, ch);
+       return ret;
+}
+
+int
+nv_rdaux(struct nouveau_i2c_port *auxch, u32 addr, u8 *data, u8 size)
+{
+       return auxch_tx(auxch->i2c, auxch->drive, 9, addr, data, size);
+}
+
+int
+nv_wraux(struct nouveau_i2c_port *auxch, u32 addr, u8 *data, u8 size)
+{
+       return auxch_tx(auxch->i2c, auxch->drive, 8, addr, data, size);
+}
+
+static int
+aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+       struct nouveau_i2c_port *auxch = (struct nouveau_i2c_port *)adap;
+       struct i2c_msg *msg = msgs;
+       int ret, mcnt = num;
+
+       while (mcnt--) {
+               u8 remaining = msg->len;
+               u8 *ptr = msg->buf;
+
+               while (remaining) {
+                       u8 cnt = (remaining > 16) ? 16 : remaining;
+                       u8 cmd;
+
+                       if (msg->flags & I2C_M_RD)
+                               cmd = 1;
+                       else
+                               cmd = 0;
+
+                       if (mcnt || remaining > 16)
+                               cmd |= 4; /* MOT */
+
+                       ret = auxch_tx(auxch->i2c, auxch->drive, cmd,
+                                      msg->addr, ptr, cnt);
+                       if (ret < 0)
+                               return ret;
+
+                       ptr += cnt;
+                       remaining -= cnt;
+               }
+
+               msg++;
+       }
+
+       return num;
+}
+
+static u32
+aux_func(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+const struct i2c_algorithm nouveau_i2c_aux_algo = {
+       .master_xfer = aux_xfer,
+       .functionality = aux_func
+};
index 740e399..3d2c883 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009 Red Hat Inc.
+ * Copyright 2012 Red Hat Inc.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  * Authors: Ben Skeggs
  */
 
-#include <linux/module.h>
+#include "core/option.h"
 
-#include "drmP.h"
-#include "nouveau_drv.h"
-#include <subdev/i2c.h>
-#include "nouveau_hw.h"
+#include "subdev/i2c.h"
+#include "subdev/vga.h"
 
-static void
-i2c_drive_scl(void *data, int state)
+int
+nv_rdi2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg)
+{
+       u8 val;
+       struct i2c_msg msgs[] = {
+               { .addr = addr, .flags = 0, .len = 1, .buf = &reg },
+               { .addr = addr, .flags = I2C_M_RD, .len = 1, .buf = &val },
+       };
+
+       int ret = i2c_transfer(&port->adapter, msgs, 2);
+       if (ret != 2)
+               return -EIO;
+
+       return val;
+}
+
+int
+nv_wri2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg, u8 val)
+{
+       struct i2c_msg msgs[] = {
+               { .addr = addr, .flags = 0, .len = 1, .buf = &reg },
+               { .addr = addr, .flags = 0, .len = 1, .buf = &val },
+       };
+
+       int ret = i2c_transfer(&port->adapter, msgs, 2);
+       if (ret != 2)
+               return -EIO;
+
+       return 0;
+}
+
+bool
+nv_probe_i2c(struct nouveau_i2c_port *port, u8 addr)
+{
+       u8 buf[] = { 0 };
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = addr,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = buf,
+               },
+               {
+                       .addr = addr,
+                       .flags = I2C_M_RD,
+                       .len = 1,
+                       .buf = buf,
+               }
+       };
+
+       return i2c_transfer(&port->adapter, msgs, 2) == 2;
+}
+
+static struct nouveau_i2c_port *
+nouveau_i2c_find(struct nouveau_i2c *i2c, u8 index)
+{
+       struct nouveau_bios *bios = nouveau_bios(i2c);
+       struct nouveau_i2c_port *port;
+
+       if (index == NV_I2C_DEFAULT(0) ||
+           index == NV_I2C_DEFAULT(1)) {
+               u8  ver, hdr, cnt, len;
+               u16 i2c = dcb_i2c_table(bios, &ver, &hdr, &cnt, &len);
+               if (i2c && ver >= 0x30) {
+                       u8 auxidx = nv_ro08(bios, i2c + 4);
+                       if (index == NV_I2C_DEFAULT(0))
+                               index = (auxidx & 0x0f) >> 0;
+                       else
+                               index = (auxidx & 0xf0) >> 4;
+               } else {
+                       index = 2;
+               }
+       }
+
+       list_for_each_entry(port, &i2c->ports, head) {
+               if (port->index == index)
+                       break;
+       }
+
+       if (&port->head == &i2c->ports)
+               return NULL;
+
+       if (nv_device(i2c)->card_type >= NV_50 && (port->dcb & 0x00000100)) {
+               u32 reg = 0x00e500, val;
+               if (port->type == 6) {
+                       reg += port->drive * 0x50;
+                       val  = 0x2002;
+               } else {
+                       reg += ((port->dcb & 0x1e00) >> 9) * 0x50;
+                       val  = 0xe001;
+               }
+
+               /* nfi, but neither auxch or i2c work if it's 1 */
+               nv_mask(i2c, reg + 0x0c, 0x00000001, 0x00000000);
+               /* nfi, but switches auxch vs normal i2c */
+               nv_mask(i2c, reg + 0x00, 0x0000f003, val);
+       }
+
+       return port;
+}
+
+static int
+nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what,
+                    struct i2c_board_info *info,
+                    bool (*match)(struct nouveau_i2c_port *,
+                                  struct i2c_board_info *))
 {
-       struct nouveau_i2c_chan *port = data;
-       if (port->type == 0) {
-               u8 val = NVReadVgaCrtc(port->dev, 0, port->drive);
+       struct nouveau_i2c_port *port = nouveau_i2c_find(i2c, index);
+       int i;
+
+       if (!port) {
+               nv_debug(i2c, "no bus when probing %s on %d\n", what, index);
+               return -ENODEV;
+       }
+
+       nv_debug(i2c, "probing %ss on bus: %d\n", what, port->index);
+       for (i = 0; info[i].addr; i++) {
+               if (nv_probe_i2c(port, info[i].addr) &&
+                   (!match || match(port, &info[i]))) {
+                       nv_info(i2c, "detected %s: %s\n", what, info[i].type);
+                       return i;
+               }
+       }
+
+       nv_debug(i2c, "no devices found.\n");
+       return -ENODEV;
+}
+
+void
+nouveau_i2c_drive_scl(void *data, int state)
+{
+       struct nouveau_i2c_port *port = data;
+
+       if (port->type == DCB_I2C_NV04_BIT) {
+               u8 val = nv_rdvgac(port->i2c, 0, port->drive);
                if (state) val |= 0x20;
                else       val &= 0xdf;
-               NVWriteVgaCrtc(port->dev, 0, port->drive, val | 0x01);
+               nv_wrvgac(port->i2c, 0, port->drive, val | 0x01);
        } else
-       if (port->type == 4) {
-               nv_mask(port->dev, port->drive, 0x2f, state ? 0x21 : 0x01);
+       if (port->type == DCB_I2C_NV4E_BIT) {
+               nv_mask(port->i2c, port->drive, 0x2f, state ? 0x21 : 0x01);
        } else
-       if (port->type == 5) {
+       if (port->type == DCB_I2C_NVIO_BIT) {
                if (state) port->state |= 0x01;
                else       port->state &= 0xfe;
-               nv_wr32(port->dev, port->drive, 4 | port->state);
+               nv_wr32(port->i2c, port->drive, 4 | port->state);
        }
 }
 
-static void
-i2c_drive_sda(void *data, int state)
+void
+nouveau_i2c_drive_sda(void *data, int state)
 {
-       struct nouveau_i2c_chan *port = data;
-       if (port->type == 0) {
-               u8 val = NVReadVgaCrtc(port->dev, 0, port->drive);
+       struct nouveau_i2c_port *port = data;
+
+       if (port->type == DCB_I2C_NV04_BIT) {
+               u8 val = nv_rdvgac(port->i2c, 0, port->drive);
                if (state) val |= 0x10;
                else       val &= 0xef;
-               NVWriteVgaCrtc(port->dev, 0, port->drive, val | 0x01);
+               nv_wrvgac(port->i2c, 0, port->drive, val | 0x01);
        } else
-       if (port->type == 4) {
-               nv_mask(port->dev, port->drive, 0x1f, state ? 0x11 : 0x01);
+       if (port->type == DCB_I2C_NV4E_BIT) {
+               nv_mask(port->i2c, port->drive, 0x1f, state ? 0x11 : 0x01);
        } else
-       if (port->type == 5) {
+       if (port->type == DCB_I2C_NVIO_BIT) {
                if (state) port->state |= 0x02;
                else       port->state &= 0xfd;
-               nv_wr32(port->dev, port->drive, 4 | port->state);
+               nv_wr32(port->i2c, port->drive, 4 | port->state);
        }
 }
 
-static int
-i2c_sense_scl(void *data)
+int
+nouveau_i2c_sense_scl(void *data)
 {
-       struct nouveau_i2c_chan *port = data;
-       struct drm_nouveau_private *dev_priv = port->dev->dev_private;
-       if (port->type == 0) {
-               return !!(NVReadVgaCrtc(port->dev, 0, port->sense) & 0x04);
+       struct nouveau_i2c_port *port = data;
+       struct nouveau_device *device = nv_device(port->i2c);
+
+       if (port->type == DCB_I2C_NV04_BIT) {
+               return !!(nv_rdvgac(port->i2c, 0, port->sense) & 0x04);
        } else
-       if (port->type == 4) {
-               return !!(nv_rd32(port->dev, port->sense) & 0x00040000);
+       if (port->type == DCB_I2C_NV4E_BIT) {
+               return !!(nv_rd32(port->i2c, port->sense) & 0x00040000);
        } else
-       if (port->type == 5) {
-               if (dev_priv->card_type < NV_D0)
-                       return !!(nv_rd32(port->dev, port->sense) & 0x01);
+       if (port->type == DCB_I2C_NVIO_BIT) {
+               if (device->card_type < NV_D0)
+                       return !!(nv_rd32(port->i2c, port->sense) & 0x01);
                else
-                       return !!(nv_rd32(port->dev, port->sense) & 0x10);
+                       return !!(nv_rd32(port->i2c, port->sense) & 0x10);
        }
+
        return 0;
 }
 
-static int
-i2c_sense_sda(void *data)
+int
+nouveau_i2c_sense_sda(void *data)
 {
-       struct nouveau_i2c_chan *port = data;
-       struct drm_nouveau_private *dev_priv = port->dev->dev_private;
-       if (port->type == 0) {
-               return !!(NVReadVgaCrtc(port->dev, 0, port->sense) & 0x08);
+       struct nouveau_i2c_port *port = data;
+       struct nouveau_device *device = nv_device(port->i2c);
+
+       if (port->type == DCB_I2C_NV04_BIT) {
+               return !!(nv_rdvgac(port->i2c, 0, port->sense) & 0x08);
        } else
-       if (port->type == 4) {
-               return !!(nv_rd32(port->dev, port->sense) & 0x00080000);
+       if (port->type == DCB_I2C_NV4E_BIT) {
+               return !!(nv_rd32(port->i2c, port->sense) & 0x00080000);
        } else
-       if (port->type == 5) {
-               if (dev_priv->card_type < NV_D0)
-                       return !!(nv_rd32(port->dev, port->sense) & 0x02);
+       if (port->type == DCB_I2C_NVIO_BIT) {
+               if (device->card_type < NV_D0)
+                       return !!(nv_rd32(port->i2c, port->sense) & 0x02);
                else
-                       return !!(nv_rd32(port->dev, port->sense) & 0x20);
+                       return !!(nv_rd32(port->i2c, port->sense) & 0x20);
        }
+
        return 0;
 }
 
-static const uint32_t nv50_i2c_port[] = {
+static const u32 nv50_i2c_port[] = {
        0x00e138, 0x00e150, 0x00e168, 0x00e180,
        0x00e254, 0x00e274, 0x00e764, 0x00e780,
        0x00e79c, 0x00e7b8
 };
 
-static u8 *
-i2c_table(struct drm_device *dev, u8 *version)
-{
-       u8 *dcb = olddcb_table(dev), *i2c = NULL;
-       if (dcb) {
-               if (dcb[0] >= 0x15)
-                       i2c = ROMPTR(dev, dcb[2]);
-               if (dcb[0] >= 0x30)
-                       i2c = ROMPTR(dev, dcb[4]);
-       }
-
-       /* early revisions had no version number, use dcb version */
-       if (i2c) {
-               *version = dcb[0];
-               if (*version >= 0x30)
-                       *version = i2c[0];
-       }
-
-       return i2c;
-}
-
-int
-nouveau_i2c_init(struct drm_device *dev)
+static int
+nouveau_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+                struct nouveau_oclass *oclass, void *data, u32 size,
+                struct nouveau_object **pobject)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvbios *bios = &dev_priv->vbios;
-       struct nouveau_i2c_chan *port;
-       u8 version = 0x00, entries, recordlen;
-       u8 *i2c, *entry, legacy[2][4] = {};
-       int ret, i;
-
-       INIT_LIST_HEAD(&dev_priv->i2c_ports);
-
-       i2c = i2c_table(dev, &version);
-       if (!i2c) {
-               u8 *bmp = &bios->data[bios->offset];
-               if (bios->type != NVBIOS_BMP)
-                       return -ENODEV;
-
-               legacy[0][0] = NV_CIO_CRE_DDC_WR__INDEX;
-               legacy[0][1] = NV_CIO_CRE_DDC_STATUS__INDEX;
-               legacy[1][0] = NV_CIO_CRE_DDC0_WR__INDEX;
-               legacy[1][1] = NV_CIO_CRE_DDC0_STATUS__INDEX;
-
-               /* BMP (from v4.0) has i2c info in the structure, it's in a
-                * fixed location on earlier VBIOS
-                */
-               if (bmp[5] < 4)
-                       i2c = &bios->data[0x48];
-               else
-                       i2c = &bmp[0x36];
-
-               if (i2c[4]) legacy[0][0] = i2c[4];
-               if (i2c[5]) legacy[0][1] = i2c[5];
-               if (i2c[6]) legacy[1][0] = i2c[6];
-               if (i2c[7]) legacy[1][1] = i2c[7];
-       }
-
-       if (version >= 0x30) {
-               entry     = i2c[1] + i2c;
-               entries   = i2c[2];
-               recordlen = i2c[3];
-       } else
-       if (version) {
-               entry     = i2c;
-               entries   = 16;
-               recordlen = 4;
-       } else {
-               entry     = legacy[0];
-               entries   = 2;
-               recordlen = 4;
-       }
+       struct nouveau_device *device = nv_device(parent);
+       struct nouveau_bios *bios = nouveau_bios(parent);
+       struct nouveau_i2c_port *port;
+       struct nouveau_i2c *i2c;
+       struct dcb_i2c_entry info;
+       int ret, i = -1;
+
+       ret = nouveau_subdev_create(parent, engine, oclass, 0,
+                                   "I2C", "i2c", &i2c);
+       *pobject = nv_object(i2c);
+       if (ret)
+               return ret;
+
+       i2c->find = nouveau_i2c_find;
+       i2c->identify = nouveau_i2c_identify;
+       INIT_LIST_HEAD(&i2c->ports);
+
+       while (!dcb_i2c_parse(bios, ++i, &info)) {
+               if (info.type == DCB_I2C_UNUSED)
+                       continue;
 
-       for (i = 0; i < entries; i++, entry += recordlen) {
                port = kzalloc(sizeof(*port), GFP_KERNEL);
-               if (port == NULL) {
-                       nouveau_i2c_fini(dev);
-                       return -ENOMEM;
-               }
-
-               port->type = entry[3];
-               if (version < 0x30) {
-                       port->type &= 0x07;
-                       if (port->type == 0x07)
-                               port->type = 0xff;
-               }
-
-               if (port->type == 0xff) {
-                       kfree(port);
-                       continue;
+               if (!port) {
+                       nv_error(i2c, "failed port memory alloc at %d\n", i);
+                       break;
                }
 
+               port->type = info.type;
                switch (port->type) {
-               case 0: /* NV04:NV50 */
-                       port->drive = entry[0];
-                       port->sense = entry[1];
+               case DCB_I2C_NV04_BIT:
+                       port->drive = info.drive;
+                       port->sense = info.sense;
                        break;
-               case 4: /* NV4E */
-                       port->drive = 0x600800 + entry[1];
+               case DCB_I2C_NV4E_BIT:
+                       port->drive = 0x600800 + info.drive;
                        port->sense = port->drive;
                        break;
-               case 5: /* NV50- */
-                       port->drive = entry[0] & 0x0f;
-                       if (dev_priv->card_type < NV_D0) {
-                               if (port->drive >= ARRAY_SIZE(nv50_i2c_port))
+               case DCB_I2C_NVIO_BIT:
+                       port->drive = info.drive & 0x0f;
+                       if (device->card_type < NV_D0) {
+                               if (info.drive >= ARRAY_SIZE(nv50_i2c_port))
                                        break;
                                port->drive = nv50_i2c_port[port->drive];
                                port->sense = port->drive;
@@ -228,167 +301,107 @@ nouveau_i2c_init(struct drm_device *dev)
                                port->sense = port->drive;
                        }
                        break;
-               case 6: /* NV50- DP AUX */
-                       port->drive = entry[0] & 0x0f;
+               case DCB_I2C_NVIO_AUX:
+                       port->drive = info.drive & 0x0f;
                        port->sense = port->drive;
-                       port->adapter.algo = &nouveau_dp_i2c_algo;
+                       port->adapter.algo = &nouveau_i2c_aux_algo;
                        break;
                default:
                        break;
                }
 
                if (!port->adapter.algo && !port->drive) {
-                       NV_ERROR(dev, "I2C%d: type %d index %x/%x unknown\n",
+                       nv_error(i2c, "I2C%d: type %d index %x/%x unknown\n",
                                 i, port->type, port->drive, port->sense);
                        kfree(port);
                        continue;
                }
 
                snprintf(port->adapter.name, sizeof(port->adapter.name),
-                        "nouveau-%s-%d", pci_name(dev->pdev), i);
+                        "nouveau-%s-%d", device->name, i);
                port->adapter.owner = THIS_MODULE;
-               port->adapter.dev.parent = &dev->pdev->dev;
-               port->dev = dev;
+               port->adapter.dev.parent = &device->pdev->dev;
+               port->i2c = i2c;
                port->index = i;
-               port->dcb = ROM32(entry[0]);
+               port->dcb = info.data;
                i2c_set_adapdata(&port->adapter, i2c);
 
-               if (port->adapter.algo != &nouveau_dp_i2c_algo) {
-                       port->adapter.algo_data = &port->bit;
-                       port->bit.udelay = 10;
-                       port->bit.timeout = usecs_to_jiffies(2200);
-                       port->bit.data = port;
-                       port->bit.setsda = i2c_drive_sda;
-                       port->bit.setscl = i2c_drive_scl;
-                       port->bit.getsda = i2c_sense_sda;
-                       port->bit.getscl = i2c_sense_scl;
-
-                       i2c_drive_scl(port, 0);
-                       i2c_drive_sda(port, 1);
-                       i2c_drive_scl(port, 1);
-
-                       ret = i2c_bit_add_bus(&port->adapter);
+               if (port->adapter.algo != &nouveau_i2c_aux_algo) {
+                       nouveau_i2c_drive_scl(port, 0);
+                       nouveau_i2c_drive_sda(port, 1);
+                       nouveau_i2c_drive_scl(port, 1);
+
+#ifdef CONFIG_NOUVEAU_I2C_INTERNAL_DEFAULT
+                       if (nouveau_boolopt(device->cfgopt, "NvI2C", true)) {
+#else
+                       if (nouveau_boolopt(device->cfgopt, "NvI2C", false)) {
+#endif
+                               port->adapter.algo = &nouveau_i2c_bit_algo;
+                               ret = i2c_add_adapter(&port->adapter);
+                       } else {
+                               port->adapter.algo_data = &port->bit;
+                               port->bit.udelay = 10;
+                               port->bit.timeout = usecs_to_jiffies(2200);
+                               port->bit.data = port;
+                               port->bit.setsda = nouveau_i2c_drive_sda;
+                               port->bit.setscl = nouveau_i2c_drive_scl;
+                               port->bit.getsda = nouveau_i2c_sense_sda;
+                               port->bit.getscl = nouveau_i2c_sense_scl;
+                               ret = i2c_bit_add_bus(&port->adapter);
+                       }
                } else {
-                       port->adapter.algo = &nouveau_dp_i2c_algo;
+                       port->adapter.algo = &nouveau_i2c_aux_algo;
                        ret = i2c_add_adapter(&port->adapter);
                }
 
                if (ret) {
-                       NV_ERROR(dev, "I2C%d: failed register: %d\n", i, ret);
+                       nv_error(i2c, "I2C%d: failed register: %d\n", i, ret);
                        kfree(port);
                        continue;
                }
 
-               list_add_tail(&port->head, &dev_priv->i2c_ports);
+               list_add_tail(&port->head, &i2c->ports);
        }
 
        return 0;
 }
 
-void
-nouveau_i2c_fini(struct drm_device *dev)
+static void
+nouveau_i2c_dtor(struct nouveau_object *object)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_i2c_chan *port, *tmp;
+       struct nouveau_i2c *i2c = (void *)object;
+       struct nouveau_i2c_port *port, *temp;
 
-       list_for_each_entry_safe(port, tmp, &dev_priv->i2c_ports, head) {
+       list_for_each_entry_safe(port, temp, &i2c->ports, head) {
                i2c_del_adapter(&port->adapter);
+               list_del(&port->head);
                kfree(port);
        }
-}
-
-struct nouveau_i2c_chan *
-nouveau_i2c_find(struct drm_device *dev, u8 index)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_i2c_chan *port;
-
-       if (index == NV_I2C_DEFAULT(0) ||
-           index == NV_I2C_DEFAULT(1)) {
-               u8 version, *i2c = i2c_table(dev, &version);
-               if (i2c && version >= 0x30) {
-                       if (index == NV_I2C_DEFAULT(0))
-                               index = (i2c[4] & 0x0f);
-                       else
-                               index = (i2c[4] & 0xf0) >> 4;
-               } else {
-                       index = 2;
-               }
-       }
-
-       list_for_each_entry(port, &dev_priv->i2c_ports, head) {
-               if (port->index == index)
-                       break;
-       }
-
-       if (&port->head == &dev_priv->i2c_ports)
-               return NULL;
 
-       if (dev_priv->card_type >= NV_50 && (port->dcb & 0x00000100)) {
-               u32 reg = 0x00e500, val;
-               if (port->type == 6) {
-                       reg += port->drive * 0x50;
-                       val  = 0x2002;
-               } else {
-                       reg += ((port->dcb & 0x1e00) >> 9) * 0x50;
-                       val  = 0xe001;
-               }
-
-               /* nfi, but neither auxch or i2c work if it's 1 */
-               nv_mask(dev, reg + 0x0c, 0x00000001, 0x00000000);
-               /* nfi, but switches auxch vs normal i2c */
-               nv_mask(dev, reg + 0x00, 0x0000f003, val);
-       }
-
-       return port;
+       nouveau_subdev_destroy(&i2c->base);
 }
 
-bool
-nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr)
+static int
+nouveau_i2c_init(struct nouveau_object *object)
 {
-       uint8_t buf[] = { 0 };
-       struct i2c_msg msgs[] = {
-               {
-                       .addr = addr,
-                       .flags = 0,
-                       .len = 1,
-                       .buf = buf,
-               },
-               {
-                       .addr = addr,
-                       .flags = I2C_M_RD,
-                       .len = 1,
-                       .buf = buf,
-               }
-       };
-
-       return i2c_transfer(&i2c->adapter, msgs, 2) == 2;
+       struct nouveau_i2c *i2c = (void *)object;
+       return nouveau_subdev_init(&i2c->base);
 }
 
-int
-nouveau_i2c_identify(struct drm_device *dev, const char *what,
-                    struct i2c_board_info *info,
-                    bool (*match)(struct nouveau_i2c_chan *,
-                                  struct i2c_board_info *),
-                    int index)
+static int
+nouveau_i2c_fini(struct nouveau_object *object, bool suspend)
 {
-       struct nouveau_i2c_chan *i2c = nouveau_i2c_find(dev, index);
-       int i;
-
-       if (!i2c) {
-               NV_DEBUG(dev, "No bus when probing %s on %d\n", what, index);
-               return -ENODEV;
-       }
-
-       NV_DEBUG(dev, "Probing %ss on I2C bus: %d\n", what, i2c->index);
-       for (i = 0; info[i].addr; i++) {
-               if (nouveau_probe_i2c_addr(i2c, info[i].addr) &&
-                   (!match || match(i2c, &info[i]))) {
-                       NV_INFO(dev, "Detected %s: %s\n", what, info[i].type);
-                       return i;
-               }
-       }
-
-       NV_DEBUG(dev, "No devices found.\n");
-       return -ENODEV;
+       struct nouveau_i2c *i2c = (void *)object;
+       return nouveau_subdev_fini(&i2c->base, suspend);
 }
+
+struct nouveau_oclass
+nouveau_i2c_oclass = {
+       .handle = NV_SUBDEV(I2C, 0x00),
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nouveau_i2c_ctor,
+               .dtor = nouveau_i2c_dtor,
+               .init = nouveau_i2c_init,
+               .fini = nouveau_i2c_fini,
+       },
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c
new file mode 100644 (file)
index 0000000..1c4c9a5
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "subdev/i2c.h"
+
+#ifdef CONFIG_NOUVEAU_I2C_INTERNAL
+#define T_TIMEOUT  2200000
+#define T_RISEFALL 1000
+#define T_HOLD     5000
+
+static inline void
+i2c_drive_scl(struct nouveau_i2c_port *port, int state)
+{
+       nouveau_i2c_drive_scl(port, state);
+}
+
+static inline void
+i2c_drive_sda(struct nouveau_i2c_port *port, int state)
+{
+       nouveau_i2c_drive_sda(port, state);
+}
+
+static inline int
+i2c_sense_scl(struct nouveau_i2c_port *port)
+{
+       return nouveau_i2c_sense_scl(port);
+}
+
+static inline int
+i2c_sense_sda(struct nouveau_i2c_port *port)
+{
+       return nouveau_i2c_sense_sda(port);
+}
+
+static void
+i2c_delay(struct nouveau_i2c_port *port, u32 nsec)
+{
+       udelay((nsec + 500) / 1000);
+}
+
+static bool
+i2c_raise_scl(struct nouveau_i2c_port *port)
+{
+       u32 timeout = T_TIMEOUT / T_RISEFALL;
+
+       i2c_drive_scl(port, 1);
+       do {
+               i2c_delay(port, T_RISEFALL);
+       } while (!i2c_sense_scl(port) && --timeout);
+
+       return timeout != 0;
+}
+
+static int
+i2c_start(struct nouveau_i2c_port *port)
+{
+       int ret = 0;
+
+       port->state  = i2c_sense_scl(port);
+       port->state |= i2c_sense_sda(port) << 1;
+       if (port->state != 3) {
+               i2c_drive_scl(port, 0);
+               i2c_drive_sda(port, 1);
+               if (!i2c_raise_scl(port))
+                       ret = -EBUSY;
+       }
+
+       i2c_drive_sda(port, 0);
+       i2c_delay(port, T_HOLD);
+       i2c_drive_scl(port, 0);
+       i2c_delay(port, T_HOLD);
+       return ret;
+}
+
+static void
+i2c_stop(struct nouveau_i2c_port *port)
+{
+       i2c_drive_scl(port, 0);
+       i2c_drive_sda(port, 0);
+       i2c_delay(port, T_RISEFALL);
+
+       i2c_drive_scl(port, 1);
+       i2c_delay(port, T_HOLD);
+       i2c_drive_sda(port, 1);
+       i2c_delay(port, T_HOLD);
+}
+
+static int
+i2c_bitw(struct nouveau_i2c_port *port, int sda)
+{
+       i2c_drive_sda(port, sda);
+       i2c_delay(port, T_RISEFALL);
+
+       if (!i2c_raise_scl(port))
+               return -ETIMEDOUT;
+       i2c_delay(port, T_HOLD);
+
+       i2c_drive_scl(port, 0);
+       i2c_delay(port, T_HOLD);
+       return 0;
+}
+
+static int
+i2c_bitr(struct nouveau_i2c_port *port)
+{
+       int sda;
+
+       i2c_drive_sda(port, 1);
+       i2c_delay(port, T_RISEFALL);
+
+       if (!i2c_raise_scl(port))
+               return -ETIMEDOUT;
+       i2c_delay(port, T_HOLD);
+
+       sda = i2c_sense_sda(port);
+
+       i2c_drive_scl(port, 0);
+       i2c_delay(port, T_HOLD);
+       return sda;
+}
+
+static int
+i2c_get_byte(struct nouveau_i2c_port *port, u8 *byte, bool last)
+{
+       int i, bit;
+
+       *byte = 0;
+       for (i = 7; i >= 0; i--) {
+               bit = i2c_bitr(port);
+               if (bit < 0)
+                       return bit;
+               *byte |= bit << i;
+       }
+
+       return i2c_bitw(port, last ? 1 : 0);
+}
+
+static int
+i2c_put_byte(struct nouveau_i2c_port *port, u8 byte)
+{
+       int i, ret;
+       for (i = 7; i >= 0; i--) {
+               ret = i2c_bitw(port, !!(byte & (1 << i)));
+               if (ret < 0)
+                       return ret;
+       }
+
+       ret = i2c_bitr(port);
+       if (ret == 1) /* nack */
+               ret = -EIO;
+       return ret;
+}
+
+static int
+i2c_addr(struct nouveau_i2c_port *port, struct i2c_msg *msg)
+{
+       u32 addr = msg->addr << 1;
+       if (msg->flags & I2C_M_RD)
+               addr |= 1;
+       return i2c_put_byte(port, addr);
+}
+
+static int
+i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+       struct nouveau_i2c_port *port = (struct nouveau_i2c_port *)adap;
+       struct i2c_msg *msg = msgs;
+       int ret = 0, mcnt = num;
+
+       while (!ret && mcnt--) {
+               u8 remaining = msg->len;
+               u8 *ptr = msg->buf;
+
+               ret = i2c_start(port);
+               if (ret == 0)
+                       ret = i2c_addr(port, msg);
+
+               if (msg->flags & I2C_M_RD) {
+                       while (!ret && remaining--)
+                               ret = i2c_get_byte(port, ptr++, !remaining);
+               } else {
+                       while (!ret && remaining--)
+                               ret = i2c_put_byte(port, *ptr++);
+               }
+
+               msg++;
+       }
+
+       i2c_stop(port);
+       return (ret < 0) ? ret : num;
+}
+#else
+static int
+i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+       return -ENODEV;
+}
+#endif
+
+static u32
+i2c_bit_func(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+const struct i2c_algorithm nouveau_i2c_bit_algo = {
+       .master_xfer = i2c_bit_xfer,
+       .functionality = i2c_bit_func
+};
index 4f0d9bd..35b0a8f 100644 (file)
@@ -528,7 +528,7 @@ static int dcb_entry_idx_from_crtchead(struct drm_device *dev)
        return dcb_entry;
 }
 
-static struct nouveau_i2c_chan *
+static struct nouveau_i2c_port *
 init_i2c_device_find(struct drm_device *dev, int i2c_index)
 {
        if (i2c_index == 0xff) {
@@ -537,9 +537,9 @@ init_i2c_device_find(struct drm_device *dev, int i2c_index)
                /* note: dcb_entry_idx_from_crtchead needs pre-script set-up */
                int idx = dcb_entry_idx_from_crtchead(dev);
 
-               i2c_index = NV_I2C_DEFAULT(0);
+               i2c_index = 0x80; //NV_I2C_DEFAULT(0);
                if (idx != 0x7f && dcb->entry[idx].i2c_upper_default)
-                       i2c_index = NV_I2C_DEFAULT(1);
+                       i2c_index = 0x81; //NV_I2C_DEFAULT(1);
        }
 
        return nouveau_i2c_find(dev, i2c_index);
@@ -920,7 +920,7 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                break;
        case 5:
        {
-               struct nouveau_i2c_chan *auxch;
+               struct nouveau_i2c_port *auxch;
                int ret;
 
                auxch = nouveau_i2c_find(dev, bios->display.output->i2c_index);
@@ -929,7 +929,7 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                        return 3;
                }
 
-               ret = nouveau_dp_auxch(auxch, 9, 0xd, &cond, 1);
+               ret = auxch_rd(dev, auxch, 0xd, &cond, 1);
                if (ret) {
                        NV_ERROR(dev, "0x%04X: auxch rd fail: %d\n", offset, ret);
                        return 3;
@@ -1166,7 +1166,7 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        uint8_t i2c_index = bios->data[offset + 1];
        uint8_t i2c_address = bios->data[offset + 2] >> 1;
        uint8_t count = bios->data[offset + 3];
-       struct nouveau_i2c_chan *chan;
+       struct nouveau_i2c_port *chan;
        int len = 4 + count * 3;
        int ret, i;
 
@@ -1189,7 +1189,7 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                uint8_t data = bios->data[offset + 6 + i * 3];
                union i2c_smbus_data val;
 
-               ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0,
+               ret = i2c_smbus_xfer(nouveau_i2c_adapter(chan), i2c_address, 0,
                                     I2C_SMBUS_READ, reg,
                                     I2C_SMBUS_BYTE_DATA, &val);
                if (ret < 0) {
@@ -1206,7 +1206,7 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 
                val.byte &= mask;
                val.byte |= data;
-               ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0,
+               ret = i2c_smbus_xfer(nouveau_i2c_adapter(chan), i2c_address, 0,
                                     I2C_SMBUS_WRITE, reg,
                                     I2C_SMBUS_BYTE_DATA, &val);
                if (ret < 0) {
@@ -1241,7 +1241,7 @@ init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        uint8_t i2c_index = bios->data[offset + 1];
        uint8_t i2c_address = bios->data[offset + 2] >> 1;
        uint8_t count = bios->data[offset + 3];
-       struct nouveau_i2c_chan *chan;
+       struct nouveau_i2c_port *chan;
        int len = 4 + count * 2;
        int ret, i;
 
@@ -1270,7 +1270,7 @@ init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                if (!bios->execute)
                        continue;
 
-               ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0,
+               ret = i2c_smbus_xfer(nouveau_i2c_adapter(chan), i2c_address, 0,
                                     I2C_SMBUS_WRITE, reg,
                                     I2C_SMBUS_BYTE_DATA, &val);
                if (ret < 0) {
@@ -1304,7 +1304,7 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        uint8_t i2c_address = bios->data[offset + 2] >> 1;
        uint8_t count = bios->data[offset + 3];
        int len = 4 + count;
-       struct nouveau_i2c_chan *chan;
+       struct nouveau_i2c_port *chan;
        struct i2c_msg msg;
        uint8_t data[256];
        int ret, i;
@@ -1333,7 +1333,7 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                msg.flags = 0;
                msg.len = count;
                msg.buf = data;
-               ret = i2c_transfer(&chan->adapter, &msg, 1);
+               ret = i2c_transfer(nouveau_i2c_adapter(chan), &msg, 1);
                if (ret != 1) {
                        NV_ERROR(dev, "0x%04X: i2c wr fail: %d\n", offset, ret);
                        return len;
@@ -1769,7 +1769,7 @@ init_i2c_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        uint8_t reg = bios->data[offset + 3];
        uint8_t mask = bios->data[offset + 4];
        uint8_t data = bios->data[offset + 5];
-       struct nouveau_i2c_chan *chan;
+       struct nouveau_i2c_port *chan;
        union i2c_smbus_data val;
        int ret;
 
@@ -1782,7 +1782,7 @@ init_i2c_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        if (!chan)
                return -ENODEV;
 
-       ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0,
+       ret = i2c_smbus_xfer(nouveau_i2c_adapter(chan), i2c_address, 0,
                             I2C_SMBUS_READ, reg,
                             I2C_SMBUS_BYTE_DATA, &val);
        if (ret < 0) {
@@ -3167,7 +3167,7 @@ init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
         */
 
        struct drm_device *dev = bios->dev;
-       struct nouveau_i2c_chan *auxch;
+       struct nouveau_i2c_port *auxch;
        uint32_t addr = ROM32(bios->data[offset + 1]);
        uint8_t count = bios->data[offset + 5];
        int len = 6 + count * 2;
@@ -3192,7 +3192,7 @@ init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        for (i = 0; i < count; i++, offset += 2) {
                uint8_t data;
 
-               ret = nouveau_dp_auxch(auxch, 9, addr, &data, 1);
+               ret = auxch_rd(dev, auxch, addr, &data, 1);
                if (ret) {
                        NV_ERROR(dev, "INIT_AUXCH: rd auxch fail %d\n", ret);
                        return len;
@@ -3201,7 +3201,7 @@ init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                data &= bios->data[offset + 0];
                data |= bios->data[offset + 1];
 
-               ret = nouveau_dp_auxch(auxch, 8, addr, &data, 1);
+               ret = auxch_wr(dev, auxch, addr, &data, 1);
                if (ret) {
                        NV_ERROR(dev, "INIT_AUXCH: wr auxch fail %d\n", ret);
                        return len;
@@ -3226,7 +3226,7 @@ init_zm_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
         */
 
        struct drm_device *dev = bios->dev;
-       struct nouveau_i2c_chan *auxch;
+       struct nouveau_i2c_port *auxch;
        uint32_t addr = ROM32(bios->data[offset + 1]);
        uint8_t count = bios->data[offset + 5];
        int len = 6 + count;
@@ -3249,7 +3249,7 @@ init_zm_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 
        offset += 6;
        for (i = 0; i < count; i++, offset++) {
-               ret = nouveau_dp_auxch(auxch, 8, addr, &bios->data[offset], 1);
+               ret = auxch_wr(dev, auxch, addr, &bios->data[offset], 1);
                if (ret) {
                        NV_ERROR(dev, "INIT_ZM_AUXCH: wr auxch fail %d\n", ret);
                        return len;
@@ -3285,7 +3285,7 @@ init_i2c_long_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        uint8_t reghi = bios->data[offset + 4];
        uint8_t mask = bios->data[offset + 5];
        uint8_t data = bios->data[offset + 6];
-       struct nouveau_i2c_chan *chan;
+       struct nouveau_i2c_port *chan;
        uint8_t buf0[2] = { reghi, reglo };
        uint8_t buf1[1];
        struct i2c_msg msg[2] = {
@@ -3304,7 +3304,7 @@ init_i2c_long_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                return -ENODEV;
 
 
-       ret = i2c_transfer(&chan->adapter, msg, 2);
+       ret = i2c_transfer(nouveau_i2c_adapter(chan), msg, 2);
        if (ret < 0) {
                BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X:0x%02X, Value: [no device], "
                              "Mask: 0x%02X, Data: 0x%02X\n",
@@ -6270,10 +6270,6 @@ nouveau_bios_init(struct drm_device *dev)
        if (ret)
                return ret;
 
-       ret = nouveau_i2c_init(dev);
-       if (ret)
-               return ret;
-
        ret = nouveau_mxm_init(dev);
        if (ret)
                return ret;
@@ -6318,8 +6314,5 @@ nouveau_bios_init(struct drm_device *dev)
 void
 nouveau_bios_takedown(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-
        nouveau_mxm_fini(dev);
-       nouveau_i2c_fini(dev);
 }
index b4529a0..52fce11 100644 (file)
@@ -25,7 +25,6 @@
 #define __NOUVEAU_BIOS_H__
 
 #include "nvreg.h"
-#include <subdev/i2c.h>
 
 #define DCB_MAX_NUM_ENTRIES 16
 #define DCB_MAX_NUM_I2C_ENTRIES 16
index 81fc849..76582b0 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <subdev/bios.h>
 #include <subdev/gpio.h>
+#include <subdev/i2c.h>
 
 void *nouveau_newpriv(struct drm_device *);
 
@@ -130,3 +131,52 @@ nouveau_gpio_isr_del(struct drm_device *dev, int idx, u8 tag, u8 line,
        if (gpio && gpio->isr_del)
                gpio->isr_del(gpio, idx, tag, line, exec, data);
 }
+
+struct nouveau_i2c_port *
+nouveau_i2c_find(struct drm_device *dev, u8 index)
+{
+       struct nouveau_drm *drm = nouveau_newpriv(dev);
+       struct nouveau_i2c *i2c = nouveau_i2c(drm->device);
+
+       return i2c->find(i2c, index);
+}
+
+bool
+nouveau_probe_i2c_addr(struct nouveau_i2c_port *port, int addr)
+{
+       return nv_probe_i2c(port, addr);
+}
+
+struct i2c_adapter *
+nouveau_i2c_adapter(struct nouveau_i2c_port *port)
+{
+       return &port->adapter;
+}
+
+
+int
+nouveau_i2c_identify(struct drm_device *dev, const char *what,
+                    struct i2c_board_info *info,
+                    bool (*match)(struct nouveau_i2c_port *,
+                                  struct i2c_board_info *),
+                    int index)
+{
+       struct nouveau_drm *drm = nouveau_newpriv(dev);
+       struct nouveau_i2c *i2c = nouveau_i2c(drm->device);
+
+       return i2c->identify(i2c, index, what, info, match);
+}
+
+int
+auxch_rd(struct drm_device *dev, struct nouveau_i2c_port *port,
+        u32 addr, u8 *data, u8 size)
+{
+       return nv_rdaux(port, addr, data, size);
+}
+
+int
+auxch_wr(struct drm_device *dev, struct nouveau_i2c_port *port,
+        u32 addr, u8 *data, u8 size)
+{
+       return nv_wraux(port, addr, data, size);
+}
index f1143c3..9b3298b 100644 (file)
@@ -20,4 +20,17 @@ int  nouveau_gpio_isr_add(struct drm_device *, int idx, u8 tag, u8 line,
                          void (*)(void *, int state), void *data);
 void nouveau_gpio_isr_del(struct drm_device *, int idx, u8 tag, u8 line,
                          void (*)(void *, int state), void *data);
+
+struct nouveau_i2c_port *nouveau_i2c_find(struct drm_device *, u8);
+bool nouveau_probe_i2c_addr(struct nouveau_i2c_port *, int addr);
+struct i2c_adapter *nouveau_i2c_adapter(struct nouveau_i2c_port *);
+int nouveau_i2c_identify(struct drm_device *dev, const char *what,
+                        struct i2c_board_info *info,
+                        bool (*match)(struct nouveau_i2c_port *,
+                                      struct i2c_board_info *), int index);
+
+int auxch_rd(struct drm_device *, struct nouveau_i2c_port *, u32, u8 *, u8);
+int auxch_wr(struct drm_device *, struct nouveau_i2c_port *, u32, u8 *, u8);
+
+
 #endif
index cbf8348..f9cc3b3 100644 (file)
@@ -105,7 +105,7 @@ nouveau_connector_destroy(struct drm_connector *connector)
        kfree(connector);
 }
 
-static struct nouveau_i2c_chan *
+static struct nouveau_i2c_port *
 nouveau_connector_ddc_detect(struct drm_connector *connector,
                             struct nouveau_encoder **pnv_encoder)
 {
@@ -113,7 +113,7 @@ nouveau_connector_ddc_detect(struct drm_connector *connector,
        int i;
 
        for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
-               struct nouveau_i2c_chan *i2c = NULL;
+               struct nouveau_i2c_port *i2c = NULL;
                struct nouveau_encoder *nv_encoder;
                struct drm_mode_object *obj;
                int id;
@@ -217,7 +217,7 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
        struct nouveau_connector *nv_connector = nouveau_connector(connector);
        struct nouveau_encoder *nv_encoder = NULL;
        struct nouveau_encoder *nv_partner;
-       struct nouveau_i2c_chan *i2c;
+       struct nouveau_i2c_port *i2c;
        int type;
 
        /* Cleanup the previous EDID block. */
@@ -229,7 +229,7 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
 
        i2c = nouveau_connector_ddc_detect(connector, &nv_encoder);
        if (i2c) {
-               nv_connector->edid = drm_get_edid(connector, &i2c->adapter);
+               nv_connector->edid = drm_get_edid(connector, nouveau_i2c_adapter(i2c));
                drm_mode_connector_update_edid_property(connector,
                                                        nv_connector->edid);
                if (!nv_connector->edid) {
index bb0faf9..9503cfa 100644 (file)
@@ -28,7 +28,8 @@
 #define __NOUVEAU_CONNECTOR_H__
 
 #include "drm_edid.h"
-#include <subdev/i2c.h>
+
+struct nouveau_i2c_port;
 
 enum nouveau_underscan_type {
        UNDERSCAN_OFF,
index 63c0e82..9e18b35 100644 (file)
  */
 
 #include "drmP.h"
+#include "drm_dp_helper.h"
 
 #include "nouveau_drv.h"
-#include <subdev/i2c.h>
 #include "nouveau_connector.h"
 #include "nouveau_encoder.h"
 #include "nouveau_crtc.h"
 
-/******************************************************************************
- * aux channel util functions
- *****************************************************************************/
-#define AUX_DBG(fmt, args...) do {                                             \
-       if (nouveau_reg_debug & NOUVEAU_REG_DEBUG_AUXCH) {                     \
-               NV_PRINTK(KERN_DEBUG, dev, "AUXCH(%d): " fmt, ch, ##args);     \
-       }                                                                      \
-} while (0)
-#define AUX_ERR(fmt, args...) NV_ERROR(dev, "AUXCH(%d): " fmt, ch, ##args)
-
-static void
-auxch_fini(struct drm_device *dev, int ch)
-{
-       nv_mask(dev, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000);
-}
-
-static int
-auxch_init(struct drm_device *dev, int ch)
-{
-       const u32 unksel = 1; /* nfi which to use, or if it matters.. */
-       const u32 ureq = unksel ? 0x00100000 : 0x00200000;
-       const u32 urep = unksel ? 0x01000000 : 0x02000000;
-       u32 ctrl, timeout;
-
-       /* wait up to 1ms for any previous transaction to be done... */
-       timeout = 1000;
-       do {
-               ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50));
-               udelay(1);
-               if (!timeout--) {
-                       AUX_ERR("begin idle timeout 0x%08x", ctrl);
-                       return -EBUSY;
-               }
-       } while (ctrl & 0x03010000);
-
-       /* set some magic, and wait up to 1ms for it to appear */
-       nv_mask(dev, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq);
-       timeout = 1000;
-       do {
-               ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50));
-               udelay(1);
-               if (!timeout--) {
-                       AUX_ERR("magic wait 0x%08x\n", ctrl);
-                       auxch_fini(dev, ch);
-                       return -EBUSY;
-               }
-       } while ((ctrl & 0x03000000) != urep);
-
-       return 0;
-}
-
-static int
-auxch_tx(struct drm_device *dev, int ch, u8 type, u32 addr, u8 *data, u8 size)
-{
-       u32 ctrl, stat, timeout, retries;
-       u32 xbuf[4] = {};
-       int ret, i;
-
-       AUX_DBG("%d: 0x%08x %d\n", type, addr, size);
-
-       ret = auxch_init(dev, ch);
-       if (ret)
-               goto out;
-
-       stat = nv_rd32(dev, 0x00e4e8 + (ch * 0x50));
-       if (!(stat & 0x10000000)) {
-               AUX_DBG("sink not detected\n");
-               ret = -ENXIO;
-               goto out;
-       }
-
-       if (!(type & 1)) {
-               memcpy(xbuf, data, size);
-               for (i = 0; i < 16; i += 4) {
-                       AUX_DBG("wr 0x%08x\n", xbuf[i / 4]);
-                       nv_wr32(dev, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]);
-               }
-       }
-
-       ctrl  = nv_rd32(dev, 0x00e4e4 + (ch * 0x50));
-       ctrl &= ~0x0001f0ff;
-       ctrl |= type << 12;
-       ctrl |= size - 1;
-       nv_wr32(dev, 0x00e4e0 + (ch * 0x50), addr);
-
-       /* retry transaction a number of times on failure... */
-       ret = -EREMOTEIO;
-       for (retries = 0; retries < 32; retries++) {
-               /* reset, and delay a while if this is a retry */
-               nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl);
-               nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl);
-               if (retries)
-                       udelay(400);
-
-               /* transaction request, wait up to 1ms for it to complete */
-               nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl);
-
-               timeout = 1000;
-               do {
-                       ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50));
-                       udelay(1);
-                       if (!timeout--) {
-                               AUX_ERR("tx req timeout 0x%08x\n", ctrl);
-                               goto out;
-                       }
-               } while (ctrl & 0x00010000);
-
-               /* read status, and check if transaction completed ok */
-               stat = nv_mask(dev, 0x00e4e8 + (ch * 0x50), 0, 0);
-               if (!(stat & 0x000f0f00)) {
-                       ret = 0;
-                       break;
-               }
-
-               AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat);
-       }
-
-       if (type & 1) {
-               for (i = 0; i < 16; i += 4) {
-                       xbuf[i / 4] = nv_rd32(dev, 0x00e4d0 + (ch * 0x50) + i);
-                       AUX_DBG("rd 0x%08x\n", xbuf[i / 4]);
-               }
-               memcpy(data, xbuf, size);
-       }
-
-out:
-       auxch_fini(dev, ch);
-       return ret;
-}
-
 u8 *
 nouveau_dp_bios_data(struct drm_device *dev, struct dcb_entry *dcb, u8 **entry)
 {
@@ -208,9 +78,9 @@ nouveau_dp_bios_data(struct drm_device *dev, struct dcb_entry *dcb, u8 **entry)
  * link training
  *****************************************************************************/
 struct dp_state {
+       struct nouveau_i2c_port *auxch;
        struct dp_train_func *func;
        struct dcb_entry *dcb;
-       int auxch;
        int crtc;
        u8 *dpcd;
        int link_nr;
@@ -236,7 +106,7 @@ dp_set_link_config(struct drm_device *dev, struct dp_state *dp)
        if (dp->dpcd[2] & DP_ENHANCED_FRAME_CAP)
                sink[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
 
-       auxch_tx(dev, dp->auxch, 8, DP_LINK_BW_SET, sink, 2);
+       auxch_wr(dev, dp->auxch, DP_LINK_BW_SET, sink, 2);
 }
 
 static void
@@ -248,10 +118,10 @@ dp_set_training_pattern(struct drm_device *dev, struct dp_state *dp, u8 pattern)
 
        dp->func->train_set(dev, dp->dcb, pattern);
 
-       auxch_tx(dev, dp->auxch, 9, DP_TRAINING_PATTERN_SET, &sink_tp, 1);
+       auxch_rd(dev, dp->auxch, DP_TRAINING_PATTERN_SET, &sink_tp, 1);
        sink_tp &= ~DP_TRAINING_PATTERN_MASK;
        sink_tp |= pattern;
-       auxch_tx(dev, dp->auxch, 8, DP_TRAINING_PATTERN_SET, &sink_tp, 1);
+       auxch_wr(dev, dp->auxch, DP_TRAINING_PATTERN_SET, &sink_tp, 1);
 }
 
 static int
@@ -274,7 +144,7 @@ dp_link_train_commit(struct drm_device *dev, struct dp_state *dp)
                dp->func->train_adj(dev, dp->dcb, i, lvsw, lpre);
        }
 
-       return auxch_tx(dev, dp->auxch, 8, DP_TRAINING_LANE0_SET, dp->conf, 4);
+       return auxch_wr(dev, dp->auxch, DP_TRAINING_LANE0_SET, dp->conf, 4);
 }
 
 static int
@@ -284,7 +154,7 @@ dp_link_train_update(struct drm_device *dev, struct dp_state *dp, u32 delay)
 
        udelay(delay);
 
-       ret = auxch_tx(dev, dp->auxch, 9, DP_LANE0_1_STATUS, dp->stat, 6);
+       ret = auxch_rd(dev, dp->auxch, DP_LANE0_1_STATUS, dp->stat, 6);
        if (ret)
                return ret;
 
@@ -417,19 +287,17 @@ nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate,
        struct nouveau_connector *nv_connector =
                nouveau_encoder_connector_get(nv_encoder);
        struct drm_device *dev = encoder->dev;
-       struct nouveau_i2c_chan *auxch;
        const u32 bw_list[] = { 270000, 162000, 0 };
        const u32 *link_bw = bw_list;
        struct dp_state dp;
 
-       auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
-       if (!auxch)
+       dp.auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
+       if (!dp.auxch)
                return false;
 
        dp.func = func;
        dp.dcb = nv_encoder->dcb;
        dp.crtc = nv_crtc->index;
-       dp.auxch = auxch->drive;
        dp.dpcd = nv_encoder->dp.dpcd;
 
        /* adjust required bandwidth for 8B/10B coding overhead */
@@ -491,7 +359,7 @@ nouveau_dp_dpms(struct drm_encoder *encoder, int mode, u32 datarate,
                struct dp_train_func *func)
 {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
-       struct nouveau_i2c_chan *auxch;
+       struct nouveau_i2c_port *auxch;
        u8 status;
 
        auxch = nouveau_i2c_find(encoder->dev, nv_encoder->dcb->i2c_index);
@@ -503,14 +371,14 @@ nouveau_dp_dpms(struct drm_encoder *encoder, int mode, u32 datarate,
        else
                status = DP_SET_POWER_D3;
 
-       nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1);
+       auxch_wr(encoder->dev, auxch, DP_SET_POWER, &status, 1);
 
        if (mode == DRM_MODE_DPMS_ON)
                nouveau_dp_link_train(encoder, datarate, func);
 }
 
 static void
-nouveau_dp_probe_oui(struct drm_device *dev, struct nouveau_i2c_chan *auxch,
+nouveau_dp_probe_oui(struct drm_device *dev, struct nouveau_i2c_port *auxch,
                     u8 *dpcd)
 {
        u8 buf[3];
@@ -518,11 +386,11 @@ nouveau_dp_probe_oui(struct drm_device *dev, struct nouveau_i2c_chan *auxch,
        if (!(dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT))
                return;
 
-       if (!auxch_tx(dev, auxch->drive, 9, DP_SINK_OUI, buf, 3))
+       if (!auxch_rd(dev, auxch, DP_SINK_OUI, buf, 3))
                NV_DEBUG_KMS(dev, "Sink OUI: %02hx%02hx%02hx\n",
                             buf[0], buf[1], buf[2]);
 
-       if (!auxch_tx(dev, auxch->drive, 9, DP_BRANCH_OUI, buf, 3))
+       if (!auxch_rd(dev, auxch, DP_BRANCH_OUI, buf, 3))
                NV_DEBUG_KMS(dev, "Branch OUI: %02hx%02hx%02hx\n",
                             buf[0], buf[1], buf[2]);
 
@@ -533,7 +401,7 @@ nouveau_dp_detect(struct drm_encoder *encoder)
 {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct drm_device *dev = encoder->dev;
-       struct nouveau_i2c_chan *auxch;
+       struct nouveau_i2c_port *auxch;
        u8 *dpcd = nv_encoder->dp.dpcd;
        int ret;
 
@@ -541,7 +409,7 @@ nouveau_dp_detect(struct drm_encoder *encoder)
        if (!auxch)
                return false;
 
-       ret = auxch_tx(dev, auxch->drive, 9, DP_DPCD_REV, dpcd, 8);
+       ret = auxch_rd(dev, auxch, DP_DPCD_REV, dpcd, 8);
        if (ret)
                return false;
 
@@ -566,58 +434,3 @@ nouveau_dp_detect(struct drm_encoder *encoder)
 
        return true;
 }
-
-int
-nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
-                uint8_t *data, int data_nr)
-{
-       return auxch_tx(auxch->dev, auxch->drive, cmd, addr, data, data_nr);
-}
-
-static int
-nouveau_dp_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
-{
-       struct nouveau_i2c_chan *auxch = (struct nouveau_i2c_chan *)adap;
-       struct i2c_msg *msg = msgs;
-       int ret, mcnt = num;
-
-       while (mcnt--) {
-               u8 remaining = msg->len;
-               u8 *ptr = msg->buf;
-
-               while (remaining) {
-                       u8 cnt = (remaining > 16) ? 16 : remaining;
-                       u8 cmd;
-
-                       if (msg->flags & I2C_M_RD)
-                               cmd = AUX_I2C_READ;
-                       else
-                               cmd = AUX_I2C_WRITE;
-
-                       if (mcnt || remaining > 16)
-                               cmd |= AUX_I2C_MOT;
-
-                       ret = nouveau_dp_auxch(auxch, cmd, msg->addr, ptr, cnt);
-                       if (ret < 0)
-                               return ret;
-
-                       ptr += cnt;
-                       remaining -= cnt;
-               }
-
-               msg++;
-       }
-
-       return num;
-}
-
-static u32
-nouveau_dp_i2c_func(struct i2c_adapter *adap)
-{
-       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
-}
-
-const struct i2c_algorithm nouveau_dp_i2c_algo = {
-       .master_xfer = nouveau_dp_i2c_xfer,
-       .functionality = nouveau_dp_i2c_func
-};
index 3dc14a3..1e79ee5 100644 (file)
@@ -32,6 +32,8 @@
 
 #define NV_DPMS_CLEARED 0x80
 
+struct nouveau_i2c_port;
+
 struct dp_train_func {
        void (*link_set)(struct drm_device *, struct dcb_entry *, int crtc,
                         int nr, u32 bw, bool enhframe);
@@ -87,8 +89,6 @@ get_slave_funcs(struct drm_encoder *enc)
 }
 
 /* nouveau_dp.c */
-int nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
-                    uint8_t *data, int data_nr);
 bool nouveau_dp_detect(struct drm_encoder *);
 void nouveau_dp_dpms(struct drm_encoder *, int mode, u32 datarate,
                     struct dp_train_func *);
index b2b326b..7ca129d 100644 (file)
@@ -471,7 +471,7 @@ mxm_dcb_sanitise(struct drm_device *dev)
 }
 
 static bool
-mxm_shadow_rom_fetch(struct nouveau_i2c_chan *i2c, u8 addr,
+mxm_shadow_rom_fetch(struct nouveau_i2c_port *i2c, u8 addr,
                     u8 offset, u8 size, u8 *data)
 {
        struct i2c_msg msgs[] = {
@@ -479,14 +479,14 @@ mxm_shadow_rom_fetch(struct nouveau_i2c_chan *i2c, u8 addr,
                { .addr = addr, .flags = I2C_M_RD, .len = size, .buf = data, },
        };
 
-       return i2c_transfer(&i2c->adapter, msgs, 2) == 2;
+       return i2c_transfer(nouveau_i2c_adapter(i2c), msgs, 2) == 2;
 }
 
 static bool
 mxm_shadow_rom(struct drm_device *dev, u8 version)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_i2c_chan *i2c = NULL;
+       struct nouveau_i2c_port *i2c = NULL;
        u8 i2cidx, mxms[6], addr, size;
 
        i2cidx = mxm_ddc_map(dev, 1 /* LVDS_DDC */) & 0x0f;
index 0f5a301..d00b901 100644 (file)
@@ -264,14 +264,14 @@ nouveau_temp_safety_checks(struct drm_device *dev)
 }
 
 static bool
-probe_monitoring_device(struct nouveau_i2c_chan *i2c,
+probe_monitoring_device(struct nouveau_i2c_port *i2c,
                        struct i2c_board_info *info)
 {
        struct i2c_client *client;
 
        request_module("%s%s", I2C_MODULE_PREFIX, info->type);
 
-       client = i2c_new_device(&i2c->adapter, info);
+       client = i2c_new_device(nouveau_i2c_adapter(i2c), info);
        if (!client)
                return false;
 
@@ -296,7 +296,7 @@ nouveau_temp_probe_i2c(struct drm_device *dev)
        };
 
        nouveau_i2c_identify(dev, "monitoring device", info,
-                            probe_monitoring_device, NV_I2C_DEFAULT(0));
+                            probe_monitoring_device, 0x80); //NV_I2C_DEFAULT(0));
 }
 
 void
index c267562..c9835b9 100644 (file)
@@ -624,7 +624,7 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder)
 {
        struct drm_device *dev = encoder->dev;
        struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
-       struct nouveau_i2c_chan *i2c = nouveau_i2c_find(dev, 2);
+       struct nouveau_i2c_port *i2c = nouveau_i2c_find(dev, 2);
        struct i2c_board_info info[] = {
                {
                        .type = "sil164",
@@ -646,7 +646,7 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder)
                return;
 
        drm_i2c_encoder_init(dev, to_encoder_slave(encoder),
-                            &i2c->adapter, &info[type]);
+                            nouveau_i2c_adapter(i2c), &info[type]);
 }
 
 static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = {
index 3eb605d..3d7dd22 100644 (file)
@@ -188,7 +188,7 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry)
        struct drm_device *dev = connector->dev;
        struct drm_encoder_helper_funcs *hfuncs;
        struct drm_encoder_slave_funcs *sfuncs;
-       struct nouveau_i2c_chan *i2c =
+       struct nouveau_i2c_port *i2c =
                nouveau_i2c_find(dev, entry->i2c_index);
        int type, ret;
 
@@ -221,7 +221,7 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry)
 
        /* Run the slave-specific initialization */
        ret = drm_i2c_encoder_init(dev, to_encoder_slave(encoder),
-                                  &i2c->adapter, &nv04_tv_encoder_info[type]);
+                                  nouveau_i2c_adapter(i2c), &nv04_tv_encoder_info[type]);
        if (ret < 0)
                goto fail_cleanup;