return -ENODEV;
        if (WARN_ON(msg->size > 16))
                return -E2BIG;
-       if (msg->size == 0)
-               return msg->size;
 
        ret = nvkm_i2c_aux_acquire(aux);
        if (ret)
 
        drm_mode_connector_attach_encoder(connector, encoder);
 
        if (dcbe->type == DCB_OUTPUT_DP) {
+               struct nv50_disp *disp = nv50_disp(encoder->dev);
                struct nvkm_i2c_aux *aux =
                        nvkm_i2c_aux_find(i2c, dcbe->i2c_index);
                if (aux) {
-                       nv_encoder->i2c = &nv_connector->aux.ddc;
+                       if (disp->disp->oclass < GF110_DISP) {
+                               /* HW has no support for address-only
+                                * transactions, so we're required to
+                                * use custom I2C-over-AUX code.
+                                */
+                               nv_encoder->i2c = &aux->i2c;
+                       } else {
+                               nv_encoder->i2c = &nv_connector->aux.ddc;
+                       }
                        nv_encoder->aux = aux;
                }
 
                /*TODO: Use DP Info Table to check for support. */
-               if (nv50_disp(encoder->dev)->disp->oclass >= GF110_DISP) {
+               if (disp->disp->oclass >= GF110_DISP) {
                        ret = nv50_mstm_new(nv_encoder, &nv_connector->aux, 16,
                                            nv_connector->base.base.id,
                                            &nv_encoder->dp.mstm);
 
 
 nvkm-y += nvkm/subdev/i2c/aux.o
 nvkm-y += nvkm/subdev/i2c/auxg94.o
+nvkm-y += nvkm/subdev/i2c/auxgf119.o
 nvkm-y += nvkm/subdev/i2c/auxgm200.o
 
 nvkm-y += nvkm/subdev/i2c/anx9805.o
 
 nvkm_i2c_aux_xfer(struct nvkm_i2c_aux *aux, bool retry, u8 type,
                  u32 addr, u8 *data, u8 *size)
 {
+       if (!*size && !aux->func->address_only) {
+               AUX_ERR(aux, "address-only transaction dropped");
+               return -ENOSYS;
+       }
        return aux->func->xfer(aux, retry, type, addr, data, size);
 }
 
 
 #include "pad.h"
 
 struct nvkm_i2c_aux_func {
+       bool address_only;
        int  (*xfer)(struct nvkm_i2c_aux *, bool retry, u8 type,
                     u32 addr, u8 *data, u8 *size);
        int  (*lnk_ctl)(struct nvkm_i2c_aux *, int link_nr, int link_bw,
 int nvkm_i2c_aux_xfer(struct nvkm_i2c_aux *, bool retry, u8 type,
                      u32 addr, u8 *data, u8 *size);
 
+int g94_i2c_aux_new_(const struct nvkm_i2c_aux_func *, struct nvkm_i2c_pad *,
+                    int, u8, struct nvkm_i2c_aux **);
+
 int g94_i2c_aux_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_aux **);
+int g94_i2c_aux_xfer(struct nvkm_i2c_aux *, bool, u8, u32, u8 *, u8 *);
+int gf119_i2c_aux_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_aux **);
 int gm200_i2c_aux_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_aux **);
 
 #define AUX_MSG(b,l,f,a...) do {                                               \
 
        return 0;
 }
 
-static int
+int
 g94_i2c_aux_xfer(struct nvkm_i2c_aux *obj, bool retry,
                 u8 type, u32 addr, u8 *data, u8 *size)
 {
        }
 
        ctrl  = nvkm_rd32(device, 0x00e4e4 + base);
-       ctrl &= ~0x0001f0ff;
+       ctrl &= ~0x0001f1ff;
        ctrl |= type << 12;
-       ctrl |= *size - 1;
+       ctrl |= (*size ? (*size - 1) : 0x00000100);
        nvkm_wr32(device, 0x00e4e0 + base, addr);
 
        /* (maybe) retry transaction a number of times on failure... */
        return ret < 0 ? ret : (stat & 0x000f0000) >> 16;
 }
 
-static const struct nvkm_i2c_aux_func
-g94_i2c_aux_func = {
-       .xfer = g94_i2c_aux_xfer,
-};
-
 int
-g94_i2c_aux_new(struct nvkm_i2c_pad *pad, int index, u8 drive,
-               struct nvkm_i2c_aux **paux)
+g94_i2c_aux_new_(const struct nvkm_i2c_aux_func *func,
+                struct nvkm_i2c_pad *pad, int index, u8 drive,
+                struct nvkm_i2c_aux **paux)
 {
        struct g94_i2c_aux *aux;
 
                return -ENOMEM;
        *paux = &aux->base;
 
-       nvkm_i2c_aux_ctor(&g94_i2c_aux_func, pad, index, &aux->base);
+       nvkm_i2c_aux_ctor(func, pad, index, &aux->base);
        aux->ch = drive;
        aux->base.intr = 1 << aux->ch;
        return 0;
 }
+
+static const struct nvkm_i2c_aux_func
+g94_i2c_aux = {
+       .xfer = g94_i2c_aux_xfer,
+};
+
+int
+g94_i2c_aux_new(struct nvkm_i2c_pad *pad, int index, u8 drive,
+               struct nvkm_i2c_aux **paux)
+{
+       return g94_i2c_aux_new_(&g94_i2c_aux, pad, index, drive, paux);
+}
 
--- /dev/null
+/*
+ * Copyright 2017 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.
+ */
+#include "aux.h"
+
+static const struct nvkm_i2c_aux_func
+gf119_i2c_aux = {
+       .address_only = true,
+       .xfer = g94_i2c_aux_xfer,
+};
+
+int
+gf119_i2c_aux_new(struct nvkm_i2c_pad *pad, int index, u8 drive,
+                 struct nvkm_i2c_aux **paux)
+{
+       return g94_i2c_aux_new_(&gf119_i2c_aux, pad, index, drive, paux);
+}
 
        }
 
        ctrl  = nvkm_rd32(device, 0x00d954 + base);
-       ctrl &= ~0x0001f0ff;
+       ctrl &= ~0x0001f1ff;
        ctrl |= type << 12;
-       ctrl |= *size - 1;
+       ctrl |= (*size ? (*size - 1) : 0x00000100);
        nvkm_wr32(device, 0x00d950 + base, addr);
 
        /* (maybe) retry transaction a number of times on failure... */
 
 static const struct nvkm_i2c_aux_func
 gm200_i2c_aux_func = {
+       .address_only = true,
        .xfer = gm200_i2c_aux_xfer,
 };
 
 
 static const struct nvkm_i2c_pad_func
 gf119_i2c_pad_s_func = {
        .bus_new_4 = gf119_i2c_bus_new,
-       .aux_new_6 = g94_i2c_aux_new,
+       .aux_new_6 = gf119_i2c_aux_new,
        .mode = g94_i2c_pad_mode,
 };
 
 static const struct nvkm_i2c_pad_func
 gf119_i2c_pad_x_func = {
        .bus_new_4 = gf119_i2c_bus_new,
-       .aux_new_6 = g94_i2c_aux_new,
+       .aux_new_6 = gf119_i2c_aux_new,
 };
 
 int