Commit a69eeb37 authored by Ben Skeggs's avatar Ben Skeggs Committed by Lyude Paul

drm/nouveau/disp: add output detect method

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: default avatarBen Skeggs <bskeggs@redhat.com>
Reviewed-by: default avatarLyude Paul <lyude@redhat.com>
Acked-by: default avatarDanilo Krummrich <me@dakr.org>
Signed-off-by: default avatarLyude Paul <lyude@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230919220442.202488-8-lyude@redhat.com
parent 21636b1a
......@@ -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
......@@ -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
......@@ -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;
......
......@@ -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,
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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)
{
......
......@@ -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)
{
......
......@@ -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,
......
......@@ -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
......
......@@ -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 *);
......
......@@ -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,
};
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment