Skip to content

Commit

Permalink
drm/nouveau/nvkm/dp: Add workaround to fix DP 1.3+ DPCD issues
Browse files Browse the repository at this point in the history
commit e4060da upstream.

Currently we use the drm_dp_dpcd_read_caps() helper in the DRM side of
nouveau in order to read the DPCD of a DP connector, which makes sure we do
the right thing and also check for extended DPCD caps. However, it turns
out we're not currently doing this on the nvkm side since we don't have
access to the drm_dp_aux structure there - which means that the DRM side of
the driver and the NVKM side can end up with different DPCD capabilities
for the same connector.

Ideally in order to fix this, we just want to use the
drm_dp_read_dpcd_caps() helper in nouveau. That's not currently possible
though, and is going to depend on having a bunch of the DP code moved out
of nvkm and into the DRM side of things as part of the GSP enablement work.

Until then however, let's workaround this problem by porting a copy of
drm_dp_read_dpcd_caps() into NVKM - which should fix this issue.

Signed-off-by: Lyude Paul <lyude@redhat.com>
Reviewed-by: Karol Herbst <kherbst@redhat.com>
Link: https://gitlab.freedesktop.org/drm/nouveau/-/issues/211
Link: https://patchwork.freedesktop.org/patch/msgid/20230728225858.350581-1-lyude@redhat.com
(cherry picked from commit cc4adf3 in drm-misc-next)
Cc: <stable@vger.kernel.org> # 6.3+
Signed-off-by: Karol Herbst <kherbst@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Lyude authored and gregkh committed Aug 16, 2023
1 parent e179b05 commit a372c3f
Showing 1 changed file with 47 additions and 1 deletion.
48 changes: 47 additions & 1 deletion drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
Expand Up @@ -26,6 +26,8 @@
#include "head.h"
#include "ior.h"

#include <drm/display/drm_dp.h>

#include <subdev/bios.h>
#include <subdev/bios/init.h>
#include <subdev/gpio.h>
Expand Down Expand Up @@ -474,6 +476,50 @@ nvkm_dp_train(struct nvkm_outp *outp, u32 dataKBps)
return ret;
}

/* XXX: This is a big fat hack, and this is just drm_dp_read_dpcd_caps()
* converted to work inside nvkm. This is a temporary holdover until we start
* passing the drm_dp_aux device through NVKM
*/
static int
nvkm_dp_read_dpcd_caps(struct nvkm_outp *outp)
{
struct nvkm_i2c_aux *aux = outp->dp.aux;
u8 dpcd_ext[DP_RECEIVER_CAP_SIZE];
int ret;

ret = nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, outp->dp.dpcd, DP_RECEIVER_CAP_SIZE);
if (ret < 0)
return ret;

/*
* Prior to DP1.3 the bit represented by
* DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT was reserved.
* If it is set DP_DPCD_REV at 0000h could be at a value less than
* the true capability of the panel. The only way to check is to
* then compare 0000h and 2200h.
*/
if (!(outp->dp.dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT))
return 0;

ret = nvkm_rdaux(aux, DP_DP13_DPCD_REV, dpcd_ext, sizeof(dpcd_ext));
if (ret < 0)
return ret;

if (outp->dp.dpcd[DP_DPCD_REV] > dpcd_ext[DP_DPCD_REV]) {
OUTP_DBG(outp, "Extended DPCD rev less than base DPCD rev (%d > %d)\n",
outp->dp.dpcd[DP_DPCD_REV], dpcd_ext[DP_DPCD_REV]);
return 0;
}

if (!memcmp(outp->dp.dpcd, dpcd_ext, sizeof(dpcd_ext)))
return 0;

memcpy(outp->dp.dpcd, dpcd_ext, sizeof(dpcd_ext));

return 0;
}

void
nvkm_dp_disable(struct nvkm_outp *outp, struct nvkm_ior *ior)
{
Expand Down Expand Up @@ -630,7 +676,7 @@ nvkm_dp_enable(struct nvkm_outp *outp, bool enable)
memset(outp->dp.lttpr, 0x00, sizeof(outp->dp.lttpr));
}

if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, outp->dp.dpcd, sizeof(outp->dp.dpcd))) {
if (!nvkm_dp_read_dpcd_caps(outp)) {
const u8 rates[] = { 0x1e, 0x14, 0x0a, 0x06, 0 };
const u8 *rate;
int rate_max;
Expand Down

0 comments on commit a372c3f

Please sign in to comment.