drm/nouveau/disp: add output hdmi config method

- was previously part of acquire()
- preparation for GSP-RM

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Reviewed-by: Lyude Paul <lyude@redhat.com>
Acked-by: Danilo Krummrich <me@dakr.org>
Signed-off-by: Lyude Paul <lyude@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230919220442.202488-20-lyude@redhat.com
This commit is contained in:
Ben Skeggs 2023-09-19 17:56:14 -04:00 committed by Lyude Paul
parent c0f7b72942
commit 6c6abab20b
7 changed files with 73 additions and 59 deletions

View File

@ -778,7 +778,6 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc,
struct drm_hdmi_info *hdmi = &nv_connector->base.display_info.hdmi;
union hdmi_infoframe infoframe = { 0 };
const u8 rekey = 56; /* binary driver, and tegra, constant */
u8 scdc = 0;
u32 max_ac_packet;
struct {
struct nvif_outp_infoframe_v0 infoframe;
@ -791,8 +790,9 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc,
max_ac_packet -= 18; /* constant from tegra */
max_ac_packet /= 32;
if (hdmi->scdc.scrambling.supported) {
if (nv_encoder->i2c && hdmi->scdc.scrambling.supported) {
const bool high_tmds_clock_ratio = mode->clock > 340000;
u8 scdc;
ret = drm_scdc_readb(nv_encoder->i2c, SCDC_TMDS_CONFIG, &scdc);
if (ret < 0) {
@ -812,8 +812,9 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc,
scdc, ret);
}
ret = nvif_outp_acquire_tmds(&nv_encoder->outp, nv_crtc->index, true,
max_ac_packet, rekey, scdc, hda);
ret = nvif_outp_hdmi(&nv_encoder->outp, nv_crtc->index, true, max_ac_packet, rekey,
mode->clock, hdmi->scdc.supported, hdmi->scdc.scrambling.supported,
hdmi->scdc.scrambling.low_rates);
if (ret)
return;
@ -1852,7 +1853,6 @@ nv50_pior_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st
switch (nv_encoder->dcb->type) {
case DCB_OUTPUT_TMDS:
ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, PROTOCOL, EXT_TMDS_ENC);
nvif_outp_acquire_tmds(&nv_encoder->outp, false, false, 0, 0, 0, false);
break;
case DCB_OUTPUT_DP:
ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, PROTOCOL, EXT_TMDS_ENC);

View File

@ -21,6 +21,8 @@ union nvif_outp_args {
#define NVIF_OUTP_V0_LOAD_DETECT 0x20
#define NVIF_OUTP_V0_HDMI 0x50
#define NVIF_OUTP_V0_INFOFRAME 0x60
#define NVIF_OUTP_V0_HDA_ELD 0x61
@ -62,7 +64,6 @@ union nvif_outp_acquire_args {
#define NVIF_OUTP_ACQUIRE_V0_DAC 0x00
#define NVIF_OUTP_ACQUIRE_V0_SOR 0x01
#define NVIF_OUTP_ACQUIRE_V0_PIOR 0x02
#define NVIF_OUTP_ACQUIRE_V0_TMDS 0x05
#define NVIF_OUTP_ACQUIRE_V0_LVDS 0x03
#define NVIF_OUTP_ACQUIRE_V0_DP 0x04
__u8 type;
@ -73,17 +74,6 @@ union nvif_outp_acquire_args {
struct {
__u8 hda;
} sor;
struct {
__u8 head;
__u8 hdmi;
__u8 hdmi_max_ac_packet;
__u8 hdmi_rekey;
#define NVIF_OUTP_ACQUIRE_V0_TMDS_HDMI_SCDC_SCRAMBLE (1 << 0)
#define NVIF_OUTP_ACQUIRE_V0_TMDS_HDMI_SCDC_DIV_BY_4 (1 << 1)
__u8 hdmi_scdc;
__u8 hdmi_hda;
__u8 pad06[2];
} tmds;
struct {
__u8 dual;
__u8 bpc8;
@ -128,6 +118,20 @@ union nvif_outp_release_args {
} vn;
};
union nvif_outp_hdmi_args {
struct nvif_outp_hdmi_v0 {
__u8 version;
__u8 head;
__u8 enable;
__u8 max_ac_packet;
__u8 rekey;
__u8 scdc;
__u8 scdc_scrambling;
__u8 scdc_low_rates;
__u32 khz;
} v0;
};
union nvif_outp_infoframe_args {
struct nvif_outp_infoframe_v0 {
__u8 version;

View File

@ -31,8 +31,6 @@ int nvif_outp_load_detect(struct nvif_outp *, u32 loadval);
int nvif_outp_acquire_dac(struct nvif_outp *);
int nvif_outp_acquire_sor(struct nvif_outp *, bool hda);
int nvif_outp_acquire_pior(struct nvif_outp *);
int nvif_outp_acquire_tmds(struct nvif_outp *, int head,
bool hdmi, u8 max_ac_packet, u8 rekey, u8 scdc, bool hda);
int nvif_outp_acquire_lvds(struct nvif_outp *, bool dual, bool bpc8);
int nvif_outp_acquire_dp(struct nvif_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE],
int link_nr, int link_bw, bool hda, bool mst);
@ -49,6 +47,9 @@ nvif_outp_acquired(struct nvif_outp *outp)
return outp->or.id >= 0;
}
int nvif_outp_hdmi(struct nvif_outp *, int head, bool enable, u8 max_ac_packet, u8 rekey, u32 khz,
bool scdc, bool scdc_scrambling, bool scdc_low_rates);
int nvif_outp_infoframe(struct nvif_outp *, u8 type, struct nvif_outp_infoframe_v0 *, u32 size);
int nvif_outp_hda_eld(struct nvif_outp *, int head, void *data, u32 size);
int nvif_outp_dp_aux_pwr(struct nvif_outp *, bool enable);

View File

@ -124,25 +124,28 @@ nvif_outp_infoframe(struct nvif_outp *outp, u8 type, struct nvif_outp_infoframe_
}
int
nvif_outp_acquire_tmds(struct nvif_outp *outp, int head,
bool hdmi, u8 max_ac_packet, u8 rekey, u8 scdc, bool hda)
nvif_outp_hdmi(struct nvif_outp *outp, int head, bool enable, u8 max_ac_packet, u8 rekey,
u32 khz, bool scdc, bool scdc_scrambling, bool scdc_low_rates)
{
struct nvif_outp_acquire_v0 args;
struct nvif_outp_hdmi_v0 args;
int ret;
args.tmds.head = head;
args.tmds.hdmi = hdmi;
args.tmds.hdmi_max_ac_packet = max_ac_packet;
args.tmds.hdmi_rekey = rekey;
args.tmds.hdmi_scdc = scdc;
args.tmds.hdmi_hda = hda;
args.version = 0;
args.head = head;
args.enable = enable;
args.max_ac_packet = max_ac_packet;
args.rekey = rekey;
args.khz = khz;
args.scdc = scdc;
args.scdc_scrambling = scdc_scrambling;
args.scdc_low_rates = scdc_low_rates;
ret = nvif_outp_acquire(outp, NVIF_OUTP_ACQUIRE_V0_TMDS, &args);
ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_HDMI, &args, sizeof(args));
NVIF_ERRON(ret, &outp->object,
"[ACQUIRE proto:TMDS head:%d hdmi:%d max_ac_packet:%d rekey:%d scdc:%d hda:%d]"
" or:%d link:%d", args.tmds.head, args.tmds.hdmi, args.tmds.hdmi_max_ac_packet,
args.tmds.hdmi_rekey, args.tmds.hdmi_scdc, args.tmds.hdmi_hda,
args.or, args.link);
"[HDMI head:%d enable:%d max_ac_packet:%d rekey:%d khz:%d scdc:%d "
"scdc_scrambling:%d scdc_low_rates:%d]",
args.head, args.enable, args.max_ac_packet, args.rekey, args.khz,
args.scdc, args.scdc_scrambling, args.scdc_low_rates);
return ret;
}

View File

@ -68,15 +68,23 @@ gm200_sor_dp = {
};
void
gm200_sor_hdmi_scdc(struct nvkm_ior *ior, u8 scdc)
gm200_sor_hdmi_scdc(struct nvkm_ior *ior, u32 khz, bool support, bool scrambling,
bool scrambling_low_rates)
{
struct nvkm_device *device = ior->disp->engine.subdev.device;
const u32 soff = nv50_ior_base(ior);
const u32 ctrl = scdc & 0x3;
u32 ctrl = 0;
ior->tmds.high_speed = khz > 340000;
if (support && scrambling) {
if (ior->tmds.high_speed)
ctrl |= 0x00000002;
if (ior->tmds.high_speed || scrambling_low_rates)
ctrl |= 0x00000001;
}
nvkm_mask(device, 0x61c5bc + soff, 0x00000003, ctrl);
ior->tmds.high_speed = !!(scdc & 0x2);
}
const struct nvkm_ior_func_hdmi

View File

@ -65,7 +65,8 @@ struct nvkm_ior_func {
const struct nvkm_ior_func_hdmi {
void (*ctrl)(struct nvkm_ior *, int head, bool enable, u8 max_ac_packet, u8 rekey);
void (*scdc)(struct nvkm_ior *, u8 scdc);
void (*scdc)(struct nvkm_ior *, u32 khz, bool support, bool scrambling,
bool scrambling_low_rates);
void (*infoframe_avi)(struct nvkm_ior *, int head, void *data, u32 size);
void (*infoframe_vsi)(struct nvkm_ior *, int head, void *data, u32 size);
} *hdmi;
@ -167,7 +168,7 @@ void gm107_sor_dp_pattern(struct nvkm_ior *, int);
void gm200_sor_route_set(struct nvkm_outp *, struct nvkm_ior *);
int gm200_sor_route_get(struct nvkm_outp *, int *);
extern const struct nvkm_ior_func_hdmi gm200_sor_hdmi;
void gm200_sor_hdmi_scdc(struct nvkm_ior *, u8);
void gm200_sor_hdmi_scdc(struct nvkm_ior *, u32, bool, bool, bool);
extern const struct nvkm_ior_func_dp gm200_sor_dp;
void gm200_sor_dp_drive(struct nvkm_ior *, int, int, int, int, int);

View File

@ -137,24 +137,28 @@ nvkm_uoutp_mthd_infoframe(struct nvkm_outp *outp, void *argv, u32 argc)
}
static int
nvkm_uoutp_mthd_acquire_tmds(struct nvkm_outp *outp, u8 head, u8 hdmi, u8 hdmi_max_ac_packet,
u8 hdmi_rekey, u8 hdmi_scdc, u8 hdmi_hda)
nvkm_uoutp_mthd_hdmi(struct nvkm_outp *outp, void *argv, u32 argc)
{
union nvif_outp_hdmi_args *args = argv;
struct nvkm_ior *ior = outp->ior;
if (!(outp->asy.head = nvkm_head_find(outp->disp, head)))
if (argc != sizeof(args->v0) || args->v0.version != 0)
return -ENOSYS;
if (!(outp->asy.head = nvkm_head_find(outp->disp, args->v0.head)))
return -EINVAL;
if (hdmi) {
if (!ior->func->hdmi ||
hdmi_max_ac_packet > 0x1f || hdmi_rekey > 0x7f ||
(hdmi_scdc && !ior->func->hdmi->scdc))
return -EINVAL;
if (!ior->func->hdmi ||
args->v0.max_ac_packet > 0x1f ||
args->v0.rekey > 0x7f ||
(args->v0.scdc && !ior->func->hdmi->scdc))
return -EINVAL;
ior->func->hdmi->ctrl(ior, head, hdmi, hdmi_max_ac_packet, hdmi_rekey);
if (ior->func->hdmi->scdc)
ior->func->hdmi->scdc(ior, hdmi_scdc);
}
ior->func->hdmi->ctrl(ior, args->v0.head, args->v0.enable,
args->v0.max_ac_packet, args->v0.rekey);
if (ior->func->hdmi->scdc)
ior->func->hdmi->scdc(ior, args->v0.khz, args->v0.scdc, args->v0.scdc_scrambling,
args->v0.scdc_low_rates);
return 0;
}
@ -209,14 +213,6 @@ nvkm_uoutp_mthd_acquire(struct nvkm_outp *outp, void *argv, u32 argc)
case NVIF_OUTP_ACQUIRE_V0_SOR:
ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_USER, args->v0.sor.hda);
break;
case NVIF_OUTP_ACQUIRE_V0_TMDS:
ret = nvkm_uoutp_mthd_acquire_tmds(outp, args->v0.tmds.head,
args->v0.tmds.hdmi,
args->v0.tmds.hdmi_max_ac_packet,
args->v0.tmds.hdmi_rekey,
args->v0.tmds.hdmi_scdc,
args->v0.tmds.hdmi_hda);
break;
case NVIF_OUTP_ACQUIRE_V0_LVDS:
ret = nvkm_uoutp_mthd_acquire_lvds(outp, args->v0.lvds.dual, args->v0.lvds.bpc8);
break;
@ -370,6 +366,7 @@ nvkm_uoutp_mthd_acquired(struct nvkm_outp *outp, u32 mthd, void *argv, u32 argc)
{
switch (mthd) {
case NVIF_OUTP_V0_RELEASE : return nvkm_uoutp_mthd_release (outp, argv, argc);
case NVIF_OUTP_V0_HDMI : return nvkm_uoutp_mthd_hdmi (outp, argv, argc);
case NVIF_OUTP_V0_INFOFRAME : return nvkm_uoutp_mthd_infoframe (outp, argv, argc);
case NVIF_OUTP_V0_HDA_ELD : return nvkm_uoutp_mthd_hda_eld (outp, argv, argc);
case NVIF_OUTP_V0_DP_RETRAIN : return nvkm_uoutp_mthd_dp_retrain (outp, argv, argc);