From: Ben Skeggs <bske...@redhat.com>

This will check the relevant hotplug pin and skip the DDC probe we
currently do if a display is present.

- preparation for GSP-RM.

Signed-off-by: Ben Skeggs <bske...@redhat.com>
Reviewed-by: Lyude Paul <ly...@redhat.com>
Acked-by: Danilo Krummrich <m...@dakr.org>
Signed-off-by: Lyude Paul <ly...@redhat.com>
---
 drivers/gpu/drm/nouveau/include/nvif/conn.h   |  5 --
 drivers/gpu/drm/nouveau/include/nvif/if0011.h | 11 ----
 drivers/gpu/drm/nouveau/include/nvif/if0012.h | 12 ++++
 drivers/gpu/drm/nouveau/include/nvif/outp.h   |  9 +++
 drivers/gpu/drm/nouveau/nouveau_connector.c   | 60 ++++++++++++-------
 drivers/gpu/drm/nouveau/nouveau_dp.c          | 10 +---
 drivers/gpu/drm/nouveau/nvif/conn.c           | 14 -----
 drivers/gpu/drm/nouveau/nvif/outp.c           | 25 ++++++++
 drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c |  1 +
 .../gpu/drm/nouveau/nvkm/engine/disp/outp.c   | 28 +++++++++
 .../gpu/drm/nouveau/nvkm/engine/disp/outp.h   |  6 ++
 .../gpu/drm/nouveau/nvkm/engine/disp/uconn.c  | 41 -------------
 .../gpu/drm/nouveau/nvkm/engine/disp/uoutp.c  | 24 ++++++++
 13 files changed, 145 insertions(+), 101 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/include/nvif/conn.h 
b/drivers/gpu/drm/nouveau/include/nvif/conn.h
index dc355e1dfafa0..8a6017a358976 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/conn.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/conn.h
@@ -18,11 +18,6 @@ nvif_conn_id(struct nvif_conn *conn)
        return conn->object.handle;
 }
 
-#define NVIF_CONN_HPD_STATUS_UNSUPPORTED 0 /* negative if query fails */
-#define NVIF_CONN_HPD_STATUS_NOT_PRESENT 1
-#define NVIF_CONN_HPD_STATUS_PRESENT     2
-int nvif_conn_hpd_status(struct nvif_conn *);
-
 int nvif_conn_event_ctor(struct nvif_conn *, const char *name, 
nvif_event_func, u8 types,
                         struct nvif_event *);
 #endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0011.h 
b/drivers/gpu/drm/nouveau/include/nvif/if0011.h
index 69b0b779f9424..0c25288a5a789 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/if0011.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/if0011.h
@@ -20,15 +20,4 @@ union nvif_conn_event_args {
                __u8 pad02[6];
        } v0;
 };
-
-#define NVIF_CONN_V0_HPD_STATUS 0x00000000
-
-union nvif_conn_hpd_status_args {
-       struct nvif_conn_hpd_status_v0 {
-               __u8 version;
-               __u8 support;
-               __u8 present;
-               __u8 pad03[5];
-       } v0;
-};
 #endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h 
b/drivers/gpu/drm/nouveau/include/nvif/if0012.h
index 7c56f653070c9..923bc30af2a92 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h
@@ -12,6 +12,8 @@ union nvif_outp_args {
        } v0;
 };
 
+#define NVIF_OUTP_V0_DETECT        0x00
+
 #define NVIF_OUTP_V0_ACQUIRE       0x11
 #define NVIF_OUTP_V0_RELEASE       0x12
 
@@ -24,6 +26,16 @@ union nvif_outp_args {
 #define NVIF_OUTP_V0_DP_RETRAIN    0x73
 #define NVIF_OUTP_V0_DP_MST_VCPI   0x78
 
+union nvif_outp_detect_args {
+       struct nvif_outp_detect_v0 {
+               __u8 version;
+#define NVIF_OUTP_DETECT_V0_NOT_PRESENT 0x00
+#define NVIF_OUTP_DETECT_V0_PRESENT     0x01
+#define NVIF_OUTP_DETECT_V0_UNKNOWN     0x02
+               __u8 status;
+       } v0;
+};
+
 union nvif_outp_load_detect_args {
        struct nvif_outp_load_detect_v0 {
                __u8  version;
diff --git a/drivers/gpu/drm/nouveau/include/nvif/outp.h 
b/drivers/gpu/drm/nouveau/include/nvif/outp.h
index fa76a7b5e4b37..c3e1e4d2f1a11 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/outp.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/outp.h
@@ -17,6 +17,15 @@ struct nvif_outp {
 
 int nvif_outp_ctor(struct nvif_disp *, const char *name, int id, struct 
nvif_outp *);
 void nvif_outp_dtor(struct nvif_outp *);
+
+enum nvif_outp_detect_status {
+       NOT_PRESENT,
+       PRESENT,
+       UNKNOWN,
+};
+
+enum nvif_outp_detect_status nvif_outp_detect(struct nvif_outp *);
+
 int nvif_outp_load_detect(struct nvif_outp *, u32 loadval);
 int nvif_outp_acquire_rgb_crt(struct nvif_outp *);
 int nvif_outp_acquire_tmds(struct nvif_outp *, int head,
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c 
b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 68b4fb4bec63f..a290a2844547c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -413,6 +413,7 @@ nouveau_connector_ddc_detect(struct drm_connector 
*connector)
 {
        struct drm_device *dev = connector->dev;
        struct pci_dev *pdev = to_pci_dev(dev->dev);
+       struct nouveau_connector *conn = nouveau_connector(connector);
        struct nouveau_encoder *nv_encoder = NULL, *found = NULL;
        struct drm_encoder *encoder;
        int ret;
@@ -421,33 +422,48 @@ nouveau_connector_ddc_detect(struct drm_connector 
*connector)
        drm_connector_for_each_possible_encoder(connector, encoder) {
                nv_encoder = nouveau_encoder(encoder);
 
-               switch (nv_encoder->dcb->type) {
-               case DCB_OUTPUT_DP:
-                       ret = nouveau_dp_detect(nouveau_connector(connector),
-                                               nv_encoder);
-                       if (ret == NOUVEAU_DP_MST)
-                               return NULL;
-                       else if (ret == NOUVEAU_DP_SST)
-                               found = nv_encoder;
+               if (nvif_object_constructed(&nv_encoder->outp.object)) {
+                       enum nvif_outp_detect_status status;
+
+                       if (nv_encoder->dcb->type == DCB_OUTPUT_DP) {
+                               ret = nouveau_dp_detect(conn, nv_encoder);
+                               if (ret == NOUVEAU_DP_MST)
+                                       return NULL;
+                               if (ret != NOUVEAU_DP_SST)
+                                       continue;
+
+                               return nv_encoder;
+                       } else {
+                               status = nvif_outp_detect(&nv_encoder->outp);
+                               switch (status) {
+                               case PRESENT:
+                                       return nv_encoder;
+                               case NOT_PRESENT:
+                                       continue;
+                               case UNKNOWN:
+                                       break;
+                               default:
+                                       WARN_ON(1);
+                                       break;
+                               }
+                       }
+               }
 
-                       break;
-               case DCB_OUTPUT_LVDS:
+               if (!nv_encoder->i2c)
+                       continue;
+
+               if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS) {
                        switcheroo_ddc = !!(vga_switcheroo_handler_flags() &
                                            VGA_SWITCHEROO_CAN_SWITCH_DDC);
-                       fallthrough;
-               default:
-                       if (!nv_encoder->i2c)
-                               break;
+               }
 
-                       if (switcheroo_ddc)
-                               vga_switcheroo_lock_ddc(pdev);
-                       if (nvkm_probe_i2c(nv_encoder->i2c, 0x50))
-                               found = nv_encoder;
-                       if (switcheroo_ddc)
-                               vga_switcheroo_unlock_ddc(pdev);
+               if (switcheroo_ddc)
+                       vga_switcheroo_lock_ddc(pdev);
+               if (nvkm_probe_i2c(nv_encoder->i2c, 0x50))
+                       found = nv_encoder;
+               if (switcheroo_ddc)
+                       vga_switcheroo_unlock_ddc(pdev);
 
-                       break;
-               }
                if (found)
                        break;
        }
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c 
b/drivers/gpu/drm/nouveau/nouveau_dp.c
index 6a4980b2d4d4e..01aa9b9c74a2a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -132,14 +132,8 @@ nouveau_dp_detect(struct nouveau_connector *nv_connector,
                }
        }
 
-       /* Check status of HPD pin before attempting an AUX transaction that
-        * would result in a number of (futile) retries on a connector which
-        * has no display plugged.
-        *
-        * TODO: look into checking this before probing I2C to detect DVI/HDMI
-        */
-       hpd = nvif_conn_hpd_status(&nv_connector->conn);
-       if (hpd == NVIF_CONN_HPD_STATUS_NOT_PRESENT) {
+       hpd = nvif_outp_detect(&nv_encoder->outp);
+       if (hpd == NOT_PRESENT) {
                nvif_outp_dp_aux_pwr(&nv_encoder->outp, false);
                goto out;
        }
diff --git a/drivers/gpu/drm/nouveau/nvif/conn.c 
b/drivers/gpu/drm/nouveau/nvif/conn.c
index a3cf91aeae2de..879569d4ba4cc 100644
--- a/drivers/gpu/drm/nouveau/nvif/conn.c
+++ b/drivers/gpu/drm/nouveau/nvif/conn.c
@@ -45,20 +45,6 @@ nvif_conn_event_ctor(struct nvif_conn *conn, const char 
*name, nvif_event_func f
        return ret;
 }
 
-int
-nvif_conn_hpd_status(struct nvif_conn *conn)
-{
-       struct nvif_conn_hpd_status_v0 args;
-       int ret;
-
-       args.version = 0;
-
-       ret = nvif_mthd(&conn->object, NVIF_CONN_V0_HPD_STATUS, &args, 
sizeof(args));
-       NVIF_ERRON(ret, &conn->object, "[HPD_STATUS] support:%d present:%d",
-                  args.support, args.present);
-       return ret ? ret : !!args.support + !!args.present;
-}
-
 void
 nvif_conn_dtor(struct nvif_conn *conn)
 {
diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c 
b/drivers/gpu/drm/nouveau/nvif/outp.c
index c24bc5eae3ecf..7f1daab35a0d2 100644
--- a/drivers/gpu/drm/nouveau/nvif/outp.c
+++ b/drivers/gpu/drm/nouveau/nvif/outp.c
@@ -210,6 +210,31 @@ nvif_outp_load_detect(struct nvif_outp *outp, u32 loadval)
        return ret < 0 ? ret : args.load;
 }
 
+enum nvif_outp_detect_status
+nvif_outp_detect(struct nvif_outp *outp)
+{
+       struct nvif_outp_detect_v0 args;
+       int ret;
+
+       args.version = 0;
+
+       ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_DETECT, &args, 
sizeof(args));
+       NVIF_ERRON(ret, &outp->object, "[DETECT] status:%02x", args.status);
+       if (ret)
+               return UNKNOWN;
+
+       switch (args.status) {
+       case NVIF_OUTP_DETECT_V0_NOT_PRESENT: return NOT_PRESENT;
+       case NVIF_OUTP_DETECT_V0_PRESENT: return PRESENT;
+       case NVIF_OUTP_DETECT_V0_UNKNOWN: return UNKNOWN;
+       default:
+               WARN_ON(1);
+               break;
+       }
+
+       return UNKNOWN;
+}
+
 void
 nvif_outp_dtor(struct nvif_outp *outp)
 {
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c 
b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
index b8ac66b4a2c4b..0d2de4769b94f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
@@ -807,6 +807,7 @@ nvkm_dp_func = {
        .dtor = nvkm_dp_dtor,
        .init = nvkm_dp_init,
        .fini = nvkm_dp_fini,
+       .detect = nvkm_outp_detect,
        .acquire = nvkm_dp_acquire,
        .release = nvkm_dp_release,
        .disable = nvkm_dp_disable,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c 
b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c
index 6094805fbd63b..fb061144438dc 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c
@@ -22,11 +22,13 @@
  * Authors: Ben Skeggs
  */
 #include "outp.h"
+#include "conn.h"
 #include "dp.h"
 #include "ior.h"
 
 #include <subdev/bios.h>
 #include <subdev/bios/dcb.h>
+#include <subdev/gpio.h>
 #include <subdev/i2c.h>
 
 void
@@ -207,6 +209,31 @@ nvkm_outp_acquire(struct nvkm_outp *outp, u8 user, bool 
hda)
        return nvkm_outp_acquire_hda(outp, type, user, false);
 }
 
+int
+nvkm_outp_detect(struct nvkm_outp *outp)
+{
+       struct nvkm_gpio *gpio = outp->disp->engine.subdev.device->gpio;
+       int ret = -EINVAL;
+
+       if (outp->conn->info.hpd != DCB_GPIO_UNUSED) {
+               ret = nvkm_gpio_get(gpio, 0, DCB_GPIO_UNUSED, 
outp->conn->info.hpd);
+               if (ret < 0)
+                       return ret;
+               if (ret)
+                       return 1;
+
+               /*TODO: Look into returning NOT_PRESENT if !HPD on DVI/HDMI.
+                *
+                *      It's uncertain whether this is accurate for all older 
chipsets,
+                *      so we're returning UNKNOWN, and the DRM will probe DDC 
instead.
+                */
+               if (outp->info.type == DCB_OUTPUT_DP)
+                       return 0;
+       }
+
+       return ret;
+}
+
 void
 nvkm_outp_fini(struct nvkm_outp *outp)
 {
@@ -328,6 +355,7 @@ nvkm_outp_new_(const struct nvkm_outp_func *func, struct 
nvkm_disp *disp,
 
 static const struct nvkm_outp_func
 nvkm_outp = {
+       .detect = nvkm_outp_detect,
 };
 
 int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h 
b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
index 4e7f873f66e27..8c9fe878f3209 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
@@ -74,6 +74,9 @@ int nvkm_outp_new(struct nvkm_disp *, int index, struct 
dcb_output *, struct nvk
 void nvkm_outp_del(struct nvkm_outp **);
 void nvkm_outp_init(struct nvkm_outp *);
 void nvkm_outp_fini(struct nvkm_outp *);
+
+int nvkm_outp_detect(struct nvkm_outp *);
+
 int nvkm_outp_acquire(struct nvkm_outp *, u8 user, bool hda);
 void nvkm_outp_release(struct nvkm_outp *, u8 user);
 void nvkm_outp_route(struct nvkm_disp *);
@@ -82,6 +85,9 @@ struct nvkm_outp_func {
        void *(*dtor)(struct nvkm_outp *);
        void (*init)(struct nvkm_outp *);
        void (*fini)(struct nvkm_outp *);
+
+       int (*detect)(struct nvkm_outp *);
+
        int (*acquire)(struct nvkm_outp *);
        void (*release)(struct nvkm_outp *);
        void (*disable)(struct nvkm_outp *, struct nvkm_ior *);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c 
b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c
index dad942be6679c..971cccc0892cc 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c
@@ -100,46 +100,6 @@ nvkm_uconn_uevent(struct nvkm_object *object, void *argv, 
u32 argc, struct nvkm_
                               nvkm_uconn_uevent_gpio);
 }
 
-static int
-nvkm_uconn_mthd_hpd_status(struct nvkm_conn *conn, void *argv, u32 argc)
-{
-       struct nvkm_gpio *gpio = conn->disp->engine.subdev.device->gpio;
-       union nvif_conn_hpd_status_args *args = argv;
-
-       if (argc != sizeof(args->v0) || args->v0.version != 0)
-               return -ENOSYS;
-
-       args->v0.support = gpio && conn->info.hpd != DCB_GPIO_UNUSED;
-       args->v0.present = 0;
-
-       if (args->v0.support) {
-               int ret = nvkm_gpio_get(gpio, 0, DCB_GPIO_UNUSED, 
conn->info.hpd);
-
-               if (WARN_ON(ret < 0)) {
-                       args->v0.support = false;
-                       return 0;
-               }
-
-               args->v0.present = ret;
-       }
-
-       return 0;
-}
-
-static int
-nvkm_uconn_mthd(struct nvkm_object *object, u32 mthd, void *argv, u32 argc)
-{
-       struct nvkm_conn *conn = nvkm_uconn(object);
-
-       switch (mthd) {
-       case NVIF_CONN_V0_HPD_STATUS: return nvkm_uconn_mthd_hpd_status(conn, 
argv, argc);
-       default:
-               break;
-       }
-
-       return -EINVAL;
-}
-
 static void *
 nvkm_uconn_dtor(struct nvkm_object *object)
 {
@@ -155,7 +115,6 @@ nvkm_uconn_dtor(struct nvkm_object *object)
 static const struct nvkm_object_func
 nvkm_uconn = {
        .dtor = nvkm_uconn_dtor,
-       .mthd = nvkm_uconn_mthd,
        .uevent = nvkm_uconn_uevent,
 };
 
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c 
b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c
index 440ea52cc7d2b..43752e216ce88 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c
@@ -275,6 +275,29 @@ nvkm_uoutp_mthd_load_detect(struct nvkm_outp *outp, void 
*argv, u32 argc)
        return ret;
 }
 
+static int
+nvkm_uoutp_mthd_detect(struct nvkm_outp *outp, void *argv, u32 argc)
+{
+       union nvif_outp_detect_args *args = argv;
+       int ret;
+
+       if (argc != sizeof(args->v0) || args->v0.version != 0)
+               return -ENOSYS;
+       if (!outp->func->detect)
+               return -EINVAL;
+
+       ret = outp->func->detect(outp);
+       switch (ret) {
+       case 0: args->v0.status = NVIF_OUTP_DETECT_V0_NOT_PRESENT; break;
+       case 1: args->v0.status = NVIF_OUTP_DETECT_V0_PRESENT; break;
+       default:
+               args->v0.status = NVIF_OUTP_DETECT_V0_UNKNOWN;
+               break;
+       }
+
+       return 0;
+}
+
 static int
 nvkm_uoutp_mthd_acquired(struct nvkm_outp *outp, u32 mthd, void *argv, u32 
argc)
 {
@@ -295,6 +318,7 @@ static int
 nvkm_uoutp_mthd_noacquire(struct nvkm_outp *outp, u32 mthd, void *argv, u32 
argc)
 {
        switch (mthd) {
+       case NVIF_OUTP_V0_DETECT     : return nvkm_uoutp_mthd_detect     (outp, 
argv, argc);
        case NVIF_OUTP_V0_ACQUIRE    : return nvkm_uoutp_mthd_acquire    (outp, 
argv, argc);
        case NVIF_OUTP_V0_LOAD_DETECT: return nvkm_uoutp_mthd_load_detect(outp, 
argv, argc);
        case NVIF_OUTP_V0_DP_AUX_PWR : return nvkm_uoutp_mthd_dp_aux_pwr (outp, 
argv, argc);
-- 
2.41.0

Reply via email to