summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/conn.h5
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/if0011.h11
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dp.c12
-rw-r--r--drivers/gpu/drm/nouveau/nvif/conn.c14
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c43
6 files changed, 88 insertions, 3 deletions
diff --git a/drivers/gpu/drm/nouveau/include/nvif/conn.h b/drivers/gpu/drm/nouveau/include/nvif/conn.h
index ad52cdafef18..f72a8f138f47 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/conn.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/conn.h
@@ -10,4 +10,9 @@ struct nvif_conn {
int nvif_conn_ctor(struct nvif_disp *, const char *name, int id, struct nvif_conn *);
void nvif_conn_dtor(struct nvif_conn *);
+
+#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 *);
#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0011.h b/drivers/gpu/drm/nouveau/include/nvif/if0011.h
index 9c910b29a730..04ba6581f840 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/if0011.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/if0011.h
@@ -9,4 +9,15 @@ union nvif_conn_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/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index c36f510d5d4c..20db8ea1a0ba 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -107,7 +107,7 @@ nouveau_dp_detect(struct nouveau_connector *nv_connector,
struct nv50_mstm *mstm = nv_encoder->dp.mstm;
enum drm_connector_status status;
u8 *dpcd = nv_encoder->dp.dpcd;
- int ret = NOUVEAU_DP_NONE;
+ int ret = NOUVEAU_DP_NONE, hpd;
/* If we've already read the DPCD on an eDP device, we don't need to
* reread it as it won't change
@@ -133,6 +133,16 @@ 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)
+ goto out;
+
status = nouveau_dp_probe_dpcd(nv_connector, nv_encoder);
if (status == connector_status_disconnected)
goto out;
diff --git a/drivers/gpu/drm/nouveau/nvif/conn.c b/drivers/gpu/drm/nouveau/nvif/conn.c
index a83b8a4a57e6..4ce935d58c90 100644
--- a/drivers/gpu/drm/nouveau/nvif/conn.c
+++ b/drivers/gpu/drm/nouveau/nvif/conn.c
@@ -26,6 +26,20 @@
#include <nvif/class.h>
#include <nvif/if0011.h>
+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/nvkm/engine/disp/conn.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c
index febc5c274488..7ed11801a3ae 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c
@@ -86,6 +86,7 @@ nvkm_conn_ctor(struct nvkm_disp *disp, int index, struct nvbios_connE *info,
conn->disp = disp;
conn->index = index;
conn->info = *info;
+ conn->info.hpd = DCB_GPIO_UNUSED;
CONN_DBG(conn, "type %02x loc %d hpd %02x dp %x di %x sr %x lcdid %x",
info->type, info->location, info->hpd, info->dp,
@@ -100,11 +101,12 @@ nvkm_conn_ctor(struct nvkm_disp *disp, int index, struct nvbios_connE *info,
ret = nvkm_gpio_find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func);
if (ret) {
- CONN_ERR(conn, "func %02x lookup failed, %d",
- info->hpd, ret);
+ CONN_ERR(conn, "func %02x lookup failed, %d", info->hpd, ret);
return;
}
+ conn->info.hpd = func.line;
+
ret = nvkm_notify_init(NULL, &gpio->event, nvkm_conn_hpd,
true, &(struct nvkm_gpio_ntfy_req) {
.mask = NVKM_GPIO_TOGGLED,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c
index 3fbbb6e6a66b..fd9f18144c26 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c
@@ -22,8 +22,50 @@
#define nvkm_uconn(p) container_of((p), struct nvkm_conn, object)
#include "conn.h"
+#include <subdev/gpio.h>
+
#include <nvif/if0011.h>
+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)
{
@@ -39,6 +81,7 @@ nvkm_uconn_dtor(struct nvkm_object *object)
static const struct nvkm_object_func
nvkm_uconn = {
.dtor = nvkm_uconn_dtor,
+ .mthd = nvkm_uconn_mthd,
};
int