Skip to content

Commit e4060da

Browse files
Lyudekarolherbst
authored andcommitted
drm/nouveau/nvkm/dp: Add workaround to fix DP 1.3+ DPCD issues
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>
1 parent 1cb9e2e commit e4060da

File tree

1 file changed

+47
-1
lines changed
  • drivers/gpu/drm/nouveau/nvkm/engine/disp

1 file changed

+47
-1
lines changed

drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
#include "head.h"
2727
#include "ior.h"
2828

29+
#include <drm/display/drm_dp.h>
30+
2931
#include <subdev/bios.h>
3032
#include <subdev/bios/init.h>
3133
#include <subdev/gpio.h>
@@ -634,6 +636,50 @@ nvkm_dp_enable_supported_link_rates(struct nvkm_outp *outp)
634636
return outp->dp.rates != 0;
635637
}
636638

639+
/* XXX: This is a big fat hack, and this is just drm_dp_read_dpcd_caps()
640+
* converted to work inside nvkm. This is a temporary holdover until we start
641+
* passing the drm_dp_aux device through NVKM
642+
*/
643+
static int
644+
nvkm_dp_read_dpcd_caps(struct nvkm_outp *outp)
645+
{
646+
struct nvkm_i2c_aux *aux = outp->dp.aux;
647+
u8 dpcd_ext[DP_RECEIVER_CAP_SIZE];
648+
int ret;
649+
650+
ret = nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, outp->dp.dpcd, DP_RECEIVER_CAP_SIZE);
651+
if (ret < 0)
652+
return ret;
653+
654+
/*
655+
* Prior to DP1.3 the bit represented by
656+
* DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT was reserved.
657+
* If it is set DP_DPCD_REV at 0000h could be at a value less than
658+
* the true capability of the panel. The only way to check is to
659+
* then compare 0000h and 2200h.
660+
*/
661+
if (!(outp->dp.dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
662+
DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT))
663+
return 0;
664+
665+
ret = nvkm_rdaux(aux, DP_DP13_DPCD_REV, dpcd_ext, sizeof(dpcd_ext));
666+
if (ret < 0)
667+
return ret;
668+
669+
if (outp->dp.dpcd[DP_DPCD_REV] > dpcd_ext[DP_DPCD_REV]) {
670+
OUTP_DBG(outp, "Extended DPCD rev less than base DPCD rev (%d > %d)\n",
671+
outp->dp.dpcd[DP_DPCD_REV], dpcd_ext[DP_DPCD_REV]);
672+
return 0;
673+
}
674+
675+
if (!memcmp(outp->dp.dpcd, dpcd_ext, sizeof(dpcd_ext)))
676+
return 0;
677+
678+
memcpy(outp->dp.dpcd, dpcd_ext, sizeof(dpcd_ext));
679+
680+
return 0;
681+
}
682+
637683
void
638684
nvkm_dp_enable(struct nvkm_outp *outp, bool auxpwr)
639685
{
@@ -689,7 +735,7 @@ nvkm_dp_enable(struct nvkm_outp *outp, bool auxpwr)
689735
memset(outp->dp.lttpr, 0x00, sizeof(outp->dp.lttpr));
690736
}
691737

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

0 commit comments

Comments
 (0)