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; struct drm_hdmi_info *hdmi = &nv_connector->base.display_info.hdmi;
union hdmi_infoframe infoframe = { 0 }; union hdmi_infoframe infoframe = { 0 };
const u8 rekey = 56; /* binary driver, and tegra, constant */ const u8 rekey = 56; /* binary driver, and tegra, constant */
u8 scdc = 0;
u32 max_ac_packet; u32 max_ac_packet;
struct { struct {
struct nvif_outp_infoframe_v0 infoframe; 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 -= 18; /* constant from tegra */
max_ac_packet /= 32; 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; const bool high_tmds_clock_ratio = mode->clock > 340000;
u8 scdc;
ret = drm_scdc_readb(nv_encoder->i2c, SCDC_TMDS_CONFIG, &scdc); ret = drm_scdc_readb(nv_encoder->i2c, SCDC_TMDS_CONFIG, &scdc);
if (ret < 0) { if (ret < 0) {
@ -812,8 +812,9 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc,
scdc, ret); scdc, ret);
} }
ret = nvif_outp_acquire_tmds(&nv_encoder->outp, nv_crtc->index, true, ret = nvif_outp_hdmi(&nv_encoder->outp, nv_crtc->index, true, max_ac_packet, rekey,
max_ac_packet, rekey, scdc, hda); mode->clock, hdmi->scdc.supported, hdmi->scdc.scrambling.supported,
hdmi->scdc.scrambling.low_rates);
if (ret) if (ret)
return; return;
@ -1852,7 +1853,6 @@ nv50_pior_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *st
switch (nv_encoder->dcb->type) { switch (nv_encoder->dcb->type) {
case DCB_OUTPUT_TMDS: case DCB_OUTPUT_TMDS:
ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, PROTOCOL, EXT_TMDS_ENC); ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, PROTOCOL, EXT_TMDS_ENC);
nvif_outp_acquire_tmds(&nv_encoder->outp, false, false, 0, 0, 0, false);
break; break;
case DCB_OUTPUT_DP: case DCB_OUTPUT_DP:
ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, PROTOCOL, EXT_TMDS_ENC); 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_LOAD_DETECT 0x20
#define NVIF_OUTP_V0_HDMI 0x50
#define NVIF_OUTP_V0_INFOFRAME 0x60 #define NVIF_OUTP_V0_INFOFRAME 0x60
#define NVIF_OUTP_V0_HDA_ELD 0x61 #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_DAC 0x00
#define NVIF_OUTP_ACQUIRE_V0_SOR 0x01 #define NVIF_OUTP_ACQUIRE_V0_SOR 0x01
#define NVIF_OUTP_ACQUIRE_V0_PIOR 0x02 #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_LVDS 0x03
#define NVIF_OUTP_ACQUIRE_V0_DP 0x04 #define NVIF_OUTP_ACQUIRE_V0_DP 0x04
__u8 type; __u8 type;
@ -73,17 +74,6 @@ union nvif_outp_acquire_args {
struct { struct {
__u8 hda; __u8 hda;
} sor; } 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 { struct {
__u8 dual; __u8 dual;
__u8 bpc8; __u8 bpc8;
@ -128,6 +118,20 @@ union nvif_outp_release_args {
} vn; } 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 { union nvif_outp_infoframe_args {
struct nvif_outp_infoframe_v0 { struct nvif_outp_infoframe_v0 {
__u8 version; __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_dac(struct nvif_outp *);
int nvif_outp_acquire_sor(struct nvif_outp *, bool hda); int nvif_outp_acquire_sor(struct nvif_outp *, bool hda);
int nvif_outp_acquire_pior(struct nvif_outp *); 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_lvds(struct nvif_outp *, bool dual, bool bpc8);
int nvif_outp_acquire_dp(struct nvif_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE], 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); 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; 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_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_hda_eld(struct nvif_outp *, int head, void *data, u32 size);
int nvif_outp_dp_aux_pwr(struct nvif_outp *, bool enable); 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 int
nvif_outp_acquire_tmds(struct nvif_outp *outp, int head, nvif_outp_hdmi(struct nvif_outp *outp, int head, bool enable, u8 max_ac_packet, u8 rekey,
bool hdmi, u8 max_ac_packet, u8 rekey, u8 scdc, bool hda) 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; int ret;
args.tmds.head = head; args.version = 0;
args.tmds.hdmi = hdmi; args.head = head;
args.tmds.hdmi_max_ac_packet = max_ac_packet; args.enable = enable;
args.tmds.hdmi_rekey = rekey; args.max_ac_packet = max_ac_packet;
args.tmds.hdmi_scdc = scdc; args.rekey = rekey;
args.tmds.hdmi_hda = hda; 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, NVIF_ERRON(ret, &outp->object,
"[ACQUIRE proto:TMDS head:%d hdmi:%d max_ac_packet:%d rekey:%d scdc:%d hda:%d]" "[HDMI head:%d enable:%d max_ac_packet:%d rekey:%d khz:%d scdc:%d "
" or:%d link:%d", args.tmds.head, args.tmds.hdmi, args.tmds.hdmi_max_ac_packet, "scdc_scrambling:%d scdc_low_rates:%d]",
args.tmds.hdmi_rekey, args.tmds.hdmi_scdc, args.tmds.hdmi_hda, args.head, args.enable, args.max_ac_packet, args.rekey, args.khz,
args.or, args.link); args.scdc, args.scdc_scrambling, args.scdc_low_rates);
return ret; return ret;
} }

View File

@ -68,15 +68,23 @@ gm200_sor_dp = {
}; };
void 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; struct nvkm_device *device = ior->disp->engine.subdev.device;
const u32 soff = nv50_ior_base(ior); 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); nvkm_mask(device, 0x61c5bc + soff, 0x00000003, ctrl);
ior->tmds.high_speed = !!(scdc & 0x2);
} }
const struct nvkm_ior_func_hdmi const struct nvkm_ior_func_hdmi

View File

@ -65,7 +65,8 @@ struct nvkm_ior_func {
const struct nvkm_ior_func_hdmi { const struct nvkm_ior_func_hdmi {
void (*ctrl)(struct nvkm_ior *, int head, bool enable, u8 max_ac_packet, u8 rekey); 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_avi)(struct nvkm_ior *, int head, void *data, u32 size);
void (*infoframe_vsi)(struct nvkm_ior *, int head, void *data, u32 size); void (*infoframe_vsi)(struct nvkm_ior *, int head, void *data, u32 size);
} *hdmi; } *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 *); void gm200_sor_route_set(struct nvkm_outp *, struct nvkm_ior *);
int gm200_sor_route_get(struct nvkm_outp *, int *); int gm200_sor_route_get(struct nvkm_outp *, int *);
extern const struct nvkm_ior_func_hdmi gm200_sor_hdmi; 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; extern const struct nvkm_ior_func_dp gm200_sor_dp;
void gm200_sor_dp_drive(struct nvkm_ior *, int, int, int, int, int); 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 static int
nvkm_uoutp_mthd_acquire_tmds(struct nvkm_outp *outp, u8 head, u8 hdmi, u8 hdmi_max_ac_packet, nvkm_uoutp_mthd_hdmi(struct nvkm_outp *outp, void *argv, u32 argc)
u8 hdmi_rekey, u8 hdmi_scdc, u8 hdmi_hda)
{ {
union nvif_outp_hdmi_args *args = argv;
struct nvkm_ior *ior = outp->ior; 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; return -EINVAL;
if (hdmi) { if (!ior->func->hdmi ||
if (!ior->func->hdmi || args->v0.max_ac_packet > 0x1f ||
hdmi_max_ac_packet > 0x1f || hdmi_rekey > 0x7f || args->v0.rekey > 0x7f ||
(hdmi_scdc && !ior->func->hdmi->scdc)) (args->v0.scdc && !ior->func->hdmi->scdc))
return -EINVAL; return -EINVAL;
ior->func->hdmi->ctrl(ior, head, hdmi, hdmi_max_ac_packet, hdmi_rekey); ior->func->hdmi->ctrl(ior, args->v0.head, args->v0.enable,
if (ior->func->hdmi->scdc) args->v0.max_ac_packet, args->v0.rekey);
ior->func->hdmi->scdc(ior, hdmi_scdc); 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; return 0;
} }
@ -209,14 +213,6 @@ nvkm_uoutp_mthd_acquire(struct nvkm_outp *outp, void *argv, u32 argc)
case NVIF_OUTP_ACQUIRE_V0_SOR: case NVIF_OUTP_ACQUIRE_V0_SOR:
ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_USER, args->v0.sor.hda); ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_USER, args->v0.sor.hda);
break; 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: case NVIF_OUTP_ACQUIRE_V0_LVDS:
ret = nvkm_uoutp_mthd_acquire_lvds(outp, args->v0.lvds.dual, args->v0.lvds.bpc8); ret = nvkm_uoutp_mthd_acquire_lvds(outp, args->v0.lvds.dual, args->v0.lvds.bpc8);
break; break;
@ -370,6 +366,7 @@ nvkm_uoutp_mthd_acquired(struct nvkm_outp *outp, u32 mthd, void *argv, u32 argc)
{ {
switch (mthd) { switch (mthd) {
case NVIF_OUTP_V0_RELEASE : return nvkm_uoutp_mthd_release (outp, argv, argc); 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_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_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); case NVIF_OUTP_V0_DP_RETRAIN : return nvkm_uoutp_mthd_dp_retrain (outp, argv, argc);